하하하 이것은 쓸만함 나한테는 재미있는데 다른 사람에게는 ㅋㅋㅋ
w00t@ubuntu:~/Desktop/ctf-tokyo/reverse$ ./reverse_box usage: ./reverse_box flag w00t@ubuntu:~/Desktop/ctf-tokyo/reverse$ ./reverse_box AAAAAAAAAAAAA e0e0e0e0e0e0e0e0e0e0e0e0e0 w00t@ubuntu:~/Desktop/ctf-tokyo/reverse$ ./reverse_box A e0 w00t@ubuntu:~/Desktop/ctf-tokyo/reverse$ ./reverse_box AA e0e0 w00t@ubuntu:~/Desktop/ctf-tokyo/reverse$ ./reverse_box AB e04f w00t@ubuntu:~/Desktop/ctf-tokyo/reverse$ ./reverse_box AC e079 w00t@ubuntu:~/Desktop/ctf-tokyo/reverse$ ./reverse_box BC 4f79 w00t@ubuntu:~/Desktop/ctf-tokyo/reverse$ |
파일의 정보를 보면
w00t@ubuntu:~/Desktop/ctf-tokyo/reverse$ file reverse_box reverse_box: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=5403acba0427c34695b1ebda8f0c678905b33456, stripped w00t@ubuntu:~/Desktop/ctf-tokyo/reverse$ |
그다음은 아이다에서 열고
이렇게 보니까 쉬워보이는데 그 당시는 매우 어려워 보였음
풀이 방법은 크게 2가지임
1. 로직을 분석해서 파이썬 코드로 변환한 사람
2. gdb에 디버깅 걸어서 1~256 대입한 사람
3. LiLi 가 푼 방법
오늘 소개할 방법은 LiLi가 푼 무식한 방법과
gdb 의 x 옵션을 걸어서 나이스하게 푼 방법을 소개함
나이스한 방법은 https://github.com/TeamContagion/CTF-Write-Ups/tree/master/TokyoWesterns-2016/Reverse%20Box 에 있는 내용을 한글로 번역함
이런 방법을 지금까지 몰랐다는 것은 함정!
LiLi가 푼 방법
프로그램을 분석해 보니
프로그램에서 1바이트만 가지고 와서 일정 위치의 바이트를 가져온다고 알고 있음
그래서 프로그램을 패치한 다음 255번 돌림
위를 몇 바이트 고쳐서 아래와 같이 패치함 그러면 입력된 길이만큼이 아니라 255 바이트 만큼 출력하도록 함
그래서 파이썬으로 프로그램을 읽어서 다시 1바이트 패치를 한 다음 출력하도록 함 이렇게 255번을 돌림
import struct #대상 프로그램을 읽음 f=open('reverse_box_p','rb') buf=f.read() #1바이트 패치함, 시드값의 자리 def mk(k): f2=open('reverse_box_p_01','wb') f2.write(buf[:0x5B5]+struct.pack("B",k)+buf[0x5B6:]) #고고 함수 def gogo(h): mk(h) #패치된 프로그램을 실행하며 변경된 메모리값을 1~255까지 출력하게 함 ans='' #filters output import subprocess proc = subprocess.Popen(['./reverse_box_p_01','A'],stdout=subprocess.PIPE) while True: line = proc.stdout.readline() if line != '': #the real code does filtering here ans = line.rstrip() else: break #키 값을 메모리에서 특정값을 읽어오는 offset 값임 key='95eeaf95ef94234999582f722f492f72b19a7aaf72e6e776b57aee722fe77ab5ad9aaeb156729676ae7a236d99b1df4a' print ans i=0 flag='' while i<len(key): k = key[i:i+2] a = find_c(k,ans) if a>0: flag += chr(a) else: break i+=2 #플래그 값을 출력함 print flag #메모리(버퍼)에서 오프셋값을 읽어오는 함수 #복호화 하는 함수 이므로 암호값이 몇번째에 있었으냐가 플레인의 값임 def find_c(s,ans): i=0 while i<256: if (s==ans[i:i+2]): return i/2 i+=2 return -1 #0부터 254까지 시드 값을 입력함 for k in range(255): gogo(k) |
위 프로그램을 실행한 결과 플래그가 출력됨
= 2^ TWCTF{5UBS717U710N_C1PH3R_W17H_R4ND0M123D_5-B0X} {FD{WT N B |
아이고 되다. 그리고 나이스하게 푼 쪽은 아래과 같다. 추가 설명은 영어가 있으니 생략한다.
# gdb ./reverse_box -x solve.py Breakpoint 2, 0x080486db in ?? () Breakpoint 1, 0x080485b1 in ?? () Breakpoint 3, 0x080486e0 in ?? () [Inferior 1 (process 46588) exited normally] TWCTF{5UBS717U710N_C1PH3R_W17H_R4ND0M123D_5-B0X} (gdb) q |
위에서 사용한 solve.py 소스
|
'CTF' 카테고리의 다른 글
[tum ctf 2016] haggis - crpyto (0) | 2016.10.03 |
---|---|
[SCTF 2016] pwn2 한땀 한땀 ROP read /bin/sh (0) | 2016.09.16 |
[tokyo ctf 2016]greeting (0) | 2016.09.06 |
[plaidCTF]butterfly (0) | 2016.04.19 |
bctf2016-bcloud (0) | 2016.03.21 |