入门一个月,第一次和全国范围的师傅们进行的比赛。一边摸索一边做题,在多方帮助下学到了一些东西。rank最后定格在了317/2410,个人感觉还是需要再努力一些。有一两道题感觉努力一下把环境配好还是能出的。配环境报错的时候真的蛮令人灰心的。
鉴于token制度的存在,具体flag应该会不一样。

签到

F12,将max的值改为1.0,拖到最右边提交可得。

1
flag{hR6Ku81-HappyHacking2020-a9833bf0c9}

猫咪问答++

1.可以爆破,大眼一扫至少有4个,就从4开始试,一直试到12就ook了。
2、3、4、5百度搜就能搜到相关信息。
答案分别是256、9、9、17098.

1
flag{b4a31f2a_G00G1e_1s_y0ur_fr13nd_e836337896}

2048

当时也有在玩2048,然后果断进去先铁头娃玩个一通,拿到2048之后发现并没有给出flag,F12看源码发现最高值是8192,以我的水平必然玩不出来。在注释出发现一段代码

1
2
3
4
<!-- 
changelog:
- 2020/10/31 getflxg @ static/js/html_actuator.js
-->

在题目地址栏后添加static/js/html_actuator.js作为一个payload,得到一个逻辑源码页面,往下寻找可以发现一段

1
2
3
4
5
if (won) {
url = "/getflxg?my_favorite_fruit=" + ('b'+'a'+ +'a'+'a').toLowerCase();
} else {
url = "/getflxg?my_favorite_fruit=";
}

脑洞一下可以大概知道baxaxa是什么单词,而且是fruit种类,那必然是banana
将题目url后加上/getflxg?my_favorite_fruit=banana作为payload

1
flxg{8G6so5g-FLXG-26aa589d52}

一闪而过的flag

下下来打开这个exe文件,会弹出flag,然后程序快速退出。只需要在打开显示flag的时候使用qq截图,截取并且识别flag即可。

1
flag {Are_you_eyes1ght_g00D?_can_you_dIst1nguish_1iI?}

从零开始的记账工具人

一开始使用的是excel批量替换,但是出现迷之错误,大致有3类坑,全被我踩过了。

1.整元没有考虑。

2.只有分、只有角的没有考虑。

3.替换十的时候,必须得从二十一开始替换,并且避开整十,最后才去替换十几,否则会出现很恶心的错误。

x.以及各种各样很烦的要注意的东西。

当时被这道题搞得心态都炸了,因为替换逻辑没处理好的话是根本得不出答案的,后面尝试了很多种替换方案,最后出来了,其中酸楚,唯有自己知道。当时心态炸裂之后甚至头铁的一条一条去替换,后来出现大量不耐烦的错误,必然也得不到答案,心如死灰。一起做的同僚自己写个VB脚本跑了出来,痛恨自己写代码的水平无限趋近于0吧,也是我在CTF之路继续前行的一个非常大但必须克服的阻碍。
主要替换的思路就是从小数点后面开始替换,从分到角,然后注意处理整数、没有元只有角分的数,以及从二十一开始替换,并且整十数和十几的数最后替换。

超简单的世界模拟器

蝴蝶效应

一道非常有教育意义和趣味性的题,我很喜欢。
百度搜生命游戏,便可以得到相当多的资料。
在左上角放置一个“轻量级飞船”即可撞烂上面的方块得到第一个flag。

一石二鸟

这个尝试了蛮多种组合,都不行。后来得到同僚的提示,只需要使用一个飞船和一个滑翔机的组合就可以,后来一直尝试成功了。具体矩阵已经丢失,也懒得去复现了

从零开始的火星文生活

试了用各种编码打开,没啥思路。
以下是官方wp:

过程

下载附件之后如直接用 GBK 打开,那就真的是题面里说的“夹杂着日语和数字的火星文”了。恭喜掉进坑,乱码又多了一层(逃

用 UTF-8 打开,看到形如“脦脪鹿楼”的文本,推断是上图中的“古文码”乱码。但是“古文码”明明是“以 GBK 方式读取 UTF-8 编码”造成的,看来“脦脪鹿楼”本来应当是 GBK下看到的结果,却又被存成了 UTF-8。所以第一步是用 GBK 重新编码文本“脦脪鹿楼…”。

然后用 UTF-8 打开,看到形如“ÎÒ¹¥ÆÆÁË”的文本,推断是上图中的“拼音码”乱码。“拼音码”是“以 ISO8859-1 方式读取 GBK 编码”,而现在文本的编码是 UTF-8。所以接下应当用 ISO8859-1 重新编码文本“ÎÒ¹¥ÆÆÁË…”。

然后用 GBK 打开,就能看到可读的汉字和 flag 了(原始编码确实是 GBK 呢!)。不过这里的 flag 全部是从 ASCII 字符转成的全角字符,不能直接复制使用。可以手动替换成 ASCII 字符,或者用其他简便方法变回 ASCII 字符。

源代码 中也给出了一个全角->半角的函数。

实践

那么具体用什么手段来解题呢?

方法一(不写代码)
例如用 VSCode 的“Select Encoding”功能。

步骤(开始时 UTF-8 打开题目附件):

1.Save with Encoding -> GBK
2.Reopen with Encoding -> UTF-8
3.Save with Encoding -> ISO8859-1
4.Reopen with Encoding -> GBK
(听说 Notepad++ 很方便,蹲一个其他人的 wp)

方法二 (写代码)
见 源代码 中的 solve 函数。

1
2
3
def solve(message):
answer=DBC2SBC(message.encode("gbk").decode("UTF-8").encode("iso-8859-1").decode('gbk'))
return answer

自复读的复读机

查了很多资料,以为输出有漏洞什么的,还考虑了eval函数、exec函数之类的,但是都不会,或者说没啥效果和思路。几天之后用百度搜“python输出自身的代码”,找到一篇知乎文章https://zhuanlan.zhihu.com/p/34882073
使用第三种方法,然后构造一下让它输出的时候带一个[::-1],即把串倒序,就能符合题目要求拿到flag,提交后发现多一个\n,在输出时加一个end=””即可。
至于sha256,其实就是多一个sha256的计算,把串放进去就行了。

233同学的字符串工具

字符串大写工具

代码的逻辑是输入一个不是flag的串,令其转换成大写之后被识别为FLAG。一开始又去找各种python的输入漏洞,没有收获。看过同僚的思路,知道的就是有一个字符会在转换大写的时候被识别成FL,只是没找到。查了下完整的ascii码表去试,也没啥效果,当时就蠢不知道打个表全输出出来对着找就是了。最后也是没做出来
以下是官方WP:
代码的意思是:如果我们输入一个字面上不是 “flag” 但转换为大写后会变成 “FLAG” 的字符串,就可以得到 flag。

我们可以以 “unicode uppercase collision” 为关键字搜索,不难找到一个连字(ligature)

fl (0xFB02)
这个“字符”将在转换为大写时变成 FL 两个字符!因此,只需输入 flag 即可得到 flag。

1
flag{badunic0debadbad}

编码转换工具

代码的意思是:如果我们输入一个字面上不是 “flag” 但从 UTF-7 转换为 UTF-8 后会变成 “flag” 的字符串,就可以得到 flag。

不妨查阅 UTF-7 相关资料。可以得知:一个 Unicode 字符串,在 UTF-7 编码下,可能有多种编码,甚至纯粹的 ASCII 字符串也可以有多种编码!

那么事情就简单了。我们依照 Wikipedia 等参考资料给出的 UTF-7 编码算法,可以构造出 “flag” 的另一种“写法”。比如,选择 f 下手。

1.f 的 Unicode 码位是 0x66
2.将 0x66 写成 16 位二进制数:0000 0000 0110 0110
3.重新分组:000000 000110 011000
4.使用 base64 的编码表,将每组变成一个字符:AGY
那么最终 “flag” 的另一种 UTF-7 替代写法就是 +AGY-lag,输入即可得到 flag。

1
flag{please_visit_www.utf8everywhere.org}

(是的,你应该去看这个网站!)

233同学的docker

docker0基础学起,其实是因为看到很多人出了这题。pull完docker到ubuntu里,然后搜dockerfile把删除的文件恢复之类的关键词,找到这样一篇文章,https://www.bbsmax.com/A/lk5a10b251/参照着去操作即可cat出flag。

1
flag{Docker_Layers!=PS_Layers_hhh}

来自一教的图片

matlab对其傅里叶变换处理,报错。openCV装不上,报错,python pip相关的包,报错。心态有点烦躁不想做了
以下是官方wp:
对图像二维傅里叶变换就结束了。灵感来自于中国科学技术大学三级大学物理实验“傅里叶光学”。

用 Python 的解法:

1
2
3
4
5
6
7
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('./4f_system_middle.bmp', 0)
f = np.fft.fft2(img)
logf = 20*np.log(np.abs(f))
plt.imshow(logf, 'gray')

由于wp腾挪得比较晚,官方wp的github页面上的配图也丢失了,一些完整的步骤没有了插图等同于没有做wp。下次养成自己做完题目保存做题过程,便于自己写wp和博客,以及和官方wp的对比的习惯,以及及时腾挪wp。

超简陋的openGL小程序

不会openGL,以下是官方wp:
https://github.com/USTC-Hackergame/hackergame2020-writeups/blob/master/official/%E8%B6%85%E7%AE%80%E9%99%8B%E7%9A%84%20OpenGL%20%E5%B0%8F%E7%A8%8B%E5%BA%8F/README.md

狗狗银行

非常有趣的一道题目。个人认为个中含有丰富的经济学知识,一开始意识到金钱的数额都是四舍五入,保留整数,这样就能利用这个漏洞去薅羊毛了。储蓄卡里有167元时,每日获利可得0.501元,四舍五入即是1元。按照这个思路去开卡,借钱,养卡去薅,后来思路以及操作上出现了一些失误导致满盘皆输,没跑赢利息,被资本撕裂。或许这辈子只能当个穷鬼而不是资本家了。看了wp才发现手动是非预期。
以下是官方wp:
解法
这道题的主要考点是利用利息四舍五入的规则将实际到手利率翻倍,次要考点是编写脚本自动执行重复性操作。

利率翻倍这一步没什么好说的,简单实验一会就不难发现,当储蓄卡存有 167 狗狗币时,每日利息应当是 0.501 狗狗币,但四舍五入就是 1 狗狗币,实际上利率约等于 0.6%,超过了信用卡利率。信用卡没有这个漏洞,不会因为利息不足 0.5 狗狗币就变成 0,这是有意设计的,避免开很多张信用卡就可以实现零利息获得任意数量的钱。

一个简单的(但不是最节约操作次数的)策略是:开一张信用卡,借很多钱,分开存到很多张储蓄卡中,每张卡存恰好 167 狗狗币。这样一来,这笔钱每天净赚 0.1% 利息,逐渐就能积累到 1000 狗狗币。每隔几天,应当把所有储蓄卡中获得的利息拿走,还回信用卡,因为每张储蓄卡存恰好 167 狗狗币时赚钱最快,越多越慢,当每张储蓄卡存 200 狗狗币时会恰好无法赚钱,之后会开始亏钱。附件中的解题脚本就是按照这个思路编写的,开了 200 张储蓄卡,每天都拿走利息,37 天可以获胜。
怎么写脚本
以下以最新版 Chrome 浏览器为例,其他主流浏览器一般都有类似功能。提到的浏览器界面上的文字都是英文版,使用中文版的请自行猜测我在说什么。(或者干脆别看这一段了,直接去网上搜搜怎么用 Python 写爬虫发请求应该就够了。)

要想编写脚本自动操作,首先需要知道在浏览器中手工操作时会产生什么样的网络请求。如果通过脚本发送一模一样的网络请求,就能取代手工操作,产生一模一样的效果。在狗狗银行页面上按 F12 键打开“开发者工具”,在其中切换到“Network”页面,就可以看到所有浏览器发送的网络请求。去办储蓄卡,会发现每当点击“办卡”按钮时就会有一个“create”请求出现,它的 Url 是 http://202.38.93.111:10100/api/create。在这一行上点右键,“Copy”,“Copy as cURL”,就能复制出类似于这样的命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
curl 'http://202.38.93.111:10100/api/create' \
-H 'Connection: keep-alive' \
-H 'Pragma: no-cache' \
-H 'Cache-Control: no-cache' \
-H 'Accept: application/json, text/plain, */*' \
-H 'DNT: 1' \
-H 'Authorization: Bearer 1:MEUCIQDG+Pwf82nVTQC07Kkmt6YkDbYo/uEsRu8f6f3HCXGQ2AIgJFlltu51Y6lNJ1sEHMviqOnoc75k1A6Qn3xoLBxM1qw=' \
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36' \
-H 'Content-Type: application/json;charset=UTF-8' \
-H 'Origin: http://202.38.93.111:10100' \
-H 'Referer: http://202.38.93.111:10100/' \
-H 'Accept-Language: en-US,en;q=0.9' \
--data-binary '{"type":"debit"}' \
--compressed \
--insecure

在 Linux(需要安装 curl)命令行上运行这条命令,再刷新网页,就会发现也能办出储蓄卡。实际上,对于这道题的后端服务器来说,这个请求重要的部分只有:

发送 POST 请求给 http://202.38.93.111:10100/api/create
包含 HTTP 请求头:Authorization: Bearer 1:MEUCIQDG+Pwf82nVTQC07Kkmt6YkDbYo/uEsRu8f6f3HCXGQ2AIgJFlltu51Y6lNJ1sEHMviqOnoc75k1A6Qn3xoLBxM1qw=,注意其中包含着 token,这说明了你在操作哪个账号。
包含 HTTP 请求头:Content-Type: application/json;charset=UTF-8,这说明了这个请求的正文是 JSON 格式的。
包含请求正文:{"type":"debit"}
除了使用 curl 命令以外,还可以用各种编程语言发送这个请求,方法上网搜索很容易找到。

再经过一些尝试,不难找到办信用卡的请求、吃饭的请求、以及转账的请求(有的请求的正文中有可以改变的参数,表示卡号等信息)。这样就有了完成这道题所需要的所有请求。可以使用复制粘贴加一点修改的方法在一份文档中整理好需要按顺序执行的所有请求,然后全部执行,当然还是推荐学习一下怎么写变量和循环语句。
wp里有一句话写得有些尖锐,但是这就是我目前的瓶颈。
遗憾是这导致手工进行所有操作所需要的时间也较短,在 7 天的比赛中完全可以完成,一些选手因此误以为手工操作也是这道题的一种预期解法,不仅没有借助这道题学会编写脚本发请求,反而浪费了大量时间和精力。今后出题应当避免类似情况,如果预期解需要自动化操作,就不应当让手工操作有完成的可能性。

其余的题感觉有些偏门了(其实就是懒),就不挪到这边了。

所有题目的wp:https://github.com/USTC-Hackergame/hackergame2020-writeups