转载

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

*原创作者:Nu1L团队

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

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

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

逆向部分(Reverse)

Re100

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

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

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

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

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

Re200

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

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

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

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

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

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

继续分析这些线程 ,发现了验证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进行分析。

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

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

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

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

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

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

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

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

之后就显示了

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

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

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

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

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

然后进入验证函数0x401F80

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

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

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

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

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

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

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

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

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

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

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

因此正确输入为 SSCTF{f5b760b64D867618fFeF48FdE92B4e5d}

Flag f5b760b64D867618fFeF48FdE92B4e5d

附上本题脚本:

 // 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() 函数里,如下图

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

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

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

第一步密码: [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 的值,如下图

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

整理出来

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() 来验证。

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

验证部分如下图, 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.0 0 ,就可以得到 FLAG 了, glRotatef(angle, 0.0, 0.0, 1.0)

最后 FLAG 图片如下:

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

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

FLAG{ETIJVA3E96GXZ+HP+E380}

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

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

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

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

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

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

第一个地方

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

第二个地方

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

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

pr0oihsn1eMgylf@J88JJJ88J8J8J8JJJ8888JJJJJJJ8J8J8JJ88J8888J8JJJ888JJJJ8J8888888J

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

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

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

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

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

其中的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 ,之前上面那两处地方的第一处地方的数据为

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

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

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

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

前面得到了

pr0oihsn1eMgylf@J88JJJ88J8J8J8JJJ8888JJJJJJJ8J8J8JJ88J8888J8JJJ888JJJJ8J8888888J

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

05162b4d677092b4 没用

0d1e23456f789abc

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

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

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

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

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

原文  http://www.freebuf.com/news/special/97432.html
正文到此结束
Loading...