WIP lakectf
This commit is contained in:
1
2025/lake/rev/android/.gitignore
vendored
Normal file
1
2025/lake/rev/android/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
src_files
|
||||
1
2025/lake/rev/android/.python-version
Normal file
1
2025/lake/rev/android/.python-version
Normal file
@@ -0,0 +1 @@
|
||||
3.12
|
||||
0
2025/lake/rev/android/README.md
Normal file
0
2025/lake/rev/android/README.md
Normal file
BIN
2025/lake/rev/android/anothapk.apk
Normal file
BIN
2025/lake/rev/android/anothapk.apk
Normal file
Binary file not shown.
BIN
2025/lake/rev/android/libohgreat2.so
Normal file
BIN
2025/lake/rev/android/libohgreat2.so
Normal file
Binary file not shown.
BIN
2025/lake/rev/android/libohgreat2.so.id0
Normal file
BIN
2025/lake/rev/android/libohgreat2.so.id0
Normal file
Binary file not shown.
BIN
2025/lake/rev/android/libohgreat2.so.id1
Normal file
BIN
2025/lake/rev/android/libohgreat2.so.id1
Normal file
Binary file not shown.
BIN
2025/lake/rev/android/libohgreat2.so.id2
Normal file
BIN
2025/lake/rev/android/libohgreat2.so.id2
Normal file
Binary file not shown.
BIN
2025/lake/rev/android/libohgreat2.so.nam
Normal file
BIN
2025/lake/rev/android/libohgreat2.so.nam
Normal file
Binary file not shown.
BIN
2025/lake/rev/android/libohgreat2.so.til
Normal file
BIN
2025/lake/rev/android/libohgreat2.so.til
Normal file
Binary file not shown.
6
2025/lake/rev/android/main.py
Normal file
6
2025/lake/rev/android/main.py
Normal file
@@ -0,0 +1,6 @@
|
||||
def main():
|
||||
print("Hello from android!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
9
2025/lake/rev/android/pyproject.toml
Normal file
9
2025/lake/rev/android/pyproject.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[project]
|
||||
name = "android"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"z3-solver>=4.15.4.0",
|
||||
]
|
||||
164
2025/lake/rev/android/solve.py
Normal file
164
2025/lake/rev/android/solve.py
Normal file
@@ -0,0 +1,164 @@
|
||||
import os
|
||||
import re
|
||||
from z3 import *
|
||||
|
||||
# ================= CONFIGURATION =================
|
||||
# Path to the folder containing the decompiled .java files
|
||||
SOURCE_DIR = "./src_files/sources/com/lake/ctf"
|
||||
|
||||
# Initial Entry Point (From the Native Init function)
|
||||
START_CLASS_HASH = "86e50149658661312a9e0b35558d84f6c6d3da797f552a9657fe0558ca40cdef"
|
||||
START_METHOD_HASH = "031b4af5197ec30a926f48cf40e11a7dbc470048a21e4003b7a3c07c5dab1baa"
|
||||
|
||||
# ================= Z3 SETUP =================
|
||||
# UPDATED: Flag length is explicitly 55 based on MainActivity
|
||||
FLAG_LEN = 55
|
||||
# UPDATED: The app checks exactly 80 links in the chain
|
||||
MAX_STEPS = 80
|
||||
|
||||
solver = Solver()
|
||||
flag_vars = [BitVec(f"flag_{i}", 8) for i in range(FLAG_LEN)]
|
||||
|
||||
# Add printable ASCII constraints
|
||||
for i in range(FLAG_LEN):
|
||||
solver.add(flag_vars[i] >= 32)
|
||||
solver.add(flag_vars[i] <= 126)
|
||||
|
||||
# ================= HELPER CLASSES =================
|
||||
|
||||
class MockString:
|
||||
"""
|
||||
A helper class to allow us to 'eval' the Java equation directly.
|
||||
"""
|
||||
def charAt(self, index):
|
||||
if index >= FLAG_LEN:
|
||||
# This is now a critical error since we know the exact length
|
||||
print(f"[!] Critical: Equation references index {index} which is >= 55.")
|
||||
return 0
|
||||
|
||||
# We must zero-extend to 32 bits because Java intermediate math is int (32-bit)
|
||||
# but our chars are 8-bit.
|
||||
return ZeroExt(24, flag_vars[index])
|
||||
|
||||
# ================= MAIN LOGIC =================
|
||||
|
||||
def load_files():
|
||||
"""Reads all Java files into a dictionary keyed by Class Hash."""
|
||||
files_map = {}
|
||||
if not os.path.exists(SOURCE_DIR):
|
||||
print(f"Error: Directory {SOURCE_DIR} not found.")
|
||||
return {}
|
||||
|
||||
print(f"[*] Loading files from {SOURCE_DIR}...")
|
||||
for f in os.listdir(SOURCE_DIR):
|
||||
if f.endswith(".java") and f.startswith("Check"):
|
||||
class_hash = f.replace("Check", "").replace(".java", "")
|
||||
with open(os.path.join(SOURCE_DIR, f), "r") as file_obj:
|
||||
files_map[class_hash] = file_obj.read()
|
||||
print(f"[*] Loaded {len(files_map)} files.")
|
||||
return files_map
|
||||
|
||||
def extract_logic(class_hash, method_hash, files_map):
|
||||
content = files_map.get(class_hash)
|
||||
if not content:
|
||||
print(f"[!] Critical: Class hash {class_hash} not found on disk.")
|
||||
return None, None, None
|
||||
|
||||
# Pattern: static boolean Check[METHOD_HASH](String str) { BODY }
|
||||
method_pattern = re.compile(rf"static boolean Check{method_hash}\(String (\w+)\)\s*\{{(.*?)\}}", re.DOTALL)
|
||||
match = method_pattern.search(content)
|
||||
|
||||
if not match:
|
||||
print(f"[!] Critical: Method {method_hash} not found in class {class_hash}.")
|
||||
return None, None, None
|
||||
|
||||
param_name = match.group(1)
|
||||
body = match.group(2)
|
||||
|
||||
# Extract the 'if' condition
|
||||
if_match = re.search(r"if\s*\((.*)\)\s*\{", body)
|
||||
if not if_match:
|
||||
return None, None, None
|
||||
|
||||
equation_str = if_match.group(1)
|
||||
|
||||
# Extract the 'Success' Nop call
|
||||
if_block_start = body.find("{")
|
||||
if_block_end = body.find("}", if_block_start)
|
||||
if_block_content = body[if_block_start:if_block_end]
|
||||
|
||||
nop_match = re.search(r'nop\("([a-f0-9]+)",\s*"([a-f0-9]+)"\)', if_block_content)
|
||||
|
||||
if not nop_match:
|
||||
return equation_str, None, None
|
||||
|
||||
return equation_str, nop_match.group(1), nop_match.group(2)
|
||||
|
||||
def solve():
|
||||
files_map = load_files()
|
||||
if not files_map: return
|
||||
|
||||
curr_class = START_CLASS_HASH
|
||||
curr_method = START_METHOD_HASH
|
||||
|
||||
step_count = 0
|
||||
visited = set()
|
||||
|
||||
print(f"[*] Starting traversal for exactly {MAX_STEPS} steps...")
|
||||
|
||||
# UPDATED: Loop exactly MAX_STEPS times
|
||||
for i in range(MAX_STEPS):
|
||||
if not curr_class:
|
||||
print("[!] Chain ended prematurely!")
|
||||
break
|
||||
|
||||
# Loop detection (just in case, though duplicates are mathematically fine)
|
||||
if (curr_class, curr_method) in visited:
|
||||
print(f"[i] Loop detected at step {i+1}. This is fine, just adding redundant constraints.")
|
||||
visited.add((curr_class, curr_method))
|
||||
|
||||
step_count += 1
|
||||
|
||||
eq_str, next_class, next_method = extract_logic(curr_class, curr_method, files_map)
|
||||
|
||||
if not eq_str:
|
||||
break
|
||||
|
||||
try:
|
||||
if "==" in eq_str:
|
||||
lhs, rhs = eq_str.split("==")
|
||||
ctx = {'str': MockString()}
|
||||
lhs_expr = eval(lhs.strip(), {}, ctx)
|
||||
rhs_val = int(eval(rhs.strip(), {}, {}))
|
||||
solver.add(lhs_expr == rhs_val)
|
||||
else:
|
||||
print(f"[!] Warning: Equation format unknown: {eq_str}")
|
||||
except Exception as e:
|
||||
print(f"[!] Error parsing equation: {eq_str}")
|
||||
break
|
||||
|
||||
curr_class = next_class
|
||||
curr_method = next_method
|
||||
|
||||
print(f"[*] Extraction complete. {step_count} constraints added.")
|
||||
print("[*] Solving with Z3...")
|
||||
|
||||
if solver.check() == sat:
|
||||
model = solver.model()
|
||||
result = []
|
||||
for i in range(FLAG_LEN):
|
||||
val = model[flag_vars[i]]
|
||||
if val is not None:
|
||||
result.append(chr(val.as_long()))
|
||||
else:
|
||||
result.append("?")
|
||||
|
||||
final_flag = "".join(result)
|
||||
print("\n" + "="*50)
|
||||
print(f"FLAG: {final_flag}")
|
||||
print("="*50 + "\n")
|
||||
else:
|
||||
print("[!] Unsatisfiable! Constraints might be contradictory.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
solve()
|
||||
28
2025/lake/rev/android/uv.lock
generated
Normal file
28
2025/lake/rev/android/uv.lock
generated
Normal file
@@ -0,0 +1,28 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[[package]]
|
||||
name = "android"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "z3-solver" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "z3-solver", specifier = ">=4.15.4.0" }]
|
||||
|
||||
[[package]]
|
||||
name = "z3-solver"
|
||||
version = "4.15.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8a/8e/0c8f17309549d2e5cde9a3ccefa6365437f1e7bafe71878eaf9478e47b18/z3_solver-4.15.4.0.tar.gz", hash = "sha256:928c29b58c4eb62106da51c1914f6a4a55d0441f8f48a81b9da07950434a8946", size = 5018600, upload-time = "2025-10-29T18:12:03.062Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/63/33/a3d5d2eaeb0f7b3174d57d405437eabb2075d4d50bd9ea0957696c435c7b/z3_solver-4.15.4.0-py3-none-macosx_13_0_arm64.whl", hash = "sha256:407e825cc9211f95ef46bdc8d151bf630e7ab2d62a21d24cd74c09cc5b73f3aa", size = 37052538, upload-time = "2025-10-29T18:11:46.233Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/84/fd7ffac1551cd9f8d44fe41358f738be670fc4c24dfd514fab503f2cf3e7/z3_solver-4.15.4.0-py3-none-macosx_13_0_x86_64.whl", hash = "sha256:00bd10c5a6a5f6112d3a9a810d0799227e52f76caa860dafa5e00966bb47eb13", size = 39807925, upload-time = "2025-10-29T18:11:49.81Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/c9/bb51a96af0091324c81b803f16c49f719f9f6ea0b0bb52200f5c97ec4892/z3_solver-4.15.4.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e103a6f203f505b8b8b8e5c931cc407c95b61556512d4921c1ddc0b3f41b08e", size = 29268352, upload-time = "2025-10-29T18:11:53.032Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/2e/0b49f7e4e53817cfb09a0f6585012b782dfe0b666e8abefcb4fac0570606/z3_solver-4.15.4.0-py3-none-manylinux_2_34_aarch64.whl", hash = "sha256:62c7e9cbdd711932301f29919ad9158de9b2f58b4d281dd259bbcd0a2f408ba1", size = 27226534, upload-time = "2025-10-29T18:11:55.59Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/91/33de49538444d4aafbe47415c450c2f9abab1733e1226f276b496672f46c/z3_solver-4.15.4.0-py3-none-win32.whl", hash = "sha256:be3bc916545c96ffbf89e00d07104ff14f78336e55db069177a1bfbcc01b269d", size = 13191672, upload-time = "2025-10-29T18:11:58.424Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/d6/a0b135e4419df475177ae78fc93c422430b0fd8875649486f9a5989772e6/z3_solver-4.15.4.0-py3-none-win_amd64.whl", hash = "sha256:00e35b02632ed085ea8199fb230f6015e6fc40554a6680c097bd5f060e827431", size = 16259597, upload-time = "2025-10-29T18:12:01.14Z" },
|
||||
]
|
||||
Reference in New Issue
Block a user