WriteUp比赛完就写了= =结果我拖到现在才整理发上来
mini-lctf是校内入门赛啊……
真正的dalao们都出题去了,没有参加,于是给我单挑打了个第五出来
然而因为没有新生在队内所以不给我奖品咯[掀桌!]
好歹我还ak了re和mobile!(虽然都是入门级的)
好咯,不管你,post一下题目的打包
链接: https://pan.baidu.com/s/1pKXa2rp 密码: gnbq
Web 50 (苏打学姐撞上碳酸钠了)
能看到源码为
1 | sha1 conllision, Can you do it<!-- |
获得pass,与key=”aa30FF9m”的sha1值比较
第一个想到的是sha1碰撞,试了下显然没什么效果,50分不应该很难
后来谷狗搜了下key的sha1值,发现了这个神奇的github
https://github.com/spaze/hashes
这个是php的问题了额
挑了个输入,得到flag
LCTF{conllision_is_so_difficult}
然后web就基本都不会做了= =
Misc 20 (回转十三位)
后面接着4个等号,base32编码,加上回转13位,想到ROT13,得到flag
Misc20 (Easy)
密文是LbbeCaarT3r}Fer{_i
典型栅栏密码
Misc60 (Document)
解压出来后用binwalk跑了下,发现了一堆隐藏的文件
直接后缀名改成.zip,是个压缩包
直接就在子文件夹中找到flag了
Misc100 (Noisy)
下载文件名是wav,音频文件嘛……后缀名改成.wmv,听一下是一段噪音
下了个Audacity分析,瞎搞一下
发现转成频谱图的时候
噢草,厉害了!
Misc150 (Sword Art Online)
一个txt文件,打开发现全是255, 255, 255
然后中间还夹杂着一些别的数据
第一反应就是RGB数据咯,统计了下共1080*1080组数据
写了个脚本复原一下
1 | #-*-coding:utf-8-*- |
当中一些点的排序有问题,导致图分成了四个部分= = (事实上是我错估了分辨率)
随意魔改了下脚本,虽然还是有问题,但是已经勉强能看出flag了2333333
LCTF{C0ngratulation_y0u_g0t_1t}
Misc玩完了……时间不够不想继续尝试了T_T
Pwn20
这个,gdb调试能发现,写v2时直接溢出就能覆盖到v3,v3只要为非0就是true了
直接输入长点瞎搞一下就出来了……
Pwn80
同样,输入能覆盖到v2、v3,0x63 0x65这些还都是正常的字符, 不需要用python构造输入
gdb调试时确定下相关位置就稳了
pwn基本没怎么接触过,shellcode还不会写T_T
狗带吧!
Mobile20 (Log)
题目都说着Log了……
然后我直接反编译看了下代码
log的数据写到了jni里,这么正常思维就是连上真机/虚拟机调试DDMS看log出来的flag
然后咸鱼如我直接ida了一下lib包……(才20分怎么可能写得很复杂嘛!)
然后就出来了呗
Mobile50 (Base)
说实话这题我不知道考点在哪……代码混淆吗……
毕竟也就50分
就是这段代码
检测是否调试器链接,然后toast输出flag
懵逼了很久……后来我甚至发现了那算法就是base32阿噗
流程就是把写死在程序里的key base32变换一下输出,key转换一下顺序再base32 一下输出
结果就是直接装上真机,按一下按钮flag就出来了……
Mobile100 (Smali)
下载下来就是一个Smali代码
而且是经过一定的处理,不能用Smali2Java之类的工具转换成java代码
那么就直接阅读吧(真棒!!!刚好给我练一下阅读smali代码!)
smali代码指令可以到这查询
http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html
很关键的几个字符串AES/ECB/PKCS5Padding
MD5
最终结果是
1 | 00000080 const-string v6, "falg" |
Log输出flag(唔,为什么是falg)
代码不长,大致流程就是
字符串this_is_your_key
,传进Encrypt.handle()函数
用这返回结果作为AES加密的秘钥,
再用这返回结果调用AESEncrypt.Encryption()函数
最后加密结果把byte转回为16进制String输出
分析一下handle函数,其实就是把奇数位和偶数位的字符交换一下
由此复原函数
1 | import java.io.UnsupportedEncodingException; |
其中CryptoTools是自己写好的相应的AES加密的类
跑一下出结果
184b4e1bc353510f7841bb126d94259449055ef296e3b665dac507032e4c01e1
值得一提的是,在初始化秘钥的函数有点混淆的地方
就是当传入秘钥参数为空时会把空字符串求MD5作为秘钥,这是库中的一点处理,正常是空字符串求不了的吧……
刚开始还在这卡了点时间,怎么能如此的不熟练
然后就是眼瞎把最后加密用的字符串或秘钥各种看错,把key换成keyChange、keyChange换成key啥的阿噗,ctf真是个考验眼睛的比赛
估计是考虑到科普向,mobile的题就这三题(这才是我主场啊喂)
不过,我也蜜汁ak了re红红火火恍恍惚惚
Re60
跑一下程序运行时让输入flag,正确就会输出对应的flag
直接拖到ida用f5神器看一下
calLenEqual32,函数名说得挺清楚的
然后进到里面也是一个很简单的判断,输入长度为32即返回5
其中sub_3c4d函数就是很简单的一个strcmp函数,相等即返回5,输出flag
所以关键就是在sub_3c4c函数中
分析可知第一个参数是输入的字符串,第二个参数是内存中一段数据,第三个是结果
进到该函数看
在OD中调试能看到strupr是把字符串都转换为大写的函数
iHenStrlenLow是数据字符串的长度,Gap那个很复杂,但input和bc2e(自己改的名)长度应该是相同的,所以都不用管。
关键就是中间一段循环,调用的两个函数
两个函数也很简单,判断输入大小跟64和9的关系,把输入的字符-55、-48或+55、+48
我一开始写解密函数时还想着改写下这两个函数,仔细一看55+9=64,这两个函数时互补的
在OD调试中看到硬编码的字符串,长度32,直接写。
1 |
|
跑出来flag是AB7E032568F1084CD8C78B7650AE30BF
Re100 (Easy GUI)
windows下的gui逆向,输入正确的password
一般来说有两种定位的思路,一是查找相应的字符串,二是在GetDlgItem这类获取控制句柄的winapi中下断点
这里字符串一下子看不到有用的信息,于是在GetDlgItem下断点,OD跑出来
然后就可以定位到关键函数了,这里发挥自己的想象瞎搞一波
可以直接到ida相关地方f5
也可以直接OD动态调试看寄存器
像这样,稍微阅读汇编发现password长度为13
cmp地方下个断点,反复跑13次程序,就能骗出flag了,这样解密程序都不用写233333
flag: w1napi_1s_old
Re150 (Easy Linux)
拖到linux中跑来看看
结果发现data.dat文件不一起放过去的话是跑不动的
所以可以猜想一部分代码在data.dat中
然后拖进ida就发现了checkpassword函数
非常简单的逻辑,跳转到secret的地方,获得13位数据
写个程序跑一下就出来了
1 |
|
flag W3lc0me2Linux
Re200 (壶中的大银河~Easy~)
然后后面这几题就真的学到很多东西了
这题提示着linux signal机制
ida看到main函数很简单,主要有alarm、pause函数
注意在gdb调试中,默认alarm信号是不传进程序的,会导致程序阻塞在pause的地方
学习了一轮signal机制,知道了这么一回事
signal函数 void (*signal(int signo, void (*handler)(int)))(int);
在接受到signo的信号后,会跳转到第二个参数(一个函数指针)去处理
这里主程序是发出了alarm的信号
ida中搜了一下signal,就能发现这个函数
跳转到handler里面
然后查看各个地址,0x8049B40中获得奇怪的字符串一个
写个程序就跑出来了
1 |
|
flag: 1s_is_also_important
Re250 (蓬莱的玉枝)
也是一个winGUI
跟之前同样道理,定位到关键函数,用ida查看
这个函数非常简单!而且Seed是写死的,rand()每次运行程序都一样
那么思路就是获得0x0041c010的数据,写个程序跑出来
嗯……然后出来一堆奇怪的东西,所以这样不对吧
然后用OD调试,发现长度27,到这里会有判断……
又是累一点下个断点一次次跑然后出结果2333333
后来再想其实那个程序为什么会不对呢,有可能在某个函数对那块空间处理了一下
在OD中看那块地址空间果然跟原来的不一样了
后来果然找到了那个函数
咦……IsDebuggerPresent()函数
如果检测到在调试模式下变换出来的字符串是错误的
结果我就发现……用OD调试时IsDebuggerPresent()函数返回的是非!厉害了OD
同时用ida调试了一下,出来的是非0值,检测到在调试,再修改下程序,就跑出来了
1 |
|
LCTF{learn_more_think_more}
Re350 (永遠の春夢)
嗯……做的时候提示还没出来
分析出来后成就感满满的啊噢!
这个比较麻烦我就直接用ida调试了,先看主操作函数
关键就是在sub_401621函数中了
刚开始就懵逼的发现前面有个异或的操作,后面有个a1(a4)这特么是个啥!
然后再前面传入的第一个参数一直分不清到底是数据还是程序
a2的长度刚好就是a1地址中数据的长度
这时看看汇编代码
看到一个call eax
所以那就是个函数咯
那前面异或?这是就想到动态自修改了
调试中看到这段汇编代码,这个就用不了f5了,直接阅读吧
1 | .text:00401584 push ebp |
大致就是每次取ds:dword_40EA40的值中的8位字符数据低四位与高四位交换一下
再把dword_40A020中的数据进行一点处理,这里似乎是取模?
然后结合外部f5出来的代码可以猜想对输入字符串都进行这个操作了
然后是第二个函数
1 | .text:004015ED push ebp ; DATA XREF: sub_4014C8+8Do |
很简单的异或一下,然后比较
所以就可以写程序跑了
1 |
|
因为前面没分析出来mul 0x80808081的作用,所以就直接强行模拟了
后来看这结合上下代码似乎是一个取模的操作
跑出来结果
LCTF{SMC_is_excited!}
Excited!