본문 바로가기

Let's Study/Hacking Technique

stack corruption basic

요즘은 Buffer Overflow 라는 표현보다 Stack corruption, Heap Corruption이라는 표현을 쓰더라구요.


저도 트랜드(?)에 맞춰서 스택커럽션이라는 표현을 쓰도록 할게요.




시스템 포스팅을 시작하기에 앞서 시스템 해킹이 뭔지 알아보겠습니다.





우선, 간단하게 취약한 코드를 코딩합니다. 

환경은 공지사항에도 올려놨듯이,  ubuntu 14.04, 커널환경은 linux 3.13.0-36-generic 입니다.


컴파일 옵션에 -fno-stack-protector, mpreferred-stack-boundary=2 옵션을 주었는데


-fno-stack-protector 를 걸면 컴파일된 프로그램에 메모리보호기법인 ssp(stack-smashing-protector) 를 걸지 않습니다. 카나리(canary)라고 하던가요. 카나리에 관련된 것은 나중에 올리도록 하겠습니다.


-mpreferred-stack-boundary=2  는 컴파일 최적화옵션을 풀어버립니다. 어느분 블로그에서는 스택영역을 2byte단위로 할당한다고 표현을 했네요. 



buf의 크기는 128이고 strcpy로 argv[1]의 문자열을 복사하여 출력하는 단순한 코드입니다.

untrusted input인 strcpy가 사용되었으므로 저는 이것을 이용하여 스택커럽션을 시도합니다.






(화면을 한번에 보여드리려고 gdb 창을 하나 더 띄웠으므로 오른쪽 pid는 신경쓰지 말아주세요.)


set disassembly-flavor intel   옵션으로 intel 어셈표현으로 바꿔주고  b* main 으로 브레이크포인트를 건 후 실행하여 

shell ps   stack의 pid를 확인합니다.

확인한 pid를 이용하여  shell cat /proc/(pid)/maps 명령어로 이 프로그램의 권한을 확인합니다.


확인해보면 코드영역과 vdso영역에 실행권한이 있지만 stack에는 없습니다. 그러므로 스택에 쉘코드를 이용한 공격은 할 수 없습니다.




이 리눅스 환경에서는 ASLR 기법도 걸려있기 때문에 주소도 랜덤하게 바뀝니다. 


ASLR을 해제해주기 위해서 ulimit -s unlimited  명령어를 씁니다.




umlimit -s unlimited  옵션을 주게 되면 스택에 제한되어있는 메모리공간을 해제합니다.스택이 더이상 확장하지 못할정도로 limit를 풀어버리는데 이것 때문에 스택에 한해서 ASLR은 작동하지 않습니다.




이제 슬슬 공격퍼즐을 찾습니다.  x/200x 0x8048000 명령어로 드영역에서 ASCII로 표현되는 글자를 찾습니다.

저는 0x0804821c에 있는 0x39를 이용하도록 하겠습니다. 그리고 p system 으로 시스템의 주소값을 출력합니다.


공격을 실행할 폴더에서 cp /bin/sh ./9  명령어로 9라는 실행파일을 생성하여 거기에 /bin/sh를 집어넣고 

export PATH=.:$PATH 로 9라는 명령어를 환경변수에 추가해줍니다. 


(9에는 /bin/sh 가 있지만 실제로 system 인자에는 9 라는 명령어를 쓸 수 없으므로 (system("9")) export PATH 를 이용해 현재 폴더를 환경변수 추가해줍니다.)



..? system의 주소 뒤에 "\x00"이 있네요. 패치됬나;; 망했네. 뒤에 0x00이 있을 경우 payload를 작성할 때에 return address 뒤에 


쓰레기값을 넣을 때 그 쓰레기값이 저기 0x00을 채우게 되서 엉뚱한 주소를 가리키게 됩니다.



RTL을 보여드리려고 했는데 우분투 패치를 착실하게 해주는 바람에 RTL은 못하게 됬습니다.

(그러나 system 함수 외에 0x00이 쓰이지 않은 함수는 쓸 수 있습니다.)

만약 system의 주소 뒤에 0x00이 없을 경우의 payload는

 ./stack `perl -e 'print "a" x 132, "\x00\xa1\x07\x40", "aaaa", "\x1c\x82\x04\x08"'` 가 됩니다. 

시스템의 주소와 string의 주소 사이의 "aaaa"는 다음에 알려드릴 것 같은데 다음 함수의 return address를 가르킵니다. 근데 다음에 호출할 함수가 없기 때문에 쓰레기값으로 채웠습니다.



코드를 바꾸고 간단한 stack corruption을 하겠습니다.





gdb로 fuck이라는 함수에 들어가서 주소를 확인해줍니다. 이것은 코드영역의 주소를 참조하기 때문에 ulimit -s unlimited 필요없습니다.


./stack `perl -e 'print "a" x 132, "\xb7\x84\x04\x08"'`

로 128바이트만큼 buf를 채워주시고 그 뒤에 4바이트는 ebp영역인데 이것도 쓰레기값으로 4바이트 마저 채워주신후 (128 + 4 = 132) return address 영역에 0x080484b7 주소를 입력해주시면 main이 끝나고 libc_start_main 영역으로 넘어가야 하는데 fuck의 주소로 넘어가게 됩니다.



보통 시스템 해킹을 하면 pwn 문제를 많이 풀게 될 것이고 리눅스를 많이 접하게 되실 건데

여러가지 기법을 이용하여 eip(다음 실행될 주소의 위치를 나타냅니다)를 컨트롤 하는 게 시스템해킹의 목표입니다.