Guest User

Untitled

a guest
Dec 29th, 2025
164
0
Never
5
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.59 KB | Cybersecurity | 0 0
  1. hxp CTF 2025: Sharing Solution
  2. hubertf, 2025-12-30
  3.  
  4. High-Level Flow:
  5. Takes flag as command-line argument (38 bytes: hxp{...34 chars...})
  6. Spawns a worker thread
  7. Both threads perform GF(251) matrix transformations
  8. Main thread accumulates results from both threads
  9. Success if all output bytes equal 0
  10.  
  11. Mathematical Model:
  12. The transformation is linear in Galois Field GF(251):
  13. output = A × flag + b (mod 251)
  14.  
  15. where:
  16. A is a 42x42 matrix in GF(251)
  17. b is a constant vector (depends on hardcoded values)
  18. flag is the user input (42 bytes, padded with zeros if shorter)
  19.  
  20. Since the transformation is linear:
  21.  
  22. A × flag + b = 0
  23. A × flag = -b
  24. flag = A⁻¹ × (-b)
  25.  
  26. Solution:
  27.  
  28. (venv.39c3) 39c3$ cat ../2solve.py
  29. #!/usr/bin/env python3
  30. """
  31. hxp CTF 2025 - "sharing" Challenge Solver
  32. """
  33.  
  34. import subprocess
  35. import json
  36. import os
  37. import sys
  38. import tempfile
  39.  
  40. def gf251_add(a, b): return (a + b) % 251
  41. def gf251_sub(a, b): return (a - b + 251) % 251
  42. def gf251_mul(a, b): return (a * b) % 251
  43. def gf251_inv(a): return pow(a, 249, 251) if a else 0
  44.  
  45. def matrix_inverse_gf251(mat):
  46. n = len(mat)
  47. aug = [[mat[i][j] for j in range(n)] + [1 if i==k else 0 for k in range(n)] for i in range(n)]
  48. for col in range(n):
  49. pivot = next((r for r in range(col, n) if aug[r][col] != 0), None)
  50. if pivot is None: return None
  51. aug[col], aug[pivot] = aug[pivot], aug[col]
  52. inv_p = gf251_inv(aug[col][col])
  53. aug[col] = [gf251_mul(x, inv_p) for x in aug[col]]
  54. for row in range(n):
  55. if row != col and aug[row][col] != 0:
  56. f = aug[row][col]
  57. aug[row] = [gf251_sub(aug[row][j], gf251_mul(f, aug[col][j])) for j in range(2*n)]
  58. return [[aug[i][n+j] for j in range(n)] for i in range(n)]
  59.  
  60. def matrix_vector_mul(mat, vec):
  61. return [sum(gf251_mul(mat[i][j], vec[j]) for j in range(len(vec))) % 251 for i in range(len(mat))]
  62.  
  63. def get_output_via_gdb(binary_path, flag_str, debug=False):
  64. """Extract 42-byte output using GDB with Python."""
  65. escaped = flag_str.replace('\\', '\\\\').replace('"', '\\"')
  66.  
  67. gdb_script = f'''set pagination off
  68. set confirm off
  69. set args "{escaped}"
  70. starti
  71. python
  72. import gdb
  73. output = gdb.execute("info proc mappings", to_string=True)
  74. base = None
  75. for line in output.split('\\n'):
  76. # Look for executable section (r-xp) of our binary
  77. if 'r-xp' in line and 'sharing' in line:
  78. parts = line.split()
  79. base = int(parts[0], 16)
  80. break
  81. if base is None:
  82. print("ERROR: Could not find base address")
  83. gdb.execute("quit")
  84. bp_addr = base + 0xb73
  85. gdb.execute(f"break *{{hex(bp_addr)}}")
  86. gdb.execute("continue")
  87. result = []
  88. for i in range(42):
  89. val = gdb.parse_and_eval(f"*(unsigned char*)($rsp+0x40+{{i}})")
  90. result.append(int(val))
  91. print("RESULT:" + ",".join(map(str, result)))
  92. end
  93. quit
  94. '''
  95.  
  96. with tempfile.NamedTemporaryFile(mode='w', suffix='.gdb', delete=False) as f:
  97. f.write(gdb_script)
  98. script_path = f.name
  99.  
  100. try:
  101. result = subprocess.run(
  102. ['gdb', '-batch', '-x', script_path, binary_path],
  103. capture_output=True, text=True, timeout=30
  104. )
  105.  
  106. if debug:
  107. print("=== GDB STDOUT ===")
  108. print(result.stdout[-2000:])
  109. print("=== GDB STDERR ===")
  110. print(result.stderr[-500:])
  111.  
  112. for line in result.stdout.split('\n'):
  113. if line.startswith('RESULT:'):
  114. vals = [int(x) for x in line[7:].split(',')]
  115. if len(vals) == 42:
  116. return vals
  117. if line.startswith('ERROR:'):
  118. print(f"[!] {line}")
  119. except Exception as e:
  120. print(f"[!] GDB error: {e}")
  121. finally:
  122. os.unlink(script_path)
  123.  
  124. return None
  125.  
  126. def extract_matrix(binary_path, size=42):
  127. print("[*] Extracting transformation matrix...")
  128. base_flag = "hxp{" + " " * 37 + "}"
  129.  
  130. print("[*] Testing GDB extraction...")
  131. base_output = get_output_via_gdb(binary_path, base_flag, debug=True)
  132. if base_output is None:
  133. raise RuntimeError("GDB extraction failed - see debug output above")
  134.  
  135. print(f"[+] Base output: {base_output[:6]}...")
  136.  
  137. A_cols = []
  138. for col in range(size):
  139. chars = list(base_flag)
  140. if col < len(chars):
  141. chars[col] = chr((ord(chars[col]) + 1) % 256)
  142. test_flag = ''.join(chars)
  143.  
  144. out = get_output_via_gdb(binary_path, test_flag)
  145. if out is None:
  146. print(f"[!] Failed at column {col}")
  147. A_cols.append([0] * size)
  148. else:
  149. A_cols.append([gf251_sub(out[i], base_output[i]) for i in range(size)])
  150.  
  151. if (col + 1) % 10 == 0:
  152. print(f"[*] Progress: {col + 1}/{size}")
  153.  
  154. return {'A': A_cols, 'b': base_output, 'base_flag': [ord(c) for c in base_flag]}
  155.  
  156. def solve(data):
  157. A = [[data['A'][j][i] for j in range(42)] for i in range(42)]
  158. A_inv = matrix_inverse_gf251(A)
  159. if A_inv is None:
  160. raise RuntimeError("Matrix singular")
  161. neg_b = [(251 - x) % 251 for x in data['b']]
  162. delta = matrix_vector_mul(A_inv, neg_b)
  163. flag = [gf251_add(data['base_flag'][i], delta[i]) for i in range(42)]
  164. while flag and flag[-1] == 0:
  165. flag.pop()
  166. return bytes(flag)
  167.  
  168. def main():
  169. binary = './sharing'
  170. cache = 'matrix_cache.json'
  171.  
  172. if not os.path.exists(binary):
  173. print(f"[!] Binary not found: {binary}")
  174. sys.exit(1)
  175.  
  176. if '--extract' in sys.argv or not os.path.exists(cache):
  177. print("[*] Extracting matrix (~2 min)...")
  178. data = extract_matrix(binary)
  179. with open(cache, 'w') as f:
  180. json.dump(data, f)
  181. print(f"[+] Saved to {cache}")
  182. else:
  183. print(f"[*] Loading {cache}")
  184. with open(cache) as f:
  185. data = json.load(f)
  186.  
  187. print("[*] Solving...")
  188. flag = solve(data)
  189. print(f"\n[+] Flag: {flag.decode()}")
  190.  
  191. result = subprocess.run([binary, flag.decode()], capture_output=True, text=True)
  192. if ':)' in result.stdout:
  193. print("[+] Verified!")
  194. else:
  195. print("[!] Verification failed")
  196.  
  197. if __name__ == '__main__':
  198. main()
  199.  
  200.  
  201. Run it:
  202.  
  203. (venv.39c3) 39c3$ python3 ../2solve.py --extract
  204. [*] Extracting matrix (~2 min)...
  205. [*] Extracting transformation matrix...
  206. [*] Testing GDB extraction...
  207. === GDB STDOUT ===
  208.  
  209. This GDB supports auto-downloading debuginfo from the following URLs:
  210. <https://debuginfod.ubuntu.com>
  211. Enable debuginfod for this session? (y or [n]) [answered N; input not from terminal]
  212. Debuginfod has been disabled.
  213. To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit.
  214.  
  215. Program stopped.
  216. 0x00007ffff7fe4540 in _start () from /lib64/ld-linux-x86-64.so.2
  217. Breakpoint 1 at 0x555555556b73
  218. [Thread debugging using libthread_db enabled]
  219. Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
  220. [New Thread 0x7ffff77ff6c0 (LWP 175730)]
  221. [Thread 0x7ffff77ff6c0 (LWP 175730) exited]
  222.  
  223. Thread 1 "sharing" hit Breakpoint 1, 0x0000555555556b73 in ?? ()
  224. RESULT:5,100,31,189,7,159,128,125,151,209,217,83,1,109,96,26,69,151,111,3,203,139,103,168,53,139,246,4,123,133,0,164,126,213,14,21,15,113,118,16,161,119
  225.  
  226. === GDB STDERR ===
  227.  
  228. [+] Base output: [5, 100, 31, 189, 7, 159]...
  229. [*] Progress: 10/42
  230. [*] Progress: 20/42
  231. [*] Progress: 30/42
  232. [*] Progress: 40/42
  233. [+] Saved to matrix_cache.json
  234. [*] Solving...
  235.  
  236. [+] Flag: hxp{te4mw0rk-maKe5-the-n!ghtm4re-w0rk}
  237. [+] Verified!
  238. (venv.39c3) 39c3$
  239. (venv.39c3) 39c3$ ./sharing 'hxp{te4mw0rk-maKe5-the-n!ghtm4re-w0rk}'
  240. :)
  241.  
  242. Enjoy!
Tags: hxp ctf
Advertisement
Comments
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
Add Comment
Please, Sign In to add comment