Debugging a buffer overrun (Digital Systems)
Jump to navigation
Jump to search
Using the debugger, it's possible to watch the attack taking place. Try the following sequence of actions. The values shown are accurate for the program as I built it, but may slightly different on your micro:bit. The order of the first few actions is quite delicate, as the victim program must be running under the debugger and ready to accept input before we squirt the attack code into it.
- Build and upload the program
total.hex
, openminicom
and reset the micro:bit. - Use Build>Debug, or the
debug
shell script to start the debugger. - Set a breakpoint on line 114 of the program (containing the final
printf
call) with the commandsbreak 114
followed bycont
. - Squirt the attack data using the
squirt attack
command, watching theminicom
window as you do so. - Manually add the final
0
in theminicom
window.
The program should now halt at the call to printf
:
114 printf("Total = %d\n", total);
- Type
next
to run theprintf
call and stop on the next line. "Total = 1978903723" appears in theminicom
window, and the debugger stops again.
115 }
Now we need to go into the machine-level debugging mode.
- Type
layout regs
, and you will see (in the middle pane)
0x25c <init+60> add sp, #44 ; 0x2c
0x25e <init+62> pop {r4, r5, pc}
- Type
stepi
once to execute theadd
instruction that adjusts the PC, then again to execute thepop
instruction that returns frominit
. Normally, the next instruction would come from somewhere in the functionstartup
that callsinit
, but because of the hack,init
in fact returns to out malicious code, and in the middle pane we see
0x20003fb0 sub sp, #56 ; 0x38
0x20003fb2 add r0, pc, #12 ; (adr r0, 0x20003fc0)
- These are the first two instructions of the attack code. Notice that the value of PC,
0x0x20003fb0
, is somewhere close to the end of RAM, rather being in the Flash space as usual.
- You can use
stepi
a few more times to see the attack unroll: after moving SP down again, the code loads the address of the stringHACKED!!
intor0
, puts the address ofprintf
inr1
, then calls it. You should see that execution soon ends up inprintf
, ready to print the message.