Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
titleOffset
gdb-peda$ vmmap
Start      End        Perm	Name
...
0xf7e00000 0xf7fad000 r-xp	/lib32/libc-2.23.so
0xf7fad000 0xf7fae000 ---p	/lib32/libc-2.23.so
0xf7fae000 0xf7fb0000 r--p	/lib32/libc-2.23.so
0xf7fb0000 0xf7fb1000 rw-p	/lib32/libc-2.23.so
...
gdb-peda$ p/x 0xf7e49020 - 0xf7e00000
$2 = 0x49020
gdb-peda$ p __kernel_sigreturn
$3 = {<text variable, no debug info>} 0xf7fd8de0 <__kernel_sigreturn>
gdb-peda$ p/x 0xf7fd8de0 - 0xf7e00000
$4 = 0x1d8de0

gdb-peda$ find "/bin/sh"
Searching for '/bin/sh' in: None ranges
Found 1 results, display max 1 items:
libc : 0xf7f5902b ("/bin/sh")
gdb-peda$ p/x 0xf7f5902b - 0xf7e00000
$5 = 0x15902b
gdb-peda$

Find Gadgets

  • 기본적으로 다음과 같이 해당 Memory Map에서 필요한 Gadgets을 찾을 수 있습니다.

Offset of __kernel_sigreturn 

  • 다음과 같이 __kernel_sigreturn() 함수를 Exploit에 사용할 수 있습니다.
    • 0xf7fd8de0 주소를 사용할 경우 "pop eax" 명령어가 포함되어 있기 때문에 0xf7fd8de0 호출 뒤에 임의의 값(4bit)이 저장되어야 합니다.
      • Ex) __kernel_sigreturn() + 임의의 값(4bit) + sigcontext 구조체
    • 0xf7fd8de1 주소를 사용할 경우 "mov eax,0x77" 명령어가 실행되기 때문에 0xf7fd8de1 호출 뒤에 sigcontext 구조체가 저장되어야 합니다.

      • Ex) __kernel_sigreturn() + sigcontext 구조체


Code Block
title__kernel_sigreturn()
gdb-peda$ x/3i 0xf7fd8de0
=> 0xf7fd8de0 <__kernel_sigreturn>:	pop    eax
   0xf7fd8de1 <__kernel_sigreturn+1>:	mov    eax,0x77
   0xf7fd8de6 <__kernel_sigreturn+6>:	int    0x80
gdb-peda$ 


Find Gadgets

  • 기본적으로 다음과 같이 해당 Memory Map에서 필요한 Gadgets을 찾을 수 있습니다.
Panel
titlelist of gadgets for different systems
OSASLRGadgetMemory MapFixed Memory Location
Linux i386(tick)sigreturn[vdso]
Linux x86-64(tick)sigreturnLibc
Linux < 3.3 x86-64(error)syscall & return[vsyscall]0xffffffffff600000
Linux
Panel
titlelist of gadgets for different systems
OSASLRGadgetMemory MapFixed Memory Location
Linux i386(tick)sigreturn[vdso]Linux x86-64(tick)sigreturnLibc
Linux < 3.3 x86-64(error)syscall & return[vsyscall]0xffffffffff600000
Linux ≥ 3.3 x86-64(tick)syscall & returnLibc
FreeBSD 9.2 x86-64(error)sigreturn
0x7ffffffff000
Mac OSX x86-64(tick)sigreturnLibc
iOS ARM(tick)sigreturnLibsystem
iOS ARM(tick)syscall & returnLibsystem
Linux < 3.11 ARM(error)sigreturn[vectors]0xffff0000
  • 테스트 프로그램이 32bit이기 때문에 sigreturn() 함수를 vdso 영역에서 확인 할 수 있습니다.
Code Block
titlevdso
gdb-peda$ p __kernel_sigreturn
$6 = {<text variable, no debug info>} 0xf7fd8de0 <__kernel_sigreturn>
gdb-peda$ x/3i 0xf7fd8de0
   0xf7fd8de0 <__kernel_sigreturn>:	pop    eax
   0xf7fd8de1 <__kernel_sigreturn+1>:	mov    eax,0x77
   0xf7fd8de6 <__kernel_sigreturn+6>:	int    0x80
gdb-peda$ vmmap
Start      End        Perm	Name
...
0xf7fd5000 0xf7fd8000 r--p	[vvar]
0xf7fd8000 0xf7fda000 r-xp	[vdso]
...
gdb-peda$ 

CS(Code segment) & SS(Stack Segment)

  • SROP의 Exploit code를 작성할 때 중요한 부분이 있습니다.

    • sigcontext 구조체 형태로 stack에 값을 저장할 때 최소한 CS, SS레지스터에 대한 값을 설정해야합니다.

  • Linux kernel에는 4개의 세그먼트만 존재합니다.

    • 공격 코드들은 User Mode에서 실행되기 때문에 0x23, 0x2b가 사용됩니다.

    • 이외의 값을 저장하게 되면 에러가 발생하게됩니다.

  • sigreturn() 함수를 vdso 영역에서 확인 할 수 있습니다.
Code Block
titlevdso
gdb-peda$ p __kernel_sigreturn
$6 = {<text variable, no debug info>} 0xf7fd8de0 <__kernel_sigreturn>
gdb-peda$ x/3i 0xf7fd8de0
   0xf7fd8de0 <__kernel_sigreturn>:	pop    eax
   0xf7fd8de1 <__kernel_sigreturn+1>:	mov    eax,0x77
   0xf7fd8de6 <__kernel_sigreturn+6>:	int    0x80
gdb-peda$ vmmap
Start      End        Perm	Name
...
0xf7fd5000 0xf7fd8000 r--p	[vvar]
0xf7fd8000 0xf7fda000 r-xp	[vdso]
...
gdb-peda$ 

CS(Code segment) & SS(Stack Segment)

  • SROP의 Exploit code를 작성할 때 중요한 부분이 있습니다.

    • sigcontext 구조체 형태로 stack에 값을 저장할 때 최소한 CS, SS레지스터에 대한 값을 설정해야합니다.

  • Linux kernel에는 4개의 세그먼트만 존재합니다.

    • 공격 코드들은 User Mode에서 실행되기 때문에 User Code, User Data / Stack 값을 사용해야 합니다.
    • 그리고 32bit 프로그램의 경우 실행되는 운영체제(32bit / 64bit) 환경에 따라 사용되는 세그먼트 값이 다릅니다.
      • 32bit 운영체제에서는 0x73, 0x7b가 사용횝니다.
      • 62bit 운영체제에서는 실행되는 32bit 프로그램의 경우 0x23, 0x2b가 사용됩니다.
    • 이외의 값을 저장하게 되면 에러가 발생하게됩니다.

Panel
titleSegment
PurposeSegment(32bit)Segment(64bit - 32bit)

Kernel Code

0x600x8

Kernel Data / Stack

0x680x18
User Code0x730x23
User Data / Stack0x7b0x2b
Code Block
languagecpp
titlehttps://elixir.bootlin.com/linux/v4.4/source/arch/x86/include/asm/segment.h#L44
#ifdef CONFIG_X86_32

...

#define GDT_ENTRY_TLS_MIN		6
#define GDT_ENTRY_TLS_MAX 		(GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1)

#define GDT_ENTRY_KERNEL_CS		12
#define GDT_ENTRY_KERNEL_DS		13
#define GDT_ENTRY_DEFAULT_USER_CS	14
#define GDT_ENTRY_DEFAULT_USER_DS	15
#define GDT_ENTRY_TSS			16
#define GDT_ENTRY_LDT			17
#define GDT_ENTRY_PNPBIOS_CS32		18
#define GDT_ENTRY_PNPBIOS_CS16		19
#define GDT_ENTRY_PNPBIOS_DS		20
#define GDT_ENTRY_PNPBIOS_TS1		21
#define GDT_ENTRY_PNPBIOS_TS2		22
#define GDT_ENTRY_APMBIOS_BASE		23
Code Block
languagecpp
firstline153
titlehttps://elixir.bootlin.com/linux/v4.4/source/arch/x86/include/asm/segment.h#L153
linenumberstrue
#else /* 64-bit: */

#include <asm/cache.h>

#define GDT_ENTRY_KERNEL32_CS		1
#define GDT_ENTRY_KERNEL_CS		2
#define GDT_ENTRY_KERNEL_DS		3

/*
 * We cannot use the same code segment descriptor for user and kernel mode,
 * not even in long flat mode, because of different DPL.
 *
 * GDT layout to get 64-bit SYSCALL/SYSRET support right. SYSRET hardcodes
 * selectors:
 *
 *   if returning to 32-bit userspace: cs = STAR.SYSRET_CS,
 *   if returning to 64-bit userspace: cs = STAR.SYSRET_CS+16,
 *
 * ss = STAR.SYSRET_CS+8 (in either case)
 *
 * thus USER_DS should be between 32-bit and 64-bit code selectors:
 */
#define GDT_ENTRY_DEFAULT_USER32_CS	4
#define GDT_ENTRY_DEFAULT_USER_DS	5
#define GDT_ENTRY_DEFAULT_USER_CS	6
...
Info
Panel
titleSegment
PurposeSegment

Kernel Code

0x8

Kernel Data / Stack

0x18
User Code0x23
User Data / Stack0x2b
Info

Exploit code

  • 다음과 같이 Exploit code를 작성 할 수 있습니다.

...