2016 Codegate compress writeup

Crypto & Math

2016.03.20 22:24

Problem


import md5
def encode(input_string):
    print input_string
    h = md5.md5(input_string[:4]).hexdigest()
    table = {
        'a': 1,
        'b': 2,
        'c': 3,
        'd': 4,
        'e': 5,
        'f': 6,
        'g': 7,
        'h': 8,
        'i': 9,
        'j': 0
    }
    out = ""
    prev = ""
    stage1 = []
    stage2 = []
    stage3 = ""
    passbyte = -1
    for ch in input_string:
        if ch in table.keys():
            stage1.append(table[ch])
        else:
            stage1.append(ch)

    for index, ch in enumerate(stage1):
        if len(stage1) <= index+1:
            if index != passbyte:
                stage2.append(ch)
            break

        if passbyte != -1 and passbyte == index:
            continue

        if type(ch) == int and type(stage1[index+1])==int:
            tmp = ch << 4
            tmp |= stage1[index+1]
            stage2.append(tmp)
            passbyte = index+1
        else:
            stage2.append(ch)

    for ch in stage2:
        if type(ch) == int:
            stage3 += chr(ch)
        else:
            stage3 += ch

    for index, ch in enumerate(stage3):
        if index >= len(h):
            choice = 0
        else:
            choice = index

        out += chr(ord(ch) ^ ord(h[choice]))

    print repr(out)


encoded = "~u/\x15mK\x11N`[^\x13E2JKj0K;3^D3\x18\x15g\xbc\\Gb\x14T\x19E"
encode(st)


Solve


hash값이 plaintext의 앞 4글자만 가지고 md5를 하기 때문에 첫 4글자만 맞추면 hash값을 알 수 있고, 디크립트 할 수 있다.

첫 4글자를 맞추기 위해 브루트포싱을 돌렸다.;;


import md5
def encode(input_string):
	#print input_string
	h = md5.md5(input_string[:4]).hexdigest()
	table = {'a': 1,'b': 2,'c': 3,'d': 4,'e': 5,'f': 6,'g': 7,'h': 8,'i': 9,'j': 0 }
	out = ""
	prev = ""
	stage1 = []
	stage2 = []
	stage3 = ""
	passbyte = -1
	for ch in input_string:
		if ch in table.keys():
			stage1.append(table[ch])
		else:
			stage1.append(ch)
	for index, ch in enumerate(stage1):
		if len(stage1) <= index+1:
			if index != passbyte:
				stage2.append(ch)
			break
		if passbyte != -1 and passbyte == index:
			continue
		if type(ch) == int and type(stage1[index+1])==int:
			tmp = ch << 4
			tmp |= stage1[index+1]
			stage2.append(tmp)
			passbyte = index+1
		else:
			stage2.append(ch)
	for ch in stage2:
		if type(ch) == int:
			stage3 += chr(ch)
		else:
			stage3 += ch
	for index, ch in enumerate(stage3):
		if index >= len(h):
			choice = 0
		else:
			choice = index
		out += chr(ord(ch) ^ ord(h[choice]))
	#print repr(out)
	return out


encoded = "~u/\x15mK\x11N`[^\x13E2JKj0K;3^D3\x18\x15g\xbc\\Gb\x14T\x19E"

import string
maps = string.printable

for a1 in maps :
	for a2 in maps :
		for a3 in maps :
			for a4 in maps :
				st = a1 + a2 + a3 + a4
				out = encode(st)
				if encoded[:len(out)] == out :
					print st



위의 브루트포싱 코드를 돌리면 FLag라는 글자가 나온다.

따라서 이 4글자가 첫글자라고 짐작하고 디크립트 코드를 짯다.




import md5
import string

def decode(s) :
	table = {'a': 1,'b': 2,'c': 3,'d': 4,'e': 5,'f': 6,'g': 7,'h': 8,'i': 9,'j': 0}
	v = table.values()
	k = table.keys()
	table.clear()
	for x, y in zip(v, k) :
		table[x] = y

	a, b = divmod(ord(s), 16)
	if a == 0 :
		out = table[b]
	else :
		out = table[a] + table[b]
	return out

if __name__ == '__main__' :
	printable = string.printable[:-5]
	encoded = "~u/\x15mK\x11N`[^\x13E2JKj0K;3^D3\x18\x15g\xbc\\Gb\x14T\x19E"
	h = md5.md5('FLag').hexdigest()
	flag = ''
	l = []

	for i in range( len(encoded) ):
		if i >= len(h) :
			l.append( chr(ord(h[0]) ^ ord(encoded[i] )))
		else :
			l.append( chr(ord(h[i]) ^ ord(encoded[i] )))

	for s in l :
		if s in printable :
			flag += s
		else :
			flag += decode(s)

	print flag