SSCTF线上赛解题报告Part1(逆向部分)

2016-03-01 301611人围观 ,发现 12 个不明物体 头条

*原创作者:Nu1L团队

XCTF中文.jpg

第二届SSCTF大赛上周落下帷幕,本系列是最终排名第三的Nu1L_XCTF团队带来的解题报告,分为逆向部分(Reverse)、杂项部分(Misc)、解密和溢出(Crypto&Exploit)、Web四个部分。

SSCTF队伍排名.png

逆向部分(Reverse)

Re100

这题很简单,首先判断用户名是否等于secl-007

re1.png

然后调用动态链接库中的getpl函数验证password,由于在函数中没有对password做处理,因此可以忽略中间的DES加密,输入39个字符或者修改寄存器的值,在最后判断的时候下断,动态调试下就能得到flag

re2.png

flag为oty3eaP$g986iwhw32j%OJ)g0o7J.CG:

Re200

拿到程序打开运行,输入任意字符串后,发现一段Bad Apple的MV… 动画结束后有验证过程。

首先查壳,发现是加过UPX壳的。upx -d 脱掉之后开始分析程序:

发现在402800处是播放动画的代码,但其中有几条关键的ResumeThread,于是nop掉动画部分代码:

re3.png

接下来根据ResumeThread处的代码找到了创建线程的位置:

re4.png

继续分析这些线程 ,发现了验证Flag的位置,根据线程运行顺序可以反向写出解密代码:

脚本:

#!/usr/bin/env python2
# -*- coding:utf-8 -*-

import hashlib
import numpy as np

def u8(x):
    return np.uint8(x)

'''
  hash[0] = -3;
    hash[2] = -3;
      hash[1] = -59;
        hash[3] = -25;
          hash[5] = -25;
            hash[4] = -59;
              hash[6] = -57;
                hash[8] = -57;
                  hash[7] = -27;
                    hash[10] = -27;
                      hash[9] = -35;
                        hash[11] = -35;
                          hash[12] = 0;
'''

md5res = 'FBC4A31E4E17D829CA2242B2F893481B'.lower()
#print md5res
d = [253,197,253,231,197,231,199,229,199,221,229,221]
#d = [u8(c) for c in data]
#print d
for x in range(256):
    p = ''.join([chr(c^x) for c in d])
    md5 = hashlib.new('md5')
    for c in p:
	if ord(c) == 0: break
	md5.update(c)
    if md5.hexdigest() == md5res: print x

# key1 = 181
v0 = (181 - 1)^2
print v0

# v0 = 182
byte_404048 = [0x57,0x78,0x7d,0x3e,0x4a,0x4c,0x5c,0x35,0x2a,0x23,0x50,0x7f,0x57,0x78,0x55,0x64,0x4b,0x42,0x25,0x35,0x22,0x66,0x48]
for x2 in range(256):
	xored = [c^x2 for c in byte_404048]
	sum = 0
	for c in xored:
		if c == 0: break
		sum ^= c
	if sum == 182:	print x2

print '-------'
# 152
for x3 in range(256):
	if ((x3^0x5a)+(x3^0x42)) == 152: print x3

print '------'
d3 = [0xF5, 0xD0, 0xDF, 0xDC, 0x99, 0xD8, 0xD5, 0xCE, 0xD8, 0xC0, 0xCA, 0x99, 0xD4, 0xD8, 0xD2, 0xDC, 0xCA, 0x99, 0xCC, 0xCA, 0x99, 0xDB, 0xD5, 0xD8, 0xDA, 0xD2, 0x99, 0xD8, 0xD7, 0xDD, 0x99, 0xDB, 
0xD5, 0xCC, 0xDC, 0x95, 0xD8, 0xD7, 0xDD, 0x99, 0xCD, 0xD1, 0xD6, 0xCA, 0xDC, 0x99, 0xCE, 0xD1, 
0xDC, 0xCB, 0xDC, 0x99, 0xCD, 0xD1, 0xDC, 0x99, 0xCE, 0xD6, 0xCC, 0xD7, 0xDD, 0x99, 0xD1, 0xD8, 
0xDD, 0x99, 0xDB, 0xDC, 0xDC, 0xD7, 0x99, 0xCD, 0xD1, 0xDC, 0x99, 0xCA, 0xCD, 0xCB, 0xD6, 0xD7, 
0xDE, 0xDC, 0xCA, 0xCD, 0x99, 0xCE, 0xD0, 0xD5, 0xD5, 0x99, 0xDB, 0xDC, 0xDA, 0xD6, 0xD4, 0xDC, 
0x99, 0xD8, 0x99, 0xC9, 0xD5, 0xD8, 0xDA, 0xDC, 0x99, 0xCE, 0xD1, 0xDC, 0xCB, 0xDC, 0x99, 0xCE, 
0xDC]

valid = []
for x4 in range(256):
	d3_xored = [x4^c for c in d3]
	xor_sum = 0
	for c in d3_xored:
		if c == 0: break
		xor_sum ^= c
	if (xor_sum^0x5a)+(xor_sum^0x42) == 152: valid.append(x4)

v = [c^0xC6 for c in valid]
n2 = [0x88, 0xEC, 0xFC, 0x9E, 0xB9, 0xFC, 0xB3, 0xAE, 0xFC, 0x92, 0xB3, 0xA8, 0xFC, 0x88, 0xB3, 0xFC, 
0x9E, 0xB9, 0xF0, 0x88, 0xB4, 0xBD, 0xA8, 0xFC, 0xB5, 0xAF, 0xFC, 0x88, 0xB4, 0xB9, 0xFC, 0x8D, 
0xA9, 0xB9, 0xAF, 0xA8, 0xB5, 0xB3, 0xB2]

v13_valid = []

for v13 in range(256):
	n2_xored = [v13^c for c in n2]
	n2xor_sum = 0
	for c in n2_xored:
		if c == 0: break
		n2xor_sum ^= c
	if n2xor_sum in v: v13_valid.append(v13)

print v13_valid

sums = []
for c in v13_valid:
	s3 = c ^ 0x6f
	s2 = c ^ 0x18
	s1 = c ^ 0x77
	s0 = c ^ 0x66
	if ((s0 + s1 + s2 + s3) & 0xFF) == 0xDC:
		sums.append([s0,s1,s2,s3])

ff = []
l = [0x63, 0x36, 0x37, 0x38, 0x64, 0x36, 0x67, 0x36, 0x34, 0x33, 0x30, 0x37, 0x67, 0x66, 0x34, 0x67,
0x60, 0x62, 0x32, 0x36, 0x33, 0x34, 0x37, 0x33, 0x67, 0x65, 0x33, 0x35, 0x62, 0x35, 0x60, 0x39]
for sum in sums:
	print sum
	f = [0]*32
	for i in range(4):
		s = sum[i]
		for j in range(8):
			if s & 1: f[i*8+7-j] = 1
			s >>= 1
	print f
	k = []
	for i in range(32):
		k.append(l[i]^f[i])
	print ''.join([chr(c) for c in k])	
		
'''
l = [0x63, 0x36, 0x37, 0x38, 0x64, 0x36, 0x67, 0x36, 0x34, 0x33, 0x30, 0x37, 0x67, 0x66, 0x34, 0x67, 
0x60, 0x62, 0x32, 0x36, 0x33, 0x34, 0x37, 0x33, 0x67, 0x65, 0x33, 0x35, 0x62, 0x35, 0x60, 0x39]
for i in range(32):
	l[i] ^= ff[i]

flag = ''.join([chr(c) for c in l])
print flag

flag = 'c678d6g65216fg5f`b263473fd24c4a8'
sum0 = 0
sum1 = 0
sum2 = 0
sum3 = 0
for i in range(8):
	sum0 = sum0 * 2 + (ord(flag[i])^l[i])
	sum1 = sum1 * 2 + (ord(flag[8+i])^l[8+i])
	sum2 = sum2 * 2 + (ord(flag[16+i])^l[16+i])
	sum3 = sum3 * 2 + (ord(flag[24+i])^l[24+i])

print sum0&0xff,sum1&0xff,sum2&0xff,sum3&0xff
'''

发现答案有多解,经过尝试发现 Flag 为:b669e6f65317ff5fac263573fe24b5a8

Re300

典型坑人题,真实的验证按钮是隐藏的。

首先拖入IDA分析,发现是MFC写程序。于是直接上xspy进行分析。

re5.png

发现有两个OnCommand处理例程,而且id不相同。

由于习惯静态分析,于是直接上PE Explorer

re6.png

发现id=03ec这个按钮是存在的。

于是直接使用ViewWizard修改控件属性

捕获窗口,右键定位到窗口列表,展开,右键捕获隐藏的按钮,点显示即可强制令其显示。

re7.png

之后就显示了

re8.png

当然,其实真正的罪魁祸首是在0x004015D0

re9.png

调用了0x41276E这个库函数,其中调用ShowWindow将真实按钮的显示状态改成了SW_HIDE

于是之后点击这个真正的验证按钮,就来到了0x401FE0这里

然后进入验证函数0x401F80

re10.png

在GetBody函数中,会首先判断输入的格式为SSCTF{32位},并将前后的SSCTF{和}去掉,保留中间的不封。

然后在GetHash部分中,会对输入进行变换

re11.png

首先寻找’0’的所在位置,

接着按照这些已经计算出来的值进行变换,对大小写字母、数字分别处理

re12.png

发现变换后的值和所在位置无关,仅和长度和’0’所在的位置有关,所以直接复制到vs中输出对应的变换。

之后在FinalVerify中会进行判断和输出结果。不过出题人好狠,一个可见字符串都不给,还用这么常见的加密手段,害的我这边数字公司一只都在拦截。。。

继续将hexrays的内容拷贝到vs中解密,得到分别是”Pls Try ag@in!”,” Y0u G0t 1t!” 和“b5h760h64R867618bBwB48BrW92H4w5r”

通过上步生成的表进行查表,得到原始内容为f5b760b64D867618fFeF48FdE92B4e5d

因此正确输入为SSCTF{f5b760b64D867618fFeF48FdE92B4e5d}

Flagf5b760b64D867618fFeF48FdE92B4e5d

附上本题脚本:

	// re300.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "windows.h"
#include "atlstr.h"

int _tmain(int argc, _TCHAR* argv[])
{
	char v6[12]; // [sp+8h] [bp-4Ch]@1
	char Text[15]; // [sp+14h] [bp-40h]@1
	char target[33]; // [sp+24h] [bp-30h]@1

	target[4] = 7;
	target[7] = 7;
	target[11] = 7;
	target[13] = 7;
	target[2] = 89;
	target[17] = 115;
	target[19] = 115;
	target[22] = 115;
	target[6] = 89;
	target[23] = 67;
	target[31] = 67;
	target[0] = 83;
	target[1] = 4;
	target[3] = 6;
	target[5] = 1;
	target[8] = 5;
	target[9] = 99;
	target[10] = 9;
	target[12] = 6;
	target[14] = 0;
	target[15] = 9;
	target[16] = 83;
	target[18] = 70;
	target[20] = 5;
	target[21] = 9;
	target[24] = 102;
	target[25] = 8;
	target[26] = 3;
	target[27] = 121;
	target[28] = 5;
	target[29] = 70;
	target[30] = 4;
	target[32] = 0;
	v6[6] = 100;
	v6[9] = 100;
	Text[3] = 100;
	Text[7] = 100;
	v6[0] = 73;
	v6[1] = 32;
	v6[2] = 101;
	v6[3] = 48;
	v6[4] = 87;
	v6[5] = 32;
	v6[7] = 48;
	v6[8] = 33;
	v6[10] = 49;
	v6[11] = 0;
	Text[0] = 20;
	Text[1] = 40;
	Text[2] = 55;
	Text[4] = 16;
	Text[5] = 54;
	Text[6] = 61;
	Text[8] = 37;
	Text[9] = 35;
	Text[10] = 4;
	Text[11] = 45;
	Text[12] = 42;
	Text[13] = 101;
	Text[14] = 0;
	int v1 = 0;
	do
	{
		target[v1] ^= 0x31u;
		++v1;
	} while (v1 < 32);
	int v2 = 0;
	if (strlen(v6) != 0)
	{
		do
		{
			v6[v2] ^= 0x10u;
			++v2;
		} while (v2 < strlen(v6));
	}
	int v3 = 0;
	if (strlen(Text) != 0)
	{
		do
		{
			Text[v3] ^= 0x44u;
			++v3;
		} while (v3 < strlen(Text));
	}

	char tihuan_low[27];
	char tihuan_cap[27];
	for (char i = 'a'; i<='z'; i++){
		char ori_chr = i;
		BOOL target = 0;
		if (ori_chr > '9' || ori_chr < '0')
		{                                         // 非数字
			if (ori_chr > 'z' || ori_chr < 'a')
			{                                       // 非小写
				if (ori_chr <= 'Z' && ori_chr >= 'A')
					ori_chr -= 'A';                     // 大写转字母表中顺序
			}
			else
			{
				ori_chr -= 'a';                       // 小写转字母表中顺序
				target = 1;
			}
			int v9 = (28 + 5 * ori_chr) % 26 + ((28 + 5 * ori_chr) % 26 < 0 ? 26 : 0);// 
			// 是字母
			if (target)
			{                                       // 是小写字母
				if (target == 1)
					v9 = (char)(v9 + 'a');
			}
			else
			{                                       // 是大写字母
				v9 = (char)(v9 + 'A');
			}
			//printf("%c - %c\n", i, (char)v9);
			tihuan_low[i - 'a'] = (char)v9;
			tihuan_cap[i - 'a'] = toupper(v9);
		}
	}
	tihuan_low[26] = 0;
	tihuan_cap[26] = 0;
	//char tihuan_cap[] = "CHMRWBGLQVAFKPUZEJOTYDINSX";
	//char tihuan_low[] = "chmrwbglqvafkpuzejotydinsx";
	//char target[] = "b5h760h64R867618bBwB48BrW92H4w5r";
	char *out = new char[strlen(target)+1];
	out[strlen(target)] = 0;
	for (int i = 0; i < strlen(target); i++){
		if (target[i] >= '0' && target[i] <= '9'){
			out[i] = target[i];
		}
		else if (target[i] >= 'a' && target[i] <= 'z'){
			for (int j = 0; j < strlen(tihuan_low); j++){
				if (tihuan_low[j] == target[i]){
					out[i] = 'a' + j;
				}
			}
		}
		else if (target[i] >= 'A' && target[i] <= 'Z'){
			for (int j = 0; j < strlen(tihuan_cap); j++){
				if (tihuan_cap[j] == target[i]){
					out[i] = 'A' + j;
				}
			}
		}
	}
	/*HCRYPTHASH phHash;
	HCRYPTPROV phProv;
	DWORD pdwDataLen;
	CString tempstr;
	
	UINT64 true_answ = 0;
	char target[] = { 0x48,0x50,0xB7,0x44,0x6B,0xBB,0x20,0xAA,0xD1,0x40,0xE7,0xB0,0xA9,0x64,0xA5,0x7D };
	for (UINT64 seed = 2453148193;; seed += 4294967296){
		BOOL bRight = TRUE;
		tempstr.Format("%I64d", seed);
		printf("%s\n", tempstr.GetBuffer());
		if (CryptAcquireContextA(&phProv, 0, 0, 1u, CRYPT_VERIFYCONTEXT))
		{
			if (CryptCreateHash(phProv, CALG_MD5, 0, 0, &phHash))
			{
				if (CryptHashData(phHash, (BYTE *)tempstr.GetBuffer(), tempstr.GetLength(), 0))
				{
					char pbData[64];
					memset(pbData, 0, 64);
					pdwDataLen = 64;
					CryptGetHashParam(phHash, HP_HASHVAL, (BYTE *)pbData, &pdwDataLen, 0);
					for (int i = 0; i < 16; i++){
						if (pbData[i] != target[i]){
							bRight = FALSE;
							break;
						}
						//bRight = TRUE;
					}
					if (bRight){
						true_answ = seed;
						break;
					}
				}
			}
		}
	}*/
	
	system("pause");
	return 0;
}
	// re300.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "windows.h"
#include "atlstr.h"

int _tmain(int argc, _TCHAR* argv[])
{
	char v6[12]; // [sp+8h] [bp-4Ch]@1
	char Text[15]; // [sp+14h] [bp-40h]@1
	char target[33]; // [sp+24h] [bp-30h]@1

	target[4] = 7;
	target[7] = 7;
	target[11] = 7;
	target[13] = 7;
	target[2] = 89;
	target[17] = 115;
	target[19] = 115;
	target[22] = 115;
	target[6] = 89;
	target[23] = 67;
	target[31] = 67;
	target[0] = 83;
	target[1] = 4;
	target[3] = 6;
	target[5] = 1;
	target[8] = 5;
	target[9] = 99;
	target[10] = 9;
	target[12] = 6;
	target[14] = 0;
	target[15] = 9;
	target[16] = 83;
	target[18] = 70;
	target[20] = 5;
	target[21] = 9;
	target[24] = 102;
	target[25] = 8;
	target[26] = 3;
	target[27] = 121;
	target[28] = 5;
	target[29] = 70;
	target[30] = 4;
	target[32] = 0;
	v6[6] = 100;
	v6[9] = 100;
	Text[3] = 100;
	Text[7] = 100;
	v6[0] = 73;
	v6[1] = 32;
	v6[2] = 101;
	v6[3] = 48;
	v6[4] = 87;
	v6[5] = 32;
	v6[7] = 48;
	v6[8] = 33;
	v6[10] = 49;
	v6[11] = 0;
	Text[0] = 20;
	Text[1] = 40;
	Text[2] = 55;
	Text[4] = 16;
	Text[5] = 54;
	Text[6] = 61;
	Text[8] = 37;
	Text[9] = 35;
	Text[10] = 4;
	Text[11] = 45;
	Text[12] = 42;
	Text[13] = 101;
	Text[14] = 0;
	int v1 = 0;
	do
	{
		target[v1] ^= 0x31u;
		++v1;
	} while (v1 < 32);
	int v2 = 0;
	if (strlen(v6) != 0)
	{
		do
		{
			v6[v2] ^= 0x10u;
			++v2;
		} while (v2 < strlen(v6));
	}
	int v3 = 0;
	if (strlen(Text) != 0)
	{
		do
		{
			Text[v3] ^= 0x44u;
			++v3;
		} while (v3 < strlen(Text));
	}

	char tihuan_low[27];
	char tihuan_cap[27];
	for (char i = 'a'; i<='z'; i++){
		char ori_chr = i;
		BOOL target = 0;
		if (ori_chr > '9' || ori_chr < '0')
		{                                         // 非数字
			if (ori_chr > 'z' || ori_chr < 'a')
			{                                       // 非小写
				if (ori_chr <= 'Z' && ori_chr >= 'A')
					ori_chr -= 'A';                     // 大写转字母表中顺序
			}
			else
			{
				ori_chr -= 'a';                       // 小写转字母表中顺序
				target = 1;
			}
			int v9 = (28 + 5 * ori_chr) % 26 + ((28 + 5 * ori_chr) % 26 < 0 ? 26 : 0);// 
			// 是字母
			if (target)
			{                                       // 是小写字母
				if (target == 1)
					v9 = (char)(v9 + 'a');
			}
			else
			{                                       // 是大写字母
				v9 = (char)(v9 + 'A');
			}
			//printf("%c - %c\n", i, (char)v9);
			tihuan_low[i - 'a'] = (char)v9;
			tihuan_cap[i - 'a'] = toupper(v9);
		}
	}
	tihuan_low[26] = 0;
	tihuan_cap[26] = 0;
	//char tihuan_cap[] = "CHMRWBGLQVAFKPUZEJOTYDINSX";
	//char tihuan_low[] = "chmrwbglqvafkpuzejotydinsx";
	//char target[] = "b5h760h64R867618bBwB48BrW92H4w5r";
	char *out = new char[strlen(target)+1];
	out[strlen(target)] = 0;
	for (int i = 0; i < strlen(target); i++){
		if (target[i] >= '0' && target[i] <= '9'){
			out[i] = target[i];
		}
		else if (target[i] >= 'a' && target[i] <= 'z'){
			for (int j = 0; j < strlen(tihuan_low); j++){
				if (tihuan_low[j] == target[i]){
					out[i] = 'a' + j;
				}
			}
		}
		else if (target[i] >= 'A' && target[i] <= 'Z'){
			for (int j = 0; j < strlen(tihuan_cap); j++){
				if (tihuan_cap[j] == target[i]){
					out[i] = 'A' + j;
				}
			}
		}
	}
	/*HCRYPTHASH phHash;
	HCRYPTPROV phProv;
	DWORD pdwDataLen;
	CString tempstr;
	
	UINT64 true_answ = 0;
	char target[] = { 0x48,0x50,0xB7,0x44,0x6B,0xBB,0x20,0xAA,0xD1,0x40,0xE7,0xB0,0xA9,0x64,0xA5,0x7D };
	for (UINT64 seed = 2453148193;; seed += 4294967296){
		BOOL bRight = TRUE;
		tempstr.Format("%I64d", seed);
		printf("%s\n", tempstr.GetBuffer());
		if (CryptAcquireContextA(&phProv, 0, 0, 1u, CRYPT_VERIFYCONTEXT))
		{
			if (CryptCreateHash(phProv, CALG_MD5, 0, 0, &phHash))
			{
				if (CryptHashData(phHash, (BYTE *)tempstr.GetBuffer(), tempstr.GetLength(), 0))
				{
					char pbData[64];
					memset(pbData, 0, 64);
					pdwDataLen = 64;
					CryptGetHashParam(phHash, HP_HASHVAL, (BYTE *)pbData, &pdwDataLen, 0);
					for (int i = 0; i < 16; i++){
						if (pbData[i] != target[i]){
							bRight = FALSE;
							break;
						}
						//bRight = TRUE;
					}
					if (bRight){
						true_answ = seed;
						break;
					}
				}
			}
		}
	}*/
	
	system("pause");
	return 0;
}

Re400

脱壳,去花后开始分析

第一层在00401d25()函数里,如下图

re13.png

图中byte_41279c是输入的字符串,然后经过change_xor()函数变换后与固定一组字符比较,即V11V11两次异或3相当于没变。

re14.png

第一步密码:[Xi`An4YeCaoAnQuanGongSi][HP]

V11:

a3=[0x7C,0xCD,0x01,0x97,0x06,0x6F,0x2C,0x29,0xFC,0x31,0x09,0xDC,0x1D,0xF5,0x8F,0x7D,0xDE,0x30,0xB6,0x49,0xFD,0x0A,0xD9,0x89,0xFD,0x9F,0x4D,0x7D,0xA2]

V11可知,密码长度为29,于是随便输入29位数后,修改内存为0×00,此时a3的值就位异或对象a2的值,如下图

re15.png

整理出来

b2=[0x27,0x95,0x68,0xF7,0x47,0x01,0x18,0x70,0x99,0x72,0x68,0xB3,0x5C,0x9B,0xDE,0x08,0xBF,0x5E,0xF1,0x26,0x93,0x6D,0x8A,0xE0,0xA0,0xC4,0x05,0x2D,0xFF]

V11对应位异或,写脚本得到最后的结果为:

[Xi`An4YeCaoAnQuanGongSi][HP]

第二步:

sub_401473()里读入第二步密码,然后调用sub_401119()来验证。

re16.png

验证部分如下图,if条件固定了密码的前两位”[/”和最后两位/]”” Sub_401c7d是对索引做浮点数运算,最后求和得到V7,判断57.1<v7<57.2时走向正确流程,由此可推出密码2的长度为20

然后将V46与密码长度异或后得到的值与V8比较。则通过V8与密码长度异或就可以求出V46即第二步密码。

V8

a4=[0x3B,0x4C,0x7D,0x7A,0x5A,0x7D,0x75,0x7A,0x5F,0x61,0x75,0x7D,0x58,0x71,0x6A,0x3B]

0×14异或后得到/XinNianKuaiLe~/

最后拼接前两位于后两位   [//XinNianKuaiLe~//]

执行完sub_401473程序走到sub_401066弹出一段图片和音乐,一个白板转啊转。然后看DisplayFunc的函数sub_402921(),修改参数1.00 ,就可以得到FLAG了,glRotatef(angle, 0.0, 0.0, 1.0)

最后FLAG图片如下:

re18.png

然后就队友们各种猜,最后得到FLAG

FLAG{ETIJVA3E96GXZ+HP+E380}

Re500—–比赛时未作出来,赛后做

做了Re400的旋转以为脑洞很大了,谁知道这题的脑洞真的。。。

这题用了debug blocker反调试技术,子进程会开启一个服务器,父进程会读取[SsCTF]Re.txt的内容向子进程发送,子进程会处理收到的数据并把结果发送给父进程,之后会读取Port.txt的内容作为端口,向自身发送UDP请求,其中的一些细节后面会说到。

题目一共有三层,第一层的关键是解密sub_401945函数,队友写程序将所有的密钥情形都输出,发现0xE9解得有意义代码,解密完后的函数是

re19.png

其中sub_40153B是对接收的数据做base64编码,然后与VURQ比较,由此得出第一层的密码为UDP,而这个字符串的ASCII码相加也正好等于0xE9,这一层Port.txt的内容为2016,记录两个地方的值,后面会用到

第一个地方

re20.png

第二个地方

re21.png

这一层的EncryptKey为0xE9,v16为2016,因此第一个地方异或后得到

pr0oihsn1eMgylf@J88JJJ88J8J8J8JJJ8888JJJJJJJ8J8J8JJ88J8888J8JJJ888JJJJ8J8888888J

buf为05162b4d677092b4,这一层会输出It is UDP!

第二层,分析服务器处理接收数据的函数得到

re22.png

由此这一层要让ret返回1,能返回1的只能是sub_4019B5函数

re23.png

其中的sub_40170B是TEA加密算法,key为[0x44434241, 0x48474645, 0x4C4B4A49, 0x504F4E4D],密文为38 95 3C F0 4E 5A 57 89 6F 84 3E 01 BC 50 C8 5C 6A 7C 59 67EC BA 77 FD 73 2E,而TEA加密是8个字节一组,生成的密文长度是8的倍数,但这组的密文长度是26,最后两个字符不做处理,对前24个字节进行解密再加上最后两个字符得到第二层的密码为

WoyaoDuanKouHaoHeFlag,Pls. ,端口号为2447,这一层的EncryptKey为2446,之前上面那两处地方的第一处地方的数据为

re24.png

第二处的buf为0d1e23456f789abc,这一层输出Port:2447

最后要让ret返回2,而这个需要调用sub_4017CF函数

这个函数中是对接收到的数据进行哈夫曼编码,最后与0000110100011110001000110100010111101101011011110111100011111001101010111100对比,那对应关系在哪呢,开始脑洞

前面得到了

pr0oihsn1eMgylf@J88JJJ88J8J8J8JJJ8888JJJJJJJ8J8J8JJ88J8888J8JJJ888JJJJ8J8888888J

re26.png

05162b4d677092b4 没用

0d1e23456f789abc

上面图片中的后面部分看成高低电平,高电平代表1,低电平代表0,按照pr0oihsn1eMgylf@这个顺序得到对应的编码:

re3.png

按照这个对应关系解码最后对比的哈夫曼编码可以得到flag为fl@gMyengl1shisp0or,最后输出0K!You Got 1t!

还有上面的0d1e23456f789abc转换成二进制表示为:

re4.png

按照这个解码得到fl@gMyen1ship0or,但是这个比正确的flag少了3个字符。

*作者:Nu1L团队,本文属FreeBuf原创奖励计划,未经许可禁止转载

更多精彩
相关推荐
发表评论

已有 12 条评论

取消
Loading...

这家伙太懒,还未填写个人描述!

5 文章数 7 评论数 0 关注者

特别推荐

填写个人信息

姓名
电话
邮箱
公司
行业
职位
css.php