Pintool을 이용한 CTF 풀이 (withcon 2017 - crackme)
왜 솔버가 아닌 사이드채널 어택이었는지
IDA로 열어봤을 때,
- 의미없는 연산이 굉장히 많았습니다.
- 솔버를 돌리기엔 correct, fail에 대한 주소값을 찾을 수가 없었습니다.
correct, fail에 대한 주소가 고정적으로 참조되는 경우에는 솔버로 풀 수 있겠지만, 이 문제의 경우 그 주소가 연산중에 동적으로 결정되었습니다.
Pintool 셋팅
icount예제 컴파일
핀툴의 예제파일 중 instruction을 카운트해주는 예제인 icount.cpp를 컴파일 환경이 마련되어있는 MyPinTool/MyPinTool.cpp로 복사해줍니다.
purelledhand@purelledhand:~/tools/pin-3.6/source/tools/SimpleExamples$ cp icount.cpp ../MyPinTool/MyPinTool.cpp
컴파일 후 obj-intel64 디렉토리와 so파일이 생성된 것을 확인할 수 있습니다.
purelledhand@purelledhand:~/tools/pin-3.6/source/tools/MyPinTool$ make
purelledhand@purelledhand:~/tools/pin-3.6/source/tools/MyPinTool$ ls obj-intel64/
MyPinTool.o MyPinTool.so
실행
purelledhand@purelledhand:~/tools/pin-3.6$ ./pin -t source/tools/MyPinTool/obj-intel64/MyPinTool.so -- ../../week5/crackme
PASSCODE : A
FAILED
Count 151993
exploit
from pwn import *
import string
import operator
password = ""
inscount = dict()
FLAG=True
before_cnt = 151993
while FLAG:
inscount = {}
for i in range(len(string.printable)):
p = process(["./pin","-t" ,"source/tools/MyPinTool/obj-intel64/MyPinTool.so", "--", "../../week5/crackme"])
p.sendline(password + string.printable[i])
res = p.recv()
cut = p.recvuntil('Count [')
if "FAILED" not in cut:
print "PASSWORD : " + password + string.printable[i]
FLAG = False
break;
cnt = p.recvall()[:-2]
p.close()
if cnt > before_cnt :
inscount[password + string.printable[i]] = cnt
before_cnt = cnt
password = sorted(inscount.items(), key=operator.itemgetter(1), reverse=True)[0][0]
before_cnt = sorted(inscount.items(), key=operator.itemgetter(1), reverse=True)[0][1]
FLAG
purelledhand@purelledhand:~/tools/pin-3.6$ python ex.py
PASSWORD : H4PPyW1THC0nCTF!