本文仅用于技术讨论与研究,文中的实现方法切勿应用在任何违法场景。如因涉嫌违法造成的一切不良影响,本文作者概不负责。
近期与朋友一起看的两个洞,Piwigo
的两枚 SQL
注入漏洞,二次注入的漏洞挺有意思的,在这里记录一下。
Piwigo
可以通过 github
或者其官网下载。
github
地址:https://github.com/Piwigo/Piwigo
Piwigo
在 12.2.0 版本的 pwg.users.php
文件中发现一枚SQL
注入漏洞,可通过该漏洞获取数据库中的数据。
cve
官方漏洞描述中已经点出漏洞文件为 pwg.users.php
,我们直接看到这里,位于 include/ws_functions/pwg.users.php
这里很多数据库操作,而且很多都是在拼接,出现注入的概率确实挺大的。
这个文件全都是函数,也就是说我们无法直接访问到这里,因此现在需要做的是找到调用的位置
第一个函数是 ws_users_getList
,直接全局搜索该函数
在这里的 ws.php
中,ws_users_getList
被 addMethod
添加到 $service
的 method
列表中,实际上这里是 piwigo
自身定义的访问模式,这里就不细讲了,大概就是将一些路由与函数绑定在一起,当出现访问时,通过回调的方式去访问。
要想访问 ws_users_getList
,我们只需要访问 ws.php
,并 get
一个 method
参数,值为 pwg.users.getList
即可。
我们再回来看这个 ws_users_getList
的内容
$params
中存放的是我们请求的值与系统默认的一些值,看到上图,当我们的输入中带有单引号等特殊字符时,会自动转义,这是系统对输入值的过滤,不允许直接输入单双引号等危险字符。如上很多的拼接字符串都使用不了,因为他们都需要闭合前面的引号,我们只能找可以直接拼接而不用闭合引号的参数。
order by
是常用的突破点,我们直接找到此处 208 行,并在输入中输入 order
参数
这里我们不用闭合单引号,因此可以直接对其进行注入
本漏洞需要登录后台利用,登录后如下点击
用户 -> 管理 -> 用户列表
抓包,但是放掉第一个包,进入第二个包如下
这里并没有 order
参数,我们添加进去即可,之后发包可见报错
仅验证,点到即止
Piwigo
在 12.2.0 版本的搜索功能中存在一个二次SQL
注入漏洞,该漏洞可以从前台获取数据库中的数据。
我们先来到前台搜索处,随意搜索,然后抓包查看,这里游客身份进入即可
通过抓包,我们可以抓到处理搜索功能的文件为 qsearch.php
,进入后直接下断点
顺利进入该文件,跟进代码,看之后经历的操作,根据网上的信息,该漏洞为二次注入漏洞,因此可以格外关注 insert into
的数据库操作。
从上面的图中可以看到搜索的参数为 q
,而在代码中也有体现
这里实际上就是根据搜索的 q
得到 search
数组,序列化数组并用 addslashes
处理后查找,存在该搜索就更新,不存在就插入,成功插入后返回搜索的 id
,这里序列化操作后 addslashes
处理了,因此不存在直接的注入漏洞。
这里先简单说一下,其余的部分在后面写出来
插入值后,寻找该值被使用的位置,直接可以搜索 SEARCH_TABLE
调用的位置不多,可以一个个看,主要关注取值的位置,来到 admin/history.php
,根据取值的位置找到如下代码
当存在get
的参数中存在 search_id
时,就会根据 search_id
查找 rules
,从上一部分的分析来看,这个 rules
是被序列化后的查询数据,我们也可以通过直接去看数据库内容看出来
取出来的值直接反序列化,得到 $page['search']
,当 get
的参数中还存在 user_id
时,则会将 $page['search']
序列化后再次插入数据库中,但是这里的序列化数据并没有进行处理,也就是说数据里面存在单引号等就可以直接闭合,刚好这里的数据是我们可以利用第一部分的搜索操作控制的,因此造成了一个二次注入。
这里的构造需要很巧妙,既要闭合 SQL
操作,又要通过序列化操作,不得不说这个漏洞发现者很强,在此之前我是想不到还可以这样玩的。
这里简单说一下构造,因为 insert
是支持一次性插入多条数据的,通过逗号隔开即可,我们第一步的搜索语句中,插入时存在 addslashes
,因此插进去时是什么样子,拿出来也会是什么样子,这里一部分先闭合,随意给一个值即可,比如给一个 test'
,此处 insert
只有一个字段,因此必须先闭合括号,然后开启插入的第二个数据,写一下大概就是如下
test'),
由于这个字段的数据都是序列化后的,因此我们必须满足序列化的规则才方便被正常取出,我们先构造一个获取管理员密码的语句如下:
SELECT password FROM piwigo_users where id=1
使用这条语句获取到密码后,再将其放入模板中
a:1:{s:1:"q";s:4:"xxxx";}
xxxx
就是我们获取到的密文,前面的4跟随密文长度变化,我看了下,这里加密方式产出的密文好像都是 34 位,因此这里直接设 34。
密码获取需要通过上面的语句获取,使用 concat
拼接获取,配合前面的内容得到
test'),((select concat('a:1:{s:1:"q";s:34:"',(SELECT password FROM piwigo_users where id=1),'";}')))#
构造如上 payload
,通过前台搜索功能插入后,在这里就可以获取到密文,并将密文存储到数据库中
接下来是获取该数据库内容,因此涉及的数据库仍然是刚刚的数据库,可以继续搜索 SEARCH_TABLE
,找到一处前台获取该数据库内容的位置,位于 include/functions_search.inc.php
这里是一个函数,直接根据 $search_id
搜索,然后反序列化 rules
后返回,我们看看调用位置
定位到 search_rules.php
比较简单就知道可以成功获取。
按照之前说的注入
记录返回的 id
值,对应插入记录的 id
但是发现之后的利用会出错,这是为什么呢?按照前面说的,这里的 q
写入的是什么,之后获取就应该是那个值,但是 $_GET
在利用前实际上会被处理一次,位于 include/common.inc.php
,这是文件开头就会调用的
因此我们这里写入的 payload
中的单引号会被加上 \
,就像上面图中的数据库 一样
这里的解决方法是将参数 q
作为一个数组写入,数组的键为 payload
,而 之后的处理由于是序列化,因此这个键也会被写入,之后取出来也适用。
如此,进入数据库的值就不会被转义了
此操作需要管理员权限
可以看到,执行完后,会在数据库中生成两条记录,其中一条就获取到了密文
这里唯一需要注意的一点是我们需要知道 search_id
,也就是插入的那条含有密文的数据的 id
值
相对来说,CVE-2022-32297
会更有意思,而且该漏洞比较难以发现,虽然需要管理员用户点击,但用户可以从前台获取到数据,比 CVE-2022-26266
的危害更加大。这个漏洞让我想起了 Laravel
CVE-2021-3129
漏洞,同样是取出来后又放进去,从而导致了漏洞,虽然造成漏洞的本质并不一样,但有着异曲同工之妙。
10 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!