经历了无数次爆零的比赛之后,终于做出来了几道题(哭
题目本身并没有想象的特别难,不过质量和创新点做的非常好。
最终rank:59

一道关于字符串匹配的问题
打开网站,查看源码,看到了一串base85加密的数据,解个密看下,工作目录都给了
1 | |
右上角有个更改颜色的按钮,随便选个抓个包看看,发现Cookie多了个asset字段,内容为assets/css/pico.green.min.css,正好与上面看到的文件路径保持一致,尝试读app.py发现需要assets/css/开头,../绕过下:asset=assets/css/../../app.py
1 | |
populate.py中写了flag在数据库secrets中
1 | |
首先需要登录,有一个匹配a.lower() != b.lower() and a.upper() == b.upper()
想到了nodejs特性:Character.toUpperCase()函数,字 符ı会转变为I,字符ſ会变为S。
看了下发现py也可以,直接alıce和ſtart2024登录
接下来(“secrets” in type.lower() or “SECRETS” in type.upper())要保证既大写不相等且小写不等
最开始以为是要弄 一个upper变 一个lower变 的两个字符,fuzz了一下发现没有这种
后来网上找了一下看到数据库utf8mb4_unicode_ci匹配中会把一些奇怪的符号匹配为正常的符号
é可以代替e
payload: ?type=ſecrétſ
拿到flag:flag{sTR1Ngs_WitH_tHE_s@mE_we1ghT_aRe_3QUAl_iN_my5q1}
是GitHub上的一个比较知名的GPT平台ChatGPT-Next-Web
题目要求限制本地IP才能问出flag
搜了一下看到一个SSRF的洞CVE-2023-49785,好像还存在
网上普遍的poc都是GET请求的poc,无法达到与GPT交互的作用
随便翻了翻设置,看到一个云数据同步的功能

里面有一个配置功能

随便配置一下,配置好后点击同步,出现的请求包恰好和网上的ssrf洞的请求包类似,但是其中出现了一处 method: PUT字段,猜测为ssrf的请求方式

改请求包,改访问路径,访问即出flag
1 | |
打开容器是一个格式化json的网站,题目描述说了给jq,看了一眼发现是一个命令行的程序,题目应该是一个web容器把参数传过去
抓个包发现确实是这样,json是json数据,args是参数,而且,如果选择两个或以上的选项,args会出现多个参数,随便填填,发现如果字符长度>5会报错,而且有命令拼接,能够回显的条件是输出为json格式的字符串。
举个例子:json={"&args=%26echo&args="{}",即使json参数传的并不是一个正常的json字符串,因为命令拼接后的输出为json格式,因此回显{},即命令拼接为jq json args...
当时拼了一会发现拼不出来json格式的(其实好像是能拼出来的,只是当时没想到),看jq的文档中

发现输入jq env可以得到当前的环境变量,并且题目中提示flag在环境变量中
直接出了payload:json={}&args=%26jq&args='env'
花时间比较长的一题,最后还是没能做出来
给了Dockerfile,直接看一下,题目用了webpsh/webp-server-go:0.11.0的容器,并且给了flask的前端代码,简单看下代码,是一个文件上传和下载的图床,使用了webp进行缩小图片
upload路由大体上没问题,使用随机数进行文件的重命名防止了目录穿越。
关键点在于查看图片的路由,其中调用了fetch_converted_image函数对23333端口进行http请求,因为其HTTP报文直接对Accept进行了拼接,会导致一个HTTP走私,举个例子
1 | |
如果accept中为image/webp%0d%0aConnection:+alive%0d%0a%0d%0aGET+/flag+HTTP/1.1,会导致报文变为
1 | |
导致服务器后端误以为是两个请求,一起发送了报文,同时,python处理返回的恰好是\r\n\r\n截断最后面的部分,最后回显的就会是走私的请求结果。
从这里就我开始走偏了,之前刚打完UNbreakable-ICTF-2024,其中一道题恰好使用了libsvg的漏洞 CVE-2023-38633,其poc为
1 | |
来对etc/passwd进行一个读取,而这题给的flag是flag.png,当时以为是要对图片进行一个包含,于是在docker上左调右调花了好多时间(关键是xml写不对那边还会有一个拒绝服务,导致每次都要重启容器)
回到正题,此题是一个CVE-2021-46104的变种,相关Issue上有讨论,是一个go的目录穿越漏洞,其漏洞最早期可以直接使用../即可打通,后面加了一些处理,已经没法打通了。但这道题中,如果HTTP报文省略了开头的/,即GET ../../flag.png,还是会导致一个目录穿越。这个的根源应该在于golangpath.Clean的第四条:如果HTTP报文中带/时,这个路径就相当于一个根目录,而根目录后的..会被自动清除。而如果不带/,path.Clean会认为这个是相对路径。同时,gofiber的path.go也完全匹配了/*,无论它是否为/开头。
所以拿到flag步骤是这样,先提交随便一个图片,拿到随机的值,然后发包进行走私
1 | |

最困惑的题目
打开站点,是一个普通的界面,其中OAuth Login会跳转到sjtu的认证页面,view note和note都会提示未登录,跳转到login,再跳转到oauth

html中存在sitemap.xml,里面可以找到一个code.php

访问它发现需要code参数,随便填一个有以下界面,此处log是粗体的,结合sitemap.xml,可以推断出还有一个/log路由

访问log路由,是一个管理员code的泄露,在sjtu jAccount网站可以看到是一个授权码,有效期为1分钟,认证模式为使用授权码-authorization-code-过程的-oidc-认证模式
带着code访问code.php,登录成功,提示flag为SSO name
想要找到SSO name,必须要有access_token,想要access_token,必须要有client_id、client_secret,以及我们上面刚刚得到的code
接下来思路没了,开始复现wp
原来是一个key的泄露,泄露在SJTUer/django/sjtuers/settings.py at master · young1881/SJTUer (github.com)处
拿到JACCOUNT_CLIENT_ID = 'ZjpxY3dA6fpkp7o4kM0g',JACCOUNT_CLIENT_SECRET = 'CE1FEABAD368510B161F8F0E582CBA6864EAF4137FC18079'
尝试获取access_token,可惜赛后已经无法复现了,大概报文如下,获取access_token
1 | |
返回结果直接jwt解密即可,或继续拿access_token对https://api.sjtu.edu.cn/v1/me/profile?access_token=进行请求
官网wp还提到了一个非预期,即使用任意泄露client_id和client_secret组合串,都可以获取到access_token,很神奇。
wp-scan扫一下,有一个NotificationX插件,插件存在CVE-2024-1698,一个sql盲注
需要搜索/抓包确认api的路径,不能直接用网上的payload。
因为对wordpress不熟悉,痛失一道题
直接给出官网payload
1 | |
flag:flag{W0rdpr355_plu61n5_4r3_vuln3r4bl3}
遇到题一定要有耐心看下去
花时间最长的一道题,但还是没有做出来
首先因为NODE_NDEBUG=1可以直接忽视require('assert-plus')
接下来是/comment/like出有一个把所有参数都注入到查询语句的查询,这里有一个注入点
1 | |
注入方式:
1 | |
先写一堆形如____________a____...、_____b__________...的评论,然后执行上述语句,查看哪个like增加
给出最后的payload:
1 | |

flag: flag{BL1nd_5ql_!NJeC71on_1S_PoS5ib13_W17h_0nLy_4_9ueRiE5}
md回头一看也不是特别难啊,主要是当时看了一眼就直接拿主机调nodejs了,没搭docker导致comment处无法注入,不过话说我拿win机cmd直接输入npm start为啥注入不了呢,好奇怪,下次一定记得搭docker(血的教训)
没怎么看的一道题
打开网站是一个登录界面,登录抓个包看看,发现Graphql请求
1 | |
根据渗透测试之graphQL_graphql 漏洞,通过IntrospectionQuery 可以查询到其中的全部信息
1 | |
使用graphiql/examples/graphiql-cdn/index.html at main · graphql/graphiql打开,有了docs和api

对其中shop字段name进行请求,得到Saleor e-commerce

GitHub直接能搜到Saleor Commerce,这里引用官方wp的一张图来描述其架构

下载前端saleor/storefront,将.env处填入后端地址,npm run dev直接跑起来

随便找找发现about

根据hint1在之前的IntrospectionQuery 返回包可以找到flag1:Channel-specific tax configuration.\n\nAdded in Saleor 3.9.🎉 Congratulations! You find flag part 1: ZmxhZ3s5ckBQSH 🎉
根据hint2,在之前的graphql中搜product,其中seoDescription有flag2:🎉 Congratulations! You find flag part 2: ExX0BQIV8zWH🎉
1 | |

接下来是网站存在源代码泄露,原网站src/pages/index.tsx中存在邮箱david@deepshop.co,配合弱口令123456可以直接登录(神奇的思路,看官方wp原来是作者自己加的)
继续本地部署saleor/saleor-dashboard,仍然以david登录,在 customer 里抓包有hint3和hint4(可能是版本的问题,从这里开始我复现得都非常艰难)

根据hint3,在Order中找到订单,抓包发现isgift字段不存在,去掉isgift重新发包,拿到flag3:🎉 Congratulations! You find flag part 3: AwNWU1X0VcL🎉

根据hint4,在 Translations - Chinese - Menu Items - GraphQL API 中找到flag4:🎉 Congratulations! You find flag part 4: zNyWStoSU45fQ==🎉

base64解码,出来flag:flag{9r@PHq1_@P!_3Xp05e5_E\/3rY+hIN9}
总算复现出来了,光是复现就花了我好长时间,一道很新颖的渗透题
经历了无数次爆零的比赛之后,终于做出来了几道题(哭
题目本身并没有想象的特别难,不过质量和创新点做的非常好。
最终rank:59

一道关于字符串匹配的问题
打开网站,查看源码,看到了一串base85加密的数据,解个密看下,工作目录都给了
1 | |
右上角有个更改颜色的按钮,随便选个抓个包看看,发现Cookie多了个asset字段,内容为assets/css/pico.green.min.css,正好与上面看到的文件路径保持一致,尝试读app.py发现需要assets/css/开头,../绕过下:asset=assets/css/../../app.py
1 | |
populate.py中写了flag在数据库secrets中
1 | |
首先需要登录,有一个匹配a.lower() != b.lower() and a.upper() == b.upper()
想到了nodejs特性:Character.toUpperCase()函数,字 符ı会转变为I,字符ſ会变为S。
看了下发现py也可以,直接alıce和ſtart2024登录
接下来(“secrets” in type.lower() or “SECRETS” in type.upper())要保证既大写不相等且小写不等
最开始以为是要弄 一个upper变 一个lower变 的两个字符,fuzz了一下发现没有这种
后来网上找了一下看到数据库utf8mb4_unicode_ci匹配中会把一些奇怪的符号匹配为正常的符号
é可以代替e
payload: ?type=ſecrétſ
拿到flag:flag{sTR1Ngs_WitH_tHE_s@mE_we1ghT_aRe_3QUAl_iN_my5q1}
是GitHub上的一个比较知名的GPT平台ChatGPT-Next-Web
题目要求限制本地IP才能问出flag
搜了一下看到一个SSRF的洞CVE-2023-49785,好像还存在
网上普遍的poc都是GET请求的poc,无法达到与GPT交互的作用
随便翻了翻设置,看到一个云数据同步的功能

里面有一个配置功能

随便配置一下,配置好后点击同步,出现的请求包恰好和网上的ssrf洞的请求包类似,但是其中出现了一处 method: PUT字段,猜测为ssrf的请求方式

改请求包,改访问路径,访问即出flag
1 | |
打开容器是一个格式化json的网站,题目描述说了给jq,看了一眼发现是一个命令行的程序,题目应该是一个web容器把参数传过去
抓个包发现确实是这样,json是json数据,args是参数,而且,如果选择两个或以上的选项,args会出现多个参数,随便填填,发现如果字符长度>5会报错,而且有命令拼接,能够回显的条件是输出为json格式的字符串。
举个例子:json={"&args=%26echo&args="{}",即使json参数传的并不是一个正常的json字符串,因为命令拼接后的输出为json格式,因此回显{},即命令拼接为jq json args...
当时拼了一会发现拼不出来json格式的(其实好像是能拼出来的,只是当时没想到),看jq的文档中

发现输入jq env可以得到当前的环境变量,并且题目中提示flag在环境变量中
直接出了payload:json={}&args=%26jq&args='env'
花时间比较长的一题,最后还是没能做出来
给了Dockerfile,直接看一下,题目用了webpsh/webp-server-go:0.11.0的容器,并且给了flask的前端代码,简单看下代码,是一个文件上传和下载的图床,使用了webp进行缩小图片
upload路由大体上没问题,使用随机数进行文件的重命名防止了目录穿越。
关键点在于查看图片的路由,其中调用了fetch_converted_image函数对23333端口进行http请求,因为其HTTP报文直接对Accept进行了拼接,会导致一个HTTP走私,举个例子
1 | |
如果accept中为image/webp%0d%0aConnection:+alive%0d%0a%0d%0aGET+/flag+HTTP/1.1,会导致报文变为
1 | |
导致服务器后端误以为是两个请求,一起发送了报文,同时,python处理返回的恰好是\r\n\r\n截断最后面的部分,最后回显的就会是走私的请求结果。
从这里就我开始走偏了,之前刚打完UNbreakable-ICTF-2024,其中一道题恰好使用了libsvg的漏洞 CVE-2023-38633,其poc为
1 | |
来对etc/passwd进行一个读取,而这题给的flag是flag.png,当时以为是要对图片进行一个包含,于是在docker上左调右调花了好多时间(关键是xml写不对那边还会有一个拒绝服务,导致每次都要重启容器)
回到正题,此题是一个CVE-2021-46104的变种,相关Issue上有讨论,是一个go的目录穿越漏洞,其漏洞最早期可以直接使用../即可打通,后面加了一些处理,已经没法打通了。但这道题中,如果HTTP报文省略了开头的/,即GET ../../flag.png,还是会导致一个目录穿越。这个的根源应该在于golangpath.Clean的第四条:如果HTTP报文中带/时,这个路径就相当于一个根目录,而根目录后的..会被自动清除。而如果不带/,path.Clean会认为这个是相对路径。同时,gofiber的path.go也完全匹配了/*,无论它是否为/开头。
所以拿到flag步骤是这样,先提交随便一个图片,拿到随机的值,然后发包进行走私
1 | |

最困惑的题目
打开站点,是一个普通的界面,其中OAuth Login会跳转到sjtu的认证页面,view note和note都会提示未登录,跳转到login,再跳转到oauth

html中存在sitemap.xml,里面可以找到一个code.php

访问它发现需要code参数,随便填一个有以下界面,此处log是粗体的,结合sitemap.xml,可以推断出还有一个/log路由

访问log路由,是一个管理员code的泄露,在sjtu jAccount网站可以看到是一个授权码,有效期为1分钟,认证模式为使用授权码-authorization-code-过程的-oidc-认证模式
带着code访问code.php,登录成功,提示flag为SSO name
想要找到SSO name,必须要有access_token,想要access_token,必须要有client_id、client_secret,以及我们上面刚刚得到的code
接下来思路没了,开始复现wp
原来是一个key的泄露,泄露在SJTUer/django/sjtuers/settings.py at master · young1881/SJTUer (github.com)处
拿到JACCOUNT_CLIENT_ID = 'ZjpxY3dA6fpkp7o4kM0g',JACCOUNT_CLIENT_SECRET = 'CE1FEABAD368510B161F8F0E582CBA6864EAF4137FC18079'
尝试获取access_token,可惜赛后已经无法复现了,大概报文如下,获取access_token
1 | |
返回结果直接jwt解密即可,或继续拿access_token对https://api.sjtu.edu.cn/v1/me/profile?access_token=进行请求
官网wp还提到了一个非预期,即使用任意泄露client_id和client_secret组合串,都可以获取到access_token,很神奇。
wp-scan扫一下,有一个NotificationX插件,插件存在CVE-2024-1698,一个sql盲注
需要搜索/抓包确认api的路径,不能直接用网上的payload。
因为对wordpress不熟悉,痛失一道题
直接给出官网payload
1 | |
flag:flag{W0rdpr355_plu61n5_4r3_vuln3r4bl3}
遇到题一定要有耐心看下去
花时间最长的一道题,但还是没有做出来
首先因为NODE_NDEBUG=1可以直接忽视require('assert-plus')
接下来是/comment/like出有一个把所有参数都注入到查询语句的查询,这里有一个注入点
1 | |
注入方式:
1 | |
先写一堆形如____________a____...、_____b__________...的评论,然后执行上述语句,查看哪个like增加
给出最后的payload:
1 | |

flag: flag{BL1nd_5ql_!NJeC71on_1S_PoS5ib13_W17h_0nLy_4_9ueRiE5}
md回头一看也不是特别难啊,主要是当时看了一眼就直接拿主机调nodejs了,没搭docker导致comment处无法注入,不过话说我拿win机cmd直接输入npm start为啥注入不了呢,好奇怪,下次一定记得搭docker(血的教训)
没怎么看的一道题
打开网站是一个登录界面,登录抓个包看看,发现Graphql请求
1 | |
根据渗透测试之graphQL_graphql 漏洞,通过IntrospectionQuery 可以查询到其中的全部信息
1 | |
使用graphiql/examples/graphiql-cdn/index.html at main · graphql/graphiql打开,有了docs和api

对其中shop字段name进行请求,得到Saleor e-commerce

GitHub直接能搜到Saleor Commerce,这里引用官方wp的一张图来描述其架构

下载前端saleor/storefront,将.env处填入后端地址,npm run dev直接跑起来

随便找找发现about

根据hint1在之前的IntrospectionQuery 返回包可以找到flag1:Channel-specific tax configuration.\n\nAdded in Saleor 3.9.🎉 Congratulations! You find flag part 1: ZmxhZ3s5ckBQSH 🎉
根据hint2,在之前的graphql中搜product,其中seoDescription有flag2:🎉 Congratulations! You find flag part 2: ExX0BQIV8zWH🎉
1 | |

接下来是网站存在源代码泄露,原网站src/pages/index.tsx中存在邮箱david@deepshop.co,配合弱口令123456可以直接登录(神奇的思路,看官方wp原来是作者自己加的)
继续本地部署saleor/saleor-dashboard,仍然以david登录,在 customer 里抓包有hint3和hint4(可能是版本的问题,从这里开始我复现得都非常艰难)

根据hint3,在Order中找到订单,抓包发现isgift字段不存在,去掉isgift重新发包,拿到flag3:🎉 Congratulations! You find flag part 3: AwNWU1X0VcL🎉

根据hint4,在 Translations - Chinese - Menu Items - GraphQL API 中找到flag4:🎉 Congratulations! You find flag part 4: zNyWStoSU45fQ==🎉

base64解码,出来flag:flag{9r@PHq1_@P!_3Xp05e5_E\/3rY+hIN9}
总算复现出来了,光是复现就花了我好长时间,一道很新颖的渗透题