cleanup
This commit is contained in:
45
2026/cscg/rev/gloomweaver/dump_hook.c
Normal file
45
2026/cscg/rev/gloomweaver/dump_hook.c
Normal file
@@ -0,0 +1,45 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int puts(const char *s) {
|
||||
FILE *maps = fopen("/proc/self/maps", "r");
|
||||
char line[512];
|
||||
uintptr_t base = 0;
|
||||
|
||||
while (fgets(line, sizeof(line), maps)) {
|
||||
if (strstr(line, "gloomweaver") && strstr(line, "rwxp")) {
|
||||
sscanf(line, "%lx", &base);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(maps);
|
||||
|
||||
if (base) {
|
||||
uintptr_t text = base - 0x1000; // file base (rwxp is at offset 0x1000)
|
||||
|
||||
// Dump the 55x55 matrix at virtual 0x1253 (in rw-p segment at offset 0)
|
||||
FILE *f;
|
||||
f = fopen("/tmp/matrix_1253.bin", "wb");
|
||||
fwrite((void *)(text + 0x1253), 1, 55*55, f); fclose(f);
|
||||
|
||||
f = fopen("/tmp/table_2605.bin", "wb");
|
||||
fwrite((void *)(text + 0x2605), 1, 55, f); fclose(f);
|
||||
|
||||
f = fopen("/tmp/table_2697.bin", "wb");
|
||||
fwrite((void *)(text + 0x2697), 1, 55, f); fclose(f);
|
||||
|
||||
// Expected output: 55 words = 110 bytes
|
||||
f = fopen("/tmp/expected_2119.bin", "wb");
|
||||
fwrite((void *)(text + 0x2119), 1, 110, f); fclose(f);
|
||||
|
||||
// Also dump the full patched code again with broader range
|
||||
f = fopen("/tmp/full_dump.bin", "wb");
|
||||
fwrite((void *)text, 1, 0x8000, f); fclose(f);
|
||||
}
|
||||
|
||||
write(1, s, strlen(s));
|
||||
write(1, "\n", 1);
|
||||
return 0;
|
||||
}
|
||||
BIN
2026/cscg/rev/gloomweaver/dump_hook.so
Executable file
BIN
2026/cscg/rev/gloomweaver/dump_hook.so
Executable file
Binary file not shown.
28
2026/cscg/rev/gloomweaver/find_hash.py
Normal file
28
2026/cscg/rev/gloomweaver/find_hash.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# find_hash.py — find a flag that passes the checksum
|
||||
import struct
|
||||
|
||||
def compute_hash(flag_bytes):
|
||||
eax = 0x65
|
||||
for b in flag_bytes:
|
||||
ecx = eax & 0xFFFFFFFF
|
||||
edx = eax & 0xFF # dl only
|
||||
ecx = (ecx << 6) & 0xFFFFFFFF
|
||||
edx = (edx >> 6) & 0xFF
|
||||
eax = (eax + ecx) & 0xFFFFFFFF
|
||||
eax = (eax + edx) & 0xFFFFFFFF
|
||||
eax ^= b
|
||||
return eax & 0xFF
|
||||
|
||||
prefix = b"CTF{th1s_"
|
||||
suffix = b"}"
|
||||
# 64 bytes total: 9 prefix + 54 middle + 1 suffix
|
||||
# Try different last middle byte
|
||||
for last in range(0x21, 0x7F):
|
||||
middle = b"A" * 53 + bytes([last])
|
||||
flag = prefix + middle + suffix
|
||||
assert len(flag) == 64
|
||||
h = compute_hash(flag)
|
||||
if h == 0x0C:
|
||||
print(f"Found: {flag.decode()}")
|
||||
print(f"Hash: 0x{h:02x}")
|
||||
break
|
||||
BIN
2026/cscg/rev/gloomweaver/gloomweaver
Executable file
BIN
2026/cscg/rev/gloomweaver/gloomweaver
Executable file
Binary file not shown.
BIN
2026/cscg/rev/gloomweaver/gloomweaver.bak
Normal file
BIN
2026/cscg/rev/gloomweaver/gloomweaver.bak
Normal file
Binary file not shown.
BIN
2026/cscg/rev/gloomweaver/gloomweaver.i64
Normal file
BIN
2026/cscg/rev/gloomweaver/gloomweaver.i64
Normal file
Binary file not shown.
1
2026/cscg/rev/gloomweaver/hash_CTF
Normal file
1
2026/cscg/rev/gloomweaver/hash_CTF
Normal file
@@ -0,0 +1 @@
|
||||
caf5d17185a42bf99e74224d738c33e555aa086b27ee5de56bc35053dc386c1a /tmp/gloom_region_0.bin
|
||||
1
2026/cscg/rev/gloomweaver/hash_dach
Normal file
1
2026/cscg/rev/gloomweaver/hash_dach
Normal file
@@ -0,0 +1 @@
|
||||
4c77553b5cfaa9c0f896574baecaf29cf0625943299999cbe436cb4e708724c1 /tmp/gloom_region_0.bin
|
||||
95
2026/cscg/rev/gloomweaver/solve.py
Normal file
95
2026/cscg/rev/gloomweaver/solve.py
Normal file
@@ -0,0 +1,95 @@
|
||||
# solve.py
|
||||
import numpy as np
|
||||
|
||||
# Load tables
|
||||
matrix_raw = open("/tmp/matrix_1253.bin", "rb").read()
|
||||
table_a = open("/tmp/table_2605.bin", "rb").read() # 55 bytes
|
||||
table_b = open("/tmp/table_2697.bin", "rb").read() # 55 bytes
|
||||
expected_raw = open("/tmp/expected_2119.bin", "rb").read() # 110 bytes
|
||||
|
||||
# Build coefficient matrix mod 256
|
||||
# coeff[i][j] = ((table_a[i] * table_b[j] * 1337) & 0xFF + matrix[i*55+j]) & 0xFF
|
||||
M = np.zeros((55, 55), dtype=np.int64)
|
||||
for i in range(55):
|
||||
for j in range(55):
|
||||
ab = table_a[i] * table_b[j] # 8x8 -> 16-bit
|
||||
val = (ab * 1337) & 0xFF # imul then take low byte
|
||||
val = (val + matrix_raw[i * 55 + j]) & 0xFF # add matrix element
|
||||
M[i][j] = val
|
||||
|
||||
# Expected values — try byte extraction (every other byte = low bytes of words)
|
||||
# The cmpsw comparison uses words, so expected is 55 x 2-byte values
|
||||
# Result bytes are at rsp[0..54], compared as words: (rsp[0],rsp[1]), (rsp[2],rsp[3])...
|
||||
# Since only odd-indexed bytes have values, let's try both interpretations
|
||||
|
||||
# Interpretation 1: expected is just the first 55 bytes
|
||||
expected_bytes = list(expected_raw[:55])
|
||||
|
||||
# Interpretation 2: expected is every other byte (word low bytes)
|
||||
expected_words_lo = [expected_raw[i*2] for i in range(55)]
|
||||
|
||||
print("Expected (first 55 bytes):", [hex(x) for x in expected_bytes[:10]])
|
||||
print("Expected (word lo bytes):", [hex(x) for x in expected_words_lo[:10]])
|
||||
|
||||
# Gaussian elimination mod 256
|
||||
def solve_mod256(M, b):
|
||||
n = len(b)
|
||||
# Augmented matrix
|
||||
aug = np.zeros((n, n+1), dtype=np.int64)
|
||||
for i in range(n):
|
||||
for j in range(n):
|
||||
aug[i][j] = M[i][j] % 256
|
||||
aug[i][n] = b[i] % 256
|
||||
|
||||
# Forward elimination
|
||||
for col in range(n):
|
||||
# Find pivot with odd value (invertible mod 256 requires gcd(pivot,256)=1)
|
||||
pivot = -1
|
||||
for row in range(col, n):
|
||||
if aug[row][col] % 2 == 1: # odd = invertible mod 256
|
||||
pivot = row
|
||||
break
|
||||
if pivot == -1:
|
||||
print(f"No odd pivot at column {col}, trying any nonzero...")
|
||||
for row in range(col, n):
|
||||
if aug[row][col] != 0:
|
||||
pivot = row
|
||||
break
|
||||
if pivot == -1:
|
||||
print(f"Singular at column {col}")
|
||||
return None
|
||||
|
||||
# Swap
|
||||
aug[[col, pivot]] = aug[[pivot, col]]
|
||||
|
||||
# Compute inverse of pivot mod 256
|
||||
pv = int(aug[col][col]) % 256
|
||||
inv = pow(pv, -1, 256) if pv % 2 == 1 else None
|
||||
if inv is None:
|
||||
print(f"Non-invertible pivot {pv} at col {col}")
|
||||
return None
|
||||
|
||||
# Scale pivot row
|
||||
aug[col] = (aug[col] * inv) % 256
|
||||
|
||||
# Eliminate
|
||||
for row in range(n):
|
||||
if row != col and aug[row][col] != 0:
|
||||
factor = int(aug[row][col])
|
||||
aug[row] = (aug[row] - factor * aug[col]) % 256
|
||||
|
||||
solution = aug[:, n] % 256
|
||||
return solution
|
||||
|
||||
# Try both interpretations
|
||||
for name, expected in [("first_55_bytes", expected_bytes),
|
||||
("word_lo_bytes", expected_words_lo)]:
|
||||
print(f"\n=== Trying {name} ===")
|
||||
sol = solve_mod256(M, expected)
|
||||
if sol is not None:
|
||||
flag_content = bytes([int(x) for x in sol])
|
||||
flag = b"CTF{th1s" + flag_content + b"}"
|
||||
printable = all(0x20 <= b < 0x7f for b in flag_content)
|
||||
print(f"Solution: {flag}")
|
||||
print(f"Printable: {printable}")
|
||||
print(f"Hex: {flag_content.hex()}")
|
||||
20
2026/cscg/rev/gloomweaver/trace_hook.c
Normal file
20
2026/cscg/rev/gloomweaver/trace_hook.c
Normal file
@@ -0,0 +1,20 @@
|
||||
// trace_hook.c — intercept signal handler to log VM state
|
||||
#define _GNU_SOURCE
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
static FILE *trace;
|
||||
|
||||
int sigaction(int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact) {
|
||||
// Log which signals are being registered
|
||||
if (!trace) trace = fopen("/tmp/vm_trace.txt", "w");
|
||||
fprintf(trace, "sigaction(%d)\n", signum);
|
||||
fflush(trace);
|
||||
|
||||
// Call real sigaction
|
||||
int (*real)(int, const struct sigaction*, struct sigaction*) =
|
||||
dlsym(RTLD_NEXT, "sigaction");
|
||||
return real(signum, act, oldact);
|
||||
}
|
||||
BIN
2026/cscg/rev/gloomweaver/trace_hook.so
Executable file
BIN
2026/cscg/rev/gloomweaver/trace_hook.so
Executable file
Binary file not shown.
BIN
2026/cscg/rev/gloomweaver/tracer
Executable file
BIN
2026/cscg/rev/gloomweaver/tracer
Executable file
Binary file not shown.
64
2026/cscg/rev/gloomweaver/tracer.c
Normal file
64
2026/cscg/rev/gloomweaver/tracer.c
Normal file
@@ -0,0 +1,64 @@
|
||||
// tracer2.c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/user.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
pid_t child = fork();
|
||||
if (child == 0) {
|
||||
ptrace(PTRACE_TRACEME, 0, 0, 0);
|
||||
raise(SIGSTOP);
|
||||
execv(argv[1], &argv[1]);
|
||||
perror("exec");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int status;
|
||||
waitpid(child, &status, 0);
|
||||
|
||||
// Use TRACEEXEC to catch the exec, then CONT (not SYSCALL)
|
||||
ptrace(PTRACE_SETOPTIONS, child, 0, PTRACE_O_TRACEEXEC);
|
||||
ptrace(PTRACE_CONT, child, 0, 0);
|
||||
|
||||
FILE *log = fopen("/tmp/signal_trace.txt", "w");
|
||||
int count = 0;
|
||||
|
||||
while (1) {
|
||||
waitpid(child, &status, 0);
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
fprintf(log, "Exited: %d (signals: %d)\n", WEXITSTATUS(status), count);
|
||||
break;
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
fprintf(log, "Killed by signal %d\n", WTERMSIG(status));
|
||||
break;
|
||||
}
|
||||
if (WIFSTOPPED(status)) {
|
||||
int sig = WSTOPSIG(status);
|
||||
|
||||
// Exec event — swallow, continue
|
||||
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_EXEC << 8))) {
|
||||
fprintf(log, "Exec event\n");
|
||||
ptrace(PTRACE_CONT, child, 0, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct user_regs_struct regs;
|
||||
ptrace(PTRACE_GETREGS, child, 0, ®s);
|
||||
fprintf(log, "Signal %2d at RIP=0x%llx RDI=%lld RSI=0x%llx\n",
|
||||
sig, regs.rip, regs.rdi, regs.rsi);
|
||||
fflush(log);
|
||||
count++;
|
||||
|
||||
// Forward the signal
|
||||
ptrace(PTRACE_CONT, child, 0, sig);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(log);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user