[SVATTT Quals 2017]

Không như thường lệ, lần nếu này bạn nào vào đây đọc để kiếm #thịphi thì có lẽ sẽ thất vọng =))

À thì nói chung là lần này đi thi thì cũng may mắn, được vào chung kết, nên cũng cảm thấy vui vẻ, cũng có tí #thịphi mà thôi, bỏ qua cho cuộc đời tươi sáng.

Nhân có mấy bạn hỏi write-up, nên mình viết vài bài mình làm được, cho nó vui nhà vui cửa. Cuộc sống mà, cứ vui đi, có gì đâu mà buồn.

1. Forensics 100.

Mặc dù trong team mình hay làm crypto, nhưng gặp một bài forensics, và chỉ có 100 điểm thì dại gì không làm, nhỉ =))

À ờ, đó là trong trường hợp bình thường thôi. Chứ trường hợp cái file pcap đề cho nó đến hai mươi mấy MB thì cũng hơi… ngán đó =))

Load vào wireshark, nói thật là file pcap trừ khi có mấy protocol lạ lạ, còn lại thì cũng có mấy dạng, làm nhiều thì quen tay thôi. File pcap này có khá nhiều http protocol, nên việc đầu tiên mình làm là File / Export Objects / HTTP

Screen Shot 2017-11-05 at 3.32.55 PM

Forensics, giống như người ta ném bạn vào đống rác, sau đó bảo bạn tìm cho ra cờ, nằm trong tờ giấy gói bánh mì vậy. Bới tung đống rác lên để tìm:

Screen Shot 2017-11-05 at 3.36.06 PM

nothing.py à =)) không tin, lừa nhau à =)) Save file lại, mở ra xem thử:

Screen Shot 2017-11-05 at 3.39.15 PM

Thuật toán chỉ đơn giản là cộng xong xor, vậy giờ làm ngược lại thôi, xor xong trừ thôi. Mình thì lười, nên mình copy hàm cộng, đổi tên biến, sửa dấu cộng thành dấu trừ…

Screen Shot 2017-11-05 at 3.44.32 PM

2. Crypto 100.

Mình khá là bất ngờ khi nhìn vào dashboard, chỉ có một bài forensics và đến ba bài crypto, lại có đến hai bài 100. Hy vọng không quá khó, chứ mang tiếng chơi crypto, làm không được thì cũng… ahihi.

Download file về, giải nén, mở source encrypt.py lên đọc:

e, có N, chắc là RSA. Quăng vào factordb.com, tạch =))

Xem kỹ hơn, ta thấy e quá nhỏ và N không quá lớn, đây là nguồn gốc của đủ thể loại tấn công RSA trên đời. c ban đầu bằng 0, vậy block đầu tiên của message sẽ là căn bậc ba của block ciphertext đầu tiên.

Screen Shot 2017-11-05 at 4.00.05 PM

Ơ nhưng mà tới đây rồi sao nữa =)) thấy hơi ngáo ngáo rồi =)) mình stuck ở đây luôn =))

Và rồi một tiếng sau đó, mình nhận ra rằng, cuộc sống này thật đáng buồn. Đã code sẵn cái lib chuyên trị RSA, tự nhiên tới lúc cần thì không lấy ra xài =))

Screen Shot 2017-11-05 at 4.05.02 PM

Mọi chuyện đã quá dễ dàng khi ta có pq

3. Web 100.

Bài này, là cái bài mình thấy khó hiểu nhất. Lần đầu tiên, mình thấy tất cả đề cho đều là thật, trừ cái flag troll.

Tóm tắt ngắn gọn: check robots.txt, thấy /.git/, dùng gitdumper lôi source về, vào trang admin.php, có flag.

Screen Shot 2017-11-05 at 4.13.06 PM

Submit, fail -_- bị lừa.

Qua trang index.php:

Screen Shot 2017-11-05 at 4.14.17 PM

Mình chỉ muốn nói, đôi khi chúng ta không tin vào những thứ mắt mình đang thấy, nhưng nó lại là sự thật.

Server tắt mất rồi, nên xem tạm log qua Burp nhé các bạn =))

Screen Shot 2017-11-05 at 4.17.04 PM

Screen Shot 2017-11-05 at 4.17.52 PM

Conclusion: Nói chung là cũng vui, teammates great, các trường bạn cũng rất tuyệt. Hẹn các bạn miền Bắc ở Đà Nẵng.

P.s: À nếu bạn nữ team áo trắng #Akira có đọc được bài này thì cho mình xin fb, sđt các kiểu nha :ethen:

Update: Unsolved problem

4. Crypto100

  1. DES-CBC, blocksize = 8.
  2. Seed (dùng để sinh key) chỉ có 2 bytes, có thể brute-force được.
  3. Xác định length của challenge: len(challenge) in range(24, 48). Trong trường hợp len(challenge) == 48, cấu trúc ciphertext trả về sẽ là:8 bytes IV | 48 bytes challenge | 8 bytes padding ("\x08" * 8)

—> Request lên server đến khi nào nhận được ciphertext có length là 256 (hex-encoded), brute-force key để decrypt last 2-blocks của ciphertext (một block là IV, block còn lại là ciphertext), nếu 8 bytes cuối sau khi decrypt là “\x08” * 8 thì xác định được key.

[Tokyo Westerns/MMA CTF 2nd 2016] – Twin Primes, ESPer

Here is my solution idea for Twin Primes and ESPer, two crypto challenges in Tokyo Westerns/MMA CTF 2nd 2016.

[Twin Primes]

Link: OfficialMirror

Look at the “encrypt.py” file, we know that the flag was encrypted by RSA cryptosystem twice, first with n1 = p*q and second with n2 = (p+2)*(q+2). By doing a simple math, we know p+q = (n2 – n1 -4)/2 and p*q = n1, so that we can get p and q by solving a simple quadratic equation “find two numbers when know their sum and product.”

[ESPer]

 nc cry1.chal.ctf.westerns.tokyo 37992 

After connecting and bypassing the boring proof_of_work, the server will generate a RSA private key, and let us choose to encrypt, decrypt, see about or exit. Choose About to know what they want us to do and how it works.


============================= About ===============================
You are very good ESPer, so that you can change any local variable
value to 2048 bit random integer.

You should specify the ESP string as the line number and variables'
name to change separated by colon.

For example, if the source code is below and your input is "2:x",
the line 2 works the same as "x = rand(2 ** 2048); puts x". So the
output is random number.
+---+-------------------------------------------------------------------------+
| 1| x = 3 |
| 2| puts x |
+---+-------------------------------------------------------------------------+
Encryption Source code is here.
+---+-------------------------------------------------------------------------+
| 1| n, e = read_publickey(ARGV[0]) |
| 2| print "Message m: " |
| 3| STDOUT.flush |
| 4| m = STDIN.gets.to_i |
| 5| c = encrypt(m, e, n) |
| 6| puts "Encrypted: #{c}" |
| 7| STDOUT.flush |
+---+-------------------------------------------------------------------------+

Decryption Source code is here
+---+-------------------------------------------------------------------------+
| 1| p, q, dp, dq, qinvp = read_privkey(ARGV[0]) |
| 2| print "Encrypted Message c: " |
| 3| STDOUT.flush |
| 4| c = STDIN.gets.to_i |
| 5| m1 = decrypt(c, dp, p) |
| 6| m2 = decrypt(c, dq, q) |
| 7| m = merge(m1, m2, p, q, qinvp) |
| 8| puts "Decrypted: #{m}" |
| 9| STDOUT.flush |
+---+-------------------------------------------------------------------------+

As it describes, we can overwrite any variable to a random 2048 bit integer. My first thought is change e, and use Wiener attack to solve it, but it failed because they don’t print e out 😥

But luckily, there is a simple way to have p and q. Because the decryption is based on RSA-CRT, and we can control message c, so what would happen if we change m1 and/or m2 to force the server print wrong m? If we input c =1 and change m2, then m = random + hq; force it to do more, we can recover q by compute gcd(result1 -1, result2 -1), and do it again with m1 we got p! With p and q we have all things to decrypt the flag!

The server is still alive, so you can do it yourself! Good luck!

#The flag is TWCTF{I_don’t_Lik3_ESPer_problems!}

[Whitehat Contest 11] – WYGINWYS (Forensics 200pts)

Binary: download ở đây.

Đề cho một file image, mình cũng không rõ nó là file gì nữa, hình như là một cái ổ đĩa thì phải. Down về xong quăng qua cho một thành viên trong team làm, anh ấy dùng Sleuth Kit moi ra cho mình được một file .pyc, mình decompile ra được file source python, ở đây.

Coi sơ qua thì thấy có vẻ đây như là một con ransomware, nó mã hóa tất cả các file có extension trong list extension trong code bằng RSA, bên cạnh đó nó cũng có một server cho get private exponent để decrypt key nếu nhập đúng payload (có sẵn trong source python), khá là dễ hiểu.

Quá trình encrypt của nó có thể tóm tắt như sau: đọc từng block 100 bytes trong file cần mã hóa, qua hàm check để thêm các bytes 00 vào (n bytes ‘0’ ở hex-encoded thì replace = 3n/2 bytes ‘0’, để đảm bảo null byte ở đầu không bị mất sau khi mã hóa RSA vì dạng số thì 0 ở đầu k có ý nghĩa), mã hóa RSA bằng n và e cho sẵn trong source, sau đó pad thêm một đoạn string (mình gọi là chuỗi padding), ghi vào file .encrypt.

Hiểu được quá trình encrypt thì quá trình decrypt cũng không có gì quá khó khăn, nhất là khi ta đã có private exponent 😀 thành viên team mình cũng đã tích cực tìm kiếm trong cái đống bùi nhùi của Sleuth Kit và gởi cho mình file đã encrypt (dấu hiệu nhận biết là file này sẽ có rất nhiều chuỗi padding), ở đây.

Ý tưởng của mình là đọc file encrypted, tìm kiếm chuỗi padding, decrypt RSA bằng key đã có đối với chuỗi trước padding, và lấy 100 bytes cuối (tránh truờng hợp lấy dư bytes do đã bị thêm bytes 00), ghi vào một file 😀 mình check thử với block đầu tiên thì đó là file ảnh jpg.

Có ý tưởng thì code thôi 😀

Không biết do mình code thọt hay sida sao mà cái ảnh nó không đẹp như mong muốn, nhưng chỉ vậy là quá đủ để có 200pts 😀

fuckflag

[0CTF 2016 Quals] – equation (Crypto 2 pts)

After 48 hours “fighting”, our team CLGT-meepwn was ranked 12th. Here is my idea for solution of a 2-point cryptography task – equation.
We was given a zip file contain a “mask” RSA private key photo, and a encoded flag.

Screenshot 2016-03-15 at 04.50.02

Instead of trying to retype the private key (or using some OCR tools), I recognize that there is a private key which was hidden in the photo. Use binwalk to extract it.
Screenshot 2016-03-15 at 04.35.42
Based on the format of normal RSA private key, we can recover something from the given key: some LSBs of q, dp, dq and qinv.

CodeCogsEqn

CodeCogsEqn (1)

CodeCogsEqn (2)

If we multiple the second equation with exponent e, it becomes:

CodeCogsEqn (3)

From above equation and assuming that e = 65537 (default value), we know k(q – 1). We also know q is prime number, so q – 1 is an even number. Try to factorize k(q – 1) and note that k < e, we can recover q. Do this again with p or using the “coefficient” qinv, we recover p.

Having p and q, now we easily decrypt the flag.

The flag is 0ctf{Keep_ca1m_and_s01ve_the_RSA_Eeeequati0n!!!}.

[Sharif CTF 2016] – Huge (Crypto 250pts)

Đề cho một file nén, bên trong có một public key và một ciphertext. Xem thử public key:

qu@n:~/ctfs/sharif2016/crypto/huge$ openssl rsa -pubin -inform PEM -text -noout < pubkey.pem
Public-Key: (18329632 bit)
Modulus:
    00:95:35:fc:1b:00:00:00:00:00:00:00:00:00:00:
    ........ ....liên tiếp các bit 00 ...........
    00:00:00:00:00:00:00:00:00:00:00:00:00:00:01
Exponent: 65537 (0x10001) 

Xem nào, công thức mã hóa RSA là 86bae03c22af912674149ed242f754b9, tuy nhiên trong trường hợp này modulus n quá lớn, vậy ta có thể chỉ cần tính căn bậc e của c là có được m.

Code một script nhỏ:

import gmpy

c = int("0x" + open("enc.raw", "r").read().encode("hex"), 16)
flag = gmpy.mpz(c).root(65537)[0]
print str(hex(flag))[2:].decode("hex")

Và đây là kết quả:

qu@n:~/ctfs/sharif2016/crypto/huge$ python huge.py
SharifCTF{d604a27c3abcbe3e077b987f5e6fbcd3}

Tèn ten, ez points.

Hihi, giải nhanh còn có điểm thưởng nữa kìa =)) Screenshot from 2016-02-05 17:20:44.png