0xd13a

A rookie in a world of pwns

VolgaCTF 2017 Quals Writeup: KeyPass

KeyPass

100

For reasons unknown an amature cryptographer wrote an application to generate “strong encryption keys”. One of these keys was used to encrypt a tar archive with the flag. They used openssl command line util with -aes-128-cbc. Could you please get the flag? It shouldn’t take much time…

flag.zip.enc

keypass

When we run the application with a parameter we get a 17-byte encryption key back:

1
2
$ ./keypass 1
.EjN$4f4%+r5SrN$Z

Let’s reverse it in Snowman. The main work seems to happen in function fun_4004a0. The algorithm first calculates the one-byte checksum of the string passed in as a parameter. It is done through a series of XORs:

1
2
3
4
while (rdi11 != rcx12) {
    ++rdi11;
    rdx13 = rdx13 ^ reinterpret_cast<uint64_t>(static_cast<int64_t>(*rdi11));
}

After the checksum is calculated it is used in another algorithm that actually generates the key. The algorithm multiplies the checksum by 0x40f7 and adds it to 0x7cc8b. The result mod 82 is then used as a pointer into an embedded character translation table (2FuMlX%3kBJ:.N*epqA0Lh=En/diT1cwyaz$7SH,OoP;rUsWv4g\Z<tx(8mf>-#I?bDYC+RQ!K5jV69&)G).

Once we have the key we can use it to decrypt the flag. Because the 1-byte checksum is used to calculate the key we can bruteforce through 256 combinations quickly. Let’s put all this knowledge into a script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import os

def gen_checksum(s):
	sum = 0
	for x in s:
		sum ^= ord(x)
	return sum
	
def gen_key(checksum):
	x = checksum
	key = ""
	
	for i in range(17):
		x = 0x40f7 * (x % 0x7fffffff) + 0x7cc8b
		key += table[x % 0x7fffffff % 82]
		
	return key
		
table = open("keypass","rb").read()[0xa40:0xa40+82]
		
assert gen_key(gen_checksum("1")) == ".EjN$4f4%+r5SrN$Z"

ciphertext = open("flag.zip.enc","rb").read()

for x in range (0x100):
	
	if 0 == os.system("openssl aes-128-cbc -d -in flag.zip.enc -out flag.zip -pass 'pass:%s'" % gen_key(x)):
		os.system("unzip -c flag.zip")
		break

When we run it we get the flag VolgaCTF{L0ve_a11_trust_@_few_d0_not_reinvent_the_wh33l}:

1
2
3
4
$ python solve.py 2>/dev/null
Archive:  flag.zip
 extracting: flag.txt                
VolgaCTF{L0ve_a11_trust_@_few_d0_not_reinvent_the_wh33l}