commit 413e5c55f8ed8ae1b1885eae05062f556050412a
parent f73a986ae16975455d86ebd440d86d90d270af6b
Author: Louis Burda <quent.burda@gmail.com>
Date: Sat, 13 Apr 2024 17:55:17 +0200
Add solution
Diffstat:
8 files changed, 105 insertions(+), 106 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,2 @@
+.gdb_history
+core.dump
diff --git a/solve/chall.hash b/solve/chall.hash
@@ -0,0 +1 @@
+c5366939f46a0f6bc44cfad38f99c0ce
diff --git a/solve/crack b/solve/crack
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+hashcat -a 3 -m 0 chall.hash -1 ?u?d '?10?1?1?1-?1?1?1N?1'
+
diff --git a/solve/flag b/solve/flag
@@ -0,0 +1 @@
+CSCG{l1c3ns3_r3v_m4st3r}
diff --git a/solve/license b/solve/license
@@ -0,0 +1 @@
+A1K9B-O33LS-BB821-00GHK-L1MNS
diff --git a/solve/licensecheck.bndb b/solve/licensecheck.bndb
Binary files differ.
diff --git a/solve/notes b/solve/notes
@@ -7,3 +7,18 @@ its only a few functions, could do it by hand.. but to actually learn
something i should try to automate it.
basically want that angr can make it through the init process so the funcs are init.
+
+we can avoid a state blowup by skipping the input checks and encoding them
+into input constraints. then we just jump ahead after the checks have been performed (0x4020d0).
+
+to avoid another blowup, we use lazy evaluation.
+
+a hacky way to get simulation state output is to use sigalarm and reschedule in the
+handler. more standard way is logging.getLogger("..").setLevel(logging.DEBUG)
+
+
+if angr just fails and you know it should be possible - its probably more
+advanced crypto that you would not be able to reverse with symbolic execution anyways
+
+the binarydb is fucked, bad signature matching caused the md5 function to look
+like it was caused address sanitizer compile..
diff --git a/solve/solve b/solve/solve
@@ -2,125 +2,100 @@
import angr
import claripy
-import sys
-import signal
-
-def sigalarm(_a, _b):
- print("STATE", sim, sim.active)
- if len(sim.active) > 0:
- print(sim.active[0].callstack)
- signal.signal(signal.SIGALRM, sigalarm)
- signal.alarm(1)
-signal.signal(signal.SIGALRM, sigalarm)
-
-def sigint(_a, _b):
- from IPython import embed
- embed()
-signal.signal(signal.SIGINT, sigint)
-
-key_addr = 0x1000
-keylen = 29
-key = [claripy.BVS(f"key_{i}", 8) for i in range(keylen)]
-
-project = angr.Project("./licensecheck", auto_load_libs=False)
-
-blank = project.factory.blank_state()
-options = {angr.options.INITIALIZE_ZERO_REGISTERS}
-state = project.factory.call_state(0x402030, key_addr,
- ret_addr=0x4016d6,
- prototype="int check(const char *)",
- add_options=options)
-
-state.memory.store(state.regs.rsp - 0x2000, 0x2000 * b"\x00")
-state.memory.store(0x4cd000, open("got.plt", "rb").read())
-state.regs.rbp = state.regs.rsp
-state.regs.fs = blank.regs.fs
-
-#state.memory[0x401980].uint8_t = 0xc3
-
-binfile = angr.SimFile("licensecheck", open("licensecheck", "rb").read())
-binfile.set_state(state)
-
-for i in range(0, keylen):
- if (i + 1) % 6 == 0:
- key[i] = b'-'
- elif i in (4, 12, 14):
- key[i] = b'B'
- else:
- isalpha = claripy.And(key[i] >= 0x41, key[i] <= 0x41 + 0x19)
- isnum = claripy.And(key[i] >= 0x30, key[i] <= 0x30 + 9)
- state.solver.add(claripy.Or(isalpha, isnum))
- #state.solver.add(key.get_byte(i) >= 0x30)
- #state.solver.add(key.get_byte(i) <= 0x41+0x19)
-
-state.memory.store(key_addr, claripy.Concat(*key, b"\x00" * 0x40))
-
-def print_key(state):
- keystr = b""
- for c in key:
- if type(c) != bytes:
- keystr += state.solver.eval(c, cast_to=bytes)
- else:
- keystr += c
- print(keystr)
-print_key(state)
-
-sim = project.factory.simgr(state)
+import logging
+import subprocess
+import cle
-# sim.explore(find=0x403800)
-# print("__libc_start_main", sim)
-# sim.stash(from_stash="found", to_stash="active")
-#
-# sim.explore(find=0x4061c0)
-# print("main", sim)
+try:
+ import binaryninja
+except:
+ pass
-#raise False
-
-def checkpoint(addr, text):
- sim.explore(find=addr)
- print(text, sim)
- assert(len(sim.found) == 1 and len(sim.active) == 0)
- sim.stash(from_stash="found", to_stash="active")
+check1 = b"A@F01"
+check2 = b"\xc56i9\xf4j\x0fk\xc4L\xfa\xd3\x8f\x99\xc0\xce"
+check2_rev = b"00GHK-L1MNS" # from cracked md5 hash
-def findall(addr, text, avoid=[]):
+def checkpoint(sim, find, text, **kwargs):
while len(sim.active) > 0:
- sim.explore(find=addr, avoid=avoid)
+ sim.explore(find=find, **kwargs, step_func=step_func)
print(text, sim)
+ assert(len(sim.found) > 0)
+ sim.stash(from_stash="found", to_stash="active")
+
+def step_func(sim):
+ if sim.active != [] and bv != None:
+ for state in sim.active:
+ for bb in bv.get_basic_blocks_at(state.solver.eval(state.regs.rip)):
+ bb.set_user_highlight(binaryninja.HighlightStandardColor.MagentaHighlightColor)
+ sim.drop(stash="avoid")
-checkpoint(0x402058, "before strlen")
-checkpoint(0x40205d, "after strlen")
-checkpoint(0x40207f, "after len check")
+ print(sim.active)
-assert(len(sim.active) == 1)
-sim.active[0].regs.rip = 0x4020e4
-signal.alarm(1)
-sim.explore(find=0x402538, avoid=0x4020a4)
-print("found!", sim)
-state = sim.found[0]
-state.solver.add(state.regs.rax != 1)
-print_key()
+def run(_bv=None):
+ global bv
+ bv = _bv
-raise 0
+ logging.getLogger('angr.sim_manager').setLevel(logging.DEBUG)
-signal.alarm(1)
-findall(0x4020d0, "before content check")
-print(sim.found[0].solver.eval(key, cast_to=bytes))
+ key = [claripy.BVS(f"key_{i}", 8) for i in range(29)] + [b"\x00"]
-sim.active[0].options.add(angr.options.LAZY_SOLVES)
+ cmd = ["gdb", "-ex", "b *0x402030", "-ex", "run",
+ "-ex", "gcore core.dump", "-ex", "exit", "--batch",
+ "--args", "./licensecheck", "12345-12345-12345-12345-12345"]
+ subprocess.run(cmd)
-while True:
- sim.explore(find=0x4016ed)
- print("found", sim)
- for state in sim.found:
- print(state.solver.eval(key, cast_to=bytes))
- sim.stash(from_stash="found", to_stash="deadended")
+ project = angr.Project("core.dump", main_opts={"backend": "elfcore"},
+ rebase_granularity=0x1000)
+ binfile = angr.SimFile("licensecheck", open("licensecheck", "rb").read())
+ state = project.factory.blank_state(fs={"licensecheck": binfile})
-raise 0
+ elfcore = None
+ for o in project.loader.all_objects:
+ if type(o) == cle.backends.elf.elfcore.ELFCore:
+ elfcore = o
+ break
+ assert(elfcore is not None)
+ for reg in elfcore.initial_register_values():
+ try:
+ setattr(state.regs, reg[0], reg[1])
+ except Exception as e:
+ print("skip-reg", e)
+ state.memory.store(state.solver.eval(state.regs.rdi), claripy.Concat(*key))
-sim.explore(find=0x4016ed, avoid=[])
-print("found", sim)
-for state in sim.found:
- print(state.solver.eval_upto(key, 2, cast_to=bytes))
+ for i in range(29):
+ if i >= 18:
+ state.solver.add(key[i] == check2_rev[i-18])
+ elif (i + 1) % 6 == 0:
+ state.solver.add(key[i] == ord(b'-'))
+ else:
+ isalpha = claripy.And(key[i] >= ord('A'), key[i] <= ord('Z'))
+ isnum = claripy.And(key[i] >= ord('0'), key[i] <= ord('9'))
+ state.solver.add(claripy.Or(isalpha, isnum))
+
+ # plt sim hooks
+ project.hook(0x4010e0, angr.SIM_PROCEDURES["libc"]["strncpy"]())
+ project.hook(0x4010f0, angr.SIM_PROCEDURES["libc"]["memcmp"]())
+ project.hook(0x401140, angr.SIM_PROCEDURES["libc"]["strcmp"]())
+ project.hook(0x401190, angr.SIM_PROCEDURES["libc"]["strlen"]())
+
+ # libc hooks
+ project.hook(0x40ce40, angr.SIM_PROCEDURES["libc"]["fopen"]())
+ project.hook(0x40cf40, angr.SIM_PROCEDURES["libc"]["fread"]())
+ project.hook(0x40d040, angr.SIM_PROCEDURES["libc"]["puts"]())
+
+ sim = project.factory.simgr(state)
+ checkpoint(sim, 0x402092, "start of loop", avoid=0x4020cb)
+
+ for state in sim.active:
+ state.regs.rip = 0x4020d0
+
+ checkpoint(sim, 0x40245c, "after check1", avoid=0x4020cb)
+ checkpoint(sim, 0x4024aa, "after check2", avoid=0x4020cb)
+ checkpoint(sim, 0x4016ed, "final", avoid=0x4016ec)
+ print(sim.active[0].solver.eval_upto(claripy.Concat(*key), cast_to=bytes, n=2))
+
+if __name__ == "__main__":
+ run()