最近在网上看到有师傅再发wookteam协作平台searchinfo接口SQL注入漏洞的复现文章,打算分析一波,大概网上翻了一下,也没找到之前发过这个漏洞的(也可能是太菜了没找到),判断这个洞应该是最新版的,就拉了最新的一个版本(wookteam 1.6.8)结果没复现成功。后续有深入跟了一下发现这个洞是 1.6.6
版本的洞,并且在 1.6.7
的时候已经修复了。
1、下载相应版本的代码
2、进入项目根目录 cd wookteam
3、一键构建项目 ./cmd install
搭建成功如图:
POC
GET /api/users/searchinfo?where%5Busername%5D=1%27%29%20UNION%20ALL%20SELECT%20NULL,CONCAT%280x7e,md5%281%29,0x7e%29,NULL,NULL,NULL%23 HTTP/1.1
Host:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,\*/\*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Wookteam 1.6.6
Wookteam 1.6.8
Wookteam 后端使用的是:Laravel7 框架。该框架所有的路由都在 routes
目录中的路由文件中定义,这些文件都由框架自动加载。routes/web.php
文件用于定义 web
界面的路由。大多数的应用构建,都是以在 routes/web.php
文件定义路由开始的。可以通过在浏览器中输入定义的路由 URL 来访问 routes/web.php
中定义的路由。
根据 poc 中提到的路由 /api/users/searchinfo
,然后去寻找一下
在该文件中我們可以得到两个重要的信息:
ApiMiddleware
中间件来处理 /api/*
路由下的请求 (只是做了一些CORS 相关的相关配置。)/api/users/searchinfo
路由处理的具体代码应该在 UsersController
这个控制器中的 searchinfo
方法中跟进 UsersController
分析一下,路径 app\Http\Controllers\Api\UsersController.php
因为 poc 中只提到了 username
这个参数,所以我们重点只关注一下和他有关的部分
public function searchinfo()
{
$keys \= Request::input('where');
$whereArr \= \[\];
$whereRaw \= null;
略.....
if ($keys\['username'\]) {
$whereRaw.\= $whereRaw ? ' AND ' : '';
$whereRaw.\= "(\`username\` LIKE '%" . $keys\['username'\] . "%' OR \`nickname\` LIKE '%" . $keys\['username'\] . "%')";
}
略......
$lists \= DBCache::table('users')\->select(\['id', 'username', 'nickname', 'userimg', 'profession'\])
\->where($whereArr)
\->whereRaw($whereRaw)
\->orderBy('id')
\->cacheMinutes(now()\->addSeconds(10))
\->take(Base::getPaginate(100, 10, 'take'))
\->get();
略......
}
首先通过 Request::input('where')
获取输入数据并存储在 $keys
数组中,然后判断 username
这个键对应的值存在。后续就是直接把 username
这个键对应的值拼接进 $whereRaw
变量。
Laravel 的数据库查询构造器为创建和运行数据库查询提供了一个方便的接口。它可用于执行应用程序中大部分数据库操作,且可在所有支持的数据库系统上运行。
有时候你可能需要在查询中使用原生表达式。
whereRaw
方法将原生的where
注入到你的查询中。 例如:DBCache::table('users')->select('username')->whereRaw( id = 1 )
不过需要注意的是:原生表达式将会被当做字符串注入到查询中
综上所述,这块发生漏洞的原因正式因为使用了原生方法 whereRaw
,并且传入的字段 $whereRaw
中存在了我们可控的变量,因此造成漏洞!
通过 diff 可以很明显的看到有两处改动:
Laravel 的查询构造器使用 PDO 参数绑定来保护您的应用程序免受 SQL 注入攻击。但也需要注意:PDO 不支持绑定列名。因此,不能让用户通过输入来指定查询语句所引用的列名,包括 order by 字段等等。如果必须要允许用户通过选择某些列来进行查询,请始终根据允许列的白名单来校验列名。
还有一个疑问就是,v 1.6.8
中虽然添加了身份认证,但是我们登录之后,再去访问 /api/users/searchinfo
接口还是依旧返回 请登录后继续... 的信息
跟进代码看看到底如什么原因
可以看着在 auth
函数中,__static_auth
不存在,并且没有获取到 token
,则会返回 $_A["__static_auth"] = false
在 authE
函数中,则会进如 if
判断,在没有 token
的情况下就会返回请登录后继续...
从之前抓的请求包中,我们可以看到并没有 token
字段,这就是根本原因。我们到别的请求中找一个 token
添加进去,发现成功访问到
但是由于 SQL做过处理了,所以漏洞不存在
https://www.ppmy.cn/news/1509537.html?action=onClick
https://learnku.com/docs/laravel/7.x
https://gitee.com/aipaw/wookteam/blob/master/install/DOCKER.md
3 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!