My Profile Photo

Giacomo Iengo


Hi, I'm Giacomo and i really like diving in things that inspire me. Unfortunately, they often become obsessions.. haha


Don't break me

The challenge

   
Event AUCTF 2020
Challenge name Don't Break Me!
Challenge category Reversing
Challenge points 763
Executable dont_break_me

What does the executable do?

The executable asks for an input.

user@pc:~$ ./dont_break_me 
54 68 65 20 6d 61 6e 20 69 6e 20 62 6c 61 63 6b 20 66 6c 
65 64 20 61 63 72 6f 73 73 20 74 68 65 20 64 65 73 65 72
74 2c 20 61 6e 64 20 74 68 65 20 67 75 6e 73 6c 69 6e 67
65 72 20 66 6f 6c 6c 6f 77 65 64 2e
Input: DUMMYINPUT
Not quite

Don’t worry about all those numbers, we don’t really need them to complete the challenge. So, our input is passed as an argument to sym.encrypt, then the encrypted string returned by the function is compared with sym.imp.strcmp to an hardcoded key and if they are equal, it prints the flag. We can see this flow through the radare2’s output.

│           0x000012f8      e853fdffff     call sym.imp.fgets 
│ ... skiping
│           0x00001321      50             push eax
│           0x00001322      e8a8010000     call sym.encrypt
│ ... skiping
│           0x00001350      ff75ec         push dword [s2]
│           0x00001353      ff75e8         push dword [s1]
│           0x00001356      e8d5fcffff     call sym.imp.strcmp 
│           0x0000135e      85c0           test eax, eax
│       ┌─< 0x00001360      7507           jne 0x1369
│       │   0x00001362      e889000000     call sym.print_flag

What can we do?

It seems that all we have to do is reverse the sym.encrypt function, so we can finally provide the correct input and get the flag. Unfortunately as we can see from the Official writeup, there are some antidebugging techniques, so the debug would be a litte tricky.

But luckly, looking at the ltrace output, we can see the hardcoded key compared to our encrypted input.

user@kvm:~$ ltrace ./dont_break_me 
printf("Input: "Input: ) = 7
fgets( DUMMYINPUT
"DUMMYINPUT\n", 8192, 0xf7f4b5c0)
    ... skiping
strcmp("SASRRWSXBIEBCMPX", "LOIIESZHOX")
printf("Not quite"Not quite)

So the key is "SASRRWSXBIEBCMPX" and "DUMMYINPUT" apparently becomes "LOIIESZHOX". Now, we can try to input all printable ascii characters for each position of the key, see what our input char becomes, and then compare it to that of the key until we get the right one. Here is the ugly script xD..

import re
import string
from pwn import *

secret = ''

for index in range(16):
	for guess in string.printable:
		p = process('ltrace ./dont_break_me', shell=True)
		data = p.recvuntil('fgets(')
		p.sendline(guess)
		data = p.recvuntil('(status 0) +++')
		line = re.findall(r'strcmp.*', data)

		try:
			key, ch = re.findall(r'"[A-Z]+"|"[A-Z]"', line[0])
		except:
			p.close()
			continue

		key = key.replace('"','')
		ch = ch.replace('"','')


		if ch == key[index]:
			secret += guess
			p.close()
			break			

		p.close()
		
log.info(secret)

After a long and ugly output, we get the key (c1cffqcnbgsbyuln) So the last step would be:

user@pc:~$ nc challenges.auctf.com 30005
54 68 65 20 6d 61 6e 20 69 6e 20 62 6c 61 63 6b 20 66 6c 
65 64 20 61 63 72 6f 73 73 20 74 68 65 20 64 65 73 65 72
74 2c 20 61 6e 64 20 74 68 65 20 67 75 6e 73 6c 69 6e 67
65 72 20 66 6f 6c 6c 6f 77 65 64 2e
Input: c1cffqcnbgsbyuln

auctf{static_or_dyn@mIc?_12923}

Thanks for reading! :D