Skip to content

Instantly share code, notes, and snippets.

@sud0woodo
Created November 9, 2024 03:35
Show Gist options
  • Save sud0woodo/a22c9f96ece8e7bdf19c0ffbe7654fde to your computer and use it in GitHub Desktop.
Save sud0woodo/a22c9f96ece8e7bdf19c0ffbe7654fde to your computer and use it in GitHub Desktop.
Flare-On 11 Challenge 5
import argparse
from unicorn import *
from unicorn.x86_const import *
KEY = "8dec9112eb760eda7c7d87a443271c35d9e0cb878993b4d904aef934fa2166d7"
NONCE = "111111111111111111111111"
ADDRESS = 0x1000000
START_ADDRESS_INIT = 0x1000A93
END_ADDRESS_INIT = 0x1000CC7
START_ADDRESS_DECRYPT = 0x1000D49
END_ADDRESS_DECRYPT = 0x1000D83
STACK_BASE = 0x2000000
STACK_SIZE = 0x40000
HEAP_BASE = 0x3000000
HEAP_SIZE = 0x400000
RAX_ADDRESS = 0x4000000
RAX_SIZE = 0x1000
RCX_ADDRESS = 0x5000000
RCX_SIZE = 0x1000
RDX_ADDRESS = 0x6000000
RDX_SIZE = 0x1000
R8_ADDRESS = 0x7000000
R8_SIZE = 0x1000
def init_emulator(code: bytes):
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(ADDRESS, 0x1000000)
# Write our binary code to the memory
mu.mem_write(ADDRESS, code)
# Create mapping for stack and heap
mu.mem_map(STACK_BASE, STACK_SIZE)
mu.mem_map(HEAP_BASE, HEAP_SIZE)
# Set up our memory mapping
mu.mem_map(RAX_ADDRESS, RAX_SIZE)
mu.mem_map(RCX_ADDRESS, RCX_SIZE)
mu.mem_map(RDX_ADDRESS, RDX_SIZE)
mu.mem_map(R8_ADDRESS, R8_SIZE)
# Adjust RBP based on our mapping and create a stack frame
mu.reg_write(UC_X86_REG_RBP, STACK_BASE + STACK_SIZE - 4)
return mu
def decrypt_data(code: bytes, rax: bytes, stackdata: bytes) -> bytes:
mu = init_emulator(code=code)
# Set RIP at the start of the function
mu.reg_write(UC_X86_REG_RIP, START_ADDRESS_DECRYPT)
# Set RSP
mu.reg_write(UC_X86_REG_RSP, STACK_BASE + STACK_SIZE)
# Set RAX to our chacha20 init data
mu.mem_write(RAX_ADDRESS, rax)
mu.reg_write(UC_X86_REG_RAX, RAX_ADDRESS)
# Set RDX to the data we're trying to bruteforce
mu.mem_write(RDX_ADDRESS, stackdata)
mu.reg_write(UC_X86_REG_RDX, RDX_ADDRESS)
# Set RCX to the length of the data
mu.reg_write(UC_X86_REG_RCX, len(stackdata))
try:
mu.emu_start(START_ADDRESS_DECRYPT, END_ADDRESS_DECRYPT)
return mu.mem_read(RDX_ADDRESS, len(stackdata))
except UcError as e:
print("ERROR: %s" % e)
print("at: %x" % mu.reg_read(UC_X86_REG_RIP))
def init_chacha(code: bytes) -> bytes:
mu = init_emulator(code=code)
# Set RSP
mu.reg_write(UC_X86_REG_RSP, STACK_BASE + STACK_SIZE)
# Write the stack data to RDX
mu.mem_write(RDX_ADDRESS, bytes.fromhex(KEY))
mu.reg_write(UC_X86_REG_RDX, RDX_ADDRESS)
# Write the length of the data to decrypt to RCX
mu.mem_write(RCX_ADDRESS, bytes.fromhex(NONCE))
mu.reg_write(UC_X86_REG_RCX, RCX_ADDRESS)
# Set RAX to some nullbytes to write the data to
mu.mem_write(RAX_ADDRESS, b"\x00" * 1024)
mu.reg_write(UC_X86_REG_RAX, RAX_ADDRESS)
# Set RIP at the start of the function
mu.reg_write(UC_X86_REG_RIP, START_ADDRESS_INIT)
try:
mu.emu_start(START_ADDRESS_INIT, END_ADDRESS_INIT)
return mu.mem_read(RAX_ADDRESS, 192)
except UcError as e:
print("ERROR: %s" % e)
print("at: %x" % mu.reg_read(UC_X86_REG_RIP))
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--infile", required=True, help="Flare-On Challenge 5 liblzma.so.5.4.1")
parser.add_argument("--stack", required=True, help="The dumped stack data")
args = parser.parse_args()
with open(args.infile, "rb") as elf_fh, open(args.stack, "rb") as stack_fh:
code = elf_fh.read()
stack = stack_fh.read()
rax = init_chacha(code=code)
# Fix the 64th byte to accomodate for the decryption loop
rax[64] = ord("@")
pos = 0
while pos < len(stack) - 32:
block = stack[pos : pos + 32]
if block != b"\x00" * 32:
ret_data = decrypt_data(code=code, rax=bytes(rax), stackdata=block)
if b"flare" in ret_data:
print(ret_data)
break
pos += 1
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment