0x00 php7 opcache执行 PHP 代码
1. 环境配置
文章介绍:
http://drops.wooyun.org/web/15450
http://blog.gosecure.ca/2016/04/27/binary-webshell-through-opcache-in-php-7/ 使用docker拉取php:7.0.8-apache镜像,配置使用opcache。php7默认安装了opcache,这里只需要修改下php.ini文件:
| 1 | [opcache] | 
在phpinfo中能看到opcache就成功了。
2. 利用
利用此攻击向量,攻击者可以绕过“Web 目录禁止文件读写”的限制 ,也可以执行他自己的恶意代码。
- 计算 system_id
使用作者提供的工具php7-opcache-override,算一下system_id。
| 1 | ./system_id_scraper.py http://angelwhu.com:8083/phpinfo.php | 
与自己find .搜索下的./opcache/7a838f426f8184a949f4dde75f3ef030/var/www/html/phpinfo.php.bin一样。
- 利用上传文件漏洞,去替换缓存的php.bin文件
这里可以简单先做个实验: 首先,写一个test.php:
| 1 | 
 | 
访问后,会产生一个./opcache/7a838f426f8184a949f4dde75f3ef030/var/www/html/test.php.bin文件。 然后,删除test.php。访问test.php会返回404。 再次,新建test.php,写入内容:
| 1 | 
 | 
访问之,依然输出:test。 
 本地使用php7生成一个我们需要的shell文件,然后去覆盖原有的缓存php的bin文件(
 本地使用php7生成一个我们需要的shell文件,然后去覆盖原有的缓存php的bin文件(/opcache/7a838f426f8184a949f4dde75f3ef030/var/www/html/目录),即可完成利用。 这里需要一个上传文件漏洞,并且可以控制上传的目录。具体过程省略,请看参考文章。记录下一个要点:
| 1 | 本地生成的payload,用vi -b修改其二进制内容。只需要修改头部system_id即可,其余都不用修改。 | 
0x01 LD_PRELOAD绕过disable_function和open_basedir
文章介绍:
http://drops.wooyun.org/tips/16054 首先进行环境配置:
| 1 | open_basedir = /var/www/html:/tmp | 
并且上传了一个shell:
| 1 | 
 | 
1. LD_PRELOAD hack 样例
verifypasswd.c:
| 1 | 
 | 
编译:
| 1 | gcc verifypasswd.c -o verifypasswd | 
hack.c:
| 1 | 
 | 
编译:
| 1 | gcc -c -fPIC hack.c -o hack | 
运行测试:
| 1 | $ export LD_PRELOAD="./hack.so" | 
在调用系统的strcmp前,优先加载了hack.so动态链接库。调用了我们自定义的strcmp函数。
2. 利用
文章介绍:
http://drops.wooyun.org/tips/17248 提取里面的payload,进行编译:
| 1 | gcc -c -fPIC hack.c -o hack | 
上传的时候,碰到了没有临时文件的问题,于是配置了下:
| 1 | upload_tmp_dir = /tmp | 
上传文件页面,upload.html:
| 1 | <form action="http://10.10.10.135/shell_test/shell_basic.php" method="post" enctype="multipart/form-data"> | 
选择上传hack.so 文件即可成功获取反弹shell。 

0x02 CBC加密模式
文章介绍:
http://drops.wooyun.org/tips/7828
可以好好看看《白帽子讲web安全》的加密算法章节。 从乌云文章截的图,理解一下CBC模式的解密流程: 
Ciphertext-N-1(密文-N-1)是用来产生下一块明文;
我们可以通过改变Ciphertext-N-1(密文-N-1),来构造解密出来的明文。 三个白帽(招聘又开始了,你怕了吗?)题目样例:
| 1 | 
 | 
我们的目的是在不知道key的情况下,伪造一个admin用户出来。(注册不了admin用户)
针对CBC模式攻击有padding Oracle,详情可以看《白帽子讲web安全》。这里记录下两种方法,重现下。
- CBC模式字节反转攻击
首先注册一个账号为tdmin的账号,与admin只有一个字节的差异。
得到:
| 1 | 7x1ws5FicJqiJXViLIxF9NcE1g8diGwjV1KtXLFrdj0 | 
解码会发现是32位,不过有不可见字符:
| 1 | var_dump(base64url_decode("7x1ws5FicJqiJXViLIxF9NcE1g8diGwjV1KtXLFrdj0")); | 
由于AES128是以16字节为一个块的。根据CBC模式解密的原理,如果改变前面16自己的IV,会影响加密结果。和流密码一样,存在Reused Key Attack攻击。
| 1 | AES解密('密文后16位') xor iv(密文前16位) = tdmin | 
求?的值:
| 1 | 两个等式异或可以得到: | 
因此,我们只需要改变iv的第一个字节,使t变为a即可:
| 1 | $encrypt_string = substr(base64url_decode("7x1ws5FicJqiJXViLIxF9NcE1g8diGwjV1KtXLFrdj0"),16,16); | 
结果顺利输出:admin
- 截取密文一部分
我们看到解密算法中,每个块(block)都是16字节。因此,我们注册一个16字节+admin的用户名,如:
| 1 | 1234567890123456admin | 
得到一个加密结果:4-ymjbq1u1i_vJPE_Cn3uusb-avuQ4R-Pyn52e35BOwSmaG6HiNzDg47n2cvmIE1,解码后为48字节。这48字节的组成为:
| 1 | 密文第一个16字节: iv | 
根据解密流程,可以知道先从最后一个字节开始解密,即:
| 1 | AES解密(密文第三个16字节) xor 密文第二个16字节 = admin | 
我们有了上述等式需要的密文第二个和第三个16字节,因此可以直接截取后32个字节:
| 1 | $admin_encrypt_string_2 = base64_encode(substr(base64url_decode("4-ymjbq1u1i_vJPE_Cn3uusb-avuQ4R-Pyn52e35BOwSmaG6HiNzDg47n2cvmIE1"),16)); | 
顺利得到admin。
