CS2107 CTF answers
answers and take-aways
Assignment 1
E.1: Huuuuuge RSA
This task is asking us to crack a RSA. Using normal methods is impossible because RSA has 1024-bit security. So I search for rainbow table online. And I indeed find the prime factorization of n.
Steps:
- Search for p and q from factordb.com.
- Use the RSA formula to calculate message m, and turn m into bytes, and output.
E.2: Password attack
We can brute force attack the password using hashcat. I found a rock_you file from the Internet, and use these frequently used passwords to conduct an attack.
Steps:
- Download rock_you.txt and hashcat
- get the hash of the office file
- conduct dictionary attack using hashcat.
E.3: Plaintext attack
We know some content inside the encrypted zip file, and we want decrypt the file. Inside zip files, there are in fact derived keys generated by your initial key. Using bkcrack, we don't need the initial key and can directly crack the derived key and decrypt the whole file.
Steps:
- Find that "Assignment1.pdf" is included in "sus_package.zip".
- Use bkcrack with "Assignment1.pdf" to get the three derived keys.
- Since we know the key, we can enter it into bkcrack and decrypt everything.
M.1: Rolling Thunder!
png files has fixed prefix. The encryption use the key to xor the png file. Since we know the prefix plaintext, we can easily obtain the key. k = p xor c.
Steps:
- Use 'xortool' to get the key of the encrypted image. The key is 'elephant', and the image is as follows:

M.2: Secret Message
Monoalphabetic substitution cipher has a very small key space. We can easily crack it using brute force attack.
Steps:
- find the website dcode.fr and paste the cipher text into it.
- find the flag from the big chunk of text.
M.3: Red Herring
The weakness here is that it pads each byte into 16 bytes so the key space size is only 256 (since the same byte will be deterministically encrypted into the same cipher text).
Steps:
- Write a program to match each byte with the corresponding 16 byte cipher text. (since we already know most of the plaintexts).
- run the program to get the full plaintext.
M.4: Spill Some Tea
The ChaCha20-Poly1305 encryption scheme here uses the same nonce all the time. So if I enter a chosen plaintext p1, we will obtain the cipher c1.
c1 xor c = p1 xor p
p1 is known
p = c1 xor c xor p1.
Steps:
- Input my favorite p1: all zeros, and get c1
- p = c1 xor c xor p1
H.1: Lazy Programmer
We are given the time, so we are given the random seed. Using the seed we can easily recur the random numbers. Some strange thing here is that the server time is in UTC time, while my clock is UTC+8 time. I write the program in C, and only when entering my current clock time it works. C seems to be highly bound with the os system.
Steps:
- Write a program that use the time entered as input, generate the random seed, derive the key, and calculate the MD5 string.
- Note down the time, submit the MD5 to the server.
H.2: PDF Collisions?!
We need to forge two pdfs that has the same appearance as Assignment1.pdf, but has different hash codes. We leave the message part of the pdf the same (prefix), and conduct IPC attack. Be aware that you can also conduct CPC attack but that takes way longer time.
Steps:
- find a tool called hashclash.
- use md5fastcoll in hashclash to generate the two pdfs and upload to the website.
Assignment 2
E.1 Duck
idea
The task gives us a picture whose height is modified. We need to modify it back using binary text editor. I use ghex here. The height is 0x14-0x17 bytes, we need to update it to the correct height. I don't bother to find the exact height so I just made it a bigger number, 0x400. But another thing to be aware of is the CRC code. It is a verification code to see if the IHDR is correct. I used online CRC to generate the code.
steps
- modify the height using ghex.
- modify the CRC using crccalc.com
E.2 Bad Stack
idea
It seems that if the secret is the same as our input, then it will give me the flag. So I just use a long input to cause buffer overflow and overwrite the secret.
steps
- my input are all 1's, very long string of 1's to overwrite the secret.`x
E.3 Self-made NextCloud
idea
The website only checks the last extension. That means I can have many extensions as long as my last extension is correct. And I looked through the .htaccess file, and found that all the aaa.php.xxx files will be recognized as .php files and execute automatically by the website. So I write a php program that outputs all the files in the working directory, and change its extension to .php.jpg And I found the flag.txt (since .txt cannot be uploaded, this must be the flag). And I wrote another .php program to read the flag.txt.
steps
- read through the web code
- write a .php to scan the files -> change extension to .php.jpg
- write a .php to read flag.txt -> change extension to .php.jpg
flag
CS2107{ph9_png_cmDbYp4ss_F1l3_upl04d_vu1n?????}
M.2 Evil Cowsay


idea
The code given is not complete. We need to first decompile the executable given, and found that there is a win function inside. There are no function call to win function, so we must do buffer overflow attack to force the program to jump to win function. The first thing we need to know is what is the offset. It turns out to be 56, so the first 56 characters can be whatever, and what really matters is the last 8 characters. I found that win is at 0x401209, and using little endian for the system, so we need to turn it into x09 x12 x40 x00 x00 x00 x00 x00 x00. By constructing this payload, and load it into the program using pipeline |, we can jump to win function and obtain the flag.
steps
- decompile, and find the win function
- get the address of win
- using cyclical pattern to obtain offset
- construct the payload, given the offset and address (little endian)
- use pipeline to enter this payload
M.3 Onion-haseyo
idea
The method to use in decrypting one layer is written in exec. We just need to output it into another file, and continue solving the next file. I first tried to solve it manually, but it turns out to be too many layers. So after that I wrote a script to solve it automatically. It seems that there are 50 layers wrapping around the flag.
steps
- write a program that substitutes 'exec(' to 'with open("layer_{i+1}", "w") as f:\n\tf.write(', and then execute layer_{i+1}
- open the last file generated, and it should contain the flag
H.1 Why so complicated?
idea
I found that the encrypted flag is already stored somewhere in the program. The program basically takes in our input, and do some byte-to-byte encryption, and compare it with the encrypted flag. Using info files, we can obtain the address of .data. And then we can print out the bytes in .data using x/200x 0xaaaaaaa.
Since it is a byte-to-byte encryption, we don't need to iterate through all n^51 possible inputs, but to check the inputs one by one. Every time, we examine a specific position, leaving other 50 bytes random. After some decompile, we find that the encryption function is called _o_e, and in instruction memory 0x401476, the $al stores the encrypted byte. So we print this register out, and compare it with our encrypted flag. But this requires us to iterate through all 51*n possibilities, so we need to use some automation. I wrote a python program to iterate through all the possibility of each character one-by-one, and when the encrypted byte hit the encrypted flag, it prints out the input of that position.

steps
- obtain encrypted flag using
info filesandx/200x 0xaaaaaaaa - byte-to-byte encryption, so we just need to iterate through each position one by one. For example, we need to pin down the first character, then we set all other characters random, and try all possibilities of this position. We obtain the encrypted outcome by tracing
$alin_o_efunction with gdb. And we compare the encrypted outcome with the encrypted flag. If the two match, then the input of this position is fixed. - Write a program to automate this process.
take-aways
- buffer overflow: 先用cyclical pattern找到offset(通过输入一段有规律的输入,找到saved rip覆盖的值,就能找到offset了。)到offset的长度都可以随便输入,重要的是把saved rip输入成什么,我的系统是little endian,并且saved rip中存储的是绝对address,所以我应该覆盖为0x401209,然后little endian 一下变成x09 x12 x40 x00 x00...。这个是无法直接输入到终端的,所有都会被识别为字符,所以我们要用print "" | ./xxx这个pipeline来输入。
- disassembly命令可以获得函数的assemble code
- 反编译retdec可以生成比较容易读懂的code
- gdb里面有支持python脚本的库,这个库只在gdb中存在,无法在外部导入。python可以靠它来自动化操作gdb。
info frame(输出frame),info registers(输出当前reg),info file(输出各个字段.data, .text等等)- saved rip是return返回地址
Comments
No comments yet.