Chào các bạn, lần này thì mình cùng 1 số người bạn tham gia giải MeePwnCTF 2018 và cảm nhận được hành như thế nào :( . Kết thúc cuộc thi mình làm được 4 bài crypto và sau đây sẽ là write up của mình
1 - Bazik
sau một hồi test thử các function thì mình nhận ra:
1 - pubkey thay đổi qua mỗi session, (e = 3)
2 - Test OTP có dạng: 'Your OTP for transaction #731337 in ABCXYZ Bank is XXXXXXXXX.'
=> RSA thôi hehe, mà có plain trả về dạng thế này thì Stereotyped messages attack thôi.
Và đây là kết quả:
Code sage: find_secret.sage
2 - Ezchall
Đây là 1 bài crypto mà cho dạng web, với chỉ chức năng register thôi, đầu tiên vào là mình reg thử và nhận thấy như sau
okay fake flag :))))
Oke got it!!
chú ý đường link :
http://206.189.92.209/ezchallz/users/e07750a9bde7c37bbb59580fc7348b6d/flag.php
'e07750a9bde7c37bbb59580fc7348b6d', 32 char có thể là md5 chăng
Thử thay thế đường dẫn trên:
http://206.189.92.209/ezchallz/users/md5('admin').hexdigest()/flag.php
404 - Page not found =))) lulz
Sau một lúc không biết làm tiếp như thế nào, thì nghĩ nhỡ md5 xor phát với cái key thì sao? Check thử thôi, lấy 2 cái md5 từ reg, xor vs md5 gốc nếu ra 2 cái key giống nhau thì hiểu rồi =)))
Và may mắn là đã guess đúng :)))
lấy key đó XOR vs md5('admin') rồi lấy flag thôi
3 - Old School
Đề bài cho ta 3 part gồm n,e,c (RSA)
Part 3:
Vì part 3 có source nên mình làm part 3 trước
Nhìn qua thì ta biết đây là dạng 1 nửa bit đầu của p, ta có thể recover lại tất cả p,q. Sau đó thì decode RSA lấy part3 flag
Hoàn toàn có thể recover sấp sỉ tmp, sau đó wrap around cận trên p với 2**512. Dùng small_roots() sage để tìm ra phần dư từ đó tính được p ban đầu
code: high_bit_known.sage
Futher reading: http://inaz2.hatenablog.com/entry/2016/01/20/022936
Part 1:
Đề cho n,e,c thì chỉ biết factor thôi, thử fermat và ta được part 1
code: fermat.sage
Part2:
Đây có lẽ là phần hấp dẫn nhất và sử dụng não nhiều hơn các part khác. Mục tiêu vẫn là factor :( . Ngày thứ 7 cắm cho máy factor đến sáng mà không kết quả gì :))). thôi thì ngẫm lại xem có gì đặc biệt không ✌
hex(n) đặc biệt vlllll :))))
Đến đây mình liên tưởng đến 2 số rất lớn 0x1 XXXXX (X số 0) YYYY( tận cùng là một số nào đó) nhân với nhau ( 2 số có cùng độ dài =)))) Magic là đây)
Bạn có thấy đặc biệt là ở khúc giữa và khúc cuối là 1 số khác 0 :thinking:
Lúc này mình không để ý thằng ở giữa lắm, factor cái đuôi đã:
a = 159194337501875828204387406768511796461 (hex = 77c3b6d3012f12b2fa0d5cd648ea44ed)
b = 66531009071759863663973548083717500837 (hex = 320d6800aa755d7d82fd10a9e61a6fa5)
2 số mình nêu ban đầu có dạng như thế, để ý thêm hex(n) 0x10000010000.....
thế thì một trong 2 số phải có dạng 0x1000001000... ở đầu, bây h tìm 2 số thỏa như trên (cùng độ dài), nhân lại có độ dài như n. Đến đây thì có thể biết được số ở giữa sinh ra ntn rồi, do thằng số 1 trong 0x1000001000… khi nhân vs 0x1000000000…
Thử 2 phát thôi, p = 0x1000001000…77c3b6d3012f12b2fa0d5cd648ea44ed
và p = 0x1000001000…320d6800aa755d7d82fd10a9e61a6fa5
kết quả:
Thật ra thì cách làm của mình không có cơ sở toán học gì cả, mình chỉ cảm nhận và làm thử, may mắn là ra :))) . Ban đầu cũng cay vl vì ra 2/3 flag.
BTW, tks @btmd for this interesting challenge.
4 - ESOR
Vì một số lý do nên mình up code server và file xinetd để các bạn có thể chạy local và thử nhé.
Còn đây là code:
Bài này mã hóa AES_CBC + hmac để tăng phần security (lúc này là khỏi inject gì vào luôn=)))) ) và điều khá là lạ là ở hàm pad() và unpad() không phải theo PKCS7. Server lại cho ta option check xem cipher valid hay invalid ( chắc là padding oracle rồi :)))) ). Nhưng mà có phải PKCS7 đâu =))) lulz
Dựa vào pad() tìm len(flag) thôi
ta thấy prefix = 'a'*12 thì cipher tăng thêm 1 block => len_flag = 80 - 12 - 20(hmac_length) = 48
Vậy: len_flag = 48 ( 3 block).
Sau một hồi search thì đọc được WU của anh l4wio link thì biết đây là POODLE ATTACK.
Ý tưởng là lợi dụng hàm unpad() và option 2 để check payload có valid hay không từ đó decrypt được từng byte trong flag. Bài của a l4wio đã giải thích khá rõ nên mình xin phép up code thôi.
Code: link
Và kết quả:
BTW, tks @qd for this cool challenge.
Cảm ơn các bạn đã dành thời gian để đọc WU của mình
[*] WU của nghiadt 3 bài babysandbox, image_crackme và white snow and black snow [*]
1 - BabySandBox[100pts]-Pwnable
Service sau khi truyền payload sẽ đưa vào Unicorn framework để chạy sandbox thử. Nếu chạy thấy sử dụng các ngắt đã bị filter thì sẽ cho ra kết quả “Bad Syscal”
Dễ dàng thấy
Initialize stack:
mu.reg_write(UC_X86_REG_ESP,ADDRESS+0x200000)
Để phát hiện ra sandbox, ta có thể kiểm tra esp có đúng bằng 0x1200000 không .
MOV EAX,ESP
CMP EAX,012000000h
JE Out
Shellcode:
Out:
Vì không thể tương tác với console nên ta sử dụng kỹ thuật reverse shell.
exploit: link
2 - Image_crackme
Phán đoán được binary được build bằng golang.
Kiểm tra hàm main
Trace 1 lúc ta thấy được follow của chương trình:
B1: Đọc ảnh, map ảnh img vào mem.
B2: Gen ra 1 ảnh WxH pixel[i][j]=B(img[i][j])*input[(i*160+j)%len(input)])
B3: Gen ra file txt
Từ bước 2 , do chương trình sử dụng repeat cipher và ta đã có file ascii và binary nên ta không cần quan tâm thuật toàn gen ở Bước 3 ra sao mà ta có thể brute ra được flag.
Brute với fake flag Mee*********** được length của flag ra 33.
Để cho code brute đơn giản, ta chỉ cần so sánh trên dòng đầu.
Kết quả thu được là MeePw{{g0l4ng_Asc11Art_1S+4wS0me}
Fix lại flag cho khớp với file .bak là MeePwn{g0l4ng_Asc11Art_1S_4wS0me}
Code: link
3) White Snow, Black Shadow
Giải nén ra được file evidence.jpg
Dễ thấy trong file evidence.jpg còn chứa 1 PK Header Lấy nó ra ta được file zip.
Bỏ file zip lên https://extract.me/ giải nén hộ.
Ta được 1 file PDF.
Ctrl+A nội dung của File paste vào notepad ta sẽ thấy Flag ẩn sau các khoảng trống.
Flag: MeePwnCTF{T3xt_Und3r_t3Xt!!!!}