使用原生GET,POST,REQUEST变量是完全不过滤的
测试方法:
最简单的就是这样了
顺便找处系统中可外部访问的地方
如图:
根据结果就可以确定当使用了原生GET,POST,REQUEST变量带入数据库之类,是有可能产生注入,储蓄xss之类的
路径:PbootCMS-V1.2.1\core\function\helper.php
函数_1:function get(
函数_2:function post(
函数_3:function request(
这3个函数 get(), post(), request()
函数:filter(
最后都会调用 filter函数
这个函数没有用所以直接看 filter 里面调用的方法 escape_string函数进行最终过滤
因为filter无用的内容太多所以我们忽略掉直接看escape_string 函数
路径:PbootCMS-V1.2.1\core\function\handle.php
函数:function escape_string(
// 获取转义数据,支持字符串、数组、对象
function escape_string($string, $dropStr = true)
{
if (! $string)
return $string;
if (is_array($string)) { // 数组处理
foreach ($string as $key => $value) {
$string[$key] = escape_string($value);
}
} elseif (is_object($string)) { // 对象处理
foreach ($string as $key => $value) {
$string->$key = escape_string($value);
}
} else { // 字符串处理
if ($dropStr) {
$string = preg_replace('/(0x7e)|(0x27)|(0x22)|(updatexml)|(extractvalue)|(name_const)|(concat)/i', '', $string);
}
$string = htmlspecialchars(trim($string), ENT_QUOTES, 'UTF-8');
$string = addslashes($string);
}
return $string;
}
可以看得到所有传过来的内容都会先过一个正则匹配过滤
会将 0x7e,0x27,0x22,updatexml,extractvalue,name_const,concat 将其替换为''然后在进行
htmlspecialchars 函数的html实体编码
addslashes 函数转义。
注意点:
1. 过滤只针对 value
2. key 完全无不过滤
3. 那个正则绕过很简单只需要 updatupdatexmlexml 经过过滤以后就可以转为 updatexml
那么看到这里对于系统的初步情况其实就已经很明确了
在挖sql注入的时候,我最喜欢的就是先看这个系统的底层了。
会对挖洞有很大的帮助,看的时候并不需要全看懂,只需要对一些关键的地方看个大概即可
路径:PbootCMS-V1.2.1\core\basic\Model.php
看了一下以后发现,这里没什么好讲的,因为里面全是字符串拼接。
例如: where方法
/**
* 连贯操作:设置查询条件
*
* @param mixed $where
* 设置条件,可以为字符串、数组,
* 字符串模式:如"id<1","name like %1",
* 数组模式:array('username'=>'xie',"realname like '%谢%'")
* @param string $inConnect
* 调用本方法时$where参数数组内部的条件默认使用AND连接
* @param string $outConnect
* 调用本方法时与前面条件使用AND连接
* @param boolean $fuzzy
* 条件是否为模糊匹配,即in匹配
* @return \core\basic\Model
*/
final public function where($where, $inConnect = 'AND', $outConnect = 'AND', $fuzzy = false)
{
if (! $where) {
return $this;
}
if (isset($this->sql['where']) && $this->sql['where']) {
$this->sql['where'] .= ' ' . $outConnect . '(';
} else {
$this->sql['where'] = 'WHERE(';
}
if (is_array($where)) {
$where_string = '';
$flag = false;
foreach ($where as $key => $value) {
if ($flag) { // 条件之间内部AND连接
$where_string .= ' ' . $inConnect . ' ';
} else {
$flag = true;
}
if (! is_int($key)) {
if ($fuzzy) {
$where_string .= $key . " like '%" . $value . "%' ";
} else {
$where_string .= $key . "='" . $value . "' ";
}
} else {
$where_string .= $value;
}
}
$this->sql['where'] .= $where_string . ')';
} else {
$this->sql['where'] .= $where . ')';
}
return $this;
}
初步结论:整个db 类的底层都是类似的字符串拼接,所以(≧∇≦)ノ 只要能够带入 '
或是\
那么就可以确定是有注入的了
注意点:在查看的时候发现了 insert 方法的注释,也是需要注意的,这里我把代码贴一下
/**
* 数据插入模型
*
* @param array $data
* 可以为一维或二维数组,
* 一维数组:array('username'=>"xsh",'sex'=>'男'),
* 二维数组:array(
* array('username'=>"xsh",'sex'=>'男'),
* array('username'=>"gmx",'sex'=>'女')
* )
* @param boolean $batch
* 是否启用批量一次插入功能,默认true
* @return boolean|boolean|array
*/
final public function insert(array $data = array(), $batch = true)
{
// 未传递数据时,使用data函数插入数据
if (! $data && isset($this->sql['data'])) {
return $this->insert($this->sql['data']);
}
if (is_array($data)) {
if (! $data)
return;
if (count($data) == count($data, 1)) { // 单条数据
$keys = '';
$values = '';
foreach ($data as $key => $value) {
if (! is_numeric($key)) {
$keys .= "`" . $key . "`,";
$values .= "'" . $value . "',";
}
}
if ($this->autoTimestamp || (isset($this->sql['auto_time']) && $this->sql['auto_time'] == true)) {
$keys .= "`" . $this->createTimeField . "`,`" . $this->updateTimeField . "`,";
if ($this->intTimeFormat) {
$values .= "'" . time() . "','" . time() . "',";
} else {
$values .= "'" . date('Y-m-d H:i:s') . "','" . date('Y-m-d H:i:s') . "',";
}
}
if ($keys) { // 如果插入数据关联字段,则字段以关联数据为准,否则以设置字段为准
$this->sql['field'] = '(' . substr($keys, 0, - 1) . ')';
} elseif (isset($this->sql['field']) && $this->sql['field']) {
$this->sql['field'] = "({$this->sql['field']})";
}
$this->sql['value'] = "(" . substr($values, 0, - 1) . ")";
$sql = $this->buildSql($this->insertSql);
} else { // 多条数据
if ($batch) { // 批量一次性插入
$key_string = '';
$value_string = '';
$flag = false;
foreach ($data as $keys => $value) {
if (! $flag) {
$value_string .= ' SELECT ';
} else {
$value_string .= ' UNION All SELECT ';
}
foreach ($value as $key2 => $value2) {
// 字段获取只执行一次
if (! $flag && ! is_numeric($key2)) {
$key_string .= "`" . $key2 . "`,";
}
$value_string .= "'" . $value2 . "',";
}
$flag = true;
if ($this->autoTimestamp || (isset($this->sql['auto_time']) && $this->sql['auto_time'] == true)) {
if ($this->intTimeFormat) {
$value_string .= "'" . time() . "','" . time() . "',";
} else {
$value_string .= "'" . date('Y-m-d H:i:s') . "','" . date('Y-m-d H:i:s') . "',";
}
}
$value_string = substr($value_string, 0, - 1);
}
if ($this->autoTimestamp || (isset($this->sql['auto_time']) && $this->sql['auto_time'] == true)) {
$key_string .= "`" . $this->createTimeField . "`,`" . $this->updateTimeField . "`,";
}
if ($key_string) { // 如果插入数据关联字段,则字段以关联数据为准,否则以设置字段为准
$this->sql['field'] = '(' . substr($key_string, 0, - 1) . ')';
} elseif (isset($this->sql['field']) && $this->sql['field']) {
$this->sql['field'] = "({$this->sql['field']})";
}
$this->sql['value'] = $value_string;
$sql = $this->buildSql($this->insertMultSql);
// 判断SQL语句是否超过数据库设置
if (get_db_type() == 'mysql') {
$max_allowed_packet = $this->getDb()->one('SELECT @@global.max_allowed_packet', 2);
} else {
$max_allowed_packet = 1 * 1024 * 1024; // 其他类型数据库按照1M限制
}
if (strlen($sql) > $max_allowed_packet) { // 如果要插入的数据过大,则转换为一条条插入
return $this->insert($data, false);
}
} else { // 批量一条条插入
foreach ($data as $keys => $value) {
$result = $this->insert($value);
}
return $result;
}
}
} elseif ($this->sql['from']) {
if (isset($this->sql['field']) && $this->sql['field']) { // 表指定字段复制
$this->sql['field'] = "({$this->sql['field']})";
}
$sql = $this->buildSql($this->insertFromSql);
} else {
return;
}
return $this->getDb()->amd($sql);
}
简单的说,就是insert 方法支持二维数组,当使用二维数组时表示批量插入。
所以如果我们可以插入二维数组并且可以控制key那么我们就可以注入了。
下图为触发点查看:
经过0x05.1与0x05.2 还有0x06组合下来我们其实可以确定了一些基本漏洞了
5.1 反应给我的情况
首先是xss漏洞
储蓄xss
如果是使用了 5.1 的外部变量并且入库的时候没有转义的话,那么就会产生xss反射xss
反不动 只要 GET 请求中出现了 A-Z a-z 0-9 之外的数,就会直接报错然后是sql注入漏洞
如果是使用了 5.1 的外部变量并且入库的时候没有转义的话,那么就会产生sql注入5.2 反应给我的情况
首先是xss漏洞储蓄xss
如果是使用了 5.2 的外部变量入库的,想找xss 那么就要看使用了 htmlspecialchars_decode 函数的地方,否则的话就只能查看类似这种点 <img src=# {{variate}}> variate 可控的情况反射xss
射不动 只要 GET 请求中出现了 A-Z a-z 0-9 之外的数,就会直接报错然后是sql注入漏洞
key 没有过滤所以如果我能够控制 key 进入sql的话,那么就基本上百分之90有sql注入了6.0 给我的情况
底层全是字符串拼接,只要能够引入 ' 或是 \ 就可以造成注入
5.1 只要我们可以控制就有注入
5.2 因为所有的 value 都会进行 htmlspecialchars 函数的html实体编码 addslashes 函数转义
所以利用value 注入不现实,那么我们找注入的关键点就是查看key了
嗯,可以看到这就很明了了,我的审计收集工作也正式算是做完了。
接下来就是正式审计了。
不过其实到这一步,基本上在看两眼搜索一下打打 debug 就可以确定漏洞了。