🇬🇧 DUCTF | Sideways
Table of Contents
Sideways
Sideways was a medium challenge from the DUCTF 2023.
I managed to solve it using the miasm framework
Initial recon
We are facing a rust compiled binary, the binary is asking for an argument, our flag.
Lets take a look at the check method.
The flag must have a lenght of 26 (0x1a)
Then, each character of the flag is computed like this schema, in “sideways”
the product is then send to a absolutely chaotic set of manipulation.
Emulation and flag
The transformation by this inline function is then compared to an array of the flag size lenght / 2.
To prepare the emulation with miasm i’m copying a section of the stack (the flag is located in the stack) from the same location of the emulation start address (0x55555555c973
).
dump binary memory stack.bin $rsp 0x1500
This writeup is from September 2023 so some parts of the implementation are hit or miss but this is working well
from miasm.analysis.binary import Container
from miasm.analysis.machine import Machine
from miasm.core.locationdb import LocationDB
from miasm.jitter.csts import PAGE_READ, PAGE_WRITE
from string import printable
FLAG_OFFSET = 0x857
f = open("stack.bin", "rb")
data_stack = f.read()
f.close()
flag = list(b'abcdefghijklmnopqrstuvwxyz')
known = {0:ord("D"),1:ord("U"),2: ord("C"), 3: ord("T"),4 :ord("F"),5:ord("{")}
myprintable = printable[:-5]
r11reg = 0xdeadbeef
indice = 0
def init_stack(jitter):
jitter.vm.add_memory_page(jitter.cpu.RSP, PAGE_READ | PAGE_WRITE, data_stack)
return True
def sentinelle(jitter):
jitter.vm.set_mem(myjit.cpu.RSP+0x857, bytes(flag))
add = myjit.cpu.RSP+0x857
jitter.vm.set_mem(myjit.cpu.RSP+0xc8, add.to_bytes(8, 'little'))
return True
def checkreg(jitter):
print(hex(jitter.cpu.RCX))
data = jitter.vm.get_mem(jitter.cpu.RCX, 26)
print(data)
jitter.running = False
return True
def r11dloc(jitter):
r11d = myjit.cpu.R11
global r11reg
global indice
r11reg = r11d
myjit.cpu.RSI = indice
jitter.running = False
return True
def finalflag(jitter):
exit(1)
return False
loc_db = LocationDB()
f = open("sideways", 'rb')
data = f.read()
f.close()
cont = Container.from_string(data, loc_db)
machine = Machine("x86_64")
mdis = machine.dis_engine(cont.bin_stream, loc_db=loc_db)
myjit = machine.jitter(loc_db)
myjit.init_stack()
base_addr = 0x555555554000
myjit.vm.add_memory_page(base_addr, PAGE_READ | PAGE_WRITE, data)
myjit.add_breakpoint(0x55555555c973, init_stack)
myjit.add_breakpoint(0x55555555c998, r11dloc)
myjit.run(0x55555555c973)
myjit.remove_breakpoints_by_address(0x55555555c973)
myjit.add_breakpoint(0x55555555c973, sentinelle)
myjit.add_breakpoint(0x55555555d4df, finalflag)
checkusmlist = [0xDB9BDB0D,0xFDE8FB2,0xCA379BBB,0xACAC25B8,0x464FD6E5,0x52584811,0xE27DC301,0x55E48BF8,0xB984194,0xB23AADE7,0x1B9D2631,0xFDB5C4CC,0xA3D6A5B3]
#myjit.set_trace_log()
while indice !=12:
s = indice
try:
flag[indice] = known[indice]
for elm2 in myprintable.encode():
flag[len(flag)-indice-1] = elm2
myjit.run(0x55555555c973)
if(r11reg == checkusmlist[indice]):
print(b"".join([chr(x).encode() for x in flag]), hex(r11reg))
indice+=1
break
except KeyError:
for elm1 in myprintable.encode():
for elm2 in myprintable.encode():
flag[indice] = elm1
flag[len(flag)-indice-1] = elm2
myjit.run(0x55555555c973)
if(r11reg == checkusmlist[indice]):
print(b"".join([chr(x).encode() for x in flag]), hex(r11reg))
indice+=1
break
if indice == s:
print("ERROR: Not found")
exit(1)
Flag: DUCTF{s1de_ch4nn3ld_af39c}
Conclusion
It was one of the first challenges I did using the miasm framework, a very nice challenge too.