07u4
상위 디렉토리 - Midnight Sun CTF 2024
This challenge does not provide a challenge file. Instead, a description of this challenge can be found on the nc server.
description
Automatically generate validating input
for each of the 25 random gzipped binaries
provided to get your flag.
If choose play
option, then gzip compressed binary is given.
Given binary has hexstring
format.
Groundwork
To solve this challenge, the given binary needs to be cracked automatically. So what I do first is write skeleton code to receive the gzip hexstring format binary, decompress it, and generate the binary file.
import gzip
from pwn import *
#context.log_level = 'debug'
p = remote("07u4-1.play.hfsc.tf", 3991)
def unzip_gz(hex_string):
byte_string = bytes.fromhex(hex_string)
return gzip.decompress(byte_string)
p.sendline(str(2).encode())
for i in range(25):
dummy = p.recvuntil(b":" + b"\x20")
p.recvline()
hex_string = p.recvline().decode()
binary = unzip_gz(hex_string)
f = open("sample", "wb")
f.write(binary)
f.close()
p.interactive()
Now all that’s left is to analyse the given binary and write code to crack it automatically.
analyse binaries
There were a lot of different types of binaries, but I was able to narrow them down to about three types.
There are very very simple binary, so it is not difficult to solve each one separately.
However, each binary has different offset and I don’t know which type of binary is given… To distinguish between the different types and offsets, it was necessary to create a signature for each type and offset.
I could make a type signature just using some characteristics instructions for each type. Fortunately, there aren’t that many types of offsets, I created all the branches for them.
Exploit Code
import gzip
from pwn import *
import os
#context.log_level = 'debug'
p = remote("07u4-1.play.hfsc.tf", 3991)
def unzip_gz(hex_string):
byte_string = bytes.fromhex(hex_string)
return gzip.decompress(byte_string)
def determine_type(binary):
if binary[0x1202:0x1202+3] == b"\x66\xc7\x85" or binary[0x1202:0x1202+3] == b"\x66\xc7\x45":
return first_type(binary, 0x1202)
elif binary[0x1214:0x1214+3] == b"\x66\xc7\x85" or binary[0x1214:0x1214+3] == b"\x66\xc7\x45":
return first_type(binary, 0x1214)
elif binary[0x126e:0x126e+3] == b"\x66\xc7\x85" or binary[0x126e:0x126e+3] == b"\x66\xc7\x45":
return first_type(binary, 0x126e)
elif binary[0x1280:0x1280+3] == b"\x66\xc7\x85" or binary[0x1280:0x1280+3] == b"\x66\xc7\x45":
return first_type(binary, 0x1280)
elif binary[0x1292:0x1292+3] == b"\x66\xc7\x85" or binary[0x1292:0x1292+3] == b"\x66\xc7\x45":
return first_type(binary, 0x1292)
elif binary[0x119c:0x119c+2] == b"\xc6\x45":
return sec_type(binary, 0x119c)
elif binary[0x11b6:0x11b6+2] == b"\xc6\x45":
return sec_type(binary, 0x11B6)
elif binary[0x1202:0x1202+2] == b"\xc6\x45":
return sec_type(binary, 0x1202)
else:
return last_type()
def sub_2byte(a, b):
res = a - b
if res < 0:
res += 0x10000
return res
def first_type(binary, offset):
start_addr = offset
command = binary[start_addr:]
l = list()
while True:
if command[0] == 0xc7:
break
command = command[2:]
if command[0] == 0x85:
command = command[5:]
else:
command = command[2:]
val = command[0] + (command[1] << 8)
command = command[2:]
if val == 0:
break
l.append(val)
#print(hex(val))
cnt = len(l)
l1 = l[:cnt // 2]
l2 = l[cnt // 2:]
flag = []
for i in range(cnt // 2):
res = sub_2byte(l2[i], l1[i])
flag.append((res >> 8) & 0xff)
flag.append(res & 0xff)
return bytes(flag)
def sec_type(binary, offset):
start_addr = offset
command = binary[start_addr:]
l = list()
while True:
if command[0] == 0xc7:
break
command = command[3:]
val = command[0]
l.append(val)
#print(hex(val))
command = command[1:]
tmp = 0x11f4 - 0x11b6
if binary[start_addr + tmp] == 0x34:
xor_val = binary[start_addr + tmp+1]
else:
xor_val = binary[start_addr + tmp-1]
#print(xor_val)
flag = list()
for i in l:
flag.append(xor_val ^ i)
return bytes(flag)
def last_type():
os.system("strings ./sample >> string.txt")
f = open("string.txt", "r")
data = f.readline()
min_len = len("_ITM_deregisterTMCloneTable\n")
flag = ""
while(data):
if len(data) > min_len:
if "GCC: (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0" not in data:
flag = data.replace("\n", "")
break
data = f.readline()
f.close()
os.remove("./string.txt")
return flag
p.sendline(str(2).encode())
for i in range(25):
p.recvuntil(b"BIN")
dummy = p.recvuntil(b":" + b"\x20")
if b"FAIL" in dummy:
break
print(p.recvline())
hex_string = p.recvline().decode()
binary = unzip_gz(hex_string)
#print(binary[0x11b6:0x11b6+0x100])
f = open("sample", "wb")
f.write(binary)
f.close()
flag = determine_type(binary)
p.sendline(flag)
p.interactive()
flag: midnight{Ti_esrever_dna_ti_pilf_nwod_gnaht_ym_tup_i}