-
-
Save sud0woodo/a22c9f96ece8e7bdf19c0ffbe7654fde to your computer and use it in GitHub Desktop.
Flare-On 11 Challenge 5
This file contains hidden or 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
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