HGame week1

Warning
This article was last updated on 2020-02-01, the content may be out of date.

给了一串base64,解码之后得到了一串摩尔斯

/2020/02/week1/img000.png

找了摩尔斯的树状查找表

/2020/02/week1/img001.png

拿到flag

hgame{W3LCOME_TO_2020_HGAM3}


首先给了一个压缩包,解压之后是一张二次元的写真,binwalk看一下

/2020/02/week1/img003.png

可以看到是个图种,里面有个看起来像加密过的压缩包,有flag.txt还有注释 WinHex打开发现jpg文件尾FF D9后面跟了一个zip的数据头,剪切出来得到一个真加密的压缩包

/2020/02/week1/img004.png

一开始看这个Picture ID没什么头绪,identify分析了半天也没找出这个ID是什么 想到之前国庆的时候有道类似的题目是放到搜索引擎里搜索,于是就用了Google的图片搜索,找了半天发现这张图源自P站,并且找到了对应的ID76953815 试着当作密码输了进去,成功解密 把里面的flag.txt解压出来,得到了一串Unicode字符串

/2020/02/week1/img005.png

写了个转换脚本,拿到flag

hgame{Do_y0u_KnOW_uNiC0d3?}


拿到压缩包后打开,里面有一个bacon.txt和一个Novel.zip

/2020/02/week1/img006.png

解压出来,发现这个压缩包是经过加密的,里面也有一个bacon.txt和一个doc

/2020/02/week1/img007.png

打开txt发现里面是一段培根密码

/2020/02/week1/img008.png

找了个解密工具,拿到明文

/2020/02/week1/img009.png

由于有两个名称相同的文件,比较了一下CRC校验码发现一样,于是就想到了明文攻击,把明文调好压缩算法后放进AAPR里跑明文攻击,很快就得出了密钥

/2020/02/week1/img010.png

打开文档发现还是要密码,于是想到之前没用到的密码,提示说密码是大写,于是用了大写形式,顺利打开,大致看了下是篇小说,没有看到flag,于是设置里把隐藏文字打开

/2020/02/week1/img011.png

拿到flag

hgame{Y0u_h@Ve_F0Und_mY_S3cRet}


拿到压缩包后打开,里面有一个加密的压缩包OK.zipPassword.txt

/2020/02/week1/img012.png

打开txt看了下,发现有两段密码

/2020/02/week1/img013.png

下面hint给了栅栏密码和凯撒密码,然后这两个密码都需要key来加密,刚好有两个数字3和5, 于是直接拿去栅栏解密和凯撒位移

/2020/02/week1/img014.png

/2020/02/week1/img015.png

然后再把解密结果直接拿去做凯撒位移

/2020/02/week1/img016.png

符合描述,一段英文句子,一个大写字母串(密码), 然后把得到的大写字母串拿去解压缩包,成功打开

/2020/02/week1/img017.png

打开之后发现有很多Ook,但是感觉有点熟悉(之前看的一篇介绍各种乱七八糟密码的博客),然后就翻了翻发现这个是一个叫ook的密码,而且在博客里面也找到了对应的解密工具,这里放一下以防忘记

/2020/02/week1/img018.png

解密后发现是一段Base32,根据字段头看起来这个ook密文好像也是从这里生成的233

/2020/02/week1/img019.png

然后拿去在线Base32转码,又得到了一段Base64,继续转发现是张图片,然后找了找在线的Base64转PNG的工具

/2020/02/week1/img020.png

看起来是个二维码,拿手机扫一下

/2020/02/week1/img021.png

拿到flag

hgame{3Nc0dInG_@lL_iN_0Ne!}

到此终于把web和misc两个方向全ak了,学到了挺多东西,感觉还是不错的,下一步试试看看哪个方向容易点。。毕竟人菜只能捡漏,不像同届霸榜的那几位才一天多就破千了,然后赶紧补一下php和sql准备下周的web,至少今晚可以安心的休息了233


首先拿到的是一个压缩包,解压得到WireShark的流量文件Capture1.pacpng,用WireShark打开过滤http看能不能发现什么

/2020/02/week1/img024.png

发现有一条报文POST了一个压缩包,应该跟flag有关,追踪下HTTP流看看

/2020/02/week1/img025.png

发现压缩包名称是song.zip,结合题目网易云每日推荐,可以断定flag应该就在这里面

/2020/02/week1/img026.png

找到对应的报文序号并导出资源,后缀是php,将其改为zip打开,里面有一个加密的mp3

/2020/02/week1/img027.png

根据密码提示为6位数字,直接进行AAPR爆破得到密码, 用密码解压后得到一个纯音乐的mp3,听了两遍也没听出什么, 用Audacity查看波形,没有找到跟摩尔斯比较像的波形 试着用MP3Stego解密文件,由于没有密码也没什么进展, binwalk分析,也没得到什么有价值的线索

然后Google音频隐写相关的博客发现了这个 CTF中音频隐写的一些整理总结 其中提到flag有可能是在音频文件的频谱图中,于是Audacity看一下频谱,果然

/2020/02/week1/img028.png

拿到flag

hgame{I_love_EDM233}


/2020/02/week1/img029.png

题目很明显提示了版本管理工具 GitHub,可以想到网页所在目录是一个git仓库,然后随便找了个自己电脑里的git仓库看了下内容

/2020/02/week1/img030.png

发现config文件里应该有需要的内容,于是修改URIhttp://cosmos.hgame.n3ko.co/.git/config

访问一下,果然得到了上游仓库的信息

/2020/02/week1/img031.png

clone到本地,git show看一下提交信息

/2020/02/week1/img032.png

发现是Base64

/2020/02/week1/img033.png
拿到flag

hgame{g1t_le@k_1s_danger0us_!!!!}


这题虽然因为自己眼瞎卡了好久,不过确实对首部字段的作用有了更深入的了解

首先打开题目是张含有暴力血腥元素的图片(雾)和提示

/2020/02/week1/img034.png

既然是接头,又是web,那应该就跟请求头有关了,于是用chrome的插件Modify Header加了个Referer的字段

/2020/02/week1/img035.png

刷新一下看看,页面发生了变化,看来方向是对的

/2020/02/week1/img036.png

然后翻了翻之前做的有关首部字段的笔记,看起来应该再加一个XFF字段

/2020/02/week1/img037.png

又要改浏览器名称,这个简单,加个User-Agent字段即可

/2020/02/week1/img038.png

又要用POST方法,于是打开Postman手动发包

/2020/02/week1/img039.png

看起来要修改某个跟时间有关的字段才行,试了DateIf-Modified-SinceCache-Control:max-age等字段都没用,然后其他杂七杂八的方法也都是了也没什么用,卡了好久,于是厚着脸皮去找大🍆要了提示,让我再看看If-Modified-Since的有关内容

然后就去Google相关信息,在其中一篇博客中发现了这样的描述

/2020/02/week1/img040.png

发现If-Modified-Since字段对POST方法是无效的,然后在这篇博客下面的其他文章发现了有关If-Unmodified-Since的描述

/2020/02/week1/img041.png

可以看到这个字段适用于POST方法,于是在Postman里添加了这一项

/2020/02/week1/img042.png

拿到flag

hgame{W0w!Your_heads_@re_s0_many!}

到此终于把web给ak了,虽然这题卡了很久,不过感觉每道题卡的地方都是自己知识点的漏洞,做完这四道题也算是对自己的web知识有了一个很大的补充,感觉还是很有收获的!


/2020/02/week1/img043.png

打开发现403

/2020/02/week1/img044.png

因为403是拒绝访问,想了想已经有人做出来了那肯定就是故意弄成这样的,既然GET不了,那我POST总可以吧,于是改了下方法重新发包

/2020/02/week1/img045.png

于是把参数改成a=5+5传进去,不行,然后突然发现忘记urlencode了,于是改成a=5%2b5

/2020/02/week1/img046.png

拿到flag

hgame{C0d3_1s_s0_S@_sO_C0ol!}


打开题目后是一个HTML5和JS写的CXK打篮球的小游戏

/2020/02/week1/img047.png
当然玩是不可能玩的,肯定是要用console修改Js变量来达到目标,那就F12打开console,然后输入dir(window)查看所有对象

/2020/02/week1/img048.png

展开后发现一个Game类的对象canvas_g,成员变量名比较可疑

/2020/02/week1/img049.png

运行一下游戏,果然分数储存在这里

/2020/02/week1/img050.png

调试几次后发现storageScore储存的是当前回合得分,globalScore是总分,于是在console里直接赋值

/2020/02/week1/img051.png

拿到flag

hgame{j4vASc1pt_w1ll_tel1_y0u_someth1n9_u5efu1?!}


虽然密码学毫无基础,既然说了是真·签到题,想来应该也不会太难,直接给出了一段代码

/2020/02/week1/img052.png

Google了一下RSA相关的算法,发现在没有密钥的情况下加密解密只跟pqe有关,并且找到了这个博客CTF|玩转RSA加密算法(一), 于是根据这个博客还有题目所给的部分代码写了个Python脚本,跑出了d和明文m

/2020/02/week1/img053.png

审计一下题目所给代码,发现这段代码的作用是将flag(字节码)转换成十进制然后进行RSA运算得到了密码c,然后现在已经得到了m,接下来要做的就是将m转换成字节码便能得到flag了

改完代码,跑一下,然而flag并没有出现

/2020/02/week1/img054.png

不过看起来也不是什么大问题,搜了一下找到了解决方案

/2020/02/week1/img055.png

一顿CV顺利拿到flag

/2020/02/week1/img056.png

hgame{t3Xt6O0k_R5A!!!}


首先拿到的是一段Python代码,看了一下发现就是将flag单字符加密后组成密文

/2020/02/week1/img057.png

首先用注释补充了一些相关信息(cipher的内容是题目给的),方便分析,然后注意到跟加密有关的应该只有else块里的两行代码,于是根据已知flag的格式hgame{...}可以得到一段明文和对应的密文

hgame <==> A8I5z

写行代码算下索引

1
print("zxcvbnmasdfghjklqwertyuiop1234567890QWERTYUIOPASDFGHJKLZXCVBNM".find(input()))

于是可以列5个方程来求解未知数

/2020/02/week1/img058.png

很容易能够算出A = 13, B = 14,然后可以将flag每一位都用暴力算法求出来

/2020/02/week1/img059.png

编写解密脚本拿到flag

/2020/02/week1/img060.png

hgame{M4th_u5Ed_iN_cRYpt0}


首先还是给了一个加密脚本,只不过是部署在远程服务器上,需要nc才能交互

/2020/02/week1/img061.png

看了一下代码,发现是一个流密码,即对于一个明文,用多个密钥对其进行加密

m ^ k1 = c1

m ^ k2 = c2

m ^ k3 = c3

其中k1,k2,k3,...是随机生成的密钥,题目所给的脚本每次运行都会随机生成一串范围为大小写字母+数字的长度为flag长度的字符串keystream,然后将其与flag按位异或,之后再转成base64编码打印出来

/2020/02/week1/img062.png

连上远端,果然输出了一串base64 于是放进Base64解码Python脚本里看一下flag的长度

/2020/02/week1/img063.png

算上hgame{}一共有43个字符,把已知条件列一下

flag长度: 43

flag范围: string.printable

keystream长度: 43

keystream范围: string.ascii_letters+string.digits

想到可以多次访问获取多个加密后的序列,对于每个序列将其每个元素都与flag范围内的所有字符进行异或运算,如果结果映射ASCII后符合keystream的范围,则将其储存在临时列表中,最后再对所有的临时列表取交集以限定范围,多次运行后便能得到一个稳定的flag

理清思路后开始编写exp

/2020/02/week1/img064.png

其中对flag限定了128次,足够得到一个组成较为固定的flag了

/2020/02/week1/img065.png

运行脚本,拿到flag

hgame{r3us1nG+M3$5age-&&~rEduC3d_k3Y-5P4Ce}


这题刚开始只给了个nc,于是远程连上随便输入了点东西看看

/2020/02/week1/img066.png

发现会把输入的东西随机排列,直接回车或者输入10次则会打印一个乱序的flag。研究了一下发现这个加密的算法一次只加密16位,如果是32位的话则分成两个16位的字符串分开加密然后再合并

/2020/02/week1/img067.png

然后看了看flag的长度,正好是32位,于是把16进制的字符输进去,将明文与密文进行对比,发现flag也是按照这样的顺序排列的

/2020/02/week1/img068.png

于是写了个能根据已知的明文和密文算出flag的exp

/2020/02/week1/img069.png

运行一下,拿到flag

hgame{jU$t+5ImpL3_PeRmuTATi0n!!}


嗯。。第一次做Re方向的题,只有一点汇编基础,不过还好学长给了很多学习资料,首先看了关于maze的介绍,大概明白了解题思路就是通过逆向分析程序找到由限定字符组成的"行进方式"在预设的迷宫内找到路线,输入行进路线字符串即可通过迷宫

拿到文件后首先checksec了下发现是ELF,于是用wsl打开

/2020/02/week1/img070.png

第一次见到这种文字图,有点被惊艳到,随意打了几个字进去, 结果提示You died,看起来要把路径字符串输入到这里,于是打开IDA拖进去F5查看源码

/2020/02/week1/img071.png

嗯,大致看了下,行进的单位应该是一个(char*)类型的变量v6,然后根据代码列了一个映射表

w ==> -64

s ==> 64

a ==> -4

d ==> 4

然后看到了一段跟flag有关的代码

/2020/02/week1/img072.png

/2020/02/week1/img073.png

源代码里把v6初始化为0x6020C4了,简单算了一下

0x60243C - 0x6020C4 = 888 = 64 * 14 - 4 * 2

看起来好像只要让v6等于0x60243C就可以了,然后上面的if语句给v6加了一个限制范围,不过刚开始第三个条件没怎么看懂,于是看了下第三个条件的汇编代码

/2020/02/week1/img074.png

发现作用是将v6放入RAX并且把RAX指向的内存空间的值赋值给EAX,然后与1进行与运算并把结果放入EAX,之后再自身进行与运算,如果EAX等于1则跳转到loc_4008C6处,也就是You died。 然后发现从v6的初始值0x6020C4开始是一段0和1的序列

/2020/02/week1/img075.png

看来这个就是迷宫,前面算出的888是路径长度,于是把这段数据复制出来单独分析

一开始想的是手动寻路,但是拿计算器算了一会发现不太行,于是想写个Python脚本自动寻路 思路是先读入字段并格式化成一个类似指针的字典,[Address]=0/1,然后根据字典的键值(0/1)判断是通路还是堵路,但是由于还没学过DFS,写出的算法直接爆栈了,于是只好精简代码,手动寻路,但是由Python来帮我计算是否能够通行,我只需要输入wasd就可以了,虽然还是有点麻烦但是比拿计算器一个一个算还是快多了

/2020/02/week1/img076.png

于是就像这样一步一步的摸索

/2020/02/week1/img077.png

同时在纸上也画了条路出来

/2020/02/week1/img078.jpg

不过少画了一步,后来才发现添上去了 然后根据画出来的路径图又重新走了一遍全0的路线,得到路径字符串ssssddddddsssssddwwdddssssdssdd

/2020/02/week1/img079.png

拿到flag

hgame{ssssddddddsssssddwwdddssssdssdd}


拿到的依然是一个ELF文件,拖进IDA然后F5

/2020/02/week1/img080.png

可以看到有大量的位运算和异或运算 于是打算重构一下代码,先从最上面的if开始

/2020/02/week1/img081.png

然后注意到中间有两行奇怪的函数

/2020/02/week1/img082.png

点进去看了下

/2020/02/week1/img083.png

看起来应该是对输入的两个参数进行了一些处理,于是重构一下

/2020/02/week1/img084.png

观察if语句可以看出对str2有一些限制条件,其只能是小写的16进制字符,然后将其转换成十进制并通过一些运算赋值给str1,然后根据基址偏移重构了一下数据类型,其中flag内容由两个16字节的字符串flag_part1flag_part2组成,其经过函数运算后赋给part1part2,然后对part1part2进行操作

/2020/02/week1/img085.png

/2020/02/week1/img086.png

重构位+异或运算部分并解释,并且将之前那个函数的功能用Python语法注释了一下

/2020/02/week1/img087.png

观察异或运算部分

/2020/02/week1/img088.png

/2020/02/week1/img089.png
/2020/02/week1/img090.png

然后发现上面这部分有两个byte指针,然后点进去发现是两个8字节的字符串面量,于是继续重构

/2020/02/week1/img091.png

可以看到part1part2在经过一系列的运算之后与str1str2相等才能得到flag

现在整个源代码已经重构完毕,由于最后要跟str1str2进行比较,所以从异或部分开始反推,根据下面的公式

a ^ b = c

a = b ^ c

可知涉及到三个数的异或运算,只要知道其中两个便能求得第三个,然后观察上面两个异或运算,当等式成立时变换形式可以得到

part1 = part1 ^ key = str1

part2 = part2 ^ (part1 ^ key) = str2

由于第一行改变了part1的值,所以要先从第二行开始逆运算

part2 = str2 ^ (part1 ^ key)

part1 = str1 ^ key

于是这样就可以还原出异或运算之前的part1part2了,然后开始逆推上面的位+异或运算

观察其的结构可知,除了第一行外,剩余三行均可用下面的形式表示

a = b ^ a

然后可以得到下面的式子

a(new) = b ^ a(old)

a(old) = b ^ a(new)

所以要想逆推,只需要从下往上再执行一次上面的代码即可,然后再将012位和34567位进行交换即可得到原始的part1part2的值

理清思路后开始编写解密程序

/2020/02/week1/img092.png

编译运行,得到part1part2的值

/2020/02/week1/img093.png

然后开始逆推最开始的func函数,由于已经用Python描述其功能了,那就直接用Python将每一位爆破出来

/2020/02/week1/img094.png

将解密程序所得到的part1part2的值填进去爆破

/2020/02/week1/img095.png

拿到flag

hgame{0f233e63637982d266cbf41ecb1b0102}

这道题虽然重构代码花了好久,不过对IDA的反编译代码格式和数据类型的底层又有了更深的理解,而且还拿到了150分,也算是收获颇丰


这次拿到的是一个exe,于是直接打开看看

/2020/02/week1/img096.png

看来又是一个直接将flag加密的程序,拖进IDA然后F5

/2020/02/week1/img097.png

重构一下

/2020/02/week1/img098.png

可以看到程序的作用是将输入的flag通过encode函数转化成字符串str并与"0g371wvVy9qPztz7xQ+PxNuKxQv74B/5n/zwuPfX"比较,但是这个字符串看起来有点像base64编码,于是重构一下encode函数

/2020/02/week1/img099.png

可以看到是一个换表Base64转码,于是在网上找了一个换表的Base64解码脚本

/2020/02/week1/img100.png

修改一下然后运行

/2020/02/week1/img101.png

拿到flag

hgame{b45e6a_i5_50_eazy_6VVSQ}


首先拿到的是一个二进制文件,checksec看了一下发现是一个32位的ELF文件而且开了栈保护,由于wsl不支持这个格式,所以用了ubuntu环境来调试

/2020/02/week1/img102.png

拖进IDA看一下机器码,发现有一个backdoor函数,由于开了栈保护,所以虽然有gets函数但是用溢出覆盖返回值的方法是行不通的,于是继续往下看发现有一个memcmp函数,这个函数会返回比较结果,而返回结果默认储存在寄存器EAX中,下面的testEAX进行了判断,如果为0则跳转到backdoor函数。于是打开gdb,在getsmemcmp函数处下断点看一下传入参数的地址

/2020/02/week1/img103.png

看起来gets读入的内容储存在0xffffd0cc中。 IDA里可以看到memcmp函数的三个参数分别是("0O0o",0xffffd0cc+0x7b,7), 第二个参数里进行了内存偏移,所以比较的实际是"0O0o"和gets读入字符串的123位开始往后7位

/2020/02/week1/img104.png

输入了123个a再加上0O0o进去,然后跳到下个断点,可以看到传入的参数正是0xffffd0cc偏移了0x7b的地址

但是比较完发现一个奇怪的事,EAX并不是预期的0

/2020/02/week1/img105.png

然后想到比较了7位但是传入的两个参数只有4位,于是看了下往后8位的地址的内容

/2020/02/week1/img106.png

可以看到0x80486e0第五位是0x00,但是第六位和第七位还有数据,但输入的字符串却是都是0,导致返回结果EAX的值非0 看了下后面的内容

/2020/02/week1/img107.png
说明比较的7位里包含了两个字符串,但是gets用键盘输入的方式并不能在字符串中间插入'\0',不过还好Python的pwntools可以对nc直接传输数据,就可以传输’\0’过去了

编写exp

/2020/02/week1/img108.png

Pwn!的一声的敲下回车就直接拿到shell(虽然前面分析了好久,不过这一下还是挺爽的233)

/2020/02/week1/img109.png

拿到flag

hgame{0OoO0oo0O0Oo}


拿到的依旧是一个二进制文件,checksec看了下发现没有内存溢出保护,,于是想到这题应该要覆盖内存来拿到flag

直接拖进IDA,然后F5看源码

/2020/02/week1/img110.png

发现是将flag文件读入到变量flag中,然后读一个字符串,读一个指针,然后把这个指针指向的内容改为1,看来要找一个合法的能读写的地址

看一下静态内存分布

/2020/02/week1/img111.png

发现读入的name和文件指针fd是相连的,那只要覆盖这个文件指针的内容便能将flag连着一块打印出来,然后在本地生成了一个测试用的flag文件,然后名字输入32个a,指针就找一个合法地址,便取了name的首地址0x006010c0

/2020/02/week1/img112.png

但是预期的flag并没有出现,于是考虑到变量flag的首地址的内容可能是\0,所以程序识别成字符串结尾,然后源代码里刚好可以让指针指向的值改为1,于是输入flag的首地址0x006010e0试试

/2020/02/week1/img113.png

果然把测试flag打印出来了

/2020/02/week1/img114.png

然后写exp直接远程交互

/2020/02/week1/img115.png

拿到一个残缺的flag,修复一下即可

hgame{On3_Sh0t_0ne_Fl4g}