MoonBox的一次代码审计

本文最后更新于:13 小时前

github项目地址:https://github.com/vivo/MoonBox

环境搭建

这里直接用了官方提供的docker启动方式

1
docker-compose -f docker-compose.yml up

瞎摸索

开局先到处摸索一波功能点,流量走bp代理

在这里的运行,进去后配置好ssh的账号密码,点击执行

然后抓到对应的流量

这时候我去观察了一眼moonbox-server的控制台,发现了一处有趣的地方

这里执行了一串的命令,先从本地的8080端口下载下一个压缩包文件,然后解压,并且执行了一个脚本

1
2
3
4
5
6
7
8
9
10
curl -o sandboxDownLoad.tar http://127.0.0.1:8080/api/agent/downLoadSandBoxZipFile &&
curl -o moonboxDownLoad.tar http://127.0.0.1:8080/api/agent/downLoadMoonBoxZipFile &&
rm -fr ~/sandbox &&
rm -fr ~/.sandbox-module &&
tar -xzf sandboxDownLoad.tar -C ~/ >> /dev/null &&
tar -xzf moonboxDownLoad.tar -C ~/ >> /dev/null &&
dos2unix ~/sandbox/bin/sandbox.sh &&
dos2unix ~/.sandbox-module/bin/start-remote-agent.sh &&
rm -f moonboxDownLoad.tar sandboxDownLoad.tar &&
sh ~/.sandbox-module/bin/start-remote-agent.sh moon-box-web rc_id_ce5bf691ceb653883c27b3c7e6f96779%26http%3A%2F%2F127.0.0.1%3A8080%26INFO%26INFO

8080端口刚好是moonbox-server的内部端口,对外映射了8081

于是我尝试去访问

http://127.0.0.1:8081/api/agent/downLoadSandBoxZipFile

下载下来了一个

解压完里面是一个二进制文件,暂时想不到有什么用,

在docker的终端里,我新建了一个测试目录来调试

到了这一步,发现/root/下新增了一个sandbox目录,里面居然有一堆的东西

emm懂了刚刚压缩包里面那个没后缀的玩意是一个压缩文件,用7z确实提取出来了

没去细看脚本,但是执行的命令中,给两个脚本都规范化了,下面虽然只执行了一个脚本但是应该里面的逻辑是有和另一个脚本联动的

继续寻找有用的地方

在下面这一处agent文件管理我发现了一个关键点

这个地方仅支持.tar文件的上传,一个sandbox-agent和moonbox-agent,很难不让人想起上面的那两个压缩包

右边的文件更新让人激动了一下,,

假如说能够控制那个压缩包里的脚本,,岂不是,,?

直接把他原来的压缩包原样打包回去,nginx提示传输文件太大了hhh

把lib目录删了之后小多了,然后在sandbox.sh下面插入一句反弹shell命令

用7z的tar压缩,提示,合着得是gz,但是前端只让上传tar嘎嘎,被坑了

简单弄了一下,构造压缩包成功

还差一个问题,,怎么在springboot里面运行就这样

直接终端里面跑成功触发

这时候才恍然大悟!

之所以要填写ssh的账号密码正是因为这个命令是在我们自己的vps上执行的,通过远程的方式来管理agent的启动!

所以说如果我们的ssh账号密码是moonbox-server的,那么就能够在server上执行这个命令~

开始着手于寻找server的ssh密码

但是cmd5无果

不慌,既然有root密码,就说明在创建容器的时候肯定有写入,去配置看看

成功拿到账号密码root/123456,此时已经激动到起飞,,

成功执行命令~

继续尝试

审计的时候注意到这个月光宝盒有大量的hessian字眼,就想着看看有没有hessian反序列化可利用

于是全局搜索”deserial”、”serial”、”反序列化”等等(当然也搜过原生的readObject()但是没啥结果,,)

一搜deserialize()东西可太多了,,可谓是眼花缭乱

于是我就想着找找web端的controller吧,看看有没有能找到传参啊之类的地方

运气真好,,来到了下面这个文件,从直观上看saveReplay的参数可控

com/vivo/internet/moonbox/web/agent/MoonBoxAgentController.java

直接访问接口:

然后跟进saveReplay()看看

不跟不要紧,这一跟,直接整激动起来了,,

继续跟进去这个hessianDeserialize

走到一个接口,但是还好只有一处实现

看看实现吧,大致逻辑非常清晰了,就是将我们传入的参数(这里跟回去实际上就是我们传入的request body)进行base64解码之后,再传入deserialize()

跟到底层来到com/vivo/internet/moonbox/common/api/serialize/HessianSerializer.java的deserialize()方法

其中很明显地进行了非常直接的hessian反序列化

观察到SerializerWrapper包下有一个hessianSerialize()方法,和hessianDeserialize()互逆

简单在包下写了个测试类来生成序列化数据,随便丢个bean类进去看看

成功反序列化(这个报错只是因为反序列化之后没有结果,但是确实执行了hissian反序列化的这个过程)

然后就开始学习hessian反序列化了,,,(挖个坑

在寻找利用过程中有需要注意一点就是jdk版本,8u342,算挺高的了