[BSides Delhi CTF 2019] — Writeup

Nicholas
HMIF ITB Tech
Published in
7 min readSep 30, 2019

Writeup for BSides Delhi CTF 2019 by Nicholas.

BSides Delhi CTF 2019

Yesterday, I spend my lovely Sunday by playing BSides Delhi CTF 2019. At first, I want to play for fun because they said that it is “beginner friendly CTF”. Turn out, from my point of view, the challenge is very good and not a beginner friendly. So right now, I will try to explain writeup for every problems that I have solved.

Crypto: BabyRSA — 930 point

On this challenge, we were given two file, encrypt.py and data.txt that contains every information that we need to tackle this challenge. Let us examine the encrypt.py first.

encrypt.py

Okay, so they give us c1, c2, c3, n1, n2, e1, e2, enc, p*q, and ed. Looking the code at a glance, we could see that we need to recover salt and magic_value in order to retrieve the flag. As you can see, we already given ed, which is the private exponent for the salt encryption. Using the ed, we could recover the salt. Yeay, we have finished our first step. Let’s move to the second step, recovering the magic_value, which is very tricky.

Using the c3 value, if we could get the p1*p2 value, we will be able to factorize n1 and n2. But the problem is, we need to get ee value in order to recover the p1*p2 value. We could see that ed is big enough, so I’m pretty sure we could use rsaCtfTool to retrieve the ee by putting ed as public exponent, p*q as public modulus. The result would be ee value.

We got the ee value

After getting the ee value, we could decrypt c3 and get the p1*p2 value. Doing simple operation GCD(p1*p2, n1) and GCD(p1*p2, n2) will give us p1 and p2 value, which means we also got q1 and q2 value.

Finally, we have arrived to the trickiest part of this challenge. WE COULDN’T DO MODULAR INVERSE ON (e1, phi1) AND (e2, phi2) BECAUSE THEY ARE NOT RELATIVELY PRIME. After doing some math, trial and error, and reading some theory, I found out a way on how to retrieve the magic_value.

Notice that GCD(e1, (q1–1)) is 2, and GCD(e2, (q2–1)) is also 2. Our first step is we could try to transform our equation into mod q1 and mod q2. After that, we just need to modify our exponent. Notice that GCD(e1/2, (q1–1)) = 1, GCD(e2/2,(q2–1)) = 1. We could try to modify our equation again to be similar like below code:

Magic with number theory :D

As you can see, now our equation is much clearer than before, and if you notice, because q1 and q2 is coprime, we could use Chinese Remainder Theorem to get the (magic_value**2), and we just need to square root its value to recover our magic_value.

CRT for the win!!

Finally, we have successfully retrieve the salt and magic_value, and We Got Our Flag.

FLAGGGGG
Flag: bsides_delhi{JuG1iNg_WiTh_RS4}

Crypto: SecureMAC — 871 point

We were given file service.py for this challenge.

service.py

When we connect to the service, the service will give us n, c, and enc_key value. After that, there will be a prompt that ask us to input two messages that will be signed by the service. If the sign value is same, the service will give us the flag.

Looking at a glance, the service generate a key, encrypt the key with RSA, and give us the encrypted key. The key will be used as the AES key for the sign function. Okay, so our first mission of course to recover the key that was used on the sign function.

So, we could see that the service return c which is the encrypted value of “fake_flag”. The encryption method using RSA-CRT. If you look closely, that is a faulty encryption. Referring to my previous writeup about faulty encryption, we could easily recover the p value using GCD(c_faulty-c_real, n), which mean we are able to factors the modulus. That mean we could recover the key value.

After retrieving the key, the next step is to craft our message so that we have different message with the same sign value. Take a look at the sign function.

Sign function

Well, we could abuse the strxor method. If our messageblocks[i] is the same with tag, the xor result would be 0 right?. We could see that if our messageblocks[1] is the result of ECB.encrypt(messageblocks[0]), the xor result would be 0. So, we just need to send 32byte message, where the messageblocks[1] is the encryption result of messageblocks[0]. Whatever the messageblocks[0] value, the sign value would be the same if our messageblocks[1] is the encryption result of messageblocks[0]. Here is my full solver script that abuse the xor method and the faulty encryption.

Here is the flag:

FLAGGGGG
Flag: bsides_delhi{F4ult'n'F0rg3_1s_@_b4d_c0mb1n4ti0n}

Reverse: JrAppy — 793 point

On this challenge, we were given file .pyc. Decompile it, we will get the python code. Basically, the code doing some calculation, and check whether our input is correct or not. We just need to use z3-solver to solve this challenge. After using z3-solver, we got our first part of flag. Putting that first part as our input, the python program will give us a dump file. After checking the dump file, we found that it is a java class. Decompile it, we got the java code, that basically will check whether our input is correct or not. We just need to rewrite it on python, and for once again, using the almighty z3-solver. The code is pretty long though, so I will not share it on here (you could access it on this link), but we just need to be carefully craft the z3-solver to solve this challenge.

FLAGGG
Flag: bsides_delhi{compilersXareXmoreXfunXthanXinterpretorsX}

Forensics: Easy & Peasy — 775 point

On this challenge, we were given a file .raw, which is a memory dump. Fire up our volatility, we try to look for the imageinfo first.

Image Info

Using that imageinfo, we try to look for the process list.

Process List

So there is a notepad.exe process which is pretty interesting. In order to know which file did the notepad open, we use volatility cmdline.

Result of cmdline

You could see that the notepad open Hm.txt, and we found another interesting file called Important.zip

We try to do filescan to find that file.

0x0000000006772288      1      0 R--rwd \Device\HarddiskVolume1\Program Files\Hm.txt
0x00000000064f0ef8 1 0 R--r-- \Device\HarddiskVolume1\Documents and Settings\2PAC\My Documents\My Pictures\Important.zip

After that, we dump the Important.zip file and Hm.txt file. Opening the Hm.txt file, we got the second part of our flag, while the Important.zip was protected by password. Using john, we try to crack the zip with rockyou.txt, and we found that the password is princess.

John on action!

Extract the Important.zip with 7z, we got the first part of our flag.

Flag: bsides_delhi{I'm_th3_r3al_5LiM_Sh4dy_bUt_1_LIKE_Em1n3m_M0r3Haha!!}

Forensics: Business Planning Group — 100 point

We were given a PNG file. After checking it on its hexdump, we found a picture with BPG format inside the PNG File. Extract it, we will see a base64 string on the BPG Picture. Decode it and we will get the flag.

The Hidden Image
Flag: bsides_delhi{BPG_i5_b3tt3r_7h4n_JPG}

Forensics: 0110 — 100 point

On this challenge, we were given two file, the first one is full QRCode, while the second one is partial QRCode. Open it on photoshop, put the partial QRCode on the top of the full QRCode, apply difference filter on it, save the new QRCode. Decoding the QRCode will give us the flag.

Flag: bsides_delhi{X0r1ng_tw0_f1l3s_g1v3s_7h3_r3sul7}

Web: Weird Calculator — 100 point

We were given a file that contains the web sourcecode. The website is a Node JS application. Looking at the NodeJS code, the web will eval our given input. This mean that we could do readFile and try to read the index.js source code to get our first part flag, and read flag.txt to get the second part of flag. My full payload on the input is

res.end(require(‘fs’).readFileSync(‘index.js’).toString() + require(‘fs’).readFileSync(‘flag.txt’).toString())
FLAGGGG
Flag: bsides_delhi{Prototype_and_sh3ll1ng_by_the_Cs1de}

--

--