CTF刷题记录

目录

日期:2023.5.11

题目:[ACTF新生赛2020]usualCrypt

日期:2023.5.13

题目:[MRCTF2020]Xor

日期:2023.5.14

题目:Youngter-drive

日期:2023.5.15

题目:[MRCTF2020]hello_world_go

日期:2023.5.17

题目:[FlareOn4]IgniteMe

日期:2023.5.18

题目:[GWCTF 2019]xxor

题目:[WUSTCTF2020]Cr0ssfun

日期:2023.5.19

题目:[FlareOn6]Overlong

日期:2023.5.20

题目:[UTCTF2020]basic-re

题目:[FlareOn3]Challenge1

日期:2023.5.23

题目:[ACTF新生赛2020]Oruga

日期:2023.5.25

题目:特殊的 BASE64

日期:2023.5.26

题目:[ACTF新生赛2020]Universe_final_answer

日期:2023.5.27

题目:[羊城杯 2020]easyre

日期:2023.5.28

题目:[ACTF新生赛2020]fungame

日期:2023.5.30

题目:[RoarCTF2019]polyre


日期:2023.5.11

题目:[ACTF新生赛2020]usualCrypt

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,将文件放入IDA中进行分析,找到main函数。查看main函数:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // esi
  int v5[3]; // [esp+8h] [ebp-74h] BYREF
  __int16 v6; // [esp+14h] [ebp-68h]
  char v7; // [esp+16h] [ebp-66h]
  char v8[100]; // [esp+18h] [ebp-64h] BYREF

  sub_403CF8(&unk_40E140);
  scanf("%s", v8);
  memset(v5, 0, sizeof(v5));
  v6 = 0;
  v7 = 0;
  sub_401080(v8, strlen(v8), v5);
  v3 = 0;
  while ( *(v5 + v3) == byte_40E0E4[v3] )
  {
    if ( ++v3 > strlen(v5) )
      goto LABEL_6;
  }
  sub_403CF8(aError);
LABEL_6:
  if ( v3 - 1 == strlen(byte_40E0E4) )
    return sub_403CF8(aAreYouHappyYes);
  else
    return sub_403CF8(aAreYouHappyNo);
}

可以猜测sub_403CF8是输出函数,密文存放在byte_40E0E4中,查看sub_401080函数:

int __cdecl sub_401080(int a1, int a2, int a3)
{
  int v3; // edi
  int v4; // esi
  int v5; // edx
  int v6; // eax
  int v7; // ecx
  int v8; // esi
  int v9; // esi
  int v10; // esi
  int v11; // esi
  _BYTE *v12; // ecx
  int v13; // esi
  int v15; // [esp+18h] [ebp+8h]

  v3 = 0;
  v4 = 0;
  sub_401000();
  v5 = a2 % 3;
  v6 = a1;
  v7 = a2 - a2 % 3;
  v15 = a2 % 3;
  if ( v7 > 0 )
  {
    do
    {
      LOBYTE(v5) = *(a1 + v3);
      v3 += 3;
      v8 = v4 + 1;
      *(v8 + a3 - 1) = aAbcdefghijklmn[(v5 >> 2) & 0x3F];
      *(++v8 + a3 - 1) = aAbcdefghijklmn[16 * (*(a1 + v3 - 3) & 3) + ((*(a1 + v3 - 2) >> 4) & 0xF)];
      *(++v8 + a3 - 1) = aAbcdefghijklmn[4 * (*(a1 + v3 - 2) & 0xF) + ((*(a1 + v3 - 1) >> 6) & 3)];
      v5 = *(a1 + v3 - 1) & 0x3F;
      v4 = v8 + 1;
      *(v4 + a3 - 1) = aAbcdefghijklmn[v5];
    }
    while ( v3 < v7 );
    v5 = v15;
  }
  if ( v5 == 1 )
  {
    LOBYTE(v7) = *(v3 + a1);
    v9 = v4 + 1;
    *(v9 + a3 - 1) = aAbcdefghijklmn[(v7 >> 2) & 0x3F];
    v10 = v9 + 1;
    *(v10 + a3 - 1) = aAbcdefghijklmn[16 * (*(v3 + a1) & 3)];
    *(v10 + a3) = 61;
LABEL_8:
    v13 = v10 + 1;
    *(v13 + a3) = 61;
    v4 = v13 + 1;
    goto LABEL_9;
  }
  if ( v5 == 2 )
  {
    v11 = v4 + 1;
    *(v11 + a3 - 1) = aAbcdefghijklmn[(*(v3 + a1) >> 2) & 0x3F];
    v12 = (v3 + a1 + 1);
    LOBYTE(v6) = *v12;
    v10 = v11 + 1;
    *(v10 + a3 - 1) = aAbcdefghijklmn[16 * (*(v3 + a1) & 3) + ((v6 >> 4) & 0xF)];
    *(v10 + a3) = aAbcdefghijklmn[4 * (*v12 & 0xF)];
    goto LABEL_8;
  }
LABEL_9:
  *(v4 + a3) = 0;
  return sub_401030(a3);
}

将密文进行base64解密后,发现不是flag,猜测可能进行了换表。查看函数,发现在进行base64加密前,sub_401000函数对base64表进行了修改。

int sub_401000()
{
  int result; // eax
  char v1; // cl

  for ( result = 6; result < 15; ++result )
  {
    v1 = aAbcdefghijklmn[result + 10];
    aAbcdefghijklmn[result + 10] = aAbcdefghijklmn[result];
    aAbcdefghijklmn[result] = v1;
  }
  return result;
}

通过动态调试来获取修改后的base64表,进行解密发现仍然是错误的,继续查看问题,发现在加密的末尾还有个sub_401030函数,查看函数发现是将密文的字母大小写进行了互换。

int __cdecl sub_401030(const char *a1)
{
  __int64 v1; // rax
  char v2; // al

  v1 = 0i64;
  if ( strlen(a1) )
  {
    do
    {
      v2 = a1[HIDWORD(v1)];
      if ( v2 < 97 || v2 > 122 )
      {
        if ( v2 < 65 || v2 > 90 )
          goto LABEL_9;
        LOBYTE(v1) = v2 + 32;
      }
      else
      {
        LOBYTE(v1) = v2 - 32;
      }
      a1[HIDWORD(v1)] = v1;
LABEL_9:
      LODWORD(v1) = 0;
      ++HIDWORD(v1);
    }
    while ( HIDWORD(v1) < strlen(a1) );
  }
  return v1;
}

思路理清后,完善解密脚本,脚本如下:

import base64
def main():
    str1 = "zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9"
    str1 = str1.swapcase()
    string1 = "ABCDEFQRSTUVWXYPGHIJKLMNOZabcdefghijklmnopqrstuvwxyz0123456789+/"
    string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    print (base64.b64decode(str1.translate(str.maketrans(string1,string2))))
if __name__ == '__main__':
    main()

# b'flag{bAse64_h2s_a_Surprise}'

FLAG:flag{bAse64_h2s_a_Surprise}

日期:2023.5.13

题目:[MRCTF2020]Xor

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,32位,放入IDA中进行分析,找到main函数,但是无法将程序转成伪代码,因为程序很短,所以直接阅读汇编。

先将一段字符串压入栈中,再跳转进一个函数,猜测sub_2E1020是一个输出函数,而后面的sub_2E1050函数有一个"%s"参数,猜测是输入函数。

这一段指令对计算了一下输入的字符串长度,并与0x1b进行比较,这里可以知道输入长度为0x1b,也就是27。 

"xor     eax, eax"这里将eax寄存器清零,后面用al寄存器与cl进行异或,cl中存放的是输入内容,因为eax作为下标,可以判断是将输入值与其对应下标进行异或。最后再与byte_2FEA08中存放的密文进行比较。

由此理清思路后,即可写出解密脚本,脚本如下: 

cipher = "MSAWB~FXZ:J:`tQJ\"N@ bpdd}8g"
for i in range(len(cipher)):
    print(chr(ord(cipher[i]) ^ i),end="")

# MRCTF{@_R3@1ly_E2_R3verse!}

FLAG:flag{@_R3@1ly_E2_R3verse!}

日期:2023.5.14

题目:Youngter-drive

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,通过查壳工具发现存在UPX壳。

 对其进行脱壳后,放入IDA中进行分析,找到main函数。

int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  HANDLE Thread; // [esp+D0h] [ebp-14h]
  HANDLE hObject; // [esp+DCh] [ebp-8h]

  sub_3610FF();
  ::hObject = CreateMutexW(0, 0, 0);
  j_strcpy(Destination, Source);
  hObject = CreateThread(0, 0, StartAddress, 0, 0, 0);
  Thread = CreateThread(0, 0, sub_36119F, 0, 0, 0);
  CloseHandle(hObject);
  CloseHandle(Thread);
  while ( dword_368008 != -1 )
    ;
  sub_361190();
  CloseHandle(::hObject);
  return 0;
}

可以看出程序创建了两个线程来执行两个函数,查看StartAddress函数和sub_36119F函数下的sub_361B10函数。

void __stdcall __noreturn StartAddress_0(int a1)
{
  while ( 1 )
  {
    WaitForSingleObject(hObject, 0xFFFFFFFF);
    if ( dword_368008 > -1 )
    {
      sub_36112C(Source, dword_368008);
      --dword_368008;
      Sleep(0x64u);
    }
    ReleaseMutex(hObject);
  }
}
void __stdcall __noreturn sub_361B10(int a1)
{
  while ( 1 )
  {
    WaitForSingleObject(hObject, 0xFFFFFFFF);
    if ( dword_368008 > -1 )
    {
      Sleep(0x64u);
      --dword_368008;
    }
    ReleaseMutex(hObject);
  }
}

先执行第一个线程,执行一次对输入的字符串第一个元素进行操作后休眠,再执行第二个线程对下一个元素进行操作后休眠,实际就是将输入的字符串下标为奇或偶时进行不同操作,于是可以写出下面的解密脚本:

cipher = "TOiZiZtOrYaToUwPnToBsOaOapsyS"
dist = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"
flag = ""
flag1 = []
for i in range(29):
    if i % 2 == 1:
        if ord(cipher[i]) >= ord('A') and ord(cipher[i]) <= ord('Z'):
            flag += chr(dist.index(cipher[i])+96)
        else:
            flag += chr(dist.index(cipher[i])+38)
    else:
        flag += cipher[i]
print(flag)

# ThisisthreadofwindowshahaIsES

但是提交发现是错误的,而后看到其他师傅写的wp才知道,实际加密的是30个字符,检查时只检查了29个字符。那最后一个字符需要去猜一下。

FLAG:flag{ThisisthreadofwindowshahaIsESE}

日期:2023.5.15

题目:[MRCTF2020]hello_world_go

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,在IDA中打开,找到一个main_main函数,flag就在这里。

// main.main
void __cdecl main_main()
{
  __int64 v0; // rcx
  __int64 v1; // rax
  __int64 v2; // rax
  __int64 v3; // [rsp+20h] [rbp-90h]
  __int64 v4; // [rsp+58h] [rbp-58h]
  __int64 *v5; // [rsp+60h] [rbp-50h]
  __int64 v6[2]; // [rsp+68h] [rbp-48h] BYREF
  __int64 v7[2]; // [rsp+78h] [rbp-38h] BYREF
  __int64 v8[2]; // [rsp+88h] [rbp-28h] BYREF
  __int64 v9[2]; // [rsp+98h] [rbp-18h] BYREF

  v5 = runtime_newobject(&RTYPE_string);
  v9[0] = &RTYPE_string;
  v9[1] = &off_4EA530;
  fmt_Fprint(&go_itab__ptr_os_File_comma_io_Writer, os_Stdout, v9, 1LL, 1LL);
  v8[0] = &RTYPE__ptr_string;
  v8[1] = v5;
  fmt_Fscanf(&go_itab__ptr_os_File_comma_io_Reader, os_Stdin, "%s", 2LL, v8, 1LL, 1LL);
  v0 = v5[1];
  v1 = *v5;
  if ( v0 != 24 )
    goto LABEL_2;
  v4 = *v5;
  if ( !runtime_memequal("flag{hello_world_gogogo}", v1, 24LL) )
  {
    v1 = v4;
    v0 = 24LL;
LABEL_2:
    runtime_cmpstring("flag{hello_world_gogogo}", 24LL, v1, v0, v3);
    if ( v3 >= 0 )
      v2 = 1LL;
    else
      v2 = -1LL;
    goto LABEL_4;
  }
  v2 = 0LL;
LABEL_4:
  if ( v2 )
  {
    v6[0] = &RTYPE_string;
    v6[1] = &off_4EA550;
    fmt_Fprintln(&go_itab__ptr_os_File_comma_io_Writer, os_Stdout, v6, 1LL, 1LL);
  }
  else
  {
    v7[0] = &RTYPE_string;
    v7[1] = &off_4EA540;
    fmt_Fprintln(&go_itab__ptr_os_File_comma_io_Writer, os_Stdout, v7, 1LL, 1LL);
  }
}

FLAG:flag{hello_world_gogogo}

日期:2023.5.17

题目:[FlareOn4]IgniteMe

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,32位,无壳。

根据Description.txt可以知道flag的格式:

 

 在IDA中找到一个sub_401050函数,这里对输入值进行了加密,并于密文进行了比较。

int sub_401050()
{
  int v1; // [esp+0h] [ebp-Ch]
  int i; // [esp+4h] [ebp-8h]
  unsigned int j; // [esp+4h] [ebp-8h]
  char v4; // [esp+Bh] [ebp-1h]

  v1 = sub_401020(byte_403078);
  v4 = sub_401000();
  for ( i = v1 - 1; i >= 0; --i )
  {
    byte_403180[i] = v4 ^ byte_403078[i];
    v4 = byte_403078[i];
  }
  for ( j = 0; j < 39; ++j )
  {
    if ( byte_403180[j] != byte_403000[j] )
      return 0;
  }
  return 1;
}

在第一个for语句处下一个断点,可以知道v4的值为4,接着就可以写解密脚本:

cipher = [  0x0D, 0x26, 0x49, 0x45, 0x2A, 0x17, 0x78, 0x44, 0x2B, 0x6C, 0x5D, 0x5E, 0x45, 0x12, 0x2F, 0x17, 0x2B, 0x44, 0x6F, 0x6E, 0x56, 0x09, 0x5F, 0x45, 0x47, 0x73, 0x26, 0x0A, 0x0D, 0x13, 0x17, 0x48, 0x42, 0x01, 0x40, 0x4D, 0x0C, 0x02, 0x69]
key = 4
flag = ""
for i in range(len(cipher)-1,-1,-1):

    cipher[i] = cipher[i] ^ key
    key = cipher[i]

for j in range(len(cipher)):
    print(chr(cipher[j]),end="")

# R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com

FLAG:flag{R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com}

日期:2023.5.18

题目:[GWCTF 2019]xxor

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,64位,无壳。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值