首页
社区
课程
招聘
[原创] 看雪CTF2018-第四题-密界寻踪writeup
2018-6-23 19:57 4079

[原创] 看雪CTF2018-第四题-密界寻踪writeup

2018-6-23 19:57
4079

目录

0x00 初步分析程序

0x01 破解第一处验证

0x02 破解第二处验证

0x03 最终脚本


0x00 初步分析程序

由题目提示,应该是使用了一些加密算法,先使用PEID的一个插件看下有没有常见加密算法特征:

看到程序使用了Miracl大数库和S盒,可能是调用了AES算法,IDA打开,先shift+f5加载miracl大数库和常见加密函数的签名(签名文件放在https://github.com/sherlly/encryption了,需要自取~):


开始分析程序,发现程序中存在不少花指令,用于干扰IDA正常反编译:

通过加入一些无关的call指令,使堆栈不平衡,在IDA中体现为sp-analysis failed,也就是不能F5反编译,可以手动去花,但其实在这道题中,逻辑比较清楚,不能F5的关系也不大(好吧就是懒-。-)

根据字符串搜索,可以确定打印欢迎信息的位置:

xor_enc函数是将输入的字符串进行简单的异或操作得到解密的字符串:

接着定位到主函数中,可以看到输入的地方:

之后进入的应该就是验证逻辑,首先将输入的字符串进行分割,前3位进入验证函数2进行校验,后20位进入验证函数1校验:



具体验证函数的算法见下面分析。

0x01 破解第一处验证

进入第一处验证函数处,首先看到的是一些赋值的操作:

接下来同样调用了xor_enc函数对刚刚赋值的数据进行异或解密,动态调试记录下两个值为208CBB7CD6ECC64516D07D978F5F0681F534EAD235D5C49ADD72D2DB840D5304和7da39de66016477b1afc3dc8e309dc429b5de855f0d616d225b570b68b88a585,后面可以知道是校验用的密文和模数n:


接下来在函数中调用了大数库miracl,一些函数功能可以参考文章https://blog.csdn.net/shuilan0066/article/details/8520337

首先是调用mirvar函数进行赋值的操作,然后调用cinstr函数将大数字符串转换成大数:

看到调用了幂模函数powmod,猜想是使用了RSA算法:


在使用RSA进行加密后,将得到的密文和刚刚初始化的一段密文进行校验,相等则返回1:


尝试恢复下验证函数1的源码:

int RSA_ENC()
{
	xor_enc(enc_data1,n_str);     //生成模数n
	// 7da39de66016477b1afc3dc8e309dc429b5de855f0d616d225b570b68b88a585
	xor_enc(enc_data2,c_check);   //生成校验用的密文
	// 208CBB7CD6ECC64516D07D978F5F0681F534EAD235D5C49ADD72D2DB840D5304
	hex_encode(input,hex_input);  //input为输入字符串的后20位
	mirsys(0x1f4,16);             //初始化500位的16进制数
	c=mirvar(0);                  //初始化为miracl大数类型的0                 
	n=mirvar(0);
	e=mirvar(0);
	m=mirvar(0);

	cinstr(m,hex_input);
	cinstr(n,n_str);                // 模n    
	cinstr(e,"3e9");                // e
	powmod(m,e,n,c);                // c = (m ^ e) mod n
	big_to_bytes(0,c,c_str,0);      //将大数转换为字符串

	mirkill(c);
	mirkill(n);
	mirkill(e);
	mirkill(m);
	mirexit();

	output_enc(c_str,output_hex,strlen(c_str));
	if(strcmp(output_hex,c_check) == 0)
		return 1;
	else
		return 0;
}
因此,验证函数1的破解可以转换为RSA攻击中的经典问题,已知模数n,指数e,密文c,如何求明文m。这里模数n可以通过大数分解网站(http://factordb.com)分解,得到p,q。解密脚本见最后,解密得到的明文为iamahandsomeguyhaha1:

0x02 破解第二处验证

验证函数2对输入字符串的前3位进行校验,首先调用了check_digit函数校验是否满足都是纯数字:

可以进入该函数看下:


接下来进入验证函数2,在该函数中,首先也是调用了xor_enc函数解密了两个字符串0001314000000000和912CA2036A9A0656D17B6B552F157F8E,后面可以知道是原始的key和校验用的密文:



然后可以看到,函数将输入的前三位写入到了刚刚初始化的key的前三位中,并且第三位进行了加1的操作,得到最终的密钥key:


接下来调用了AES加密算法,动态调试可以知道加密的明文为pediy:


最后将加密后的密文和刚刚生成的校验的密文进行比较,相同则返回1:


因此,验证函数2的破解为爆破密钥,得到符合的密文,由于是纯数字,且未知的只有3位,破解速度很快,写脚本跑下得到密钥为521,因为在生成密钥时加了1,所以原始的输入应该是520:


输入完整flag验证下,成功:


flag:520iamahandsomeguyhaha1

0x03 最终脚本

# coding:utf-8
# author:sherllyyang00@gmail.com
flag_len = 23
serial="rgqmdj="  # i=0; xor i;i++ serial:
def get_part2():
	c_check=0x208CBB7CD6ECC64516D07D978F5F0681F534EAD235D5C49ADD72D2DB840D5304
	n=0x7da39de66016477b1afc3dc8e309dc429b5de855f0d616d225b570b68b88a585
	e=0x3e9  #1001
	p=208096057845685678782766058500526476379
	q=273086345401562743300402731618892888991
	def egcd(a, b):
		if a==0:
			return (b,0,1)
		else:
			g, y, x = egcd(b%a, a)
			return (g, x-(b//a)*y, y)
	def modinv(a, m):
		g, x, y = egcd(a, m)
		if g!=1:
			raise Exception('modular inverse does not exist')
		else:
			return x%m

	d=modinv(e,(p-1)*(q-1))
	m=pow(c_check,d,n)
	flag2 = hex(m)[2:-1].decode('hex')
	print flag2
	# iamahandsomeguyhaha1
	return flag2

def get_part1():
	from Crypto.Cipher import AES
	import string
	enc_s="831GD47;?K2M=8:&U#$V#T\"-+\\*)*X'e"
	enc_key="123567389:;<=>?"
	plain="pediy"
	enc_check="912CA2036A9A0656D17B6B552F157F8E"
	def encrypt(plain,key):
		bs = AES.block_size
		plain = plain+"\x00"*(bs-len(plain))
		cipher = AES.new(key)
		return cipher.encrypt(plain).encode('hex').upper()

	table = string.digits
	for i in table:
		for j in table:
			for k in table:
				key="%s1314000000000"%(i+j+k)
				enc = encrypt(plain,key)
				if enc == enc_check:
					print "key: "+i+j+k
					flag1=i+j+chr(ord(k)-1)
					return flag1
	return 0
			
flag2=get_part2()
flag1=get_part1()
print flag1+flag2
# 520iamahandsomeguyhaha1


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞1
打赏
分享
最新回复 (6)
雪    币: 223
活跃值: (32)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
泪落晨曦 2018-7-3 19:56
2
0
大佬真的厉害,请教下sig文件需要怎么使用的呢,我把这个文件放在7.0和6.8版本的ida sig目录里,加载文件里都找不到这两个sig
雪    币: 155
活跃值: (120)
能力值: ( LV13,RANK:330 )
在线值:
发帖
回帖
粉丝
sherlly 4 2018-7-3 22:08
3
0
泪落晨曦 大佬真的厉害,请教下sig文件需要怎么使用的呢,我把这个文件放在7.0和6.8版本的ida sig目录里,加载文件里都找不到这两个sig
你放到sig目录下的pc目录试试
雪    币: 223
活跃值: (32)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
泪落晨曦 2018-7-6 14:16
4
0
sherlly 你放到sig目录下的pc目录试试
厉害了,确实放在pc目录下就能识别了,感谢大佬
雪    币: 1699
活跃值: (760)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
wx_Dispa1r 2018-7-9 22:48
5
0
萌新想问sig怎么生成的QAQ,自己编译的miracl.lib一直没法生成
雪    币: 9
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
之幽灵 2018-7-25 11:20
6
0
factordb输入是不是需要10进制数呀,如何把大数16进制转换成10进制,网上好多工具都溢出了?
雪    币: 714
活跃值: (82)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
xyy吸氧羊 2018-8-1 17:08
7
0
之幽灵 factordb输入是不是需要10进制数呀,如何把大数16进制转换成10进制,网上好多工具都溢出了?
直接用python的语法:int('需要转换的数字', 16)
游客
登录 | 注册 方可回帖
返回