(不知道放什么图好,那就找张海报当题图吧)
前言
中国科学技术大学第八届信息安全大赛
比赛时间: 北京时间 2021 年 10 月 23 日 中午 12:00 ~ 10 月 30 日 中午 12:00(共七天);添加到日历
为了让参赛的同学们更好地平衡学习和比赛,按照传统,我们将于 10 月 24 日(周日)晚 20:00 至 10 月 25 日(周一)早 8:00 期间关闭比赛平台。在此期间选手们可以好好休息,完成自己的作业,准备迎接新的一周。
赛制: 个人线上赛,解题模式,约 25 道题目,有实时排行榜。
比赛题目分为 4 类,分类如下:
- 综合技能(general)
- 程序逆向与漏洞利用(binary)
- 密码学与数学(math)
- 网站安全(web)
一年一度的 USTC Hackergame 又来了喵!
顺便,喵喵 Hackergame 2020 的 Writeup 详见:
这次比赛大部分题目的题解是边做边写的,所以与其说是题解,不如说是 解题的过程记录,你可以认为这篇博客里是一堆废话,里面 可能包含了错误或者有可能误导正确解题的内容,这太正常了 hhh。
由于最近比较忙,本来还想复现几道题再发博客的,发现一不小心咕了,想想还是算了,直接发出来吧。(摊手.jpg
后面可能还会陆续复现更新,大概可能估计吧,毕竟题目出得还是很不错的~
签到
为了能让大家顺利签到,命题组把每一秒的 flag 都记录下来制成了日记本的一页。你只需要打开日记,翻到 Hackergame 2021 比赛进行期间的任何一页就能得到 flag!
提示:完成题目遇到困难?你可以参考 2018 年签到题题解、2019 年签到题题解 和 2020 年签到题题解。
http://202.38.93.111:10000/?token=xxxxxxx
是去年那个 FLAG 提取器 的背景!(跑
试了一下,很明显这个参数 page 就是时间戳啦~
比如现在的话就访问 http://202.38.93.111:10000/?page=1634984522 完事了。
进制十六——参上
为严防 flag 泄漏以及其他存在于未来所有可能的意外灾难,神通广大的 Z 同学不仅强制要求每一道题目都加上权限和资源的限制,还给所有参与 Hackergame 2021 命题的计算机施加了一层法术结界。任何试图从结界逃逸的 flag 都会被无情抹除。
而一位明面上是计算机学院的新生,实则为物理学院暗部核心成员的 X 同学,在 Hackergame 2021 命题组已经潜伏多时。妄想趁比赛开始的午时,借阳火正旺之势,冲破 Z 同学的结界,以图片而非明文的形式,将 flag 悄悄传递出来。
好在 Z 同学法力之深厚,不可管窥蠡测。在 flag 被传出去的前两天,就已预知此事并将图片中的 flag 无声消泯了。
只是,这位 X 同学,虽然不会退出 Vim,但是似乎对打开十六进制编辑器颇有造诣……
直接 OCR 大法,然后 hex 转 ASCII 完事。
flag{Y0U_SH0U1D_kn0w_H0W_t0_C0nv3rt_HEX_to_TexT}
去吧!追寻自由的电波
(前情提要) 为了打破 Z 同学布下的结界,X 同学偷偷搬出社团的业余无线电台试图向外界通讯。
当然,如果只是这样还远远不够。遵依史称“老爹”的上古先贤的至理名言,必须要“用魔法打败魔法”。X 同学向上级申请到了科大西区同步辐射实验室设备的使用权限,以此打通次元空间,借助到另一个平行宇宙中 Z 同学的法力进行数据对冲,方才于乱中搏得一丝机会,将 flag 用无线电的形式发射了出去。
考虑到信息的鲁棒性,X 同学使用了无线电中惯用的方法来区分字符串中读音相近的字母。即使如此,打破次元的强大能量扭曲了时空,使得最终接受到的录音的速度有所改变。
为了保障同步辐射设备的持续运转,组织牺牲了大量的能源,甚至以东北部分地区无计划限电为代价,把这份沉甸甸的录音文件送到了你的手上。而刚刚起床没多久,试图抢签到题一血还失败了的你,可以不辜负同学们对你的殷切期望吗?
注:flag 花括号内只包含小写字母。
先放慢一丢丢,然后对照 无线电中的英语字母读法
可以得到是
flag{phoneticab}
卖瓜
有一个人前来买瓜。
HQ:哥们,这瓜多少钱一斤啊?
你:两块钱一斤。
HQ:What’s up!这瓜皮子是金子做的还是瓜粒子是金子做的?
你:你瞧瞧现在哪有瓜啊?这都是大棚的瓜,只有 6 斤一个和 9 斤一个的,你嫌贵我还嫌贵呢。
(HQ 心里默默一算)
HQ:给我来 20 斤的瓜。
你:行!
HQ:行?这瓜能称出 20 斤吗?
你:我开水果摊的,还不会称重?
HQ:我问你这瓜能称出 20 斤吗?
你:你是故意找茬,是不是?你要不要吧!
HQ:你这瓜要是刚好 20 斤吗我肯定要啊。那它要是没有怎么办啊?
你:要是不是 20 斤,我自己吃了它,满意了吧?
(你开始选瓜称重)
补充说明:当称的数字变为浮点数而不是整数时,HQ 不会认可最终的称重结果。
进行一个🍉的卖。
(测试工程师走进了这家瓜铺,)尝试构造个负数
操作无效:不能放负数个瓜。
1.5个6 斤 -> 6斤
整个超级大的数,多来几次,嗯,溢出啦!
重新开始,单独放6斤的瓜 18446744073709551615(0xFFFFFFFFFFFFFFFF,64位全1)个,得到0个;
单独放9斤这么多个 -> -9223372036854775808 斤,也就是 -0x8000000000000000
然后不管了,反正先用个负数,然后再加回去到正的20就完事了,注意一下要 x6 或者 x9 而且不要溢出。
比如先放 1537228672809129301个 9斤的
电子秤上已有 -4611686018427387904/20 斤的瓜。
然后放 4611686018427387904//6 == 768614336404564650 个 6 斤的,得到 -4 斤。
最后再放 4 个 6 斤的完事。
猫咪问答 Pro Max
我猛然一看,就猛然看到这个猫咪问答,我直呼我直呼,上次看到这么这么的发言还是上次,这问答属于是典型的典型了,我之前还没发现,当我发现的时候我已经发现了,这问答就像一个问答,问答的内容充满了内容,我不禁感慨了一句感慨:希望下次看到这么这么的猫咪问答是下次。
提示:解出谜题不需要是科大在校学生。解题遇到困难?你可以参考 2018 年猫咪问答题解 和 2020 年猫咪问答++ 题解。
20190928http://ftp.lug.ustc.edu.cn/%E7%A4%BE%E5%9B%A2%E7%AE%A1%E7%90%86/%E7%AB%A0%E7%A8%8B/
https://lug.ustc.edu.cn/wiki/lug/events/
试了 20201024 也不对,看这个 slide 里面貌似也有投票的。(
再看题目,他问的是 信息安全俱乐部的社团章程 啊,那应该是2017年之前的了。。
那既然给了域名,直接去 webarchive 找吧。
https://web.archive.org/web/20181004003308/http://sec.ustc.edu.cn/doku.php/codes
5
为了表彰其出色表现,协会于 2011 年 5 月被评为中国科学技术大学优秀学生社团,于 2012 年 5 月、2013 年 5 月及 2014 年 5 月分别被评为中国科学技术大学四星级学生社团,并于 2015 年 5 月、2017 年 7 月、2018 年 9 月、2019 年 8 月及 2020 年 9 月被评为中国科学技术大学五星级学生社团。
然而发现试了4不对,看来今年也有吧
(不及时更新害人不浅啊
这个还是有点难找的,其实吧,喵喵先是翻 tg 找到了这张图(跑然后咕咕噜搜到啦(
Development Team of Library
13
可以找到这篇论文 http://sigbovik.org/2021/
http://sigbovik.org/2021/proceedings.pdf
然后后面他举了13个数据集的例子,13张图……
/dev/null
完事(
透明的文件
一个透明的文件,用于在终端中展示一个五颜六色的 flag。
可能是在 cmd.exe 等劣质终端中被长期使用的原因,这个文件失去了一些重要成分,变成了一堆乱码,也不会再显示出 flag 了。
注意:flag 内部的字符全部为小写字母。
给的文件大概长这样……
[0;0H[20;58H[8;34H[13;27H[4;2H[38;2;1;204;177m [39m[14;10H[20;51H[23;4H[12;2H[38;2;2;207;173m [39m[19;61H[9;12H[22;8H[20;2H[38;2;3;210;169m [39m[3;23H[8;68H[19;10H[4;3H[38;2;4;214;165m [39m[19;23H[17;34H[11;52H[22;70H[12;3H[38;2;5;217;161m [39m[24;22H[2;25H[19;76H[19;3H[38;2;6;220;157m [39m[23;14H[21;12H[10;37H[2;37H[22;66H[16;45H[21;3H[38;2;7;222;153m
很明显是 shell 的转义序列,然后 垃圾 cmd 显示不出来锅了。
参考
Bash tips: Colors and formatting (ANSI/VT100 Control sequences)
或者看 TaQini 师傅的 设置终端输出字符的属性(颜色+格式+超链接)
可以知道 \033[y;xH
用来设置光标位置,那其实就相当于鼠标画图了(老考点了
那就依次提取出各个点,画个图连一起就好了。
画出来发现这是啥啊……
其实只有每一行(即原始数据的空格之前)的最后一个坐标有用啦。
然后摸了,直接替换文件把最后的颜色输出个字符出来算了(跑
先加个 ESC
的转义字符 \033
,然后最后随便加个字符。
(当然你用 sed
也行
echo -e `cat transparent_fix.txt`
全小写字母
flag{abxnniohkalmcowsayfiglet}
旅行照片
你的学长决定来一场说走就走的旅行。通过他发给你的照片来看,他应该是在酒店住下了。
从照片来看,酒店似乎在小区的一栋高楼里,附近还有一家 KFC 分店。突然,你意识到照片里透露出来的信息比表面上看起来的要多。
请观察照片并答对全部 5 道题以获取 flag。注意:图片未在其他地方公开发布过,也未采取任何隐写措施(通过手机拍摄屏幕亦可答题)。
是图片社工大手子啊(怎么你们都会做啊
很明显这个是在海边,看起来是面朝偏南方向,阳光从右往左照,那应该是从西边照过来。当前就是傍晚了。
这个肯德基蓝色的很有特征,咕咕噜一搜,找到了小红书的一个笔记,啊,不就是这个嘛。
秦皇岛新奥海地世界,很好。
百度地图 搜一波,就你了。拍摄的角度如图所示。
肯德基号码 0335-7168800
百度这个实景地图还是老的啊,不过也能看出是 海豚馆 了。
楼层的话,根据对面的楼,这个拍的不超过15楼,再考虑到拍摄角度偏下,俯拍的感觉,应该也在这个附近了。最后试了发现就是14F。
完事。
有意思的是,题目的答案是通过将选项内容序列化之后请求后端的一个文件来得到的。
FLAG 助力大红包
“听说没?【大砍刀】平台又双叒做活动啦!参与活动就送 0.5 个 flag 呢,攒满 1 个 flag 即可免费提取!”
“还有这么好的事情?我也要参加!”
“快点吧!我已经拿到 flag 了呢!再不参加 flag 就要发完了呢。”
“那怎么才能参加呢?”
“这还不简单!点击下面的链接就行”
公告:本题在小概率情况下会产生操作时间限制无法重置的现象,表现为一直显示“操作速度太快了,请稍后再试!”,现已修复,请大家重新点击按钮后稍等几秒钟即可恢复。
啊,是拼夕夕
又是可恶的砍价!噢不对,是集 flag!
前端会调用 https://pv.sohu.com/cityjson?ie=utf-8 这个接口获取IP,后端比对是否相符,如果相符则可助力成功。
然后发现咱校 IP 出口分流策略不一样,导致前后端结果不一致(
不过发现直接加个 X-Forwarded-For
头就好了。
接下来就是遍历 /8 段,依次发包就完事了。
import time
import requests
url = "http://202.38.93.111:10888/invite/a7009a3c-6bd0-4674-8586-e36a9b4b7e58"
for i in range(256):
ip = f'{i}.1.1.1'
data = "ip=" + ip
headers = {
"X-Forwarded-For": ip,
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0",
"Content-Type": "application/x-www-form-urlencoded"
}
r = requests.post(url, headers=headers, data=data)
# print(r.status_code)
# print(r.text)
if "助力成功" in r.text:
print(i, 'OK')
time.sleep(1.25)
注意不能太快,不然会无效。
等到跑完就能提现了。
flag{r3d-enve10p3-bf6a7f44ac}
(要是拼夕夕也能这么刷就好了
Amnesia
你的程序只需要输出字符串
Hello, world!
(结尾有无换行均可)并正常结束。编译指令:
gcc -O file.c -m32
运行指令:
./a.out
编译器版本:Docker 镜像
ustclug/debian:10
中apt update && apt -y upgrade && apt install -y gcc=4:8.3.0-1 gcc-multilib=4:8.3.0-1
的版本轻度失忆
编译后 ELF 文件的
.data
和.rodata
段会被清零。连接题目:
nc 202.38.93.111 10051
或网页终端判题脚本:下载
记忆清除
编译后 ELF 文件的
.text
段会被清零。连接题目:
nc 202.38.93.111 10061
或网页终端判题脚本:下载
轻度失忆
linux 目标文件(*.o) bss,data,text,rodata,堆,栈
数据段(BSS段、DATA段)、代码段(.RODATA)、堆栈段的区别
volatile关键字通常用来修饰多线程共享的全局变量和IO内存。告诉编译器,不要把此类变量优化到寄存器中,每次都要老老实实的从内存中读取,因为它们随时都可能变化。这个关键字可能比较生僻,但千万不要忘了它,否则一个错误让你调试好几天也得不到一点线索。
(注:这个相当于stm32文件中定义的__IO,代表了每次读取用这个关键词定义的值的时候,需要去内存中实时的读取。也就是说每次得到的都是最新的值)
整个 volatile
试试吧(好久没写C了啊
#include <stdio.h>
int main()
{
volatile char *x = "Hello, world!";
puts(x);
return 0;
}
虽然 puts
函数中变量定义的类型是 const char *
,会报 warning,但不影响正常输出呀(跑
要是换成用数组,一个一个元素赋值应该就不会有这个问题。
再或者,一个一个字符 putchar
也行。
图之上的信息
小 T 听说 GraphQL 是一种特别的 API 设计模式,也是 RESTful API 的有力竞争者,所以他写了个小网站来实验这项技术。
你能通过这个全新的接口,获取到没有公开出来的管理员的邮箱地址吗?
u1s1 第一次用 GraphQL,虽然早就知道 GitHub 新版 API(好像是 v4?)是基于这个进行查询的了。
这题是个笔记阅读系统,guest 登录进去,有个 /graphql
接口请求后端。
先 dump 一下所有对象和字段,通过 IntrospectionQuery 来返回足够多信息。
query IntrospectionQuery{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description locations args{...InputValue}}}}fragment FullType on __Type{kind name description fields(includeDeprecated:true){name description args{...InputValue}type{...TypeRef}isDeprecated deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated:true){name description isDeprecated deprecationReason}possibleTypes{...TypeRef}}fragment InputValue on __InputValue{name description type{...TypeRef}defaultValue}fragment TypeRef on __Type{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name}}}}}}}}
or
query IntrospectionQuery{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description args{...InputValue}onOperation onFragment onField}}}fragment FullType on __Type{kind name description fields(includeDeprecated:true){name description args{...InputValue}type{...TypeRef}isDeprecated deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated:true){name description isDeprecated deprecationReason}possibleTypes{...TypeRef}}fragment InputValue on __InputValue{name description type{...TypeRef}defaultValue}fragment TypeRef on __Type{kind name ofType{kind name ofType{kind name ofType{kind name}}}}
得到
{"data":{"__schema":{"queryType":{"name":"Query"},"mutationType":null,"subscriptionType":null,"types":[{"kind":"OBJECT","name":"Query","description":null,"fields":[{"name":"note","description":"Get a specific note information","args":[{"name":"id","description":null,"type":{"kind":"SCALAR","name":"Int","ofType":null},"defaultValue":"null"}],"type":{"kind":"OBJECT","name":"GNote","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"notes","description":"Get notes information of a user","args":[{"name":"userId","description":null,"type":{"kind":"SCALAR","name":"Int","ofType":null},"defaultValue":"null"}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"GNote","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"user","description":"Get a specific user information","args":[{"name":"id","description":null,"type":{"kind":"SCALAR","name":"Int","ofType":null},"defaultValue":"null"}],"type":{"kind":"OBJECT","name":"GUser","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"GNote","description":null,"fields":[{"name":"id","description":null,"args":[],"type":{"kind":"SCALAR","name":"Int","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"contents","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Int","description":"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"String","description":"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"GUser","description":null,"fields":[{"name":"id","description":null,"args":[],"type":{"kind":"SCALAR","name":"Int","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"username","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"privateEmail","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Boolean","description":"The `Boolean` scalar type represents `true` or `false`.","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Schema","description":"A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.","fields":[{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"types","description":"A list of all types supported by this server.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"queryType","description":"The type that query operations will be rooted at.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"mutationType","description":"If this server supports mutation, the type that mutation operations will be rooted at.","args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"subscriptionType","description":"If this server support subscription, the type that subscription operations will be rooted at.","args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"directives","description":"A list of all directives supported by this server.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Directive","ofType":null}}}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Type","description":"The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional `specifiedByUrl`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.","fields":[{"name":"kind","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"ENUM","name":"__TypeKind","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"specifiedByUrl","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"fields","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":"false"}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Field","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"interfaces","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"possibleTypes","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"enumValues","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":"false"}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__EnumValue","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"inputFields","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":"false"}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"ofType","description":null,"args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"ENUM","name":"__TypeKind","description":"An enum describing what kind of type a given `__Type` is.","fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"SCALAR","description":"Indicates this type is a scalar.","isDeprecated":false,"deprecationReason":null},{"name":"OBJECT","description":"Indicates this type is an object. `fields` and `interfaces` are valid fields.","isDeprecated":false,"deprecationReason":null},{"name":"INTERFACE","description":"Indicates this type is an interface. `fields`, `interfaces`, and `possibleTypes` are valid fields.","isDeprecated":false,"deprecationReason":null},{"name":"UNION","description":"Indicates this type is a union. `possibleTypes` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"ENUM","description":"Indicates this type is an enum. `enumValues` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"INPUT_OBJECT","description":"Indicates this type is an input object. `inputFields` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"LIST","description":"Indicates this type is a list. `ofType` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"NON_NULL","description":"Indicates this type is a non-null. `ofType` is a valid field.","isDeprecated":false,"deprecationReason":null}],"possibleTypes":null},{"kind":"OBJECT","name":"__Field","description":"Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.","fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"args","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":"false"}],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__InputValue","description":"Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.","fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"defaultValue","description":"A GraphQL-formatted string representing the default value for this input value.","args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__EnumValue","description":"One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.","fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Directive","description":"A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.","fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"isRepeatable","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"locations","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"ENUM","name":"__DirectiveLocation","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"args","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"ENUM","name":"__DirectiveLocation","description":"A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.","fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"QUERY","description":"Location adjacent to a query operation.","isDeprecated":false,"deprecationReason":null},{"name":"MUTATION","description":"Location adjacent to a mutation operation.","isDeprecated":false,"deprecationReason":null},{"name":"SUBSCRIPTION","description":"Location adjacent to a subscription operation.","isDeprecated":false,"deprecationReason":null},{"name":"FIELD","description":"Location adjacent to a field.","isDeprecated":false,"deprecationReason":null},{"name":"FRAGMENT_DEFINITION","description":"Location adjacent to a fragment definition.","isDeprecated":false,"deprecationReason":null},{"name":"FRAGMENT_SPREAD","description":"Location adjacent to a fragment spread.","isDeprecated":false,"deprecationReason":null},{"name":"INLINE_FRAGMENT","description":"Location adjacent to an inline fragment.","isDeprecated":false,"deprecationReason":null},{"name":"VARIABLE_DEFINITION","description":"Location adjacent to a variable definition.","isDeprecated":false,"deprecationReason":null},{"name":"SCHEMA","description":"Location adjacent to a schema definition.","isDeprecated":false,"deprecationReason":null},{"name":"SCALAR","description":"Location adjacent to a scalar definition.","isDeprecated":false,"deprecationReason":null},{"name":"OBJECT","description":"Location adjacent to an object type definition.","isDeprecated":false,"deprecationReason":null},{"name":"FIELD_DEFINITION","description":"Location adjacent to a field definition.","isDeprecated":false,"deprecationReason":null},{"name":"ARGUMENT_DEFINITION","description":"Location adjacent to an argument definition.","isDeprecated":false,"deprecationReason":null},{"name":"INTERFACE","description":"Location adjacent to an interface definition.","isDeprecated":false,"deprecationReason":null},{"name":"UNION","description":"Location adjacent to a union definition.","isDeprecated":false,"deprecationReason":null},{"name":"ENUM","description":"Location adjacent to an enum definition.","isDeprecated":false,"deprecationReason":null},{"name":"ENUM_VALUE","description":"Location adjacent to an enum value definition.","isDeprecated":false,"deprecationReason":null},{"name":"INPUT_OBJECT","description":"Location adjacent to an input object type definition.","isDeprecated":false,"deprecationReason":null},{"name":"INPUT_FIELD_DEFINITION","description":"Location adjacent to an input object field definition.","isDeprecated":false,"deprecationReason":null}],"possibleTypes":null}],"directives":[{"name":"include","description":"Directs the executor to include this field or fragment only when the `if` argument is true.","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Included when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]},{"name":"skip","description":"Directs the executor to skip this field or fragment when the `if` argument is true.","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Skipped when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]},{"name":"deprecated","description":"Marks an element of a GraphQL schema as no longer supported.","locations":["FIELD_DEFINITION","ARGUMENT_DEFINITION","INPUT_FIELD_DEFINITION","ENUM_VALUE"],"args":[{"name":"reason","description":"Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/).","type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":"\"No longer supported\""}]},{"name":"specifiedBy","description":"Exposes a URL that specifies the behaviour of this scalar.","locations":["SCALAR"],"args":[{"name":"url","description":"The URL that specifies the behaviour of this scalar.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}]}]}}}
然后可以发现 email 相关的是 privateEmail
,查询用户的话用 user
,args 里用 id: 1
来查 admin 的信息。
payload:
{"query":"{ user(id: 1) { id\nprivateEmail }}"}
打过去就能拿到 flag 啦!
Extensive Reading:
Hack In Paris 2019 CTF – “Meet Your Doctor” (GraphQL challenge)
一个工具 GraphQLmap - a scripting engine to interact with a graphql endpoint for pentesting purposes.
加密的 U 盘
这是一个关于 LUKS (Linux Unified Key Setup) 的故事。
第一天
小 T:「你要的随机过程的课件我帮你拷好了,在这个 U 盘里,LUKS 加密的密码是
suijiguocheng123123
。」小 Z:「啊,你又搞了 Linux 文件系统加密,真拿你没办法。我现在不方便用 Linux,我直接把这块盘做成磁盘镜像文件再回去处理吧。」
第二天
小 Z:「谢谢你昨天帮我拷的课件。你每次都搞这个加密,它真的安全吗?」
小 T:「当然了!你看,你还给我之后,我已经把这块盘的弱密码改掉了,现在是随机生成的强密码,这样除了我自己,世界上任何人都无法解密它了。」
小 Z:「我可不信。」
小 T:「你不信?你看,我现在往 U 盘里放一个 flag 文件,然后这个 U 盘就给你了,你绝对解密不出来这个文件的内容。当初搞 LUKS 的时候我可研究了好几天,班上可没人比我更懂加密!」
放进 winhex 里可以发现这俩文件都是完整的磁盘镜像,包含 EFI 之类的引导扇区,而后包含了 LUKS 加密分区。
参考
扫盲 dm-crypt — — 多功能 Linux 磁盘加密工具(兼容 TrueCrypt & VeraCrypt)
去年 hackergame 室友的加密硬盘 一题 (那个是提取 AESKEY,不大一样
先把我们需要的这两个文件的 LUKS 分区给导出来,分别为 1.001
, 2.001
.
或者用 parted
获取 offset,然后挂载 loop。
发现二者的 UUID 相同。
然后用 cryptsetup
挂载,看看情况。day1 的密钥就是题目给的 suijiguocheng123123
。
# cryptsetup luksOpen 1.001 day1
# cryptsetup status day1
/dev/mapper/day1 is active.
type: LUKS2
cipher: aes-xts-plain64
keysize: 512 bits
key location: keyring
device: /dev/loop0
loop: /mnt/hgfs/games/Hackergame2021USTC/lukspwd/1.001
sector size: 512
offset: 32768 sectors
size: 6111 sectors
mode: readonly
# mkdir /mnt/day1
# mount /dev/mapper/day1 /mnt/day1
mount: /mnt/day1: WARNING: source write-protected, mounted read-only.
# df -hT
文件系统 类型 容量 已用 可用 已用% 挂载点
udev devtmpfs 1.4G 0 1.4G 0% /dev
tmpfs tmpfs 293M 1.9M 291M 1% /run
/dev/sda1 ext4 39G 23G 14G 62% /
tmpfs tmpfs 1.5G 0 1.5G 0% /dev/shm
tmpfs tmpfs 5.0M 0 5.0M 0% /run/lock
vmhgfs-fuse fuse.vmhgfs-fuse 256G 245G 12G 96% /mnt/hgfs
tmpfs tmpfs 293M 64K 293M 1% /run/user/0
/dev/mapper/day1 ext4 2.0M 33K 1.7M 2% /mnt/day1
# cd /mnt/day1/
# ll
总用量 31K
-rw-r--r-- 1 root root 19K 10月 18 23:52 随机过程.txt
drwx------ 2 root root 12K 10月 18 23:52 lost+found
看一下两个盘里的 Key Slot
# cryptsetup luksDump 1.001
LUKS header information
Version: 2
Epoch: 3
Metadata area: 16384 [bytes]
Keyslots area: 16744448 [bytes]
UUID: e9a660d5-4a91-4dca-bda5-3f6a49eea998
Label: (no label)
Subsystem: (no subsystem)
Flags: (no flags)
Data segments:
0: crypt
offset: 16777216 [bytes]
length: (whole device)
cipher: aes-xts-plain64
sector: 512 [bytes]
Keyslots:
0: luks2
Key: 512 bits
Priority: normal
Cipher: aes-xts-plain64
Cipher key: 512 bits
PBKDF: pbkdf2
Hash: sha256
Iterations: 1581562
Salt: b6 95 26 1a d3 8d bb 51 fb 78 c2 1b 87 6b 9f 5a
66 10 4c 01 8f ae eb 30 53 c4 93 03 fd 1a 68 d6
AF stripes: 4000
AF hash: sha256
Area offset:32768 [bytes]
Area length:258048 [bytes]
Digest ID: 0
Tokens:
Digests:
0: pbkdf2
Hash: sha256
Iterations: 104857
Salt: 3c f9 97 83 b9 08 0e b0 c8 ee b5 cc 63 f1 79 1f
1f df a5 11 cc 6e 48 53 b9 04 24 36 a4 4b 8d 55
Digest: 67 59 6a 45 a1 a1 6a 8e 09 75 71 5c b6 3c 83 9f
6c 00 ad d0 a4 df fe 9a 13 01 70 f8 de 03 a2 2b
# cryptsetup luksDump 2.001
LUKS header information
Version: 2
Epoch: 5
Metadata area: 16384 [bytes]
Keyslots area: 16744448 [bytes]
UUID: e9a660d5-4a91-4dca-bda5-3f6a49eea998
Label: (no label)
Subsystem: (no subsystem)
Flags: (no flags)
Data segments:
0: crypt
offset: 16777216 [bytes]
length: (whole device)
cipher: aes-xts-plain64
sector: 512 [bytes]
Keyslots:
1: luks2
Key: 512 bits
Priority: normal
Cipher: aes-xts-plain64
Cipher key: 512 bits
PBKDF: pbkdf2
Hash: sha256
Iterations: 1615678
Salt: d7 da 36 0c 04 52 0d 52 7a cc 3b 6a 33 14 5c d9
ed ff 5d ec 74 d0 13 06 1d 0a c2 60 c5 de 08 3f
AF stripes: 4000
AF hash: sha256
Area offset:290816 [bytes]
Area length:258048 [bytes]
Digest ID: 0
Tokens:
Digests:
0: pbkdf2
Hash: sha256
Iterations: 104857
Salt: 3c f9 97 83 b9 08 0e b0 c8 ee b5 cc 63 f1 79 1f
1f df a5 11 cc 6e 48 53 b9 04 24 36 a4 4b 8d 55
Digest: 67 59 6a 45 a1 a1 6a 8e 09 75 71 5c b6 3c 83 9f
6c 00 ad d0 a4 df fe 9a 13 01 70 f8 de 03 a2 2b
可以发现他们 header 是相同的。
参考
于是先导出 day1 的 header backup file,然后用它来给 day2 恢复,再用 day1 的密钥就能解开加密分区了。
cryptsetup luksHeaderBackup --header-backup-file header 1.001
cryptsetup --header header luksOpen 2.001 day2
flag{changing_Pa55w0rD_d0esNot_ChangE_Luk5_ma5ter_key}
果然是没改 master key(23333
最后再卸载文件系统,关闭加密盘.
umount /mnt/day1
umount /mnt/day2
cryptsetup close day1
cryptsetup close day1
赛博厨房
虽然这是你的餐厅,但只有机器人可以在厨房工作。机器人精确地按照程序工作,在厨房中移动,从物品源取出食材,按照菜谱的顺序把食材依次放入锅内。
机器人不需要休息,只需要一个晚上的时间来学习你教给它的程序,在此之后你就可以在任何时候让机器人执行这个程序,程序的每一步执行都会被记录下来,方便你检查机器人做菜的过程。
另外为了符合食品安全法的要求,赛博厨房中的机器人同一时间手里只能拿一种食物,每次做菜前都必须执行清理厨房的操作,把各处的食物残渣清理掉,然后回到厨房角落待命。
每天的菜谱可能不同,但也许也存在一些规律。
对机器人编程可以使用的指令有(
n, m
为整数参数,程序的行号从 0 开始,注意指令中需要正确使用空格):向上 n 步 向下 n 步 向左 n 步 向右 n 步 放下 n 个物品 拿起 n 个物品 放下盘子 拿起盘子 如果手上的物品大于等于 n 向上跳转 m 行 如果手上的物品大于等于 n 向下跳转 m 行
赶紧进入赛博厨房开始做菜吧!
Level 0
向右 1 步
拿起 1 个物品
向下 1 步
向左 2 步
放下 1 个物品
向右 1 步
向上 1 步
拿起 1 个物品
向下 1 步
向左 1 步
放下 1 个物品
Level 1
今日菜谱物品 ID:0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
73 个 0
草,才发现它的 向上跳转 2 行
是说从程序执行的上面两行再继续往下执行。。而且在边界上不会再次移动了。那就简单了呀。
向右 1 步
拿起 75 个物品
向下 1 步
向左 1 步
放下 1 个物品
如果手上的物品大于等于 3 向上跳转 1 行
放下盘子
阵列恢复大师
2021 年 10 月 3 日,阴转小雨。
你发现你运行在实验室机器上的炼丹脚本挂了。
「好好的国庆假期,怎么我还得来改程序……」收到邮件通知后,你登录了机器,看到的却是一大堆
Input/Output Error
,回过神来才发现,放数据的阵列好像出了问题。「完了!上面的数据我从来没有备份过!这下赶不上 DDL 发不了 paper 了!」你赶忙跑到机房,检查了一下阵列的情况——看起来盘没坏,都能读,只是可能是受到神秘宇宙射线(误)的影响,阵列的管理页面看不了,每块盘的 RAID 元数据好像也全不见了,更要命的是,你忘了当初组阵列时候盘的顺序和其他的参数。怎么恢复数据呢?上网搜索一下,好像得花不少钱。但你听说你的同学最近在搞信息什么大赛——或许可以让他们试试?
以下是两个压缩包,分别是一个 RAID 0 阵列的磁盘压缩包,和一个 RAID 5 阵列的磁盘压缩包,对应本题的两小问。你需要解析得到正确完整的磁盘阵列,挂载第一个分区后在该分区根目录下使用 Python 3.7 或以上版本执行
getflag.py
脚本以获取 flag。磁盘数据保证无损坏。RAID 0 阵列压缩包,SHA256:
f73bee3a2dce201566573f51bd28026c467182601eb6e55130db10c7c0c8127f
RAID 5 阵列压缩包,SHA256:
5eb1d2042ab5f8e2ee1508bf5e66632b4c307a595099e499aa9bc2a7255a6009
RAID 5
RAID级别
该程序支持使用操作系统或主板以及使用各种制造商的控制器和外部存储设备创建的磁盘阵列
硬盘阵列:
- JBOD是磁盘的顺序合并。用信息填充磁盘后,数据将写入下一个数据。用于增加空间。至少需要2个(两个)磁盘。
- RAID 0 是向所有磁盘写入块的顺序替换。用于增加空间并加快数据访问。最少2(两)个磁盘。
- RAID 1这是阵列中所有磁盘上的数据重复。用于保护数据以防丢失。至少2(两)个磁盘。
- RAID 10 (1 + 0).至少4(四)个磁盘。
- RAID 1E (1 + 0 包括改进).至少3(三)个磁盘。
- RAID 5 是将数据与校验和的保留进行交织。 2个(两个)磁盘发生故障后可以自行恢复。加快磁盘工作,扩展空间并保护数据不丢失。至少三(3)个磁盘。
- RAID 50 (5 + 0).至少6(六)个磁盘。
- RAID 5E 和 5EE (类似于级别5,在“热插拔”的情况下有一个额外的磁盘)。级别5EE与5E的不同之处在于,热插拔驱动器不是空闲的,而是与其余驱动器一起使用。 至少4(四)个磁盘。
- RAID 6 是使用两个校验和的数据交织。使用里德(Reed)所罗门编码。系统可以从两个磁盘故障中自我恢复。与第五级相比,第六级用于增加磁盘空间,读取和写入速度并提高可靠性 最少4(四)个磁盘。
- RAID 60 (6 + 0).最少8(八)个磁盘。
- RAID 2 –结合了两组磁盘:带有数据和带有纠错代码。基于汉明码,与大量光盘有关。 最少3(三)个磁盘。
- RAID 3 与第五级类似,但是校验和不是在所有磁盘之间交错,而是始终写入其中一个磁盘。这会大大增加带有校验和的磁盘磨损。该级别使用1(一个)字节大小的块。
- RAID 4 此级别是从RAID 3继承的,区别在于块大小可以大于1(一个)字节。
搜了一下,用 Hetman RAID Recovery™ 这玩意可以恢复(
好像 EasyRecovery 也行,不过咱没试。
但感觉这个软件中文界面有点锅,会出现 Zenithal Z佬式问号(�
EXT4 格式
还有 Windows 上用感觉有点问题,直接导出 zip 会卡住,喵喵是先导出整个镜像 dsk 文件,然后在 DiskGenius 里再把 /files/
目录下文件恢复出来的。
getflag.py
#!/usr/bin/env python3
# Flag is here.
# Don't peek in my file, as they are my privacy.
# Just execute me to get flag please!
import hashlib
import os
import sys
ans = ""
paths = []
if __name__ == '__main__':
path = os.environ.get("FILES", "./files/")
if not os.path.exists(path):
print("files folder not found: set FILES environment variable if you are not in the root of my disk image.")
sys.exit(-1)
for root, dirs, files in os.walk(path):
for filename in files:
if filename == '.DS_Store':
continue
filepath = os.path.join(root, filename)
paths.append(filepath)
paths.sort()
for filepath in paths:
h = hashlib.sha256()
with open(filepath, 'rb') as f:
while True:
chunk = f.read(h.block_size)
if not chunk:
break
h.update(chunk)
hexdigest = h.hexdigest()
print(filepath, hexdigest)
ans += hexdigest
check = hashlib.sha256(ans.encode("utf-8")).hexdigest()
if check == "df81eca70a025e5f2b5d3ba56ac1289b2112a1c041cbe1b199ac5a8049fbf9d7":
print("Flag:", f"flag{{{hashlib.md5(ans.encode('utf-8')).hexdigest()}}}")
else:
print("Did you recover my data correctly?")
发现得在 Linux 下跑,Windows 下不成功,会问你 Did you recover my data correctly?
flag{a18325a1ec0f58292908455c2df8ffcd}
赛后听说直接 DiskGenius 组建虚拟 raid,排一下顺序就能解,摸了。
RAID 0
同理,但这个自动搜索起来巨慢……跑了二十几分钟,发现了507个配置。
XFS
草,不懂为啥这个文件系统不管是否恢复被删除的文件出来,最后算出来的结果都不对,不懂哪里锅了,佛了……
哪位师傅能提供个正确恢复出来的文件给喵喵 diff 一下呢(
噢对,讲个故事,这个镜像排好的顺序忘记记录下来了,惨惨,啥时候换种方式重新拼吧。
minecRaft
kk 同学很喜欢玩 Minecraft,他最近收到了一张 MC 地图,地图里面有三盏灯,还有很多奇奇怪怪的压力板。
但他发现这些灯好像不太符合 MC 电磁学(Red stone),你能帮他把灯全部点亮吗?
注:本题解法与原版 Minecraft 游戏无关。
补充说明:flag 花括号内为让三盏灯全部点亮的最短的输入序列。例如,如果踩踏压力板输入的最短的序列为 abc,则答案为 flag{abc}。
这个 MC 可不简单……
看上去是个游戏,实际上是个逆向题。
首先这题里面有个用来反爬虫的定时器 debugger
卡死浏览器调试窗口,可以抓包,改返回包把这部分去掉。
入口在这里,输入的字符长度为32,会调用 flag.js
里的 gyflagh
函数进行校验,如果返回 true
则结果正确。
然而,flag.js
里函数进行了混淆,可恶啊!!!
进行了好一番静态+动态调试,大概的逻辑是下面这样。
前面有个匿名函数,给 Strings
类定义了一个 encrypt
方法。
gyflagh
的参数就是我们的输入,经过 encrypt
后与 6fbde674819a59bfa12092565b4ca2a7a11dc670c678681daf4afb6704b82f0c
做对比,相同则正确。
而 encrypt
里依次取出 flag 的前四位、后四位,转换为 long 类型,进行 code
。
再看 code
,实际上它进行了 32 轮变化,这个 2654435769
其实就是熟悉的 0x9e3779b9,即 Tiny Encryption Algorithm (TEA) 算法常量。这里其实用到的是 XTEA 加密算法。
String['prototype']["encrypt"] = function (param) {
// param = "1356853149054377"
x1 = new Array(2),
x2 = new Array(4);
let result = '';
plaintext = escape(this); //flag
for (var i = 0; i < 4; i++) x2[i] = Str4ToLong("1356853149054377" ["slice"](i * 4, (i + 1) * 4));
// x2 = [ 909456177, 825439544, 892352820, 926364468 ]
for (i = 0; i < 32; i += 8) { //plaintext["length"]
x1[0] = Str4ToLong(plaintext['slice'](i, i + 4)), //前4位
x1[1] = Str4ToLong(plaintext["slice"](i + 4, i + 8)), //后4位
//console.log('x1:', x1, 'x2:', x2);
code(x1, x2),
//console.log('===code===> x1:', x1, 'x2:', x2);
let tmp = LongToBase16(x1[0]) + LongToBase16(x1[1]);
console.log(tmp);
result += tmp;
// LongToBase16 8位 e.g. "00000926"
}
return result; // "6fbde674819a59bfa12092565b4ca2a7a11dc670c678681daf4afb6704b82f0c" length=64
}
function gyflagh(_0x111955) {
// const _0x50051f = _0x22517d;
let _0x3b790d = _0x111955["encrypt"]("1356853149054377");
if (_0x3b790d === "6fbde674819a59bfa12092565b4ca2a7a11dc670c678681daf4afb6704b82f0c") return true;
return false;
}
function code(x1, x2) {
// x2 = [ 909456177, 825439544, 892352820, 926364468 ]
let y1 = x1[0],
y2 = x1[1];
let i = 0;
while (i != 84941944608) { // 32轮
y1 += (y2 << 4 ^ y2 >>> 5) + y2 ^ i + x2[i & 3],
i += 2654435769,
y2 += (y1 << 4 ^ y1 >>> 5) + y1 ^ i + x2[i >>> 11 & 3];
}
x1[0] = y1,
x1[1] = y2;
}
于是解密就反过来写就完事了。
Exp:
function decrypt(v) {
let key = [909456177, 825439544, 892352820, 926364468];
let i;
let v0 = v[0],
v1 = v[1],
delta = 0x9E3779B9,
sum = delta * 32;
for (i = 0; i < 32; i++) {
v1 -= (((v0 << 4) ^ (v0 >>> 5)) + v0) ^ (sum + key[(sum >>> 11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >>> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0] = v0;
v[1] = v1;
return v;
}
var cipher = "6fbde674819a59bfa12092565b4ca2a7a11dc670c678681daf4afb6704b82f0c";
var x1_list = [];
for (let i = 0; i < 64; i += 8) {
console.log(cipher["slice"](i, (i + 8)));
let tmp = Base16ToLong(cipher["slice"](i, (i + 8)));
console.log(tmp);
x1_list.push(tmp);
}
var result = '';
for (let i = 0; i < 8; i += 2) {
let xx = [x1_list[i], x1_list[i + 1]];
decrypt(xx);
r0 = LongToStr4(xx[0]);
console.log(r0);
r1 = LongToStr4(xx[1]);
console.log(r1);
result += r0 + r1;
}
console.log(result);
// "McWebRE_inMlnCrA1t_3a5y_1cIuop9i"
flag{McWebRE_inMlnCrA1t_3a5y_1cIuop9i}
这题耗费了喵喵好几天时间,刚开始在想为啥 Base16ToLong
和 LongToBase16
结果不一样,后者只取了8位的 hex,导致转换回去不对。
但最后发现其实不是上面那个问题,是 XTEA 解密函数写错了,发现又没考虑 有符号数与无符号数的问题,也就是 >>
和 >>>
。。。
喵喵是 fw(
Unsigned right shift (>>>)
The unsigned right shift operator (
>>>
) (zero-fill right shift) shifts the first operand the specified number of bits to the right. Excess bits shifted off to the right are discarded. Zero bits are shifted in from the left. The sign bit becomes0
, so the result is always non-negative. Unlike the other bitwise operators, zero-fill right shift returns an unsigned 32-bit integer.via https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unsigned_right_shift
卷王与野生的 GPA
“24 岁,是卷王。”
即便一早学会了养生、收获了强者的发型,24 岁的科大卷王仍然无法超脱开“电子鸦片”的荼毒。
最近,他喜欢玩一款经典的掌机。这台掌机推出于 2001 年,曾经风靡全球,销量累计 8100 万台。
令卷王非常快乐的是,这台掌机使用了 ARM 指令集,正好就是上个学期在《微机原理与嵌入式系统》中学习的内容。
就算是沉迷“电子鸦片”,卷王也不忘记要在轻松娱乐的时光中获取 GPA。
这天,卷王得到了一张破旧的游戏卡带。(顺带地,他还得到了卡带烧录之前编译的 ELF 文件)
当年在这台游戏机上,少年们夜以继日捕捉着传说中的精灵;
而就在卷王冒险的过程中、野生的 GPA 跳了出来!
手上没有任何装备的卷王卷不起来,不愿躺平的他在惊慌之中输入了经典的作弊码。
就在他向野生的 GPA 扔出球时,他发现,要抓住野生的 GPA,远没有那么简单……
经典 .gba
,是任天堂游戏机啊!
参考 小破站的视频 GBA游戏用什么姿势玩?GBA最佳运行方案集结!
我们可以买个实体机然后刷进去玩(雾
当然,喵喵懒了,用 Visual Boy Advance(VBA)模拟器来玩吧(
VisualBoyAdvance(以下简称“VBA”)是一个根据GNU General Public License发布的免费软件。它能够在电脑上模拟任天堂所发行的手提游戏机,包括:Game Boy、Super Game Boy、Game Boy Color和Game Boy Advance。由于VBA模拟效果与真正的GBA基本无异,直至2006年是Win32电脑上最受欢迎的模拟器。VBA和gnuboy是广泛分布的Game Boy模拟器,且VBA已有中文化版本。
VisualBoyAdvance-M(或简作VBA-M)是一个改良分支,来自不活跃的VisualBoyAdvance项目。VisualBoyAdvance-M中的“M”据信是“Merge(合并)”的缩写。另外的独立版本称为VBA-ReRecording,它提供了工具辅助回放功能。
可以到 SourceForge 或者 emulator-zone 下载 VBA 或者 VBA-M。
或者 VBA-M 官网 也行,里面还提供了语言包 Language Files。
打开 .gba
(TODO
马赛克
共享单车只剩下一辆,走近一看,果然是一辆二维码被坏人涂掉一大块的车,谁也骑不走。
我今天还非就要把这个辆车骑走。
于是你开始研究起来这个二维码。
点击下面按钮下载源代码与图片
https://hack.lug.ustc.edu.cn/media/07ef998b-ea49-51a7-b8ed-8ab733ba0273/mosaic.zip
查到了这个:黑客将打了马赛克的二维码还原,并成功窃取资金
经典社工啊(
其实就是根据周围的像素点来推断边缘处的像素,然后逐渐缩小边界,最后即使不能完全修复,但凭借二维码的冗余特性,还是能识别出来的。
(TODO
Micro World
宇宙中某一片极其微小的区域里的粒子被一股神秘力量初始化设置成了 flag 的形状,程序忠实地记录了一段时间之后这片区域的粒子运动情况。
https://hack.lug.ustc.edu.cn/media/6f3f9a71-a6a3-5393-ab90-57080553a279/microworld.exe
又是 pyinstaller 打包的,python38,没有加密,很舒服。
python3 pyinstxtractor.py microworld.exe
根据 struct.pyc
把 2.pyc
文件头改一下
uncompyle6 2.pyc > 2.py
根据提示,初始化设置成了 flag 的形状
,一段时间之后这片区域的粒子运动情况
,说明这个数据是进行了一段时间的运动后的,要恢复回去。
当前的状态如下(没啥用看起来
然而发现反编译之后跑这个 2.py
,只剩一个点在动了,好奇怪啊……
折腾了好一阵子都没搞定,甚至开始研究起这是啥运动,觉得还是不对劲啊。
最后换了个反编译的工具,用了 python-decompile3 这个,对比一下。
decompyle3 2.pyc > 22.py
难怪,uncompyle6 把这个循环位置搞错了啊……(绝绝子
源码如下。
# decompyle3 version 3.7.6
# Python bytecode 3.8.0 (3413)
# Decompiled from: Python 3.7.3 (default, Mar 27 2019, 17:13:21) [MSC v.1915 64 bit (AMD64)]
# Embedded file name: 2.py
# Compiled at: 1995-09-28 00:18:56
# Size of source mod 2**32: 272 bytes
import time, pygame, random, math
WIDTH = 800
HEIGHT = 480
FPS = 30
RADIUS = 6
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Micro world')
clock = pygame.time.Clock()
running = True
count = 0
list_ = [
(104.57999766036382, 294.30576115498934, 0.1577677901040423, 0.41776948474620357), (97.87091160071468, 284.0771467313936, -0.05370797410649919, -1.5117973702589511), (394.1386262922653, 342.409197651039, 1.257922260374631, -0.6461638773589035), (383.764164219779, 351.02042667556873, 0.20006041825672996, 0.6886413335669115),
(180.44019240845162, 133.7535956479616, -1.2484762435639396, -0.24929662016190135), (184.78982911642964, 145.40211792122318, -0.0022636999589985274, 0.5513600856872762), (115.03335937165885, 300.9993063319222, -0.5676054221924623, -0.6695938101055833), (428.3301722808014, 85.83680504269783, -0.0513590947698387, 0.2619177140188991), (421.5916683285764, 72.17809124687787, 0.2014421765254144, -1.4100046681437837), (162.58901945971377, 126.99241616764206, 0.030293407742100736, -0.8004786559033131), (160.9895035322225, 145.70895141366148, 0.34929641702611086, 1.0244323100199488), (99.54962866775641, 349.46917135540673, 0.8725254958889044, 0.18026779894381553), (113.4935960089335, 350.07171367926867, 1.3948726673436584, -0.054645034381742424), (243.53937023444496, 324.4815163708293, 0.7754113027163299, -0.35104389069767705), (236.07107039080046, 336.93661006373446, 0.48878994205902065, 0.3668410462786823), (142.25100857351947, 107.18317281548164, 0.8769918696942771, 0.3381787797086514), (126.65532126550701, 101.44841747837386, -0.23643662821636835, -0.7474233162903591), (93.89796091125481, 337.69531331910224, 1.0011924240124088, 0.3786722871573705), (80.48068970171919, 325.1970583485235, -0.7399280117105376, -0.1701776000030069), (562.4548633698985, 293.8157173337281, 0.9232890949122534, -0.6707164772798287), (544.2230504332125, 298.5096170399827, -0.45781767619323493, 0.20143165105280758), (591.0728484545633, 384.0271820277358, -0.3546100658269741, -0.11818203300203947), (587.8300731972232, 397.21466538385005, 0.1658293862635661, 0.42343564083856233), (160.96290809954047, 113.1243147430774, 0.3297720052539864, -0.9088842057483848), (341.609111706211, 174.90102865131772, -0.6451128281395191, 0.6625764312805231), (361.89732768708996, 171.7398998209568, 0.9626383465113062, -0.45377732846689295), (413.2372099784884, 109.2059457838029, 0.06068110806079574, 0.7460129288950222), (428.03790114833487, 103.0981885607253, 0.7102816563423606, 0.5965135218875973), (632.823035103914, 183.41308729879773, 0.9426699419434019, -0.17948947163331008), (619.693443152725, 171.6281942118759, -0.4050225991049363, -0.3004630650084027), (234.93804029190275, 314.4850986917503, 0.6079647151190387, -0.3527147434952942), (388.84210326921414, 329.1140520966929, -0.25641606835531666, 0.013640064895390436), (431.54831561818656, 328.2835752571257, 0.0862740779218544, 0.30203328636401916), (449.4737324005318, 318.59090969779714, 0.8493162548457772, -0.39087008306977955), (414.9662287493531, 321.7992369591167, -0.38427287382474645, -0.8225562013945713), (393.14019608044197, 166.3219823104028, -0.8606903726780473, 0.44501048112586244),
(407.74279750683405, 174.07932270043037, -0.41221110195676625, 0.5621672919603494), (459.79766287684146, 367.8798142900581, -0.013886373621122439, -0.3180180360181074), (481.3079661009345, 389.2929845754805, 1.308536261884114, 0.6279064260682542), (299.0319011022105, 142.56295134440845, 0.5129247847316193, 0.6861624164039957), (284.8757848267405, 115.44737423970206, -0.39395187391162256, -0.7247085199267874), (721.0242237005709, 208.11018311759165, 0.5031252275481168, 0.45273074175310746), (698.5559327045538, 206.46532762419102, -0.4253037092008059, -0.10234863067289382), (238.01728536837834, 96.94484935393817, -1.0004911938691854, -0.649305316642717), (231.42367571047265, 113.24222441346936, -1.0247825937879875, -0.17624171000468863), (219.78600179605175, 374.1104577170864, -0.6368728728325652, -0.17569384553335526), (246.11065722883504, 371.79606791842366, 0.5219343181987446, -0.3462866864847798), (61.288999430029705, 325.3049764118085, 0.06327048049117068, 0.43129466994014554), (44.508614390256625, 300.0898728637909, -0.6949149408422702, -0.6606674558084397), (444.7436476698611, 97.43495673585237, 0.0767541318435591, -0.2776251496223229), (744.2355976846196, 142.86962390689527, 0.9981335574540283, -0.24606523573449057), (722.4382189578434, 148.50423479439266, 0.17497076263720399, -0.184532590143744), (418.5327228664219, 136.72695351434712, 0.5475576395865829, -0.8913163462276698), (695.9021288583592, 180.5828160193858, -0.9488479900701872, -0.7148885273332122), (514.3530295181225, 176.69505705865964, 0.4250410294309581, 0.24872469962151272), (491.3217475016306, 192.06501755019133, -0.5852344731438237, 0.6683151007063167), (404.93366351040646, 355.33847789785887, -0.2208752264067056, 0.5785115096521176), (660.6042829909404, 388.98594646068375, -0.2802404219269444, -0.8854758825918975), (657.1412902684084, 422.0142602600062, -0.09955316106014461, 0.6262242796545058), (324.601539532362, 71.99880574130555, -0.44523640628825367, -0.7982939572849916), (313.7688791782026, 100.51158011600064, -0.8550429986673138, 0.23687636012864005), (463.05020279897207, 354.3841115016863, 0.5259364738387711, -0.030002820893658896), (307.8633146779248, 151.5952286725273, 0.6622908641009807, -0.03664136082024409), (398.41892028466214, 111.78772135693538, 0.11954324115479029, -0.8254277998217231), (381.45123257781245, 136.6036806395423, -0.6799079499520264, -0.08600175586428575), (292.6839863142225, 92.60685790044825, 0.536452531252875, -0.7140993636579337), (107.00966574475697, 373.9070654764243, -0.7010200558637464, -0.1381120246392485), (145.16889322345122, 365.860466913724, 0.5965222398714648, -0.5001275164663491), (353.3938458530145, 92.28564527857638, 0.27648661676701847, 0.4055937158607218), (332.6003342739462, 150.35292606144606, 0.16791054337808475, 0.19838069473157122), (333.2155442174266, 135.41367942003444, -0.1948746996045789, -0.8713050639597644), (341.7828985904844, 176.40085292375244, 0.15777998878645658, 0.45702848410002833), (352.9649338991208, 63.40320810353417, 0.31005939791813875, -0.35531540613337653), (558.759849975508, 335.82850463010334, -0.3751838713627865, 0.6972047893312435), (658.9879897953409, 243.4647341215956, -0.2407221233734072, -0.9276449712809698), (680.2245351443412, 296.75251078114536, 0.4337786026208906, 0.9727281158269319), (341.72634396514303, 378.7867598373575, -0.03596521226118493, 0.51167641447653), (697.0597317905844, 409.2588838533252, 0.9048830590914927, -0.4657488561253242), (665.1731546911783, 437.3925803649936, -0.007368744952089001, 0.3787660493964195), (67.00785464657952, 103.1274278061125, 0.03732794987331456, -0.5508360071810254), (105.96964960562794, 128.97178091353496, 0.8136907261343687, 0.4063622560568454), (105.07041437177854, 61.05750261646497, 0.26186719895475497, -0.5163887919827821), (68.49603305059723, 73.94521027290915, -0.7594061833112205, -0.7798070269292883), (71.34190872889897, 124.87773643827933, -0.4688181952259638, -0.5600838356192892), (64.27757202298889, 159.8496885573903, -0.6934232584078162, -0.042604127504053846), (70.57044794264237, 176.93801328964406, -0.4233167428650957, -0.11340691519836832), (144.63770817171127, 69.41378490162104, -0.08749228993661817, -0.28097092956958947), (137.8210753472867, 150.33804975066357, -0.191812024174572, 0.6051129537282753), (137.26460390655052, 180.16854638211603, -0.21242207753516196, 0.11735356970799926), (165.50112593068218, 175.5434604690403, 0.3148565159511876, -0.3132051678133363), (158.21970276683984, 160.0662466663162, -0.399270267894807, -0.47902790124753714), (162.68670402259963, 93.7322224457243, -0.9745665176814846, -0.9728806501583553), (200.74175804924195, 121.50562533623162, -0.6762311833614205, -0.2034953579173453), (224.47067029408507, 148.9360402550957, 0.46187667755869377, -0.22459110166312768), (249.5998504282539, 128.78709867759278, 0.8740685343797732, -0.6745519008298879), (222.1623163178933, 162.24461613732666, -0.40139569192986624, 0.04609689397505523), (270.1496673364134, 119.26292107574434, 0.44998767912644677, -0.8791510712687354), (251.7055547368385, 167.7628397486525, -0.9368313060430262, 0.6578829536537905), (275.1172494773191, 184.09798794704585, -0.5141759452844961, -0.033407853813111066), (265.9957830031348, 199.51750836889886, -0.25941544432835606, 0.056204013662934704), (282.07956665413514, 164.958740535395, 0.8918358020049804, -0.7422688690594414), (353.4402011639725, 114.78109493306745, 0.7570444875545246, -0.415515002478986), (356.5222794940665, 213.68778310329276, 0.6860103516321112, 0.9143623371590044), (330.49971249176855, 226.5949460000718, -0.6111217595640996, 0.873886888891541), (454.61901786077544, 150.71441166327446, 0.8747784392879676, 0.9153485801212855), (388.60627446909075, 197.93977442346403, -0.23680464929294276, 0.14591757123939741), (423.67540627845943, 205.2755085720821, -0.5305405082052022, 0.8620558730400902), (477.52821141998515, 197.94782386045253, 0.8714152377772004, -0.11304356072398081), (509.7764508897392, 142.38940000013736, -0.3416129300096671, 0.4959037037087939), (517.4542284218678, 157.00198576512298, -0.8720656140048659, 0.7778513246341929), (489.14570184081595, 143.71628106431027, -0.43904807996975315, 0.17467707645594244), (484.36624455679043, 162.18554614981508, -0.3197687201188777, 0.006872079622769922), (538.1915570784884, 186.90845701394394, 0.2663539658698997, 0.9595724819979277),
(558.4402698588482, 151.2562488554182, 0.20149147625361707, -0.1756944868363639), (498.8936687068798, 219.16941966684988, -0.522456714559989, 0.747015543216671), (557.5264047150413, 194.47492406099926, 0.686163137594151, -0.13055836811114152), (572.2642293852141, 133.05544915189392, -0.36058409684388026, 0.18723885747756386),
(593.233462901164, 148.90845332339745, 0.11975788522826214, -0.04042765468897547), (592.1067952919601, 200.97587238888386, -0.2553038780755985, 0.7398471255142076), (620.8001885800545, 156.51793210692475, -0.5999930155535687, 0.3525160039601669), (630.0497687231773, 138.21403356381515, -0.7018604176601002, 0.3042234653264848), (656.2600646659411, 156.841032404578, -0.9903679753354846, 0.7348530520214087), (711.2887269504378, 97.8513508705996, 0.3810639611272786, -0.8943944122000136), (738.7664844418454, 116.88118100970506, 0.6209809052535715, -0.41180811075166335), (703.8040510631283, 152.5920657076647, 0.511261150486223, -0.5706642330494665), (740.09107559372, 198.6981029696348, 0.5218916886562541, 0.1740038136901716), (657.6864804602145, 215.93482850112167, -0.9745747977698767, 0.034623277819314735), (71.54711083768379, 350.36060634700226, 0.6498929939882905, -0.6162738389999025),
(150.9033697831391, 276.73234512286984, 0.9223470290051474, 0.582679448995163), (172.75073798985846, 238.05776406669546, 0.9907680736984741, -0.886749479011274), (166.14454393170783, 261.9146208279891, -0.10575763215896572, -0.04019922859299774), (135.8179319546022, 304.5167891568187, 0.51177525757786, 0.6117329317340197), (109.29600036825342, 324.14080376797784, -0.32237035673135206, -0.47626652711191975), (128.25054047146125, 342.5039087606924, 0.41668668412819376, -0.6480033792336315), (160.9435843133916, 336.7772890102673, 0.22013275234783625, 0.4732329263061923), (159.99063987213424, 357.3713520468878, 0.14780147674570876, -0.8751351093745308), (203.82463986148133, 294.85292265982395, 0.36387555042522823, -0.8943361977843205), (238.77834673828744, 257.8957469467245, 0.69549432364027, -0.966824187158376), (234.71098679446786, 302.43763534262735, 0.6189254368321369, -0.02082832064340412), (199.13592069493149, 350.92258754952445, -0.5134844187062317, -0.2621263870546515), (246.08239218788768, 387.5706266290919, 0.5215700810328909, -0.12701382855216137), (279.81163336690304, 310.1193743783627, -0.5995691345591287, 0.8192360880875091), (312.43826713316605, 326.3110183009928, 0.6088247086357645, -0.02551784070396379), (278.3124563204679, 346.2774946054354, -0.618057173316024, 0.23249980020133165), (309.0606334597058, 364.2832298989901, 0.5578012392483811, 0.34382332959224393),
(277.86613144487796, 384.4110746203211, -0.5605136501896855, 0.422632393345197), (297.7963837815137, 417.4215462126431, 0.1776438437597616, 0.978575785653446), (308.64648313310744, 389.32195957645587, -0.8279080321071313, 0.048961465794687076), (332.9030266443413, 352.59935912758954, -0.9665545687281056, 0.614791078799594), (348.26013943242486, 314.11612768512305, -0.842217058058359, -0.032736011662137576), (360.3306887191309, 292.2383422919451, -0.7655300474395692, -0.32450584103905666), (396.9404109804546, 370.8911519658965, -0.15035514887206558, -0.04106844570751811), (400.104874692782, 411.57211198606, -0.1442639002673347, 0.761930073557795), (440.30114216085207, 361.3409051871098, 0.9000423022537898, -0.2836701782551865), (429.3543769941238, 341.9294444418788, 0.3094213701527606, -0.33594650215266264), (447.43603366759595, 277.2285471339229, 0.38651976546653843, -0.880424180225089), (481.7939322275633, 301.5421301772078, -0.15578028786801723, -0.09103221565894848), (496.05798504633856, 291.5141421831062, -0.0719264797652579, -0.09206880803313222), (509.5366997343411, 286.81707674748407, -0.16530741724662823, 0.14137321286975357), (512.6359971378648, 331.33312820778906, -0.7542223282272489, 0.9012269706588789), (565.2777793457861, 322.789250206497, -0.8786007649708629, 0.6588611187591347), (616.2993903993898, 307.1147976370016, 0.30738482960705515, 0.07832583840747809), (549.4707698926467, 355.7327131244734, -0.6862677817538163, 0.5086190046101378), (566.0048628120813, 359.0888370802809, -0.8146347106636107, 0.521808780751152), (603.0173174232779, 355.65724327656727, -0.22158083617492497, 0.09841641765061859), (627.8321653818715, 343.97419893606997, 0.4011913104396747, -0.9268815208862793), (537.4339433151019, 408.0628758894442, -0.9839280253666145, 0.5949213292386479), (640.8558916665046, 286.24303230003744, -0.30163364198134635, 0.3052974925939915), (693.3776564065166, 322.7209553086005, 0.6806539409820418, 0.8785539003185334), (677.9197897159304, 332.5251925812629, 0.1451773968863177, 0.42685898449123116), (715.7380915196851, 359.6720022622894, 0.8791885748031647, 0.9508148986033234), (654.241096201209, 350.8310224121308, -0.8058853258811696, 0.25300083007890595), (660.0062961624873, 367.58093595080226, -0.6293964384264055, 0.09559022040005982), (674.0852620040955, 376.20299215975325, -0.07091622207048798, -0.362852142231338)]
class Point:
def __init__(self, pos, vx, vy):
self.x, self.y = pos
self.vx = vx
self.vy = vy
self.flag = 1
def dotproduct(v1, v2):
return v1[0] * v2[0] + v1[1] * v2[1]
def checkcrush(point1, point2):
distance = math.sqrt((point1.x - point2.x) ** 2 + (point1.y - point2.y) ** 2)
a = (point1.vx - point2.vx) ** 2 + (point1.vy - point2.vy) ** 2
b = 2 * (point1.x - point2.x) * (point1.vx - point2.vx) + 2 * (point1.y - point2.y) * (point1.vy - point2.vy)
c = distance ** 2 - 4 * RADIUS ** 2
delta = b ** 2 - 4 * a * c
if delta < 0:
return
time = (-b - math.sqrt(delta)) / (2 * a)
if time > 0:
if time < 1:
return time
return
def get_new_point(time, point1, point2):
distance = math.sqrt((point1.x - point2.x) ** 2 + (point1.y - point2.y) ** 2)
standard_displacement = ((point2.x - point1.x) / distance, (point2.y - point1.y) / distance)
v_1 = (point1.vx, point1.vy)
v_2 = (point2.vx, point2.vy)
v_par_1 = dotproduct(standard_displacement, v_1)
v_par_2 = dotproduct(standard_displacement, v_2)
v_ver_1 = (point1.vx - v_par_1 * standard_displacement[0], point1.vy - v_par_1 * standard_displacement[1])
v_ver_2 = (point2.vx - v_par_2 * standard_displacement[0], point2.vy - v_par_2 * standard_displacement[1])
v_after_par_1 = v_par_2
v_after_par_2 = v_par_1
v_after_1 = (v_after_par_1 * standard_displacement[0] + v_ver_1[0], v_after_par_1 * standard_displacement[1] + v_ver_1[1])
v_after_2 = (v_after_par_2 * standard_displacement[0] + v_ver_2[0], v_after_par_2 * standard_displacement[1] + v_ver_2[1])
afterpos_1 = (point1.x + point1.vx * time + v_after_1[0] * (1 - time), point1.y + point1.vy * time + v_after_1[1] * (1 - time))
afterpos_2 = (point2.x + point2.vx * time + v_after_2[0] * (1 - time), point2.y + point2.vy * time + v_after_2[1] * (1 - time))
return (
Point(afterpos_1, v_after_1[0], v_after_1[1]), Point(afterpos_2, v_after_2[0], v_after_2[1]))
def drawpoint(screen, list_):
for item in list_:
pygame.draw.circle(screen, BLUE, (round(item.x), round(item.y)), RADIUS, 3)
def next_pos_list(Pointlist):
pointlist = []
for i in range(len(Pointlist)):
for point in Pointlist[i + 1:]:
times = checkcrush(Pointlist[i], point)
if times != None:
a, b = get_new_point(times, Pointlist[i], point)
pointlist.extend([a, b])
Pointlist[i].flag = 0
point.flag = 0
else:
for item in Pointlist:
if item.flag != 0:
pointlist.append(Point((item.x + item.vx, item.y + item.vy), item.vx, item.vy))
else:
for poi in pointlist:
poi.x = poi.x % WIDTH
poi.y = poi.y % HEIGHT
else:
return pointlist
Pointlist = []
for item in list_:
Pointlist.append(Point((item[0], item[1]), item[2], item[3]))
else:
def value(lis):
count = 0
for item in lis:
count = count + (item.x - round(item.x)) ** 2 + (item.y - round(item.y)) ** 2
else:
return count
while True:
if running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
else:
screen.fill(BLACK)
drawpoint(screen, Pointlist)
Pointlist = next_pos_list(Pointlist)
pygame.display.flip()
pygame.quit()
# okay decompiling 2.pyc
那就把速度改成负的,然后倒着运动回去就完事了,也就是初始化点的坐标列表这里。
Pointlist = []
for item in list_:
Pointlist.append(Point((item[0], item[1]), -item[2], -item[3]))
跑一下,得到 flag。
flag{Rev3sEtiM^5}
小结
啊!今年的 Hackergame 就这么结束啦!
u1s1,今年 题目很有梯度,基础的很能划水,中等的题目能摸摸鱼,有些题目还是挺难的,然而喵喵这周忙于作业、其他比赛、balabala,还有好几题觉得有点思路的没来得及看了。
摸了摸了,咱还是来学习为主,2333
完结 撒花,撒 mcfx!
感谢所有幕后工作人员,喵喵今年也学到了许多,明年有机会一定再来。
其他资源
- 官方题解 repo: hackergame2021-writeups (这 wp 写得可良心了!Orz
- Hackergame 2021 幕后工作人员
- 花絮
- 榜一 mcfx 的全部 wp:Hackergame 2021 Writeup 或者 GitHub (mcfx! Orz!
- GZTime’s writeup: Hackergame 2021 Summary
- ranwen’s writeup: USTC Hackergame 2021 划水记 或者 GitHub
- etc.
顺便放几个梗(
(溜了溜了喵~