Intro
Gần đây thì team mình có rủ nhau tham gia cuộc thi CTF Namhamcon2022 và nhờ sự try hard của mọi người, team cũng kết thúc giải ở vị trí top 200 của cuộc thi😂. Qua cuộc thi này, mọi người cũng học được thêm nhiều trick và skill mới 😍. Mình cũng tham gia với anh em trong team một vài bài web và rev. Sau cuộc thi, xem trên CTF thì đã có rất nhiều writeup, tuy nhiên các bài rev thì có vẻ lại không hút người đọc lắm😢 (mãi sau CTF 1-2 tuần mới có người viết, mà lại còn không đủ hết các challenges💔), tiện có sự kiện Viblo Mayfest nên mình viết writeup cho các rev (Reverse Engineering) challenges: babyrev, Kamikaze, Time Machine luôn 🤪. Gét gô!
Phần một chúng ta sẽ bắt đầu bằng một challenge easy: babyrev 👶
babyrev
(ảnh chôm của team khác)
Author: @birch#9901
Point: 392
Rating: easy
Aw look! Baby is using a disassembler!
File binary: https://mega.nz/file/W1FETbZR#v6xyPDxwUWhdJZTyBFu3jltHf62HyQXeUaVOxfRskGM
Vâng, giải CTF nào thì tất nhiên sẽ có những bài dễ dễ baby rồi. Check thử xem file là gì:
➜ rev file babyrev
babyrev: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=1a48d52c4e5d664115f6cd11651f9c688e8198db, for GNU/Linux 3.2.0, stripped
Chạy thử xem thế nào:
➜ rev ./babyrev
Welcome to baby's first rev! :>
Please enter your username: vigo
Please enter your password: password
vigo? I don't know you... stranger danger...%
ok fine, chương trình yêu cầu nhập vào username và password, nếu đúng thì chắc là sẽ trả ra flag?
Load file vào IDA, tìm đến hàm main và bấm decompile 😈
Code khá là tường minh rồi (level easy mà):
- username nhập vào sẽ được lưu ở
s1
và so sánh vớibossbaby
nếu không đúng thì thoát. - password nhập vào sẽ được lưu ở
v5
sau đó đưa vào hàmsub_12B2
, kết quả trả về bằng 38 thì là đúng.
Đi tiếp vào hàm sub_12B2
chúng ta có:
Right-click và chọn
Hide casts
cho dễ nhìn nhé
Đổi tên tham số của hàm thành password
và một số biến khác để dễ hiểu hơn:
Ở đây có một đoạn khá rối rắm, tạm thời chưa cần quan tâm vội (thực ra là do mình lười đọc 🤣):
while ( buffer != (buffer - (v2 & 0xFFFFFFFFFFFFF000LL)) )
;
v3 = alloca(v2 & 0xFFF);
if ( (v2 & 0xFFF) != 0 )
*(&buffer[-1] + (v2 & 0xFFF)) = *(&buffer[-1] + (v2 & 0xFFF));
Chú ý đến dòng 29:
((&sub_1208 + 1))(same_pass, buffer);
Đây là một đoạn gọi hàm, truyền vào 2 tham số là password của chúng ta và một buffer, tuy nhiên IDA đã decompile sai (hoặc là trick anti-debug của tác giả) dẫn đến hàm đúng phải có địa chỉ là sub_1209
. Kiểm tra thử hàm sub_1208
, ta cũng thấy báo lỗi như sau:
Ok, let's fix that. Đầu tiên là undefine hết đoạn code này đi:
Sau đó click chọn ở địa chỉ .text:0000000000001209
, chuyển thành code:
vẫn ở địa chỉ đó, giờ chúng ta Create function...
:
bấm F5 lần nữa và Voilà:
Hàm này có nhiện vụ tính toán giá trị của các phần tử trong mảng buffer
dựa trên giá trị các ký tự của password. Biến a1
tương ứng với password, biến a2
tương ứng với buffer
theo lệnh call ở trên. Kết quả lưu vào các phần tử kích thước 4 bytes. Vậy là chúng ta cũng không cần quan tâm đoạn code rối rắm ở trên nữa vì đằng nào thì giá trị của buffer cũng sẽ được thiết lập ở đây.
Quay lại với hàm sub_12B2
, ở vòng for cuối cùng:
for ( i = 0; ; ++i )
{
v4 = i;
if ( v4 >= strlen(same_pass) )
break;
if ( dword_4020[i] == *(same_buffer + i) )
++result;
}
return result
Kết quả tính toán trên password được lưu vào same_buffer
, các giá trị này sẽ được so sánh với giá trị lưu sẵn trong binary ở dword_4020
, nếu đúng sẽ tăng result
thêm 1, cuối cùng trả về kết quả này. Để có được password ban đầu (và cũng chính là flag) ta cần đảo ngược thuật toán của sub_1209
với đầu vào là các phần tử của mảng dword_4020
:
Flag sẽ có độ dài là 38 ký tự.
Kiểm tra dword_4020
trong IDA:
Đúng chuẩn mảng 38 phần tử luôn . Như vậy ta đã có đủ các dữ kiện để tìm ra flag:
Code nhanh đoạn script để decode ra flag như sau:
magic = [0x66, 0x0D9, 0x188, 0x341, 0x7C0, 0x6F9, 0x18A4, 0x95, 0x10A, 0x1D5, 0x37C, 0x3A9, 0x7B0, 0x1969, 0x127, 0x1A3, 0x1C4, 0x2B9, 0x754,
0x889, 0x0F50, 0x1F0, 0x254, 0x2D9, 0x558, 0x571, 0x924, 0x1019, 0x342, 0x3AD, 0x508, 0x6E9, 0x0A30, 0x10E1, 0x1284, 0x500, 0x5D2, 0x74D]
flag = ""
for i in range(38):
flag += chr((magic[i] - i * i) >> (i % 7))
print(flag)
Kết quả: