Debugging a buffer overrun (Digital Systems)

Copyright © 2024 J. M. Spivey
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, open minicom 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 commands break 114 followed by cont.
  • Squirt the attack data using the squirt attack command, watching the minicom window as you do so.
  • Manually add the final 0 in the minicom window.

The program should now halt at the call to printf:

114          printf("Total = %d\n", total);
  • Type next to run the printf call and stop on the next line. "Total = 1978903723" appears in the minicom 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 the add instruction that adjusts the PC, then again to execute the pop instruction that returns from init. Normally, the next instruction would come from somewhere in the function startup that calls init, 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 string HACKED!! into r0, puts the address of printf in r1, then calls it. You should see that execution soon ends up in printf, ready to print the message.