I had the honor to partcipate in 2025 nexhunt ctf ,So here we are on the Blockchain Network,lets dive in and solve this challenges and get some flags.
this writeup is clearly for the blockchain challenges on this ctf.
first challenge

Goal: Find the flag hidden in the transaction data of a Sepolia testnet transaction.
Provided Information:
- Transaction Hash:
0x1c1e14180c2e5dceefc260208199e23a8c61524dd54bd2e378cee00e14555c14 - Contract Address:
0xFb67326dAacdD9163c0eeEB9E429D7D4B6c4EBb1 - Network:
Sepolia Testnet
Steps Taken
-
Analyze the Transaction on Etherscan: The first step was to view the transaction details on the Sepolia Etherscan explorer. This is the standard procedure for analyzing any on-chain activity.
- URL:
https://sepolia.etherscan.io/tx/0x1c1e14180c2e5dceefc260208199e23a8c61524dd54bd2e378cee00e14555c14
- URL:
“

-
Inspect Input Data: On the transaction details page, the most relevant field for hidden data is the**
Input Data** (also known as the transaction payload). This field contained a longhexadecimal string, which is thebytecodefor the contract creation and initialization. -
Identify the Hidden String: The challenge states the flag is “hidden somewhere in the transaction data.” In
blockchain CTFs, flags are often stored as a simple string encoded in hexadecimal (ASCII or UTF-8) within the input data. I searched the raw hexadecimal input data for the hex representation of the common flag prefix,nexus{, which is6e657875737b. -
automate:
Then for an easy path i told ai to create for me a script to decode the entire blob to get the flag.
#!/usr/bin/env python3 # evm_disasm.py # Usage: python3 evm_disasm.py bytecode.txt # or: python3 evm_disasm.py 6080604052... # # Output: readable disassembly + extracted strings + metadata sniffing import sys import re from textwrap import shorten # Minimal EVM opcode table for readability (common opcodes) OPCODES = { 0x00: "STOP",0x01:"ADD",0x02:"MUL",0x03:"SUB",0x04:"DIV",0x05:"SDIV",0x06:"MOD",0x07:"SMOD", 0x08:"ADDMOD",0x09:"MULMOD",0x0a:"EXP",0x0b:"SIGNEXTEND", 0x10:"LT",0x11:"GT",0x12:"SLT",0x13:"SGT",0x14:"EQ",0x15:"ISZERO",0x16:"AND",0x17:"OR",0x18:"XOR", 0x19:"NOT",0x1a:"BYTE",0x20:"SHA3", 0x30:"ADDRESS",0x31:"BALANCE",0x32:"ORIGIN",0x33:"CALLER",0x34:"CALLVALUE",0x35:"CALLDATALOAD", 0x36:"CALLDATASIZE",0x37:"CALLDATACOPY",0x38:"CODESIZE",0x39:"CODECOPY",0x3a:"GASPRICE", 0x3b:"EXTCODESIZE",0x3c:"EXTCODECOPY",0x3d:"RETURNDATASIZE",0x3e:"RETURNDATACOPY", 0x40:"BLOCKHASH",0x41:"COINBASE",0x42:"TIMESTAMP",0x43:"NUMBER",0x44:"DIFFICULTY",0x45:"GASLIMIT", 0x50:"POP",0x51:"MLOAD",0x52:"MSTORE",0x53:"MSTORE8",0x54:"SLOAD",0x55:"SSTORE", 0x56:"JUMP",0x57:"JUMPI",0x58:"PC",0x59:"MSIZE",0x5a:"GAS",0x5b:"JUMPDEST", 0x60:"PUSH1",0x61:"PUSH2",0x62:"PUSH3",0x63:"PUSH4",0x64:"PUSH5",0x65:"PUSH6",0x66:"PUSH7", 0x67:"PUSH8",0x68:"PUSH9",0x69:"PUSH10",0x6a:"PUSH11",0x6b:"PUSH12",0x6c:"PUSH13",0x6d:"PUSH14", 0x6e:"PUSH15",0x6f:"PUSH16",0x70:"PUSH17",0x71:"PUSH18",0x72:"PUSH19",0x73:"PUSH20",0x74:"PUSH21", 0x75:"PUSH22",0x76:"PUSH23",0x77:"PUSH24",0x78:"PUSH25",0x79:"PUSH26",0x7a:"PUSH27",0x7b:"PUSH28", 0x7c:"PUSH29",0x7d:"PUSH30",0x7e:"PUSH31",0x7f:"PUSH32", 0x80:"DUP1",0x81:"DUP2",0x82:"DUP3",0x83:"DUP4",0x84:"DUP5",0x85:"DUP6",0x86:"DUP7",0x87:"DUP8", 0x88:"DUP9",0x89:"DUP10",0x8a:"DUP11",0x8b:"DUP12",0x8c:"DUP13",0x8d:"DUP14",0x8e:"DUP15",0x8f:"DUP16", 0x90:"SWAP1",0x91:"SWAP2",0x92:"SWAP3",0x93:"SWAP4",0x94:"SWAP5",0x95:"SWAP6",0x96:"SWAP7",0x97:"SWAP8", 0x98:"SWAP9",0x99:"SWAP10",0x9a:"SWAP11",0x9b:"SWAP12",0x9c:"SWAP13",0x9d:"SWAP14",0x9e:"SWAP15",0x9f:"SWAP16", 0xf0:"CREATE",0xf1:"CALL",0xf2:"CALLCODE",0xf3:"RETURN",0xf4:"DELEGATECALL",0xf5:"CREATE2", 0xfa:"STATICCALL",0xfd:"REVERT",0xfe:"INVALID",0xff:"SELFDESTRUCT" } def read_hex_input(arg): s = None if arg.endswith('.txt'): s = open(arg, 'r').read().strip() else: s = arg.strip() s = s[2:] if s.startswith("0x") else s s = re.sub(r'[^0-9a-fA-F]', '', s) # sanitize return bytes.fromhex(s) def is_printable(b): return 0x20 <= b <= 0x7e def ascii_preview(bts): s = ''.join(chr(b) if is_printable(b) else '.' for b in bts) return shorten(s, width=40, placeholder='...') def disassemble(bts): i = 0 out = [] L = len(bts) while i < L: opc = bts[i] name = OPCODES.get(opc, hex(opc)) line = {"offset": i, "opcode": name, "opc_byte": opc, "operand": b''} i += 1 # handle PUSH1..PUSH32 if 0x60 <= opc <= 0x7f: n = opc - 0x5f # number of bytes to read if i + n <= L: operand = bts[i:i+n] line["operand"] = operand else: line["operand"] = bts[i:] # truncated i += n out.append(line) return out def extract_printable_strings(bts, min_len=4): ascii_runs = [] cur = bytearray() for b in bts: if is_printable(b): cur.append(b) else: if len(cur) >= min_len: ascii_runs.append(bytes(cur).decode('ascii', errors='ignore')) cur = bytearray() if len(cur) >= min_len: ascii_runs.append(bytes(cur).decode('ascii', errors='ignore')) return ascii_runs def find_ipfs_metadata(bts): # search for ASCII "ipfs" bytes sequence (69706673) idx = bts.find(b'ipfs') results = [] if idx != -1: # get the following bytes up to 64 bytes for inspection tail = bts[idx: idx+1+64] # many Solidity metadata patterns encode ipfs in CBOR/RLP; we will also try to find a 32-byte hash after 0x1220 pattern # search for pattern 0x1220 (0x12 0x20) which in Solidity metadata precedes 32-byte hash in some encodings p = bts.find(b'\x12\x20') if p != -1 and p+2+32 <= len(bts): hash32 = bts[p+2:p+2+32] results.append(("12 20 followed by 32 bytes", hash32.hex())) results.append(("ipfs_offset", idx, tail.hex())) return results def main(): if len(sys.argv) < 2: print("Usage: python3 evm_disasm.py bytecode.txt OR python3 evm_disasm.py 6080...") sys.exit(1) bts = read_hex_input(sys.argv[1]) print(f"Total bytes: {len(bts)}") print("="*60) dis = disassemble(bts) # print a compact disassembly (offset, opcode, operand hex, ascii preview for operand) for entry in dis: off = entry["offset"] opc = entry["opcode"] opb = entry["operand"] if opb: print(f"{off:04x}: {opc:8} {opb.hex()} ascii='{ascii_preview(opb)}'") else: print(f"{off:04x}: {opc}") print("="*60) # printable strings strings = extract_printable_strings(bts, min_len=4) print("Printable ASCII strings (len>=4):") for s in strings: print(" -", s) print("="*60) # metadata sniff meta = find_ipfs_metadata(bts) if meta: print("Possible metadata/ipfs findings:") for m in meta: print(" -", m) else: print("No obvious 'ipfs' marker or 0x1220+32 pattern found.") print("="*60) # show tail for manual inspection (last 128 bytes) tail_len = min(128, len(bts)) tail = bts[-tail_len:] print(f"Last {tail_len} bytes (hex): {tail.hex()}") print("Done.") if __name__ == "__main__": main()
The bytecode.txt content which contains the long hex string.
0x60806040526040518060400160405280601c81526020017f6e657875737b54723463335f5468335f5472346e7334637431306e7d00000000815250600190816200004a919062000301565b5034801562000057575f80fd5b50335f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550620003e5565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200011957607f821691505b6020821081036200012f576200012e620000d4565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620001937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000156565b6200019f868362000156565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f620001e9620001e3620001dd84620001b7565b620001c0565b620001b7565b9050919050565b5f819050919050565b6200020483620001c9565b6200021c6200021382620001f0565b84845462000162565b825550505050565b5f90565b6200023262000224565b6200023f818484620001f9565b505050565b5b8181101562000266576200025a5f8262000228565b60018101905062000245565b5050565b601f821115620002b5576200027f8162000135565b6200028a8462000147565b810160208510156200029a578190505b620002b2620002a98562000147565b83018262000244565b50505b505050565b5f82821c905092915050565b5f620002d75f1984600802620002ba565b1980831691505092915050565b5f620002f18383620002c6565b9150826002028217905092915050565b6200030c826200009d565b67ffffffffffffffff811115620003285762000327620000a7565b5b62000334825462000101565b620003418282856200026a565b5f60209050601f83116001811462000377575f841562000362578287015190505b6200036e8582620002e4565b865550620003dd565b601f198416620003878662000135565b5f5b82811015620003b05784890151825560018201915060208501945060208101905062000389565b86831015620003d05784890151620003cc601f891682620002c6565b8355505b6001600288020188555050505b505050505050565b61067f80620003f35f395ff3fe608060405260043610610037575f3560e01c806328b355af146100425780633ccfd60b1461007e5780638da5cb5b146100945761003e565b3661003e57005b5f80fd5b34801561004d575f80fd5b5061006860048036038101906100639190610378565b6100be565b60405161007591906103d9565b60405180910390f35b348015610089575f80fd5b50610092610116565b005b34801561009f575f80fd5b506100a8610208565b6040516100b59190610431565b60405180910390f35b5f60016040516020016100d19190610543565b60405160208183030381529060405280519060200120826040516020016100f891906105bb565b60405160208183030381529060405280519060200120149050919050565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146101a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161019a9061062b565b60405180910390fd5b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc4790811502906040515f60405180830381858888f19350505050158015610205573d5f803e3d5ffd5b50565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61028a82610244565b810181811067ffffffffffffffff821117156102a9576102a8610254565b5b80604052505050565b5f6102bb61022b565b90506102c78282610281565b919050565b5f67ffffffffffffffff8211156102e6576102e5610254565b5b6102ef82610244565b9050602081019050919050565b828183375f83830152505050565b5f61031c610317846102cc565b6102b2565b90508281526020810184848401111561033857610337610240565b5b6103438482856102fc565b509392505050565b5f82601f83011261035f5761035e61023c565b5b813561036f84826020860161030a565b91505092915050565b5f6020828403121561038d5761038c610234565b5b5f82013567ffffffffffffffff8111156103aa576103a9610238565b5b6103b68482850161034b565b91505092915050565b5f8115159050919050565b6103d3816103bf565b82525050565b5f6020820190506103ec5f8301846103ca565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61041b826103f2565b9050919050565b61042b81610411565b82525050565b5f6020820190506104445f830184610422565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061048e57607f821691505b6020821081036104a1576104a061044a565b5b50919050565b5f81905092915050565b5f819050815f5260205f209050919050565b5f81546104cf81610477565b6104d981866104a7565b9450600182165f81146104f357600181146105085761053a565b60ff198316865281151582028601935061053a565b610511856104b1565b5f5b8381101561053257815481890152600182019150602081019050610513565b838801955050505b50505092915050565b5f61054e82846104c3565b915081905092915050565b5f81519050919050565b5f5b83811015610580578082015181840152602081019050610565565b5f8484015250505050565b5f61059582610559565b61059f81856104a7565b93506105af818560208601610563565b80840191505092915050565b5f6105c6828461058b565b915081905092915050565b5f82825260208201905092915050565b7f4e6f7420746865206f776e6572000000000000000000000000000000000000005f82015250565b5f610615600d836105d1565b9150610620826105e1565b602082019050919050565b5f6020820190508181035f83015261064281610609565b905091905056fea2646970667358221220fea5cd3a84f134f4d4158109fa036ae8bfe87b4a407b8c769d6ba07f90d967ea64736f6c63430008140033
4.Extract and Decode the Hexadecimal Segment: The following 32-byte (64-character) hexadecimal segment was found embedded in the input data:for those who need the exact string part.
- Hex Segment:
6e657875737b54723463335f5468335f5472346e7334637431306e7d
“
for the brave citizens lets run the script and get the flag..

Decoding this hexadecimal string from ASCII/running the script yields the flag:
- Decoded String:
nexus{Tr4c3_Th3_Tr4ns4ct10n}
Flag
The flag for the “Chain Clue” challenge is:
nexus{Tr4c3_Th3_Tr4ns4ct10n}
Next challenge
Silent Flag

Goal: Recover the original value (flag) from an event emitted by a smart contract, given an archive file containing event log components.
Provided Information:
- Archive file
Archive.zipcontaining:abi.json,
[
{
"type": "function",
"name": "leak",
"inputs": [
{
"name": "id",
"type": "bytes32",
"internalType": "bytes32"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "event",
"name": "Stored",
"inputs": [
{
"name": "id",
"type": "bytes32",
"indexed": true,
"internalType": "bytes32"
},
{
"name": "data",
"type": "bytes",
"indexed": false,
"internalType": "bytes"
}
],
"anonymous": false
}
]
topic0,
0x2b017342b91efedb50bcabb8f1d8e8b6e6ad1dc391c876174642e80868b896ed
topic1,
0x0000000000000000000000000000000000000000000000000000000000001337
and data.
0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001c59524f42444c6f07656803757e68730474077306797068050705024a00000000
Steps Taken
-
Extract and Analyze Files: The provided archive was extracted, revealing the components of a single Ethereum event log:
abi.json: Contained the contract’s ABI, including the event signature.topic0: The Keccak-256 hash of the event signature, identifying the event type.topic1: The indexed parameter of the event.data: The non-indexed paramet00020000000000000000000000000000000000000000000000000000000000000001c59524f42444c6f07656803757e68730474077306797068050705024a00000000`
For an ABI-encoded
bytestype, the data structure is:32 bytes: Offset to the data (here,0x20).32 bytes: Length of the data (here,0x1cor 28 bytes).- Actual Encoded Data (28 bytes):
59524f42444c6f07656803757e68730474077306797068050705024a
-
Decode the Data (Single-Byte XOR): The data was suspected to be encoded using a simple XOR cipher, possibly with the hint
0x1337or a single-byte key. Assuming the flag starts with the given CTF prefixnexus{, we can deer of the event, containing the hidden data. -
Determine Event Structure: From
abi.json, the relevant event was identified:{ "type": "event", "name": "Stored", "inputs": [ { "name": "id", "type": "bytes32", "indexed": true }, { "name": "data", "type": "bytes", "indexed": false } ], "anonymous": false }- Indexed Parameter (Topic 1): The
idfield fromtopic1was0x00...001337. This value (0x1337) is a common hint in CTFs. - Non-Indexed Parameter (Data): The
datafield contained the flag, likely encoded.
- Indexed Parameter (Topic 1): The
-
Extract Encoded Data: The content of the
datafile was: `0x00000000000000000000000000000000000000000000000000000000000termine the key:- Expected first character:
n(ASCII0x6e) - Encoded first byte:
0x59 - Key Calculation:
0x6e ^ 0x59 = 0x37
Applying the single-byte XOR key
0x37to the entire encoded data:for the easy way the encoded hex it the below one
- Encoded Hex:
59524f42444c6f07656803757e68730474077306797068050705024a
- Expected first character:
-
Scriptfor the brave citizens we run the3 script and get the flag
def solve_silent_flag(): # The data field from the event log, after removing the 0x prefix and ABI encoding overhead # Data part: 59524f42444c6f07656803757e68730474077306797068050705024a encoded_hex = "59524f42444c6f07656803757e68730474077306797068050705024a" encoded_bytes = bytes.fromhex(encoded_hex) # Key determined by XORing the first byte of the encoded data (0x59) # with the first byte of the assumed flag prefix "n" (0x6e): 0x59 ^ 0x6e = 0x37. # This key is consistent for the entire prefix "nexus{". key = 0x37 decoded_bytes = bytearray() for byte in encoded_bytes: # XOR each byte of the encoded data with the single-byte key decoded_byte = byte ^ key decoded_bytes.append(decoded_byte) try: # The flag is expected to be a string flag = decoded_bytes.decode('ascii') print(f"Decoded Flag: {flag}") except UnicodeDecodeError: print("Could not decode to ASCII. Decoded bytes (hex):") print(decoded_bytes.hex()) if __name__ == "__main__": solve_silent_flag()afterrunning the script or decoding the given encoded hex your way we get.

Flag
The flag for the “Silent Flag” challenge is:
nexus{X0R_4BI_D3C0D1NG_2025}
HAPPY HACKING!!
Comments