NepCTF2023部分wp

Reverse

九龙拉棺

ida打开,找到主函数,可以看出函数是通过线程池调用的。在输入的地方下断点,运行会直接退出。猜测有反调试,搜索字符串debug,有Isdebugpresent字符串,交叉引用下断点后并没有成功断下。这里提供一个思路。就是在所有调用exit的函数下断点。看看会断在哪里。可以发现确实可以断下来。但是没有什么用。在输入下断运行还是退出。于是去看函数表,可以看到函数比较少。于是直接一个一个翻看。果然看到了有的函数调用了系统函数exitprocess。然后再下断,修改。可以跳过反调试
这里贴一下反调试关键函数

点击查看代码
int encrypt()
{
  HANDLE CurrentThread; // esi
  CONTEXT Context; // [esp+4h] [ebp-2D0h] BYREF

  memset(&Context.Dr0, 0, 0x2C8u);
  Context.ContextFlags = 65599;
  CurrentThread = GetCurrentThread();
  if ( !GetThreadContext(CurrentThread, &Context) || !Context.Dr7 )
    return 0;
  Context.Dr7 = 0;
  SetThreadContext(CurrentThread, &Context);
  Context.ContextFlags = 65599;
  if ( GetThreadContext(CurrentThread, &Context) )
  {
    if ( Context.Dr7 ) //这里下断点,改掉判断
      ExitProcess(0xFFFFFF9D);
  }
  return 1;
}
先把线程池里的函数解密了
点击查看代码
#include <stdio.h>  
#include <stdint.h>  
void decrypt(uint32_t* v) {
	uint32_t v0 = v[0], v1 = v[1], sum = 3337565984, i; 
	uint32_t delta = 0x61C88647;                     
	for (i = 0; i < 32; i++) {                         
		v1 -= ((v0 << 4) + 0x3) ^ (v0 + sum) ^ ((v0 >> 5) + 0x4); 
		v0 -= ((v1 << 4) + 0x1) ^ (v1 + sum) ^ ((v1 >> 5) + 0x2);
		sum += delta;
	}                                              
	v[0] = v0; v[1] = v1;
}
int main()
{
	uint32_t v[] = { 2293224150, 1069434279, 665506233, 2360599838, 154439674, 3785309250, 4292676998, 3988353923, 314884287, 459783449, 4154791126, 418992724, 2869955760, 13345079, 44635922, 3314355614 };
	uint32_t tmp[2] = { 0 };
	for (int i = 0; i < 16; i+=2) {
		tmp[0] = v[i];
		tmp[1] = v[i + 1];
		decrypt(tmp);
		v[i] = tmp[0];
		v[i + 1] = tmp[1];
	}
	unsigned char *bytes = (unsigned char *)v;
	for (size_t i = 0; i < sizeof(v); i++) {
		printf("%c", bytes[i]);
	}
	printf("\n");
	return 0;
} //NepCTF{c9cdnwdi3iu41m0pv3x7kllzu8pdq6mt9n2nwjdp6kat8ent4dhn5r158
可以得到部分flag。然后通过调试,dump出子进程。这里调试dump也行,自己解密也行。 大致解密思路是rc4,然后base32,base64。 调试过程省略,关键是看block变量。 dump后的程序
点击查看代码
int __usercall encrypt2@<eax>(int a1@<eax>)
{
  int v1; // ecx
  unsigned int i; // ecx
  unsigned int v3; // edi
  unsigned int v4; // esi
  int v5; // ebx
  unsigned int k; // edx
  unsigned int m; // ecx
  unsigned int j; // [esp+0h] [ebp-A0h]
  int v10; // [esp+4h] [ebp-9Ch]
  _DWORD v11[16]; // [esp+8h] [ebp-98h]
  int v12; // [esp+48h] [ebp-58h]
  int v13; // [esp+4Ch] [ebp-54h]
  int v14; // [esp+50h] [ebp-50h]
  int v15; // [esp+54h] [ebp-4Ch]
  int v16[15]; // [esp+58h] [ebp-48h]
  __int16 v17; // [esp+94h] [ebp-Ch]
  char v18; // [esp+96h] [ebp-Ah]
  int v19; // [esp+97h] [ebp-9h]
  char v20; // [esp+9Bh] [ebp-5h]
  int v21; // [esp+9Ch] [ebp-4h]

  v21 = a1;
  v1 = *(_DWORD *)(a1 + 504);
  v20 = HIBYTE(v1);
  v10 = v1 + a1 + 20;
  v16[0] = 0x1DC74989;
  v16[1] = 0xD979AF77;
  v16[2] = 0x888D136D;
  v16[3] = 0x8E26DB7F;
  v16[4] = 0xC10C3CC9;
  v16[5] = 0xC3845D40;
  v16[6] = 0xC6E04459;
  v16[7] = 0xA2EBDF07;
  v16[8] = 0xD484388D;
  v16[9] = 0x12F956A2;
  v16[10] = 0x5ED7EE59;
  v16[11] = 0x43137F85;
  v16[12] = 0xEF43F9F0;
  v16[13] = 0xB29683AA;
  v16[14] = 0x8E3640B4;
  v17 = 0x6177;
  v18 = 0xD3;
  v19 = 0xC2;
  for ( i = 0; i < 0x10; ++i )
    v11[i] = *(_DWORD *)(v10 + 4 * i);
  v12 = 18;
  v13 = 52;
  v14 = 86;
  v15 = 120;
  for ( j = 0; j < 8; ++j )
  {
    v3 = v11[2 * j];
    v4 = v11[2 * j + 1];
    v5 = 0;
    for ( k = 0; k < 0x20; ++k )
    {
      v5 -= 1640531527;
      v3 += (v13 + (v4 >> 5)) ^ (v4 + v5) ^ (v12 + 16 * v4);
      v4 += (v15 + (v3 >> 5)) ^ (v5 + v3) ^ (v14 + 16 * v3);
    }
    v11[2 * j] = v3;
    v11[2 * j + 1] = v4;
  }
  for ( m = 0; m < 0x10; ++m )
  {
    if ( v11[m] != v16[m] )
      return 0;
  }
  return 1;
}
按照上面脚本解密即,拼接整合可得最终flag

Review

先upx脱壳,程序开了aslr,使用studype++关闭aslr。然后调试就不会飘红了。
同样,与上题类似,程序开了线程池和反调试。跟进gets_s函数

点击查看代码
_BYTE *__cdecl common_gets<char>(_BYTE *a1, int a2, char a3)
{
  _BYTE *v3; // esi
  _BYTE *v5; // edi
  FILE *v6; // eax
  FILE *v7; // eax
  FILE *v8; // eax
  int v9; // eax
  int v10; // ecx
  FILE *v11; // eax
  _BYTE *v12; // edx
  FILE *v13; // eax
  FILE *v14; // eax
  _BYTE *v15; // [esp+18h] [ebp-24h]
  CPPEH_RECORD ms_exc; // [esp+24h] [ebp-18h] BYREF

  v3 = a1;
  if ( !a1 || !a2 )
  {
    *_errno() = 22;
    _invalid_parameter_noinfo();
    return 0;
  }
  v5 = a1;
  v6 = __acrt_iob_func(0);
  _lock_file(v6);
  ms_exc.registration.TryLevel = 0;
  v7 = __acrt_iob_func(0);
  if ( (unsigned __int8)__acrt_stdio_char_traits<char>::validate_stream_is_ansi_if_required(v7) )
  {
    v8 = __acrt_iob_func(0);
    v9 = _getc_nolock(v8);
    if ( v9 == -1 )
    {
      v5 = 0;
      if ( a3 )
        goto LABEL_23;
    }
    v10 = a2;
    if ( a2 == -1 )
    {
      while ( v9 != 10 && v9 != -1 )
      {
        *v3++ = v9;
        v11 = __acrt_iob_func(0);
        v9 = _getc_nolock(v11);
      }
      *v3 = 0;
      goto LABEL_23;
    }
    v12 = a1;
    v15 = a1;
    while ( v9 != 10 && v9 != -1 )
    {
      if ( v10 )
      {
        a2 = v10 - 1;
        *v12 = v9;
        v15 = v12 + 1;
      }
      v13 = __acrt_iob_func(0);
      v9 = _getc_nolock(v13);
      v10 = a2;
      v12 = v15;
    }
    if ( !v10 )//这里原本是v10,这里修改为!v10即可绕过反调试
    {
      *v12 = 0;
      goto LABEL_23;
    }
    *a1 = 0;
    *_errno() = 34;
    _invalid_parameter_noinfo();
    _local_unwind4(&__security_cookie, (int)&ms_exc.registration, 0xFFFFFFFE);
    return 0;
  }
  v5 = 0;
LABEL_23:
  v14 = __acrt_iob_func(0);
  _unlock_file(v14);
  return v5;
}

然后再绕过下面的Isdebugpresent反调试。来到关键部分。
通过findcrypto插件识别到crc32,aes,tea的特征。然后交叉引用可以发现程序先进行魔改xtea加密。然后再根据加密后结果前一位与后一位是否一致来生成aes密钥,接着aes加密后与flag密文比较。aes密钥以为要爆破。没想到试了第一个就是。
解题代码

点击查看代码
#include <stdio.h>  
#include <stdint.h>  
void decipher(uint32_t v[], uint32_t const key[4]) {
	unsigned int i;
	uint32_t delta = 0x61C88647, sum = 0x2e2ac13a,v6;
	int round = 10;
	do {
		v[11] -= ((v[0] ^ sum) + (v[10] ^ key[((sum >> 2) & 3) ^ 0xb & 3])) ^ (((16 * v[10]) ^ (v[0] >> 3)) + ((v[10] >> 5) ^ (4 * v[0])));

		for (i = 0xa; i >0; i--) {
			v[i] -= ((v[i + 1] ^ sum) + (v[i-1] ^ key[((sum >> 2) & 3) ^ i & 3])) ^ (((16 * v[i - 1]) ^ (v[i + 1] >> 3)) + ((v[i - 1] >> 5) ^ (4 * v[i + 1])));
		}
		v[0] -= ((v[1] ^ sum) + (v[11] ^ key[((sum >> 2) & 3) ^ 0 & 3])) ^ (((16 * v[11]) ^ (v[1] >> 3)) + ((v[11] >> 5) ^ (4 * v[1])));
		sum += delta;
		round -= 1;
	} while (round);
}
int main()
{
	uint32_t v[] = { 2309579534, 3094518205, 2274467788, 4072683167, 418971191, 2065596768, 236488259, 3759075494, 2770389782, 2907179657, 384852496, 1019579761 };
	uint32_t const k[4] = { 0x19,0,0x6e,3 };
	unsigned int r = 10; 
	decipher(v, k);
	unsigned char *bytes = (unsigned char *)v;
	for (size_t i = 0; i < sizeof(v); i++) {
		printf("%c", bytes[i]);
	}
	printf("\n");
	return 0;
}

Misc

CheckIn

题目描述就有flag

与AI共舞的哈夫曼

直接问chatgpt拿到脚本,就能解出flag为Nepctf{huffman_zip_666}

问卷

填问卷就有flag

Pwn

HRP-CHAT-1 HRP-CHAT-3

抽到h3,用大招打败t佬得flag
先创一个用户名,然后用该用户名进行sql注入1'--。给了源码中有exp没删

posted @ 2023-08-14 15:47  r136a1  阅读(109)  评论(0编辑  收藏  举报