Skip to content

Instantly share code, notes, and snippets.

@bruce30262
Last active October 2, 2018 03:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bruce30262/bba06ca3e30ef320fab79678156a5841 to your computer and use it in GitHub Desktop.
Save bruce30262/bba06ca3e30ef320fab79678156a5841 to your computer and use it in GitHub Desktop.
[flareon2018] level6.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pickle
import sys
import itertools
import string
from pwn import *
context.arch = "amd64"
datas = None
def read_n(addr, n):
return B[addr:addr+n]
def Qword(addr):
return u64(read_n(addr, 8))
def Dword(addr):
return u32(read_n(addr, 4))
def Byte(addr):
return u8(read_n(addr, 1))
class Data:
def __init__(self, addr):
self.parse(addr)
def parse(self, addr):
addr -= 0x600000
self.code_buf = Qword(addr)
self.code_len = Dword(addr+8)
self.key_off = Dword(addr+12)
self.int_arr_len = Dword(addr+16)
self.copy_off = Dword(addr+20)
self.xor_key = Qword(addr+24)
self.int_arr = []
for i in xrange(32):
read_addr = addr + 32 + i*8
self.int_arr.append(Qword(read_addr))
self.code = None
def print_data(self):
print("code buf: {:#x}".format(self.code_buf))
print("code len: {:#x}".format(self.code_len))
print("xor key: {:#x}".format(self.xor_key))
print("key off: {:#x}".format(self.key_off))
print("copy off: {:#x}".format(self.copy_off))
print("int_arr_len: {:#x}".format(self.int_arr_len))
print("int_arr:")
for idx, i in enumerate(self.int_arr):
print("{}. {:#x}".format(idx, i))
print("code:")
print(map(hex, self.code))
print("")
def read_data(filename):
"""
Read data structure from ELF and construct datas
"""
global datas, B
init_addr = 0x605100
with open(filename, "r") as f:
B = f.read()
datas = []
for i in xrange(33):
cur_addr = init_addr + 0x120*i
data = Data(cur_addr)
datas.append(data)
def read_buf(addr, sz, is_code=False):
if is_code:
addr -= 0x400000
else:
addr -= 0x600000
ret = []
for i in xrange(sz):
ret.append(Byte(addr+i))
return ret
def xor_code(data):
code = read_buf(data.code_buf, data.code_len, is_code=True)
key = read_buf(data.xor_key, data.code_len)
ret = []
for a, b in zip(code, key):
ret.append(a^b)
return ret
for d in datas:
d.code = xor_code(d)
def code0(int_arr_len, int_arr):
""" fibonacci """
ret = ""
for i in xrange(int_arr_len):
cur_f = 1
prev_prev = 0
prev = 1
cur_i = 1
while cur_f != int_arr[i]:
new = (cur_f + prev)&0xffffffffffffffff
prev_prev = prev
prev = cur_f
cur_f = new
cur_i += 1
ret += chr(cur_i)
return ret
def code1(key, int_arr_len, int_arr):
""" CRC32, must brute force """
cc = 0xffffffff
for idx in xrange(int_arr_len):
cc ^= ord(key[idx])
for _ in xrange(7, -1, -1):
eax = cc
eax &= 1
eax = ((~eax) + 1)&0xffffffff
bp18 = eax
edx = cc >> 1
eax = bp18 & 0xedb88320
eax ^= edx
cc = eax
if int_arr[0] == 0:
return True
else:
if int_arr[0] == ((~cc)&0xffffffff):
return True
else:
return False
def code2(int_arr_len, int_arr):
""" RC4 """
# https://github.com/bozhu/RC4-Python
def KSA(key):
keylength = len(key)
S = range(256)
j = 0
for i in range(256):
j = (j + S[i] + key[i % keylength]) % 256
S[i], S[j] = S[j], S[i] # swap
return S
def PRGA(S):
i = 0
j = 0
while True:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i] # swap
K = S[(S[i] + S[j]) % 256]
yield K
def RC4(key):
S = KSA(key)
return PRGA(S)
def convert_key(s):
return [ord(c) for c in s]
key = 'Tis but a scratch.'
key = convert_key(key)
keystream = RC4(key)
ret = ""
for i in xrange(int_arr_len):
ret += chr(ord(int_arr[i]) ^ keystream.next())
return ret
def code3(int_arr_len, int_arr):
""" base64 with customized table """
v13 = p64(0x2346A7C2645F392A)
v13 += p64(0x42704D2847746B53)
v13 += p64(0x4A4038626A522549)
v13 += p64(0x5024312D59444569)
v13 += p64(0x6671764C21547967)
v13 += p64(0x304F57516D68632B)
v13 += p64(0x6C336E75345A4E65)
v13 += p64(0x4B7A617732264837)
v13 += p16(0x56)
ret = ""
tmp = [0]*(int_arr_len+1)
for i in xrange(int_arr_len+1):
for idx, c in enumerate(v13):
if c == int_arr[i]:
tmp[i] = idx
for i in xrange(int_arr_len):
if i % 3 == 0:
ret += chr((((tmp[i]) << 2) | ((tmp[i+1]) >> 4))&0xff)
elif i % 3 == 1:
ret += chr(((((tmp[i]) & 15) << 4) | ((tmp[i + 1]) >> 2))&0xff)
else:
ret += chr(((((tmp[i]) & 3) << 6) | (tmp[i + 1]))&0xff)
return ret
def code4(int_arr_len, int_arr):
ret = ""
for i in xrange(int_arr_len):
ret += chr((ord(int_arr[i])-0xd)&0xff)
return ret
def code5(int_arr_len, int_arr):
return ''.join(int_arr)[:int_arr_len:]
def code6(int_arr_len, int_arr):
ret = ""
for i in xrange(int_arr_len):
ret += chr((ord(int_arr[i])^0x2a)&0xff)
return ret
def ints_to_bytes(int_arr):
tmp = ""
for i in int_arr:
tmp += p64(i)
return list(tmp)
sss = string.printable
# codetbl_dump: serialize object of code_tbl dict, type: {key : val} => {machince code : code id}
code_tbl = pickle.load(open("codetbl_dump", "r")) # for recognizing code id
func_tbl = [code0, code1, code2, code3, code4, code5, code6]
code_id = 0
r = process("./magic")
for rnd in xrange(666):
log.success("Round: {}".format(rnd+1))
read_data("./magic") # construct datas
key = ['']*100
for i in xrange(33):
d = datas[i]
code = ''.join(chr(c) for c in d.code)
cid = code_tbl[code]
int_arr = d.int_arr
if cid >=2 : # int_arr must turn into bytearray
int_arr = ints_to_bytes(d.int_arr)
# start decrypt
da_key = ""
if cid == 1: # CRC32, use bruteforce
for c in itertools.product(sss, repeat = d.int_arr_len):
tmp = ''.join(c)
if(func_tbl[cid](tmp, d.int_arr_len, int_arr)):
da_key = tmp
break
else : # just decrypt
da_key = func_tbl[cid](d.int_arr_len, int_arr)
key_idx = d.key_off
for k in da_key: # write key
key[key_idx] = k
key_idx += 1
ans = ''.join(key)
log.success("Round {} key: {}".format(rnd+1, repr(ans)))
r.sendline(ans)
time.sleep(0.1) # wait for write file complete
r.interactive()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment