./contents.sh

z0d1ak@ctf:~$ cat sections.md
z0d1ak@ctf:~$ _
writeup.md - z0d1ak@ctf
Reverse Engineering
0CTF
December 22, 2025
2 min read

0CTF - JSHacker1

theg1239
z0d1ak@ctf:~$ ./author.sh

# JSHacker1

## Challenge Summary

We are given a bundled V8 d8 binary and an obfuscated JS file. The service
asks for a token via nc instance.penguin.0ops.sjtu.cn <port>. A valid token
prints the real flag, otherwise it prints Fail..

## Quick Analysis

The obfuscated JS:

  • Parses the input token as R:S:ALG.

  • Computes H = sha256(R_bytes) and checks a Schnorr-style equation:
    g^s ≡ R * y^H (mod p).

  • It wires the V8 inspector and, on a Debugger.paused event inside the wasm,
    runs:

    Debugger.evaluateOnCallFrame with expression:

    "Testing " + __alg
    

Because __alg is taken directly from user input, it is injected into an
evaluated JS expression without sanitization. That gives us code execution.

## The Bug

The comparison step strips leading zeros:

ret66 = ipikjtjsod.toString(16).replace(/^0+/, "")
ret67 = jmpynkyipn.toString(16).replace(/^0+/, "")

If we override String.prototype.replace, the comparison becomes trivial.

## Exploit

We inject a payload as the ALG part. To avoid : (which would break token
splitting), use an assignment expression that is valid in the
"Testing " + __alg context:

ALG = "=0,String.prototype.replace=function(){return '0'}"

Token:

00:0:=0,String.prototype.replace=function(){return '0'}

Now both replace(...) calls return "0", so the check passes and the server
prints the flag.

## Flag

0ops{j5d8_d8j$_j$v8_v8Js_MwouixvFQ6L8J52R}

Comments(0)

No comments yet. Be the first to share your thoughts!