2021-i春秋-春季赛逆向WP

2021-i春秋-春季赛

一:backdoor

参考了一些Go语言的Socket编程
https://www.cnblogs.com/yinzhengjie/p/7261584.html
https://studygolang.com/articles/14344
https://blog.csdn.net/natpan/article/details/82866619
https://blog.csdn.net/RA681t58CJxsgCkJ31/article/details/103258253

顾名思义,就叫后门
发现是用GO语言写的,使用IDA7.6打开进行分析

void __cdecl main_main()
{
  __int64 v0; // [rsp+10h] [rbp-78h]
  __int64 v1; // [rsp+18h] [rbp-70h]
  __int64 v2; // [rsp+20h] [rbp-68h]
  __int64 v3; // [rsp+30h] [rbp-58h]
  __int64 v4; // [rsp+38h] [rbp-50h]
  __int64 v5; // [rsp+48h] [rbp-40h]
  __int64 val; // [rsp+50h] [rbp-38h]
  const __int64 *v7; // [rsp+60h] [rbp-28h] BYREF
  char **v8; // [rsp+68h] [rbp-20h]
  __int128 v9; // [rsp+70h] [rbp-18h]
  __int64 v10; // [rsp+80h] [rbp-8h] BYREF

  while ( (unsigned __int64)&v10 <= *(_QWORD *)(*(_QWORD *)NtCurrentTeb()->NtTib.ArbitraryUserPointer + 16LL) )
    runtime_morestack_noctxt();
  v2 = net_Listen((__int64)"tcp", 3LL, (__int64)"127.0.0.1:8721", 14LL);
  if ( v3 )
  {
    v9 = 0LL;
    v7 = &qword_2A7260;
    v8 = &aaErrorConnectin;
    *(_QWORD *)&v9 = *(_QWORD *)(v3 + 8);
    *((_QWORD *)&v9 + 1) = v4;
    v1 = log_Fatal((__int64)&v7, 2LL, 2LL);
  }
  while ( 1 )
  {
    val = (*(__int64 (__golang **)())(v2 + 24))();
    v5 = v0;
    if ( v1 )
    {
      v9 = 0LL;
      v7 = &qword_2A7260;
      v8 = &aaAcceptingConne;
      *(_QWORD *)&v9 = *(_QWORD *)(v1 + 8);
      *((_QWORD *)&v9 + 1) = v2;
      log_Println((__int64)&v7, 2LL, 2LL);
    }
    HIDWORD(v0) = HIDWORD(val);
    v1 = v5;
    runtime_newproc(16u, (char)&off_2D2A90, val);
  }
}

使用net_Listen监听了本机的8721端口,然后下面检测是否监听正确,没有就log_Fatal**,**再下方是读取从监听的端口发送过来的信息,最后调用的off_2D2A90地址处的main_handleConnection进行处理

main_handleConnection函数:

void __golang __noreturn main_handleConnection(__int64 a1, __int64 a2)
{
  runtime__type_0 *v2; // rdi
  void *v3; // rsi
  __int64 v4; // rax
  _QWORD *v5; // [rsp+8h] [rbp-78h]
  __int64 v6; // [rsp+8h] [rbp-78h]
  char v7; // [rsp+18h] [rbp-68h]
  __int64 v8; // [rsp+20h] [rbp-60h]
  __int64 v9; // [rsp+28h] [rbp-58h]
  __int64 v10; // [rsp+30h] [rbp-50h]
  unsigned __int64 v11; // [rsp+50h] [rbp-30h]
  __int64 addr; // [rsp+58h] [rbp-28h]
  __int64 cmp_data; // [rsp+60h] [rbp-20h]
  void *retaddr; // [rsp+80h] [rbp+0h] BYREF

  while ( (unsigned __int64)&retaddr <= *(_QWORD *)(*(_QWORD *)NtCurrentTeb()->NtTib.ArbitraryUserPointer + 16LL) )
    runtime_morestack_noctxt();
  runtime_newobject(v2, v3);
  cmp_data = (__int64)v5;
  *v5 = 0xCF6E7633149F46F5LL;
  v5[1] = 0xD33674C27C6FE28ALL;
  v5[2] = 0xF592D63BE79440D9LL;
  v5[3] = 0xD33CF4C0B83E001BLL;
  v5[4] = 0x8B615DC202F30A50LL;
  v5[5] = 0x181C7380D6FF6BBLL;
  v4 = runtime_makeslice((__int64)&dword_2A73E0, 1024LL, 1024LL);
  for ( addr = v4; ; v4 = addr )
  {
    v6 = v4;
    (*(void (**)(void))(a1 + 40))();
    if ( !v9 )
    {
      if ( (unsigned __int64)(v8 - 1) > 0x400 )
        runtime_panicSliceAcap(a2, v6);
      v11 = v8 - 1;
      v10 = encoding_base32___ptr_Encoding__EncodeToString(encoding_base32_StdEncoding, addr, v8 - 1, 1024LL, v8, 0LL);
      if ( v9 == 24 )               //验证加密之后的字符串长度是否是24
      {
        runtime_memequal();         //比较base32加密之后的字符串
        if ( v7 )
        {
          v9 = 1024LL;
          main_Decrypt(cmp_data, 48uLL, 48LL, addr, v11);
          if ( v10 )
            v8 = (*(__int64 (__golang **)(__int64, __int64))(a1 + 80))(a2, v10);
        }
      }
    }
  }
}

在这里插入图片描述

如果我们从端口发送过去的信息在base32标准加密之后和“M4YDCYLOM5BGCY3LMQYDA4Q=”相等,就进行解密,这里就有两种思路。可以将M4YDCYLOM5BGCY3LMQYDA4Q=进行base32解码然后得到我们发送的数据,为"g01angBackd00r",但是我用nc发的时候,卡了很久,最后看见在这个地方减一
在这里插入图片描述

然后多输入了一个字符,使用nc发过去之后,base32加密后才能和比较数据相等。

发送过程:

先创建一个文件
在这里插入图片描述

然后运行backdoor.exe

之后使用nc直接重定向入端口,会反弹回一个flag

在这里插入图片描述

另外一种思路就是静态解,加密后的数据我们知道

cmp_data = [0x149F46F5, 0xCF6E7633, 0x7C6FE28A, 0xD33674C2, 0xE79440D9, 0xF592D63B, 0xB83E001B, 0xD33CF4C0, 0x02F30A50, 0x8B615DC2, 0x0D6FF6BB, 0x0181C738]

跟进去看是什么解密

进去之后再跟进

在这里插入图片描述

可以很明显的看见是一个xxtea

在这里插入图片描述

在这里插入图片描述

然后所谓的key,就是把我们通过端口传过去的字符串四个字节四个字节的取了当key

可以得到:

unsigned int key[] = {0x61313067,0x6142676E,0x30646B63,0x7230};

写出解题脚本:

#include <stdio.h>
#include <stdlib.h>
#define DELTA 0x9e3779b9//0x61C88647
int main()
{
    unsigned int v[] = {0x149F46F5, 0xCF6E7633, 0x7C6FE28A, 0xD33674C2, 0xE79440D9, 0xF592D63B, 0xB83E001B, 0xD33CF4C0, 0x02F30A50, 0x8B615DC2, 0x0D6FF6BB, 0x0181C738};
    unsigned int key[] = {0x61313067,0x6142676E,0x30646B63,0x7230};
    unsigned int sum = 0;
    unsigned int y,z,p,rounds,e;
    int n = 12;                 //传入的是12
    int i = 0;
    rounds = 6 + 52/n;
    y = v[0];
    sum = (rounds*DELTA)&0xffffffff;
     do
     {
        e = sum >> 2 & 3;
        for(p=n-1;p>0;p--)
        {
            z = v[p-1];
            v[p] = (v[p] - ((((z>>5)^(y<<2))+((y>>3)^(z<<4))) ^ ((key[(p^e)&3]^z)+(y ^ sum)))) & 0xffffffff;
            y = v[p];
        }
        z = v[n-1];
        v[0] = (v[0] - (((key[(p^e)&3]^z)+(y ^ sum)) ^ (((y<<2)^(z>>5))+((z<<4)^(y>>3))))) & 0xffffffff;
        y = v[0];
        sum = (sum-DELTA)&0xffffffff;
     }while(--rounds);
    for(i=0;i<n;i++)
    {
        printf("%c%c%c%c",*((char*)&v[i]+0),*((char*)&v[i]+1),*((char*)&v[i]+2),*((char*)&v[i]+3));
    }
	  //flag{93b867f2-62b6-760a-7acb-355c80281e12}
    return 0;
}

二:hardchal

题给提示:

I designed a very HARD challenge for you, please enjoy~
How-to-run:
1. Install Icarus Verilog
2. > vvp ./chal

查看Icarus Verilog的文档,从中看一些我们分析时用的到的

https://github.com/steveicarus/iverilog/blob/master/vvp/README.txt#L852

比如:参数,函数,变量等的规范

根据最开始的一些值,初步判断是TEA一类

在这里插入图片描述

然后在下方代码的开始处找到了比较数据:
在这里插入图片描述

像这样的总共:

0xbf3e3eda,0x193f659b,0x29b74d79,0x63f67c27,0x6330fb62,0xce7d5340,0xd29371e9,0xae2f0140,0x87ab6341,0x2069c5d,0xe10392fe,0xbb0e1442

然后紧接着根据比较的结果判断结果

在这里插入图片描述

然后继续往下:

T_5 ;
    %pushi/vec4 0, 0, 1;
    %store/vec4 v00000201bba697c0_0, 0, 1;
    %pushi/vec4 0, 0, 32;
    %store/vec4 char_idx, 0, 32;   //char_idx = 0
    %pushi/vec4 1, 0, 1;
    %store/vec4 reset, 0, 1;      //reset = 1
    %pushi/vec4 1, 0, 32;
    %store/vec4 ok, 0, 32;        // ok = 1
    %pushi/vec4 2654435769, 0, 32;
    %store/vec4 delta, 0, 32;     //delta = 2654435769
    %pushi/vec4 3735928559, 0, 32;
    %store/vec4 k0, 0, 32;       // k0 = 3735928559
    %pushi/vec4 3405691582, 0, 32;
    %store/vec4 k1, 0, 32;      // k1 = 3405691582
    %pushi/vec4 269488144, 0, 32;
    %store/vec4 k2, 0, 32;      // k2 = 269488144
    %pushi/vec4 16843009, 0, 32;
    %store/vec4 k3, 0, 32;      // k3 = 16843009
    %vpi_call 2 1771 "$write", "Checking, please wait...\012" {0 0 0};
    %vpi_func 2 1772 "$" 32, "flag" {0 0 0};
    %store/vec4 file, 0, 32;
    %load/vec4 file;
    %cmpi/e 0, 0, 32;
    %jmp/0xz  T_5.0, 4;
    %vpi_call 2 1774 "$write", "Invalid flag\012" {30 0 0}; 
    %vpi_call 2 1775 "$finish" {0 0 0};

这里得到了delta和key,分别是:

0x9e3779b9
0xdeadbeef,0xcafebabe,0x10101010,0x1010101

然后根据delta,以及逻辑分析,可以确定就是TEA,且并没有其它什么怪异的操作

直接写出C脚本得到flag:

#include <stdio.h>
#include <stdint.h>

//加密函数
void encrypt (uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], sum=0, i;           /* set up */
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i < 32; i++) {                       /* basic cycle start */
        sum += delta;
        v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
    }                                              /* end cycle */
    v[0]=v0; v[1]=v1;
}

//解密函数
void decrypt (uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;  /* set up */
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i<32; i++) {                         /* basic cycle start */
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        sum -= delta;
    }                                              /* end cycle */
    v[0]=v0; v[1]=v1;
}

int main()
{
    uint32_t array[] = {0xbf3e3eda,0x193f659b,0x29b74d79,0x63f67c27,0x6330fb62,0xce7d5340,0xd29371e9,0xae2f0140,0x87ab6341,0x2069c5d,0xe10392fe,0xbb0e1442};
    uint32_t key[4] = {0xdeadbeef,0xcafebabe,0x10101010,0x1010101};
    int i = 0;
    for(i=0;i<12;i+=2)
    {
        uint32_t temp[2];
        temp[0] = array[i];
        temp[1] = array[i+1];
        decrypt(temp, key);
        printf("%c%c%c%c%c%c%c%c",*((char*)&temp[0]+3),*((char*)&temp[0]+2),*((char*)&temp[0]+1),*((char*)&temp[0]+0),*((char*)&temp[1]+3),*((char*)&temp[1]+2),*((char*)&temp[1]+1),*((char*)&temp[1]+0));
    }
    //flag{d88ca56a-b934-11eb-8529-0242ac130003}
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值