-
-
Save bruce30262/bba06ca3e30ef320fab79678156a5841 to your computer and use it in GitHub Desktop.
[flareon2018] level6.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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