CTF刷题小记(1)

这篇博客主要用来记载最近刷题遇到的有趣的题目
或者一些可以让我有所收获的题目

REVERSE

这题其实不难的。。。但因为某些原因耗了很长的时间
1
看一下程序的大致流程
//程序被我patch了些,看起来更加舒服些
首先是根据输入的长度进行判断
然后进行检查
看一下主要check函数
2
不难
一个循环左移俩位后异或操作然后进行字符串匹配
因为这个程序不知道为什么我运行不了。。。不然想直接调试出答案
比如输入25个a
拿他跑出来v11的25各值异或a再异或相应匹配的数组的元素
但是没办法,运行不了
至于为什么这题花了我那么久呢
主要是因为那个ROL1
因为凭做题的经验,一般ida反编译出的函数都是subxxxxx
如果不是,肯定是有原函数的
所以这个__ROL1__肯定是某个c的函数//猜测
然后我就开始了Google,怎么也没Google出结果
调试也不能调试
就蒙蔽了。。。
后来出去跑了会步洗了个澡突发奇想
我为什么不看汇编呢???
3
简直了。。。
上脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
a = '1A2F943C4D8C5B6EA3C9BCAD7E'
b = [0xf,0x87,0x62,0x14,0x1,0xc6,0xf0,0x21,0x30,0x11,0x50,0xd0,0x82,0x23,0xae,0x23,0xee,0xa9,
0xb4,0x52,0x78,0x57,0xc,0x86,0x8b]
flag = ''
def en(x,y):
if (x-48)>9:
x = x-55
v4 = x&0xf
v5 = (y-55)&0xf
if (y-48)<=9:
v5 = y&0xf
return v5|16*v4
flag = ''
for i in range(len(b)):
aaa = en(ord(a[i]),ord(a[i+1]))
aaa ^= b[i]
aaa=((aaa<<6)&0xff)|((aaa>>2)&0xff)
flag += chr(aaa)
print flag
#EIS{ea3y_r7Eve0rSe_r1ghT}

reverseme

这题简直了
出的很棒
能让我深入了解base系列
里面的base已经被作者改的不像样了
不认真看还真看不出
写了很久,但很值,学到了很多。
首先放在ida里看下具体流程
4
input一串字符串
然后sub_401000是一个初步加密
然后一大段循环加密
最后与”you_know_how_to_remove_junk_code”相匹配
我的思路一开始是选择黑盒
输入一大串a
然后看输出,断点断在第二次循环上面
发现经过sub函数加密后输出是3个一循环
难道sub函数只是单纯的异或嘛?猜测一下
在下断点断在strcmp那,发现经过那一大串循环后只是把每个都与0x25异或
ok了,以为这题又是一个水题,直接写脚本发现答案不对。。。
看来分析出错了。。。
跟进sub函数里看
5
又是俩个大循环
先看第一个
其实第一个应该是用来验证的,调试发现对输入没做任何改变
就不看了//懒
看第二个循环
6
可以看到有个取码表操作
看看码表
128个char
base128???
这明显不是base128的码表啊
继续看他的操作
其实就是把4个输入分别取其低6位
组成3个char
base系列
那个byte2()和byte1()可以看汇编
//上次总结的没想到那么快就用上了
接下去就可以写脚本了
再小提一下
这个base是可以逆的
一开始我以为逆不了。。。或者能多解
因为只能求出低6位//v16的低6位
所以v16如果比2^6高的话也可以
但是看看他那个码表,比2^6高的都是0x7f
所以只要求出来v16不是63就说明是唯一答案
上脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# -*- coding: UTF-8 -*-
arr = 'you_know_how_to_remove_junk_code'
dest = [0]*(len(arr)+1)
base = [127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 127, 127, 127, 127, 127]
for i in range(len(arr)):
dest[i] = ord(arr[i])^0x25
a = [0]*45 #长度定义的稍微大些
j = 0
for i in range(0,len(dest),3):
a[j] = dest[i]>>2
a[j+1] = ((dest[i]&3)<<4)|((dest[i+1]>>4))
a[j+2] = ((dest[i+1]&0xf)<<2)|(dest[i+2]>>6)
a[j+3] = dest[i+2]&0x3f
j += 4
print a
flag = ''
for i in range(len(a)):
for j in range(len(base)):
if a[i] == base[j]:
flag += chr(j)
break
print flag

我的脚本写的不怎么好打出来flag是XEpQek5LSlJ6TUpSelFKeldASEpTQHpPUEtOekZKQUAAA
但可以调试发现答案是XEpQek5LSlJ6TUpSelFKeldASEpTQHpPUEtOekZKQUA=
7
是个好题
仔细想想也不咋难

zorro_bin

第一次接触到ELF爆破
8
拖进ida里的话,也不怎么复杂,显示输入想要的饮料个数
然后进行判断
再输入饮料id
9
然后根据id个个数进行一次验证
并根据输入生成flag
所以说肯定是逆不了的了。。。难度很大
还是爆破好
for i in $(seq 1 65535); do echo -e “1\n$i” | ./zorro_bin | grep -i nullcon ; done
或者py

1
2
3
4
5
6
7
8
# -*- coding: UTF-8 -*-
import subprocess

for i in range(17,65536): #输入的数值
proc = subprocess.Popen(['./bin'],stdin=subprocess.PIPE,stdout=subprocess.PIPE) #文件
out = proc.communicate('1\n%s\n'%i)[0] #输入
if "nullcon" in out: #判断
print out

差不多2分钟不到出答案

ROCK

这题我写上来也是有原因的
虽然说不难
首先这题目没什么奇怪的
rock
放ida里看看
10
???
people’s champ???
Wrestling???
WTF???
再看看题目
???
还真是rock
天啊,我的偶像
11
这题必须认真写了!!!
一般对于这种c++写的程序
我都是直接调试的
不静态
只是稍微看看
因为c++写的看起来都很难受
调试到主要验证
12
可以看到就是俩次的异或移位操作
再看看
13
有个匹配操作
FLAG23456912365453475897834567
和这字符串匹配
那就简单了啊

1
2
3
4
5
6
a = 'FLAG23456912365453475897834567'
flag = ''
for i in range(len(a)):
flag += chr(((((ord(a[i])-9)^0x10)-20)^0x50))
print flag
#IoDJuvwxy\tuvyxwxvwzx{\z{vwxyz

ll

dMd

MD5二次加密
挺有意思的
有个不错的网站
somd5
里面可以看到经过几次md5
先来看下程序
很简单
输入md5一下再与字符串匹配
14
我们可以解一下
看到这个字符串解出来是grape,但是这是解密过俩次的
15
//我一开始用的md5网站看不了加密了几次
//所以有点懵逼
这边直接把grape加密一下,就是输入了

文章目录
  1. 1. REVERSE
  2. 2. reverseme
  3. 3. zorro_bin
  4. 4. ROCK
  5. 5. dMd
|