首页
社区
课程
招聘
[原创]KCTF2022春季赛 第二题 末日邀请
发表于: 2022-5-13 11:00 12184

[原创]KCTF2022春季赛 第二题 末日邀请

2022-5-13 11:00
12184

这是一道闯关题,没有加壳等手段,只是需要逆的逻辑比较多,稍显复杂,但只要花时间,就一定能做出来。我这里将程序分为不同的部分,依次对每个部分的算法逻辑进行还原,通过OllyDbg进行动态调试,判断每段逻辑后得到的数值,与自身逆出来的结果是否相符,若符合就继续逆下一个逻辑,直到最后一个逻辑逆完。然后再根据逻辑分析出输入的字符串。

  1. sub_40100C用来显示文本内容
  2. sub_40103A用来读取输入字符串
  3. IDA分析出的 v9 >= 0,这里的v9是单字节有符号数,因此实际运算时表现为 v9 <= 0x80(用C写wp就没这么多事了)
  4. 部分操作是单字节运算,因此运算过后,与上0xFF
  5. 最终得到一个单字节的数,保存在v72中,后面会用到
  1. 这部分是一个单走的函数sub_40106C,它用来在指定地址初始化一个大小为4096字节的缓冲区,里面包含了1024个生成的随机数
  2. 这里需要注意的是右移运算,实际用的是算术右移,因此需要注意判断操作数的正负情况,来进行对应的补符号位
  1. 这里是对输入的字符串进行一个运算,还是算术右移需要注意,由于是右移8位,对于负数右移需要或上0xFF000000
  2. 这里会计算出一个值,并最终赋给变量v67,这个v67在最后一关前会进行判断,如果v67的值为0xf52e0765,则能成功闯关,得到唯一解
  1. 这是一个操作字符串(会调用2次,第1次是传入的参数字符串)的函数,直接F5即可。减法运算需要注意只保留单字节结果
  1. 这部分在栈中生成一个长度为200的数组,变量v66指向首地址
  2. 在Part 0x0中计算出来的值会赋值给变量v72,这里会将v72进行符号扩展后,赋值给变量v13(见红框)
  3. 在运算时,乘法运算依旧是带符号的,所以需要分情况讨论一下(见橙框)
  1. 这里是一个判断,要求字符串前3个数异或后的结果,并与v66数组中靠后的3个数进行比较,若相同,才能进入下一关
  2. 经过测试,如果v72的值(在Part 0x0计算出)的小于0x80,即为正的情况下,那么v66中3个数的值异或的结果一定为0x7;否则将是一个接近-1(0xFFFFFFFF)的大数。
  3. 字符串输入的字符只能在(0-9a-zA-Z)中取,因此只要保证在v72小于0x80的情况下,凑出一个异或结果为0x7的数即可,这里我们选择"007",刚好可以过掉这一关
  1. 这部分判断字符串的第4~7位,这里的字符串是在Part 0x3中经过处理后的字符串的值。这里只要简单凑一下,就可以得到这4个字符为"KCTF"
  2. 这里是v74[0]实际指向的,Arglist[6]的位置,可以通过汇编得出
  1. 这部分运算直接F5就可以,这里只对最后9位字符串进行判断,要求这4位字符串依次读取,按照此算法,均可被整除
  2. 此时还无法得到正确的字符串序列(图中为了演示此算法已给出),需要放到后面去计算
  1. 这是一个简单的排序算法,负责将后9位数按照大小进行排序
  1. 这里会调用sub_4010B7,来操纵一个内置的字符串,然后将排序后的字符串后9位与进行操作后的字符串中的前9位依次进行比较,若相同才可进入之后的判断
  2. 可以发现,这里表明了,后9位字符串的取值正是"123456789"以某一种顺序排列后的结果
  1. 这里做一个简单的fuzz,找到后9位数的排列顺序,以满足(除了v67的值等于0xf52e0765)外的所有条件
  2. 最终可以找到一个字符串"381654729"
  1. 此时只差前3位字符串的值未确定了,还是一样,通过一个fuzz,遍历(000~ZZZ)的所有情况,找到符合要求的前3位(3个字符异或结果为7,这个条件也可以加上)
  2. 最终得到字符串"421"
  3. 拼接起来就是"421KCTF381654729"
  • sub_40100C用来显示文本内容
  • sub_40103A用来读取输入字符串

  • [注意]APP应用上架合规检测服务,协助应用顺利上架!

    最后于 2022-5-13 11:00 被Ally Switch编辑 ,原因:
    收藏
    免费 4
    支持
    分享
    最新回复 (4)
    雪    币: 5568
    活跃值: (3218)
    能力值: ( LV12,RANK:407 )
    在线值:
    发帖
    回帖
    粉丝
    2
    Part 0xC:
    res = func(s)
    这个func是如何关联到程序的?
    2022-5-13 18:14
    0
    雪    币: 8740
    活跃值: (6634)
    能力值: ( LV12,RANK:207 )
    在线值:
    发帖
    回帖
    粉丝
    3
    htg Part 0xC: res = func(s) 这个func是如何关联到程序的?
    import os
    import itertools
    
    def func(s):
    	
    	# Part 0x0
    	v70 = 0
    	v4 = len(s)
    	v5 = 0
    	v71 = v4
    	v6 = v4
    	v72 = 0
    	if v4 != 0:
    		v7 = s
    		for i in range(v6):
    			v5 = ord(v7[i]) ^ v5
    			v5 = v5 & 0xFF
    			v8 = 8
    			for j in range(8):
    				v9 = 2 * v5
    				v9 = v9 & 0xFF
    				v10 = v9 ^ 7
    				if v9 < 0x80:
    					v10 = v9
    				v5 = v10
    		v4 = v71
    		v72 = v10
    		print('Part 0x0 Calculate v72 For Part 0x4: ', hex(v72))
    		
    	
    	# Part 0x1
    	list_5B20 = sub_40106C()
    	
    	for x in list_5B20:
    		#print(hex(x))
    		pass
    		
    		
    	# Part 0x2
    	v11 = 0xFFFFFFFF
    	for i in range(v4):
    		tmp = list_5B20[0xFF & (v11 ^ ord(s[i]))]
    		if v11 >= 0x80000000:
    			v11 = ((v11 >> 8) | 0xFF000000) ^ tmp
    		else:
    			v11 = (v11 >> 8) ^ tmp
    	v67 = v11 ^ 0xFFFFFFFF	
    	print('Part 0x2, This Value Should Be 0xF52E0765: ', hex(v67))
    	if v67 == 0xf52e0765:
    		return 1
    
    	
    	# Part 0x3
    	s = sub_4010B7(s, v4)
    	print('Part 0x3 Manipulat Original String, Used For Xor: ', s)
    	
    	
    	# Part 0x4
    	v13 = v72
    	v69 = 1
    	v14 = v72 + 1
    	v66 = []
    	while(v13 < v14):
    		if v13 > 0x80:
    			v15 = 0xFFFFFF00 | v13
    			for j in range(200):
    				if (v15 & 1) != 0:
    					v15_abs = 0xFFFFFFFF - v15 + 1
    					v15_abs = 3 * v15_abs - 1
    					v15 = 0xFFFFFFFF - (v15_abs - 1)
    					
    				else:
    					if v15 > 0x80000000:
    						v15 = (v15 >> 1) | 0x80000000
    					else:
    						v15 = v15 >> 1
    				v66.append(hex(v15))
    				#print(j, ' ', hex(v15))
    			
    		else:
    			v15 = v13 & 0xFF
    			for j in range(200):
    				if (v15 & 1) != 0:
    					v15 = 3 * v15 + 1
    				else:
    					if v15 > 0x80000000:
    						v15 = (v15 >> 1) | 0x80000000
    					else:
    						v15 = v15 >> 1
    				v66.append((v15))
    				#print(j, ' ', hex(v15))
    		v13 = v13 + 1
    		
    		
    	# Part 0x5
    	if v72 < 0x80:
    		print('Part 0x5, Calculate With Or: ', (v66[195]), (v66[196]), (v66[197]))
    		v17 = (v66[195]) | (v66[196]) | (v66[197])
    		v18 = v71
    		cmp_a = (s[0])^(s[1])^(s[2])
    		print('Part 0x5, Or Result: ', hex(v17))
    		print('Part 0x5, Xor Result: ', hex(cmp_a))
    	else:
    		print('Part 0x5, Calculate With Or: ', hex(int(v66[195], 16)), hex(int(v66[196], 16)), hex(int(v66[197], 16)))
    		v17 = int(v66[195], 16) | int(v66[196], 16) | int(v66[197], 16)
    		v18 = v71
    		cmp_a = (s[0])^(s[1])^(s[2])
    		print('Part 0x5, Or Result: ', hex(v17))
    		print('Part 0x5, Xor Result: ', hex(cmp_a))
    	
    		
    	# Part 0x6
    	v19 = v17 + 2
    	v20 = v18 - v19 - 7
    	print('Part 0x6, This Value Should Be Less Than Or Equal 0: ' , v20)
    	
    	
    	# Part 0x7 ['007KCTF' can pass here]
    	print('Part 0x7, s[3] should be 0x14/20: ', s[3])
    	print('Part 0x7, s[4] should be 0xC/12: ', s[4])
    	print('Part 0x7, s[5] should be 0x1D/29: ', s[5])
    	print('Part 0x7, s[5] should be 0xF/15: ', s[6])
    	
    	 
    	
    	# Part 0x8
    	# v69 = 1, define in Part 0x4
    	# v74[0] == s[6]
    	# v74[1] ~ v74[
    	# v19, Rest Length Of String
    	# v70 = 0, define in Part 0x0
    	
    	v74 = s[6:]
    	print('Part 0x8, Rest Length Of String: ', v19)
    	v21 = 0
    	v71 = 0
    	if v19 > 0:
    		v22 = 1
    		for i in range(v19):
    			v23 = v74[v22] + 10 * v70
    			print('Part 0x8, (' ,v23, '=', v74[v22], '+', '10 *', v70, ')%', v69, '==', v23%v69)
    			v24 = v23 - 0x37373737
    			if v23 <= 0x4B435445:
    				v24 = v23
    			v70 = v24
    			if (v24 % v69):
    				print('Failed! ')
    				return 0
    				#break
    			v69 = v69 + 1
    			v22 = v69
    	
    	
    	# Part 0x9  Just A Sort
    	v25 = v19 - 1
    	if (v19 - 1) > 0:
    		v26 = v19 - 1
    		for i in range(v26):
    			v27 = 0
    			if v25 > 0:
    				for i in range(v25):
    					v28 = v74[v27 + 1]
    					v29 = v74[v27 + 2]
    					if v28 > v29:
    						v74[v27 + 1] = v29
    						v74[v27 + 2] = v28
    					v27 = v27 + 1
    			v25 = v25 - 1
    	print('Part 0x9, Last 9 Elements After Sort: ', v74[1:])
    	
    	
    	# Part 0xA
    	a_str = '1234567890_ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    	a_str = sub_4010B7(a_str, v19)
    	print('Part 0xA, a_str: ', a_str)
    	v30 = 0
    	if v19 > 0:
    		for i in range(v19):
    			print('Part 0xA, Compare 2: ', a_str[v30], v74[v30+1])
    			if a_str[v30] != v74[v30+1]:
    				print('Failed!')
    				return 0
    			v30 = v30 + 1
    	
    	return 0
    	
    	
    def sub_4010B7(s, length):
    	
    	res = []
    	for i in range(length):
    		v4 = ord(s[i])
    		v5 = 48
    		if v4 >= 58:
    			v5 = 55
    		res.append((v4 - v5) & 0xFF) 
    		#res.append(chr((v4 - v5) & 0xFF))
    	#print(''.join(res))
    	
    	return res
    	
    
    def sub_40106C():
    	
    	v1 = []
    	
    	for i in range(1024):
    		v2 = i
    		v3 = 8
    		for j in range(8):
    			if (v2 & 1) != 0:
    				tmp = 0xEDB88320
    			else:
    				tmp = 0
    			if v2 >= 0x80000000:
    				v2 = ((v2 >> 1) | 0x80000000) ^ tmp
    			else:
    				v2 = (v2 >> 1) ^ tmp
    			#print(hex(v2))
    		v1.append(v2)
    	v1.append(1)
    	
    	return v1
    
    	
    if __name__ == '__main__':
    
    	#s = 'A7AKCTF381654729'
    	#res = func(s)
    	'''
    	# Fuzz One For Last 9 Bytes
    	prefix = 'A7AKCTF'
    	maybe_result = []
    	
    	example = '123456789'
    	result = itertools.permutations(example)
    	for x in result:
    		suffix = ''.join(x)
    		s = prefix + suffix
    		#print(s)
    		res = func(s)
    		if res == 1:
    			print(res, s)
    			break
    	
    	print(maybe_result)
    	'''
    	
    	'''
    	# Fuzz Two For First 3 Bytes
    	suffix = 'KCTF381654729'
    	text = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVMXYZ'
    	result = itertools.permutations(text, 3)
    	for x in result:
    		prefix = ''.join(x)
    		s = prefix + suffix
    		#print(s)
    		res = func(s)
    		if res == 1:
    			print(res, s)
    			break
    	'''


    2022-5-13 22:22
    0
    雪    币: 8740
    活跃值: (6634)
    能力值: ( LV12,RANK:207 )
    在线值:
    发帖
    回帖
    粉丝
    4
    htg Part 0xC: res = func(s) 这个func是如何关联到程序的?
    定义了一个func,然后在main中去调用,代码写的比较呆,但恰好可以解出答案,两次fuzz都是单独去执行的。我在fuzz后9位的时候将func的返回值设置为1;fuzz前3位的时候,把Part 0x3~0xA都注释掉,然后将返回值设置为0
    2022-5-13 22:28
    0
    雪    币: 5568
    活跃值: (3218)
    能力值: ( LV12,RANK:407 )
    在线值:
    发帖
    回帖
    粉丝
    5
    2022-5-13 22:49
    0
    游客
    登录 | 注册 方可回帖
    返回
    //