WeiPHP5.0 sql注入漏洞

侵权声明

本文章中的所有内容(包括但不限于文字、图像和其他媒体)仅供教育和参考目的。如果在本文章中使用了任何受版权保护的材料,我们满怀敬意地承认该内容的版权归原作者所有。

如果您是版权持有人,并且认为您的作品被侵犯,请通过以下方式与我们联系: [[email protected]]。我们将在确认后的合理时间内采取适当措施,包括删除相关内容。

感谢您的理解与支持

0x00poc

POST /weiphp5/public/index.php/home/Index/bind_follow HTTP/1.1
Host: 192.168.249.128:81
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
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.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh-TW;q=0.9,zh;q=0.8,en;q=0.7,zh-HK;q=0.6,en-US;q=0.5
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 80

uid%5b0]=exp&uid[1]=)%20and%20updatexml%0a(1,concat(0x7e,/*!user*/(),0x7e),1)--+

0x01漏洞分析php审计

观测poc的请求行可以得出漏洞位置
application/home/controller/index.php/bind_follow()

跟进红框第一句的I方法

发现还是一个调用input方法的继续跟进

第一个if判断
检查key是否以问号字符?开头,其中strpos()函数返回参数二字符串在参数一字符串第一次出现的位置。
将去掉首字符的字符串重新赋给key,并且将has赋值为true
第二个if判断
这个判断用来检查key中是否包含点号.,将点号首次出现位置赋值给pos
将以点号分割的前部分赋值给method然后在后面集合中查找,如果找到了key会去掉这部分,否则将method赋值为param
此时看到has()函数继续跟进

发现是一个静态方法,并且对输入并没有进行任何处理。

继续回到bind_follow()函数中
$publicid = $map ['publicid'] = I('publicid');将输入进来的publiccid赋值给map数组和publiccid
$uid = $map ['uid'] = I('uid');将输入进来的uid数组赋值给map数组和uid数组
$this->assign($map);将map数组中的数据整合赋值为其他变量
继续下一条语句
$info = M('user_follow')->where(wp_where($map))->find();
跟进M()函数是对数据库的初始化,参数是指定的数据表。
紧接着跟进wp_where()函数

if语句判断key是否是数字或是数字字符串,然后判断value是否是数组并且长度为三。
elseif语句判断vlalue是否是数组。
最后else语句将key和value以键值对的形式保存到res中。
通过poc进行debug可以看到程序最后进入了elseif语句中。
其中的if语句判断value[0]全小写后是否等于exp后面判断value[1]变量是否为对象。
然后继续跟进DB::raw()函数

发现又是一个静态方法。

回到语句中find()函数继续跟进,这个find函数是在think\db\Query.php

其中instanceof关键字是判断data数据是否为Query类或是\Closure类的实例化对象。

继续跟进parseOptions()函数

该函数的大致作用是获取要查询的数据表判断是使用什么关键字对数据表进行处理,还给field赋值为*
并给['master', 'lock', 'fetch_pdo', 'fetch_sql', 'distinct']数组中的每一个字符串复制加入options数组中并且复制为false。其实每个foreach都是这样的将数组中的值加入数组中并进行初始化

然后到红框处的find()函数继续跟进,这个find()函数是在think\db\Connection.php

更进getOptions()函数将query数组中options数组赋值给当前函数的options数组

更进getPk()函数

后续还要跟进getPk函数 -> getTableInfo()函数后才主要逻辑将数据表中的字段放入info数组中,在poc的debug中查询了三个数据表的字段。

回到在think\db\Connection.php中的find()函数
$data = $options['data'];将options数组中的data值赋给函数中的data
$query->setOption('limit', 1);给query数组中的limit参数赋值1
第一个if语句没有进入
第二个if语句判断pk是否为字符串,data是否为数组将data变为数组其中的值也是data的值(如有不对请指出)

然后是生成sql语句的函数,跟进select函数

通过debug得知最终进入了parseWhere()函数,然后继续跟进

继续跟进builWhere()函数

第一个红框中将val中的值与logic拼接形成sql语句之后保存到str数组中,跟进parseWhereItem()函数
最终在第二个红框处进行拼接

在builWhere()函数中的第二个红框中将str数组中的所以sql语句碎片拼接在一起之后删除开头的logic字符。

我这里显示不完整其实后面还有语句,我也不知道为什么。
现在离最终的sql查询语句还差selec开头和*星号还有表名,where关键字在parseWhere()函数返回是拼接了。我没有找到但是我想大胆猜测一下。

在select()函数中,最后有一个变量selectSql跟进

protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%UNION%%ORDER%%LIMIT% %LOCK%%COMMENT%';

发现还行是sql语句的模板,其中的field正好也是等于*星号table也正好等于wp_user_follow

以上形成"SELECT * FROM wp_user_follow开头的过程完全是瞎猜,如果感觉有更严谨的解释请多指教,不喜勿喷
到这里sql语句的形成已经完全知道了,接下来是执行部分。回到在think\db\Connection.php中的find()函数。在下面就有sql执行函数。

跟进query()函数

在预处理这条函数就会sql语句执行就产生的报错,后续就是报错信息的回显函数了

0x02复现

没有什么好说的就是用poc修改参数user()就可以注出其他数据了

0x03总结

感觉主要的难度是堆栈非常的长,需要有足够的耐心

0x04参考

大佬一号
奇安信攻防社区-WeiPHP 5.0 sql注入漏洞(bind_follow)浅析 (butian.net)
大佬二号
待定
免责声明

本博客所提供的技术知识和信息仅旨在教育和分享网络安全最佳实践,促进网络安全意识的提升。作者严禁将这些技术和信息用于任何非法或不道德的目的。

使用本博客内容而导致的任何违法行为或后果,作者不承担任何法律责任。所有读者在使用本博客的信息时,应自行承担风险,并确保遵守当地法律法规。

我们鼓励所有读者合法地使用所提供的信息和技术,致力于维护安全和负责任的网络环境。

感谢您的理解与支持。

热门相关:冒牌老婆很神秘   特工皇后不好惹   林家有女异世归   终归田居   童养媳之桃李满天下