※ 질문/내용오류/공유할 내용이 있다면 jinkilee73@gmail.com으로 메일 주세요 :-)


정말 오랜만에 글을 쓴다. 무려 1달 이상 글을 안 썼다. 공부를 안 해서 그런게 아니다. (이 블로그를 계속 봐온 사람이라면 그런 생각은 안 할것이라고 생각한다.) 어려웠다. 조금ㅠ 회사가 조금 바쁘기도 했다. 그러니 조금 이해해주었으면 한다. 솔직히 말하면 회사가 바빴던 것은 사실이나 공부했던 것이 어려워서?는 아닌 것 같다. 이미 이전부터 다 공부했었던 내용을 실제 쉘코드 수행으로 연결시키려는 단순한 시도였을 뿐인데 그것이 조금 오래걸렸던 것 뿐이다. 아무튼 공부한 내용들을 적어보자. 

참고로 내가 요즘 공부하고 있는 책은 Hacking : the art of exploitation 이라는 책이다. 개인적으로 공격 방법만을 설명하는 책은 매우 싫어하는 편인데 이 책은 어느 정도 기본기도 설명을 해주고 있다. 특히나 GDB 사용법(조만간 자세하게 포스팅할 예정이다.), 프로시저 호출하는 과정, 혹은 다른 low level technique에 대한 설명을 생략하지 않고 상대적으로!! 자세히 설명해둔 책이다. 물론 생판 초보자는 이 책을 보고 절대 이해할 수 없다. 절대!! 서론이 길다. 아무튼 본론으로 들어가자.

나를 괴롭혔던 것은 이 책에서 나오는 notesearch.c를 exploit하기 위한 exploit_notesearch.c 라는 프로그램이다. 책에 따르면 exploit_notesearch를 실행하면 쉘코드가 실행된다고 하는데 잘 안되더라. 그래서 이것만 공부하느라 조금 시간이 걸렸던 것이다. 

우선 notesearch라는 프로그램을 이해하려면 notetaker를 먼저 이해해야한다. notetaker는 각 사용자가 자기만의 메모를 저장하는 프로그램이다. 


해당 사용자로 저장한 노트를 찾는 것이 notesearch 프로그램이다.


I love you 라는 문자열 위에 This is a note for jose는 이전에 테스트로 저장해뒀던 문자열이므로 혼동하지 않기를 바란다. notetaker와 notesearch는 이러한 프로그램이다. exploit_notesearch는 notesearch를 통해서 공격자가 의도한 코드를 수행하기 위한 프로그램이다. 우리가 수행해보려고 하는 exploit_notesearch.c의 코드는 아래와 같다. (당연히 공격자가 작성한 코드가 되겠다.)


위 코드의 목표는 간단하게 말하면 공격자가 원하는 문구로 문자열을 잘 조작해서 36번째 라인에서 system(command)명령어를 통해 notesearch를 실행하는 것이다. 잘 읽어보면 알겠지만 command라는 char* 변수는 아래와 같이 선언되게 되어있다.


무슨 말인지 모르겠지만 아무튼 exploit_notesearch를 실행하게 되면 위와 같은 이상한 문자열의 argument를 notesearch를 통해 실행하게 된다. 그리고 그 결과는 공격자의 shellcode 실행이 되겠다. notesearch를 통해 실행하게 될 그 문자들을 자세하게 보면 다음과 같다.


해당 문자열은 buffer라는 변수에 저장되기 때문에 x/80x buffer와 같이 gdb를 수행해서 그 값을 확인해봤다. 아무튼 저 값들이 무슨 값인지 알아보도록 하자. 


0x90은 NOP이다. No Operation의 약자이다. 즉 아무것도 하지 않는 명령어라는 뜻이다. 그런데 오해하지 않았으면 한다. 진짜 아무것도 안 하는 것은 아니다. 정확히 말하면 딱 하나 한다. %eip 레지스터를 다음에 수행할 address로 옮기는 역할을 한다. NOP는 1바이트 크기의 명령어이기 때문에 0x804b016부터 0x804b051까지 1바이트씩 NOP이 체워져있는 것이고 0x804b016부터 차례대로 eip의 값을 1씩(NOP은 1바이트이기 때문에) 증가시켜서 0x804b051까지 수행된다. 그 다음에 0x804b052에 있는 0xdb31c031를 수행하게 된다. 여기서부터가 공격자가 정말로 수행하고 싶어하는 쉘코드이다. 그 쉘코드가 어떻게 생겼는지 보자.


위와 같은 쉘코드를 실행하게 된다. 위의 쉘코드에 대한 분석은 각자 하시길 바란다. 해보면 정말 도움이 될만한 사실을 발견할 수 있다. 아무튼 위의 명령어를 완벽하게 수행을 하게 되면 우리는 shell을 띄울 수 있게 된다. 다들 알겠지만 shell은 명령어 해석기이다. ls라고 쳤을 때 ls라는 명령어를 shell이 해석해주기 때문에 우리는 ls 명령어를 수행할 수 있는 것이다. 즉 shell을 띄운다는 것은 공격자가 하고 싶은 명령어를 모두 실행할 수 있게 되는 것과 같다. 보안상 굉장히 무시무시한 것이다. 공격자가 조작한 코드는 아래와 같을 수 있다.


마지막에 0xbffff5ae라는 값으로 일정길이만큼 체워진다는 것을 포인트다. 이제는 공격자가 만든 문자열도 알겠다. 그런데 저게 왜 실행될까? 이제부터 우리가 생각해야할 것은 procedure call이다. procedure call에서 스택구조로 메모리에 값이 쌓인다는 것을 우리는 알아야 한다. 


exploit_notesearch를 수행했을 경우 위와 같은 스택 구조를 볼 수 있게 된다. 당연히  exploit_notesearch의 main frame이 stack의 가장 상위에 있을 것이고 36번째 줄에서 system명령어가 수행되면서 다른 함수들이 몇 개 쌓인 후 notesearch에 대한 스택 역시 쌓이게 될 것이다.


모든 공격은 정(正)도를 알고 난 후에 제대로 이해가 가능하기 때문에 notesearch 프로그램이 정상적으로 수행될 경우 어떻게 수행되는지 한번 알아보자. 예를 들어 I love you 라는 문자열을 찾을 경우 아래와 같이 메모리가 보이게 된다.


보면 I love you 라는 문자열이 0xbffff65c부터 증가하는 방향으로 쌓이고 있다는 것을 알 수 있다. 위의 프로그램이 ./notesearch "I love you"를 실행했을 때의 메모리 결과라고 했을 때 공격자가 의도한 아래의 방식으로 실행했다면 어떻게 되었을까?


0xbffff65c부터 증가하는 방향으로 위의 문자열들이 덮어씌어질 것이다. 그러면서 결국 건드리면 안 되는 곳인 return address(0xbffff6dc)까지 덮어씌어지게 된다. 이렇게 될 경우 프로그램은 원래 돌아가야 할 곳이 아닌 엉뚱한 곳으로 가서 그곳에서 instruction을 실행하게 된다. 공격자가 의도한 코드에 따르면 아래와 같이 return address가 변형될 수 있다.


0xbfaa851e라는 숫자로 0xbfb9b458 이후의 값이 변경되었다. 이제 위의 프로그램은 notesearch를 마친 후 0xbfaa851e로 점프하여 그 곳을 실행하게 될 것이다. 그런데 그곳은 현재 공격자가 의도한 값이 아닌 엉뚱한 값이 있을 것이어서 공격은 실패하게 된다.


그러면 어떻게 해야 공격이 성공하는가? 바로 return address가 0xbfb9b41c부터 0xbfb9b454 사이 값으로 초기화 될 때 성공한다. 그곳의 값이 0x9090.. 즉, NOP이기 때문에 NOP이라는 미끄럼틀을(NOP Sled) 타고 내려와서 실제 shellcode인 0xbfb9b458부터 실행을 가능하게 한다. 공격이 성공할 경우 아래와 같이 shell을 띄우게 된다


아무튼 저렇게 실행이 된다. 조금더 이해하기 쉽게 설명을 하면 아래와 같은 그림으로 설명할 수 있겠다.


exploit_notesearch에서 ret이라는 변수를 추측하는 것이 관건이다. main stack 아래로 몇 번째 칸에 notesearch stack이 쌓일지를 잘 예상해야하며 exploit_notesearch.c에서는 그 값을 대략 270(offset = 270)으로 잡았다. (그 값을 변경할 수 있도록 if 문을 통해 기능을 추가해주기도 했다.)


따라서 ret의 값을 0x90909090...값 범위(NOP range) 안으로 추측해내기 전까지는 이 무조건 실패한다. 


이제 exploit_notesearch.c를 모두 설명했다. 그런데 여기서 한 가지 더 고려해야할 부분이 있다. ret을 잘 추측해서 NOP range에 해당하는 주소값으로 notesearch의 return address를 변경해서 정상적으로 %eip값이 NOP range 사이의 값으로 변경되었다고 치자. 그런데 보통 stack은 non-executable이다. 따라서 %eip값이 아무리 정확한 값을 가지고 있어도 실행이 불가능하다. non-executable이니까. 이 책에서 이렇게 해도 가능하다고 하는 이유는 아마도 의도적으로 한참전의 리눅스 버전을 사용해서 그런 것 같다. (독자들의 이해를 위해) 아주 예전에는 stack이 executable해서 실행이 가능했다고 한다. 이런 것을 불가능하게 하기 위해서 stack을 non-executable하게 설계를 했던 것이다. 


이것을 편법으로 가능하게 하는 방법이 있다. execstack이라는 프로그램을 사용하면 된다. 이 프로그램으로는 stack을 executable하게 바꿀 수 있다. 물론 편법이다. 


아직 실행은 안 해봤지만 이 방법을 쓰지 않고 가능한 방법을 추측하면 return address를 heap의 어느 부분으로 가리키고 heap을 executable하게 하는 C 함수를 사용해서 실행할 heap 부분만 executable하게 바꾸면 되지 않을까 싶다. 이것은 독자들에게 스스로 해보도록 내버려두고 싶다. 이 부분에 대해서는 설령 내가 성공했다고 하더라도 포스팅을 하지는 않을 생각이다. 


다음 포스팅은 정해져있지는 않지만 아마도 GDB 사용법이나 ELF 파일 포멧에 관하여 일듯 하다.



'Vulnerability' 카테고리의 다른 글

[Vul] Shellshock (CVE-2014-6271)  (6) 2014.10.25
[Vul] CVE-2012-1823 Vulnerability  (1) 2014.01.21
[Vul] Format String Vulnerability  (1) 2013.11.23
[Vul] Slowloris DoS Tool  (0) 2013.10.28
[Vul] DEDECMS SQL Injection  (1) 2013.08.12
Posted by 빛나유
,