Hackergame 是由中国科学技术大学举办的线上CTF竞赛,截止2021年,已经连续举办过八届。近几年来每届有 3000人 以上参与其中,其中不乏硕士、博士、乃至信息安全职业圈选手的身影。这次我在西电的排名是第4名 ,虽然拿了二等奖 ,还是感慨与头部选手的差距明显😐。

IldFe0.png

然排名固然重要,但解题过程中不断学习新知识,自我探索求解,打通任督二脉的过程才是最酣畅的。Hackergame就是这样一场神奇的比赛,能让参赛者在解题的过程中欲罢不能,这里引一下GZTime大佬的博客。话不多说,下面请看我的第一弹wp。

签到

为了能让大家顺利签到,命题组把每一秒的 flag 都记录下来制成了日记本的一页。你只需要打开日记,翻到 Hackergame 2021 比赛进行期间的任何一页就能得到 flag!

进入页面,发现1970-01-01这个神奇的日子。

IldPLq.png

没错,计算机中的时间戳正是从这时候开始以秒为单位递增的。点击Nexturl中可以看到是通过GET方式提交变量实现页面跳转的。因此只要查询到比赛时间段内的时间戳,以GET方式提交就可以拿到flag。linux中查询指定时间点的方式:

date -d "2021-10-29 19:45:44" +%s

进制十六——参上

为严防 flag 泄漏以及其他存在于未来所有可能的意外灾难,神通广大的 Z 同学不仅强制要求每一道题目都加上权限和资源的限制,还给所有参与 Hackergame 2021 命题的计算机施加了一层法术结界。任何试图从结界逃逸的 flag 都会被无情抹除。
而一位明面上是计算机学院的新生,实则为物理学院暗部核心成员的 X 同学,在 Hackergame 2021 命题组已经潜伏多时。妄想趁比赛开始的午时,借阳火正旺之势,冲破 Z 同学的结界,以图片而非明文的形式,将 flag 悄悄传递出来。
好在 Z 同学法力之深厚,不可管窥蠡测。在 flag 被传出去的前两天,就已预知此事并将图片中的 flag 无声消泯了。
只是,这位 X 同学,虽然不会退出 Vim,但是似乎对打开十六进制编辑器颇有造诣……

IldkwV.png

简单的十六进制转字符串,2行python送走。

str = '20666C61 677B5930 555F5348 30553144 5F6B6E30 775F4830 575F7430 5F43306E 76337274 5F484558 5F746F5F 54657854 7D20466F 72206578")
print(bytes.fromhex(str))

去吧!追寻自由的电波

为了打破 Z 同学布下的结界,X 同学偷偷搬出社团的业余无线电台试图向外界通讯。
当然,如果只是这样还远远不够。遵依史称“老爹”的上古先贤的至理名言,必须要“用魔法打败魔法”。X 同学向上级申请到了科大西区同步辐射实验室设备的使用权限,以此打通次元空间,借助到另一个平行宇宙中 Z 同学的法力进行数据对冲,方才于乱中搏得一丝机会,将 flag 用无线电的形式发射了出去。
考虑到信息的鲁棒性,X 同学使用了无线电中惯用的方法来区分字符串中读音相近的字母。即使如此,打破次元的强大能量扭曲了时空,使得最终接受到的录音的速度有所改变。
为了保障同步辐射设备的持续运转,组织牺牲了大量的能源,甚至以东北部分地区无计划限电为代价,把这份沉甸甸的录音文件送到了你的手上。而刚刚起床没多久,试图抢签到题一血还失败了的你,可以不辜负同学们对你的殷切期望吗?

戳我—-》下载音频

可以确定的是录音中的声音出自于人类,只是由于音频播放速度太快,导致无法听清。这里使用potplay打开音频调至0.2倍速,降低采样率至原来的一半,音频就不会出现音速太快,音调过高,导致无法听清。同时根据题目暗示,可以查找无线电字母通信发音,根据NATO的读法可以顺利拼出flag。

猫咪问答 Pro Max

IlaxJg.png

首先看第一题,通过360搜索 ustc@sec 社团章程 很顺利的找到了社团早期的qq群号和当时负责人的联系方式,于是我们只要联系负责人就能得到当时的社团章程信息。 好吧,其实这里我是用burpsuite的爆破试出来的,利用python生成含有07年到15年的每一天的字典,之后导入 burpsuite 爆破就可以了。

import datetime
import numpy as np

def create_assist_date(datestart = None,dateend = None):
datestart=datetime.datetime.strptime(datestart,'%Y%m%d')
dateend=datetime.datetime.strptime(dateend,'%Y%m%d')
date_list = []
date_list.append(datestart.strftime('%Y%m%d'))
while datestart<dateend:
datestart+=datetime.timedelta(days=+1)
date_list.append(datestart.strftime('%Y%m%d'))
print(date_list)
with open("word.txt", 'w') as f:
for i in range(len(date_list)):
f.write(date_list[i] + '\n')

if __name__ == '__main__':
create_assist_date("20070101","20150101")

关于第一题,后来我了解到可以在搜索引擎中搜 "sec.ustc.edu.cn" (带双引号),找到网站的 Web Archive, 不失为一个小技巧。

第二题,LUG这般优秀的社团组织,必然是年年都能拿到五星的吧。这里还是放个公众号链接吧。USTCLUG 的介绍页。看到更新日期是2021年5月20日,以往社团评选的结果会在7月份后发布,所以这里还要寻找2021年的USTC五星社团信息。这里搜索 2021 中国科大 五星级社团 就会在图片中找到USTCLUG的身影。

第三题在LUG的官网搜索 活动室 便能找到 门口牌子的图片。第四题和第五题找到对应的文档后也是极其easy的,这里不做过多陈述。

卖瓜

有一个人前来买瓜。

HQ:哥们,这瓜多少钱一斤啊?

你:两块钱一斤。

HQ:What’s up!这瓜皮子是金子做的还是瓜粒子是金子做的?

你:你瞧瞧现在哪有瓜啊?这都是大棚的瓜,只有 6 斤一个和 9 斤一个的,你嫌贵我还嫌贵呢。

(HQ 心里默默一算)

HQ:给我来 20 斤的瓜。

你:行!

HQ:行?这瓜能称出 20 斤吗?

你:我开水果摊的,还不会称重?

HQ:我问你这瓜能称出 20 斤吗?

你:你是故意找茬,是不是?你要不要吧!

HQ:你这瓜要是刚好 20 斤吗我肯定要啊。那它要是没有怎么办啊?

你:要是不是 20 斤,我自己吃了它,满意了吧?

(你开始选瓜称重)

补充说明:当称的数字变为浮点数而不是整数时,HQ 不会认可最终的称重结果。

IldDTf.png

burp抓包改变量,溢出就完事。

透明的文件

一个透明的文件,用于在终端中展示一个五颜六色的 flag。可能是在 cmd.exe 等劣质终端中被长期使用的原因,这个文件失去了一些重要成分,变成了一堆乱码,也不会再显示出 flag 了。注意:flag 内部的字符全部为小写字母。

Ild400.png
文件下载链接

乍看起来,好像是一堆杂乱的、无厘头的字符,实际上了解ANSI编码的同学应该知道,在终端中就是通过这样的转义字符实现终端诸如字符颜色变化、指针跳跃等个性化操作,不熟悉的同学可以看看这个 链接。类似乱码的东西叫 ANSI escape sequence,或是 VT100 escape codes。开一个“优质”终端,在所有 ‘[‘ 前面加上 ESC,并把所有空格替换为会被显示的字符。具体做法可以直接使用记事本或word中的全部替换,也可以在linux中使用如下正则匹配命令:

cat transparent.txt | sed 's/\[/\x1b[/g' | sed 's/ /#/g'

Ilw8un.png

旅行照片

你的学长决定来一场说走就走的旅行。通过他发给你的照片来看,他应该是在酒店住下了。从照片来看,酒店似乎在小区的一栋高楼里,附近还有一家 KFC 分店。突然,你意识到照片里透露出来的信息比表面上看起来的要多。请观察照片并答对全部 5 道题以获取 flag。注意:图片未在其他地方公开发布过,也未采取任何隐写措施(通过手机拍摄屏幕亦可答题)。

IlwgUK.png

此题是一道明显的社工题,在于提醒各位注意位置隐私的同学不要随便发图片给陌生人看。从图片上可以明显看到一家蓝色装修风格的肯德基和沙滩。简单百度以下这样的KFC全国只有一家,在秦皇岛,这里是链接。接下来打开百度街景,定位到秦皇岛新澳海底世界便能解决1、4、5题。第二题拍摄时间的问题可以从影子的朝向大致推断出来。至于拍摄者的楼层,这里我是试出来的。官方的题解是这么说的:

照片上方有一处较为明显的天地交界线(较深和较浅蓝色的分界线),这条线对应的是水平面,换言之,照片上落在这条线上的所有点,其海拔高度均和拍摄者相同。那么通过照片右侧的建筑可以数出来对面高楼的 14 楼和拍摄者处于同一高度下。再根据「小区内每栋楼的层高和海拔均相同」,可推得拍摄者位于 14 楼。

Flag助力大红包

“听说没?【大砍刀】平台又双叒做活动啦!参与活动就送 0.5 个 flag 呢,攒满 1 个 flag 即可免费提取!”

“还有这么好的事情?我也要参加!”

“快点吧!我已经拿到 flag 了呢!再不参加 flag 就要发完了呢。”

“那怎么才能参加呢?”

“这还不简单!点击下面的链接就行”

IlavFS.png
IlazWQ.png

应当可以很容易发现,用户通过点击助力按钮,即可积攒 Flag 。但是题目写出会对源地址进行检查, 位于同一个 /8 网络内的用户只能助力一次。(一个 /8 网段内的所有 IP 地址的第一个字节是相同的。很容易可以知道, IPv4 中至多只有 256 个 /8 网段。

其实,如果对 Flag 数量进行多项式拟合,可以发现 flag 数量为一精确的二次函数:

flag = (-0.0000076*(count-256)^2+1)

最终需要攒齐全部 256 个 /8 网段的助力才可获得全部 Flag。

即便没有上面这一步,应当可以很快意识(也许很难)到使用好友助力或使用代理池是不可行的,这是由于不是全部 IPv4 /8 地址块是可用的。这包括:

  1. RFC1700 定义的 0.0.0.0/8 和回环地址 127.0.0.0/8。
  2. RFC1918 定义的私有地址 10.0.0.0/8、192.168.0.0/16 ,172.16.0.0/12
  3. RFC3171 定义的组播地址 224.0.0.0/4
  4. RFC1700 定义的保留地址 240.0.0.0/4
  5. 用于特殊网络的 14.0.0.0/8 , 24.0.0.0/8 以及 39.0.0.0/8
  6. 美国国防部宣告的大量 IPv4 /8 网段,例如 6.0.0.0/8 , 7.0.0.0/8 等等 十几个 /8 网段

详细信息可以参考RFC3330

因此,我们需要伪造 IPv4 源地址的方式来欺骗服务器地址。事实上,服务器通过两种手段来检测远程 IP 地址。首先是通过调用搜狐的接口https://pv.sohu.com/cityjson?ie=utf-8来识别远程地址。并将识别的远程地址通过表单中的 ip 字段传送给服务器。

IlaLeP.png

第二个手段是服务器的检测方式。这里,服务器存在 X-Forwarded-For 欺骗漏洞。 X-Forwarded-For 是一个扩展的 HTTP 头标,通常由反向代理服务器(如 Nginx )在转发 HTTP 协议时添加。这是因为代理服务器在进行转发时,后端服务器接收到的 TCP/IP 协议的源地址将是代理服务器的地址,而不是远程客户的地址。中转服务器通过这一头标来保留远程地址这一信息。然而,这一头标是不被认证且很容易被伪造的,因此可用构造出任意远程地址。另一个相似功能的头标是 X-Remote-IP。事实上,本文题目服务器对这两个头标均存在识别漏洞。 X-Forwarded-For 的格式非常简单,只需要将源地址的 IP 地址记录其中即可。当存在多个中转服务器的时候,后续中转服务器会将自己的地址写在该头标的末尾,并使用逗号进行分割。

综上,我们可用构造出用于伪造攻击的脚本如下:

import requests
import time
count = 0
while (count < 256):
url = '<YOUR TARGET URL>'
session=session = requests.session()
session.headers.update({'X-Forwarded-For':str(count)+'.200.174.11', 'content-type':'application/x-www-form-urlencoded'})
ip = {"ip":str(count)+'.200.174.11'}
result = session.post(url,ip)
count = count + 1
print(result.text)
time.sleep(2)


注意到本题为了防止 DoS 攻击,实现了一个简单的令牌桶流量控制算法,因此需要控制请求发送速率。

Amnesia

你的程序只需要输出字符串 Hello, world!(结尾有无换行均可)并正常结束。

编译指令:gcc -O file.c -m32

运行指令:./a.out
编译后 ELF 文件的 .data 和 .rodata 段会被清零。

真是如题目所描述的那般健忘啊!elf文件又称为可执行程序文件,源程序经过编译、链接后即生成elf,elf的组成部分可参考 ctfwiki

我的思路是:待输出的字符串必定会存放在.text代码段,通过在程序运行时动态申请一片内存空间来存储这段字符串,由于程序运行时所申请的动态空间属于栈或堆,故其不会被删除。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *p;
p = (char *)malloc(sizeof(char)*20);
strcpy(p, "Hello, world!");
printf(p);
return 0;
}


IlwIKA.png

最近看了很多其他人的博客,总觉得自己的博客过于简陋了,十分影响最终的文字呈现效果。下周打算花点时间重新装修以下我这毛胚房,下下周我再来更新吧。