首页
社区
课程
招聘
[原创]看雪10月ctf2017 TSRC 第三题——开源CrackMe
2017-10-29 18:27 2394

[原创]看雪10月ctf2017 TSRC 第三题——开源CrackMe

2017-10-29 18:27
2394

https://github.com/zhicheng/base64

这是Base64用的源代码

https://github.com/siddontang/pygmcrypto

这是sm3用的源代码,用的是sm3.h和sm3.c这两个文件
再来看看IDA的F5代码。。。
if ( (unsigned __int16)a3 == 1002 )
    {
      input[0] = 0;
      memset(&input[1], 0, 1023);
      input_dec1[0] = 0;
      memset(&input_dec1[1], 0, 1023);
      v4 = GetDlgItemTextA(hDlg, 1001, input, 1025);
      v23 = ret_a2(&v11 == &v11, v4);           // wojue de mei sha luan yong
      input_dec2[0] = 0;
      memset(&input_dec2[1], 0, 1023);
      base64_decode((int)input, 1024, (int)input_dec1);//开源的
      vbuf19[0] = 0;
      memset(&vbuf19[1], 0, 1023);
      base64_decode((int)input_dec1, 1024, (int)input_dec2);
      some_alg2((int)input_dec2, (int)vbuf19, 1024);
      v18 = 3;
      sm3(input_dec2, 3, sm3_hash);             // 也是开源的
      for ( i = 0; i < 32; ++i )
        sprintf((int)&v16[2 * i], "%02x", (unsigned __int8)sm3_hash[i]);
      _64 = strlen(v16);
      v6 = &input[strlen(input)];
      _1_64 = strlen(v16);
      if ( !memcmp((int)v16, (int)&v6[-_1_64], _64) )
      {
        sub_42D0B4(v11, v12, v13);
        if ( (unsigned __int8)final_critical_need_a2_haspace(&unk_49B000, vbuf19) == 1 )
        {
          v8 = MessageBoxA(0, "ok", "CrackMe", 0);
          ret_a2(&v11 == &v11, v8);
        }
      }
    }
说说我是怎么找到这个源代码的吧。。
我是先逆那个base64,感觉这个有点熟悉,我觉得可能是base64,然后写注册机的时候,想在github上找个base64来用,结果卧槽,发现一模一样
然后逆这个sm3的时候,在里面某个函数定位到了这样的特征字符串。。。
 sub_42E22A((int)"\n", v17);
  for ( i = 0; i < 64; ++i )
    v37[i] = *(&v47 + i) ^ *(&v43 + i);
  sub_42E22A((int)"Expanding message W'0-63:\n", v18);
  for ( j = 0; j < 64; ++j )
  {
    sub_42E22A((int)"%08x ", v37[j]);
    if ( !((j + 1) % 8) )
      sub_42E22A((int)"\n", v19);
  }
  sub_42E22A((int)"\n", v19);
  v36 = a1->dw_arr[0];
  v35 = a1->dw_arr[1];
  v34 = a1->dw_arr[2];
  v33 = a1->dw_arr[3];
  v32 = a1->dw_arr[4];
  v31 = a1->dw_arr[5];
  v30 = a1->dw_arr[6];
  v29 = a1->dw_arr[7];
  sub_42E22A((int)"j     A       B        C         D         E        F        G       H\n", v3);
  sub_42E22A((int)"   %08x %08x %08x %08x %08x %08x %08x %08x\n", v36);
然后是撸出了他的验证算法:

len(input) == 64


sm3(base64dec(base64dec(input))[0..3)) == input

sm3(str[0..3)) == base64(base64(str))

base64dec(base64dec(sm3(str[0..3)))) == str

其实应该还有就是我那个some_alg2 和 final_check == 1的两个算法当时我没逆了,,,看他的代码有点懵逼。。
所以就是找一个三个字符的字符串str1,使得对他进行sm3哈希运算之后base64解密两次的结果字符串str2的前面三个字符要等于str1,
然后我暴力破解,发现无解。。。
然后看了看算base64的代码,作者有个Bug,当传入的是非法Base64字符串时,不会对其合法性(返回值)进行检查,所以如果是传入
"\x00\x00\x00"的sm3哈希时,dec第二次会导致结果是空字符串(初始会memset成0,然后decode失败不对结果缓冲区进行处理。。)
所以可以前三个字符串相等。。。
爆破代码如下。。
#include "base64.h"
#include "sm3.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define UPPER_BOUND_OF_3BYTES 0x01000000
#define SM3_LEN 32
#define SM3_LEN_ASCII (SM3_LEN * 2)
#define SM3_LEN_ASCII_BUFLEN (SM3_LEN_ASCII + 1)
#define BASE64X1_LEN (SM3_LEN_ASCII / 4 * 3)
#define BASE64X2_LEN (BASE64X1_LEN  / 4 * 3)
#define BUF_LEN 1024

int flag;
char sm3_hash[SM3_LEN];
char ascii_hash[SM3_LEN_ASCII_BUFLEN];
char base64_dec1[BUF_LEN];
char base64_dec2[BUF_LEN];

void get_ascii_hash(char* hash, char* ret)
{//pre: ret has size (SM3_LEN*2+1)
	for (int i = 0; i < SM3_LEN; ++i)
		sprintf(&ret[2 * i], "%02x", (unsigned __int8)hash[i]);
	ret[SM3_LEN_ASCII] = 0;
}
/*
sm3(base64dec(base64dec(input))[0..3)) == input

sm3(str[0..3)) == base64(base64(str))
base64dec(base64dec(sm3(str[0..3)))) == str
*/

int isBase64Char(char c)
{
	return ((c | 32) >= 'a' && (c | 32) <= 'z') || c == '=' || c == '+' ||
		c == '/' || (c >= '0' && c <= '9');
}

int firstThreeSame(char* a1, char* a2)
{
	return a1[0] == a2[0] && a1[1] == a2[1] && a1[2] == a2[2];
}

int isValidBase64(char* base64, int len)
{
	for (int i = 0; i < len; i++)
	{
		if (!isBase64Char(base64[i]))
		{
			return 0;
		}
	}
	return 1;
}

int main()
{
	for (flag = 0; flag < 0x01000000; flag++)
	{
		if ((flag & 0xffff) == 0)
		{
			printf("%d\n", flag);
		}
			
		sm3((unsigned char*)&flag, 3, sm3_hash);
		get_ascii_hash(sm3_hash, ascii_hash);
		memset(base64_dec1, 0, BUF_LEN);
		base64_decode(ascii_hash, /*SM3_LEN_ASCII*/BUF_LEN, base64_dec1);
		memset(base64_dec2, 0, BUF_LEN);
		if (base64_decode(base64_dec1, /*BASE64X1_LEN*/BUF_LEN, base64_dec2))
		{
			//continue;
		}
		/*else
		{
			base64_decode(base64_dec1, BASE64X1_LEN, base64_dec2);
		}//*/
		base64_dec2[BASE64X2_LEN] = 0;
		if (firstThreeSame(base64_dec2, (char*)&flag))
		{
			printf("%s\n", ascii_hash);
			printf("%s\n", base64_dec2);
			printf("%s\n", &flag);
			//system("pause");
		}
	}
	system("pause");
}
//这个代码写的比较丑,因为一开始不利用漏洞跑的话一直无解,所以急了。。。最后直接把他的算法直接搬过来了。。。缓冲区用的也是跟他一样的长度。。。

输出。。。

183920f00e15a0433ee3a8fc90dd9ac164c4142ccf63ca189a8f645ec96ff8de a56c3b235fd9802a919afbb7b90d1944532c249e785333b8efd3dacb9d72e63f

第二个试一下,不行,

第一个试一下,过了。。。

不过真的是薛定谔的CM,有时候能过有时候不行。。。

很迷,,,不过反正提交这个能过。。。
PS:我nop掉的反调试的版本过不了,迷醉。。。不知道为什么,没去分析了。。。

然后这个题其实是昨天做出来的,今天搜索some_alg2的特征字符串,发现。。。
嗯,也是开源的。。。

https://github.com/robert1207/morse_encode

(看静态字符串一堆-*的时候我就觉得有可能是摩斯。。。

最近事有点多。。还要用OCaml写个编译器。。。 所以这个WP没写的很详细,就说了下我怎么找到github上源代码的思路和一点解题思路。。可能用的也是程序的bug。。。不知道作者原意是啥。。。那个公式的确是无解的。。 明天等其他大佬的WP吧。。

[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回