Saturday, January 30, 2016

MatesCTF (tháng 01/2016) re300 writeup


Binary không khó, tìm ra trick debug + suy luận thuật toán tí (vài tiếng đối với mình) là ra. LOL :3
Binary khá "dị", compiler = Borland C++, đuôi .exe nhưng load vào ollydbg fail, load vào IDA thì được nhưng tất nhiên là không F5 được. Gúc một lúc thì biết đây là file 16bit windows và chạy thông qua ntvdm.exe (olly, IDA không hỗ trợ debug trực tiếp file 16bit, nguyên nhân hồi sau sẽ rõ. Ntvdm là 1 file đặc biệt của windows, nó cho phép chạy file 16bit windows trên windows 32, 64bit - ntvdm có thể coi là 1 dạng máy ảo dos). _https://en.wikipedia.org/wiki/Virtual_DOS_machine#Windows_NTVDM
Vì thế, nếu bấm trực tiếp vào binary sẽ thấy hiện lên thêm tiến trình của ntvdm.exe
Có nhiều cách để debug file này, có thể dùng ida, olly attack vô ntvdm.exe (mình chưa làm cách này, nhưng m nghĩ là được), hoặc tìm 1 debugger cho phép disassembly và debug trực tiếp (cách mình làm). Công cụ mình sử dụng là _openwatcom.org
Sau khi download về mò mẫm 1 hồi tìm được cách debug file dạng này. File cần tìm \binw\wd.exe.
Chạy file đó, chỉnh open binary (có thể có một vài lỗi lằng nhằng ở bước này như không support fullscreen, mất chuột khi chạy trên win7, win8,....). Màn hình debug gần giống windbg, coi được register, flag, disassembly,....
Trick vậy là xong, tiến hành debug 1 hồi thì đến thuật toán check key:
- ký tự nằm từ 0-9, A-Z 
- key nhập vào gồm 24 ký tự sau đó được chia làm 6 block, tạm gọi từ a1-a6 (4 char/block). Ví dụ nhập vào 12345678....  thì a1= 1234, a2 = 5678 (mỗi block được xử lý thành 1 word)
- với mỗi block (ví dụ a1= ABCD), sẽ có thêm 1 giá trị đi kèm (mình gọi là sig). Nếu a1 > 0x7fff thì sig_a1 = 0xffff, ngược lại sig_a1 = 0. Hình dưới là phần thuật toán check key chính:
Thuật toán check key được mô tả như sau:
1.a6 -a1 = 0xa2ff 
2.sig_a6  - (sig_a1+carry_flag) ==0  
3.a1 - a2 = 912 tuong tu
4.sig_a1 - (sig_a2+carry_flag) ==0 
5.a2 - a3 = 5b6a             
6.sig_a2 - (sig_a3+carry_flag) == 0xffff
7.a3-a4 = b5f0  
8.sig_a3 - (sig_a4 + carry_flag) ==0
9.a4 -a5 = 3a4b
10.sig_a4 - (sig_a5 + carry_flag) ==-1
11.a6+a5 = bca0
12.sig_a6 + sig_a5 + carry_flag ==0

Tính toán, suy luận, quay cóp cẩn thận ta sẽ tính ra được
a1,a2,a4 > 0x7fff. a3, a5,a6 < 0x7fff (bước này nếu không để ý cộng luôn biểu thức 1, 3,5,7,9,11 rồi tính được a6 trước là sai luôn).
Final:
maxA = 0x7fff
for a6 in xrange(0,maxA+1):
a5 = 0xbca0 - a6
a1 = 0xffff- (0xa2ff-a6 - 1)
a2 = a1 -0x912
if a2 > 0x7fff:
a3 = a2 - 0x5b6a
a4 = 0xffff-(0xb5f0-a3-1)
if a4 > 0x7fff:
tmp = a4-0x3a4b
if tmp ==a5:
print hex(a1),hex(a2),hex(a3),hex(a4),hex(a5),hex(a6)

Tìm được a1,...a6, nhập lại theo thứ tự và lượm flag. :v