wookteam协作平台searchinfo接口SQL注入漏洞分析

Wookteam是一个支持在线协作管理和沟通的开源平台,后端使用的框架是Laravel7。在wookteam v1.6.6版本中api/users/searchinfo接口存在SQL注入且未对用户身份进行验证!

前言

最近在网上看到有师傅再发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

  • 发表于 2024-08-29 14:00:00
  • 阅读 ( 7400 )
  • 分类:CMS

0 条评论

请先 登录 后评论
Yu9
Yu9

3 篇文章

站长统计