近期解题 2024.3.14

文章目录

[SWPU2019] ReverseMe

乍一看 main() 函数里没有什么东西。切到反汇编界面,我们看到了一位老朋友——SEH。

通过使用“广撒网”的打断点方式(在每一个可疑的 call 指令打断点),找到输入函数的位置:

紧接着下面就对输入内容的长度进行判定,输入内容的长度为 0x20。

继续调试,可以看到输入的内容在下面位置进行了异或操作:

最后在下面与密文进行比较:

根据此操作的特点,流程图模式中指向自己的代码块更可能是执行加密算法的部分。

提取数据后使用脚本解密:

 1k1 = 'SWPU_2019_CTF'
 2k2 = [
 3  0x86, 0x0C, 0x3E, 0xCA, 0x98, 0xD7, 0xAE, 0x19, 0xE2, 0x77, 
 4  0x6B, 0xA6, 0x6A, 0xA1, 0x77, 0xB0, 0x69, 0x91, 0x37, 0x05, 
 5  0x7A, 0xF9, 0x7B, 0x30, 0x43, 0x5A, 0x4B, 0x10, 0x86, 0x7D, 
 6  0xD4, 0x28
 7]
 8k3 = [
 9  0xB3, 0x37, 0x0F, 0xF8, 0xBC, 0xBC, 0xAE, 0x5D, 0xBA, 0x5A, 
10  0x4D, 0x86, 0x44, 0x97, 0x62, 0xD3, 0x4F, 0xBA, 0x24, 0x16, 
11  0x0B, 0x9F, 0x72, 0x1A, 0x65, 0x68, 0x6D, 0x26, 0xBA, 0x6B, 
12  0xC8, 0x67
13]
14
15for i in range(0x20):
16    print(chr(ord(k1[i % 13]) ^ k2[i] ^ k3[i]), end = '')
17
18# output: flag{Y0uaretheB3st!#@_VirtualCC}

buuctf - rsa

不是很懂,为什么一道 RSA 被放到了逆向里。

题目附件中有两个文件: pub.keyflag.enc

万事俱备,直接解:

1from Crypto.PublicKey import RSA
2
3with open('pub.key', 'r') as pubkey:
4    key = RSA.importKey(pubkey.read())
5
6print(key.n)
7
8# output: 86934482296048119190666062003494800588905656017203025617216654058378322103517

上面的脚本从 pub.key 中读取出了 n,分解后可以解出 flag:

 1from Crypto.Util.number import *
 2import gmpy2
 3
 4n = 86934482296048119190666062003494800588905656017203025617216654058378322103517
 5p = 285960468890451637935629440372639283459
 6q = 304008741604601924494328155975272418463
 7e = 65537
 8
 9phi = (p - 1) * (q - 1)
10d = gmpy2.invert(e, phi)
11
12with open('flag.enc', 'rb') as flag:
13    c = bytes_to_long(flag.read())
14
15m = pow(c, d, n)
16print(long_to_bytes(m))
17
18# output: b'\x02\x9d {zR\x1e\x08\xe4\xe6\x18\x06\x00flag{decrypt_256}\n'

[QCTF2018] Xman-babymips

题目唯一亮点在于它是 MIPS 架构汇编,不过用 IDA 7.7 照样可以反编译。

核心代码:

 1int __fastcall main(int a1, char **a2, char **a3)
 2{
 3  int i; // [sp+18h] [+18h] BYREF
 4  char v5[36]; // [sp+1Ch] [+1Ch] BYREF
 5
 6  setbuf(stdout, 0);
 7  setbuf(stdin, 0);
 8  printf("Give me your flag:");
 9  scanf("%32s", v5);
10  for ( i = 0; i < 32; ++i )
11    v5[i] ^= 32 - i;
12  if ( !strncmp(v5, fdata, 5u) )
13    return sub_4007F0(v5);
14  else
15    return puts("Wrong");
16}
17
18int __fastcall sub_4007F0(const char *a1)
19{
20  char v1; // $v1
21  size_t i; // [sp+18h] [+18h]
22
23  for ( i = 5; i < strlen(a1); ++i )
24  {
25    if ( (i & 1) != 0 )
26      v1 = (a1[i] >> 2) | (a1[i] << 6);
27    else
28      v1 = (4 * a1[i]) | (a1[i] >> 6);
29    a1[i] = v1;
30  }
31  if ( !strncmp(a1 + 5, off_410D04, 0x1Bu) )
32    return puts("Right!");
33  else
34    return puts("Wrong!");
35}

我 NT 了,竟然在这道题上卡住,主要是脚本写的有问题。正确脚本如下:

 1c = [
 2  0x51, 0x7C, 0x6A, 0x7B, 0x67, 0x52, 0xFD, 
 3  0x16, 0xA4, 0x89, 0xBD, 0x92, 0x80, 0x13, 0x41, 0x54, 0xA0, 
 4  0x8D, 0x45, 0x18, 0x81, 0xDE, 0xFC, 0x95, 0xF0, 0x16, 0x79, 
 5  0x1A, 0x15, 0x5B, 0x75, 0x1F
 6]
 7
 8for i in range(5, 32):
 9    if i % 2 == 0:
10        c[i] = (c[i] >> 2 | c[i] << 6) & 0x7F
11    else:
12        c[i] = (c[i] << 2 | c[i] >> 6) & 0x7F
13
14for i in range(32):
15    print(chr(c[i] ^ 32 - i), end = '')
16
17# output: qctf{ReA11y_4_B@89_mlp5_4_XmAn_}

[WMCTF2020] easy_re

这道题的程序使用 Perl 语言编写,随后通过 ActivePerl 将代码打包成可执行文件。运行程序,程序会输出 "please input the flag:" 提示输入 flag。但是在 IDA 中搜索字符串,无法找到相应字符串。

根据已知的信息,Perl 语言在打包成可执行文件时,会将解释器、编译器与压缩后的代码一同装进可执行文件中。在执行时,程序会首先初始化编译器,随后解压代码并执行代码。在执行源代码,程序会向栈内压入一个字符串 "script" 用于标记。因此搜索字符串 "script" 并定位到这里。

上图中 sub_40D1A0() 是解压 Perl 脚本的部分,解压完成后原始 Perl 脚本地址会存储在 rax 寄存器中。

经调试可以得到原始 Perl 脚本:

1$flag = "WMCTF{I_WAnt_dynam1c_F1ag}";
2print "please input the flag:";
3$line = <STDIN>;
4chomp($line);
5if($line eq $flag){
6	print "congratulation!"
7}else{
8	print "no,wrong"
9}

flag 一目了然。