IDF.CN Practice 01
0x1 Preparation
既然决定要做,那就加油,写在开头,打好基础,加油吧。 Exia,斩获未来。。
0x2 Start
一、牛刀小试
被改错的密码
从前有一个熊孩子入侵了一个网站的数据库,找到了管理员密码,手一抖在数据库中修改了一下,现在的密码变成了 cca9cc444e64c8116a30la00559c042b4,那个熊孩子其实就是我!肿么办求解!在线等,挺急的。。
看起来挺像md5,直接拿去在线破,结果提示有问题,再一看,长度有问题,md5是32位哈希,这玩意33位,用python生成去掉其中某个字符的序列,然后再一个个在线破,发现是cca9cc444e64c8116a30a00559c042b4,解出来是idf,所以flag是wctf{idf}
啥
题目就是一张图片,bless打开看hex,在底部找到flag:wctf{mianwubiaoqing__}
ASCII码而已
明显一看是unicode,找个在线转换,flag为wctf{moremore_weibo_fans}
摩斯密码
一段morsecode – — .-. … . -.-. — -.. . 在线解一下,flag为wctf{morsecode}
聪明的小羊
一只小羊跳过了栅栏,两只小样跳过了栅栏,一坨小羊跳过了栅栏… tn c0afsiwal kes,hwit1r g,npt ttessfu}ua u hmqik e {m, n huiouosarwCniibecesnren.
看题目就想到古典加密,既然是栅栏,那就栅栏密码吧,正好带学一下栅栏密码,就写了个python的加解码脚本,跑一下看到flag:wctf{C01umnar}
二、包罗万象 MISC
图片里的英语
给了一张小李,binwalk一下。看到有个rar,dd提取出来,解压,得到一长flag,恩,没错,就是那张赵本山的图片,may the force be with you,然后首字母大写,wctf{Mtfbwy}
抓到一只苍蝇
给了一个pcapng网络dump包,根据他说的内容,和包名带有fly,搜索包内容,找下字符串fly,成功找到,发现是上传了一个附件fly.rar,分成了5个包上传,第一个post指出fly.rar大小为525701,接着5个包都是传向ftn开头服务器,所以猜测是附件内容,前个都是131436大小,最后一个1777,(131436×4 + 1777 - 525701) / 5 = 364,所以每个包开头364部分为分包后的包头,dd导出内容,skip掉头364字节,然后cat成fly.rar,比较下post里给的md5,一样。
解压工具打开,提示文件损坏,看上去因该不是正常的加密,而且也根本没有其他密码的信息,推测可能改了文件头,bless修改加密位(第24个字节改为0x80):
解压得到一个flag.txt,打开发现不行,binwalk一看是个pe。。。不过里面有png,而且很多60x60的,但有一个280x280的,dd解出来,打开是一张二维码,扫一下,flag为:flag{m1Sc_oxO2_Fly},不过说没改格式,额,所以应该是wctf{m1Sc_oxO2_Fly}
三、初探乾坤 PPC
简单编程-字符统计
给了一串字符串,让统计个数,妥妥的python,count函数直接搞定。直接提交,发现有坑,仔细看了下题目是要求2秒内搞定,那就只能自动接受内容然后发送post请求了
写个python脚本跑一下
|
|
谁是卧底
给了一个大文本串,打开看基本上都是乱字符,根据题意,大部分人都市文盲,卧底有点姿势,所以找个字典去统计下出现单词的地方,然后打印出最密集出现的部分,在里面找到
bananjpywlqclassifyubcjesqtqyjhazbornndomhfchvlc
what will you see if you throw the butter out the window
wzqmtwmyjutipvqetrsshyosypzydevelopponaxoezspdespairkuoqi
第二行是一句话,字面意思,丟块黄油你会看到啥,当然黄油飞啊,butter fly。。。就是butterfly,所以是wctf{butterfly}
Fuck your brain
Brain Fuck编码,直接找个在线解析器解析一下OK。 WCTF{Br31nF4ck}
倒行逆施
.Net逆向第一题
如题目说,应该是个简单的.Net逆向,用ILSpy查看代码,是个典型的des加密,key = “wctf{wol}” iv = “dy_crack}",然后加密后的结果在base64编码下和已有字符串fOCPTVF0diO+B0IMXntkPoRJDUj5CCsT进行比较。 根据这个过程逆推即可,写个python脚本跑下:
|
|
最终结果是wctf{dotnet_crackme1}, 没怎么写过C#,这里有个坑是C#的createEncrypter()可以接受byte[] iv不为8 bytes,但是python里除了DES.MODE_ECB外都不可以,刚开始用ECB解出来不对,换回ECB会提示iv应该是8 bytes,就猜可能C#有做截断处理?于是把上面代码里的iv64最后的那个'}‘去掉,再跑一下果然OK。。当然C#不熟,不知道理解的对不对。。。
简单的PE文件逆向
和题目说的一样,一道简单的PE逆向,首先运行下,命令行输入flag
丢ida, shift f12 查看string,有个
swfxc{gdv}fwfctslydRddoepsckaNDMSRITPNsmr1_=2cdsef66246087138
,是个字符数组
查找引用,在sub_4113A0里,tab查看反汇编代码,主体是个循环,和输入进行了17次判断,然后再继续用一个if判断5次,只要有一个不同就让v13为1,继而输出Wrong
继续看循环内如何从字符串数组取值,index通过
|
|
来取值,再看函数开头,从v14到v35,刚好有超过17个连续的变量可用,再看前面的代码,有从v14到v35的初始化:
这里把v14到v30的值保存,为 (0x1, 0x4, 0xe, 0xa, 0x5, 0x24, 0x17, 0x2a, 0x0d, 0x13, 0x1c, 0x0d, 0x1b, 0x27, 0x30, 0x29, 0x2a), 因为向下在if里还有5次比较,把这五次的值也保存,(49, 48, 50, 52, 125)。 接着动态运行确认下,在如下图里的位置下断:
运行几次,查看eax的值,和上面列出的相同,可知上述序列确实是用来从那个字符数组里取值的,所以最后的5次比较也是字符,因为接着v37后是四个chr类型,所以其实真正应该是一个v37[22]的数组。如此依赖用脚本跑一把。
|
|
得到结果wctf{Pe_cRackme1_1024}
简单的ELF逆向
题目给的是一个x86-64的ELF文件,跑一下和简单PE类似,要输入正确的flag,错误就打印"u r wrong。” 丢IDA反一下,ida对x64支持不太好,pseudo code显示还有点不爽(–!),不过幸好不太复杂,对着汇编还是能看的:
从上图看到v8到v15是8个int64_t的类型,v16是个int32_t,对应汇编用两次mov dword ptr指令初始化每个变量的低4bytes和个高4bytes:
接着是程序主体,接受输入,进行判断,如果和要求不符合,v24为1,打印 u r wrong,从伪码可以看出来,输入需要是个长度为22的串,否则会把v24设为1。
接下来看判断部分,和PE的类似,分两部分判定,for循环里判定前17个字符,用于进行判定比较的取值方法如下:
|
|
按照上面方法一次和输入v17[j]里的每个字符比较,这里可以看到已经把从v8开始的这些int64_t的变量看成了一个int32_t数组,刚好v8到v15有8个int64_t,刚好是16个int32_t,在加上最后的v16刚好是17个值,所以,根据上面的截图,这17的用来计算比较值的数据分别为**(0xEF, 0xC7, 0xE9, 0xCD, 0xF7, 0x8B, 0xD9, 0x8D, 0xBF, 0xD9, 0xDD, 0xB1, 0xBF, 0x87, 0xD7, 0xDB, 0xBF)** 紧接着是在if里进行5次最后的比较,用于比较的值是**(48, 56, 50, 51, 125)** 综上已经知道flag计算过程,写个脚本跑出来:
|
|
结果是wctf{ElF_lnX_Ckm_0823}
python ByteCode
看题目就知道,工具用上,uncompyle2(如果是exe可能还要用unpy2exe),得到下面的py脚本代码:
|
|
把输入存到flag, 然后通过encrypt(KEY1, 5, flag)加密,再和KEY2进行比较,相同即可,从encrypt()函数可以知道输入和KEY2长度相同,再按照encrypt()的思路反过来算一遍即可。。。 结果发现,尼码想简单了。。根本不行。。。怎么算带乱码。。只能爆破了。。。
|
|
拿到flag,WCTF{ILOVEPYTHONSOMUCH}
BreakPoint
给了一个ELF32的文件,行为和之前的一样,输入flag,正确即可。 丢IDA,程序逻辑很明显:
- 打印提示字符
- 接收输入
- 利用提示字符的地址和main的地址计算了一个值放v0和v4
- 在一个if里进行比较,比较的值都是写死在程序里
关键逻辑和对应数据如图:
ida看下main地址就知道v0的值肯定会在第一个if的do-while里算出来,需要注意的是,这里不能gdb去调试,因为gdb下断是用 int $0x3,软中断的机制是在断点处把代码替换成int $0x3,但是计算的时候会把整个程序从main(0x80483B0)到字符串(0x804872A)的数据拿来用于计算v0,所以只能把这些数据抠出来单独跑v0的值,跑到后下面就OK了。
|
|
最终拿到
|
|
但是用这个值去计算的话发现不对,多跑了几次,结果好像断点数和输入不一样这个值都会变,再看看题目的意思,估计断点不能乱下了。。。那就暴力点,直接patch二进制文件,让程序把值打出来。。。
接下来就是被霍霍成一大坨的if大判定了。。。其实都是写比较,几个函数:
- PAIR(word, word) 比较两个16bit的值
- BYTE1()~BYTE3() 分别取一个32bit值的第1~3个byte(从0开始,一个32bit的value有0,1,2,3四个byte
用来比较的值也知道了,见上面的截图,这里单独按序列出来
|
|
用来比较的值从地址0x08049908到0x08049914,而且0x08049914指向的是个dword,所以实际上是0x14-0x8 + 0x1 + 0x3 = 0x10,即我们要输入的是16个字符
如上,if里的14次比较都都分析的差不多了,下面就好办了,直接脚本跑出来,要注意的就是比较时候的字节序问题了,可以上下两个valueForCmp有什么不同
|
|