您现在的位置是:首页 >学无止境 >NSSCTF-[深育杯 2021]Press网站首页学无止境

NSSCTF-[深育杯 2021]Press

内怀童心外表成熟 2024-06-17 10:22:08
简介NSSCTF-[深育杯 2021]Press

下载链接:下载

载入IDA,查看内容

首先进入一个函数进行初始化,进入查看

unsigned __int64 sub_4007B6()
{
  int v1; // [rsp+8h] [rbp-48h]
  int i; // [rsp+Ch] [rbp-44h]
  char src[56]; // [rsp+10h] [rbp-40h] BYREF
  unsigned __int64 v4; // [rsp+48h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  memset(tmp, 0, sizeof(tmp));
  memset(s, 0, sizeof(s));
  memset(flag, 0, sizeof(flag));
  memset(enflag, 0, 0xC8uLL);
  v2 = 0;
  xiaobiao = 0;                                 // index
  dword_602268 = 0;
  f_index = 0;
  strcpy(src, "++++++++++[->++++++++++++++++<],[->-<]>>[-]+++++<*++.<");
  strcpy(s, src);
  v1 = 0;
  for ( i = 0; i <= 199; ++i )
  {
    if ( s[i] == '[' )
    {
      data[i] = ++v1;
    }
    else if ( s[i] == ']' )
    {
      data[i] = v1--;
    }
    else
    {
      data[i] = 0;
    }
  }
  return __readfsqword(0x28u) ^ v4;
}

开辟了tmp,s,flag,enflag空间,然后给一些值赋值初始化为0,s为"++++++++++[->++++++++++++++++<],[->-<]>>[-]+++++<*++.<",然后进行for循环,从循环中分析可以知道当遍历到'['或者']'的时候就会为1,其余情况为0,然后依次赋值给data数组。返回主函数继续观察。

然后读取flag文件把内容读取到flag中进入while循环,其中有一个sub_40094B()函数跟进:

这里面就类似一个虚拟机操作,看到switch条件就是遍历s这个字符串'++++++++++[->++++++++++++++++<],[->-<]>>[-]+++++<*++.<',先跟着流程走一遍。

第一次循环:

首先是10个'+',所以tmp[0]==10,然后是'[',但是tmp[0]是10不为0,所以不会进入循环,接着是‘-’,tmp[0]变为9,然后是‘>’,移动到tmp[1],然后是16个‘+’,tmp[1]==16。然后是‘<’号又移动到tmp[0]位置,然后是一个重点遇到‘]’号会进入到循环里面,这个for循环操作是不断j--,一直到data[xiaobiao + j] != data[xiaobiao],我们观看data数据可以知道这个条件不成立就是向前遍历到‘[’。即'xiabiao+j'是前面那一个'['位置,经过这个for循环xiabiao被修改变为‘xiaobiao + j - 1’,return的时候又自增1,所以经过这个for循环又遍历到前面的那个‘[’位置(每次遇到‘]’的时候都会回到前面的那个'['位置开始再一次遍历,直到tmp[v2]==0进入循环才停止)。

因为最开始tmp[0]==10,每一次tmp[1]都会加16,所以这次循环当tmp[0]==0时tmp[1]==10*16。然后就会进入到case '['里的循环修改下标为']'位置,然后return的时候下标自增+1就会从']'后的那个符合开始。

第二次循环:[->-<]

遇到',',即把读取的flag内容存放到tmp[0]中,然后遇到‘[’,此时tmp[v2]存放的是flag内容的第一个字符肯定不是0不会进入循环,然后tmp[0]-1,右移到tmp[1]然后减1,然后左移到tmp[0],遇到']',回到前面的'['处如果不是0就一直循环往复直到tmp[0]==0,所以当tmp[0]==0的时候tmp[1]==160-flag[0],进入到了‘case [’的循环体里面就会跳到'>>[-]+++++<*++.<',进入第三次循环。

第三次循环:>>[-]+++++<*++.<

经过两次'>>'会来到tmp[2],然后遇到'[',因为tmp[2]刚开始是0所以直接进入到循环体里面来到'+'号,经过5个加号tmp[2]==5,然后遇到'<'来到tmp[1]处,遇到'*'运算乘法操作tmp[1] *= tmp[2],tmp[1]==(160-flag[0])*5+2,然后遇到'.'号会把运算结果放入到enflag数组中,然后最后左移到tmp[0]再次经过如上操作直到读取完所有的flag内容放在enflag数组当中。

这里需要注意当遍历完成一次s=‘++++++++++[->++++++++++++++++<],[->-<]>>[-]+++++<*++.<’操作后tmp[1]==0,tmp[1]等于你刚刚求出来的那个flag内容,tmp[2]不是0,但是第二次循环遇到[-]时候tmp[2]会被清零。

知道上面这些就可以写代码了:

out=[0x60, 0xE1, 0x2F, 0x05, 0x79, 0x80, 0x5E, 0xE1, 0xC5, 0x57,
  0x8B, 0xCC, 0x5C, 0x9A, 0x67, 0x26, 0x1E, 0x19, 0xAF, 0x93,
  0x3F, 0x09, 0xE2, 0x97, 0x99, 0x7B, 0x86, 0xC1, 0x25, 0x87,
  0xD6, 0x0C, 0xDD, 0xCF, 0x2A, 0xF5, 0x65, 0x0E, 0x73, 0x59,
  0x1D, 0x5F, 0xA4, 0xF4, 0x65, 0x68, 0xD1, 0x3D, 0xD2, 0x98,
  0x5D, 0xFE, 0x5B, 0xEF, 0x5B, 0xCC]

flag=""
b=0
for i in range(len(out)):
	b+=160		
	for j in range(127):
		if (((b-j)*5+2)&0xff==out[i]):		
			flag+=chr(j)
			b=out[i]
			break
import base64
print(base64.b64decode(flag))

p.z师傅也写了一个z3求法,学习一下:SangFor(深育杯)-Reverse(逆向) Press Write up_水番正文的博客-CSDN博客

from z3 import *
enflag = [0x60, 0xE1, 0x2F, 0x05, 0x79, 0x80, 0x5E, 0xE1, 0xC5, 0x57, 0x8B, 0xCC, 0x5C, 0x9A, 0x67, 0x26,
        0x1E, 0x19, 0xAF, 0x93, 0x3F, 0x09, 0xE2, 0x97, 0x99, 0x7B, 0x86, 0xC1, 0x25, 0x87, 0xD6, 0x0C,
        0xDD, 0xCF, 0x2A, 0xF5, 0x65, 0x0E, 0x73, 0x59, 0x1D, 0x5F, 0xA4, 0xF4, 0x65, 0x68, 0xD1, 0x3D,
        0xD2, 0x98, 0x5D, 0xFE, 0x5B, 0xEF, 0x5B, 0xCC]
input = [BitVec('input[%d]' % i, 8) for i in range(56)]
#yyj = BitVec('yyj', 8)
s = Solver()
 
s.add( ((160 - input[0]) * 5 + 2) == enflag[0] )	#第一台液压机
for i in range(1, 56):				#之后的液压机
    s.add( (((160 + enflag[i - 1]) - input[i]) * 5 + 2) == enflag[i] )
    
if sat == s.check():
    ans = s.model()
    
flag = ""
for i in range(56):
    flag += chr(ans[input[i]].as_long())   #as_long()转成整数
print(flag)

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。