目录

日期:2023.5.3

题目:[GWCTF 2019]pyre

日期:2023.5.4

题目:[ACTF新生赛2020]easyre

题目:DASCTF Apr.2023 X SU战队2023开局之战 【简单】easyRE

日期:2023.5.5

题目:findit

题目:DASCTF Apr.2023 X SU战队2023开局之战 【中等】gotots

2023.5.6添加注释

日期:2023.5.6

题目:[ACTF新生赛2020]rome

题目:[FlareOn4]login

题目:简单注册器

日期:2023.5.7

题目:[WUSTCTF2020]level1

题目:[WUSTCTF2020]level2

题目:[WUSTCTF2020]level3

题目:[WUSTCTF2020]level4

日期:2023.5.8

题目:CrackRTF

题目:[GUET-CTF2019]re

日期:2023.5.9

题目:[MRCTF2020]Transform

题目:[2019红帽杯]easyRE


日期:2023.5.3

题目:[GWCTF 2019]pyre

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,根据题目名可知是由python编写,所以直接用uncompyle6进行反编译,dump出py文件。

# uncompyle6 version 3.9.0
# Python bytecode version base 2.7 (62211)
# Decompiled from: Python 3.9.12 (tags/v3.9.12:b28265d, Mar 23 2022, 23:52:46) [MSC v.1929 64 bit (AMD64)]
# Embedded file name: encode.py
# Compiled at: 2019-08-19 21:01:57
print 'Welcome to Re World!'
print 'Your input1 is your flag~'
l = len(input1)
for i in range(l):num = ((input1[i] + i) % 128 + 128) % 128code += numfor i in range(l - 1):code[i] = code[i] ^ code[i + 1]print code
code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']
# okay decompiling attachment.pyc

可以看出程序对输入内容进行了两个加密,这两个加密可逆并知道了密文,开始写解密脚本。

code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']
flag = ""
for i in range(len(code)-2,-1,-1):code[i] = chr(ord(code[i]) ^ ord(code[i+1]))for i in range(len(code)):flag += chr(((ord(code[i]) - i) % 128 + 128) % 128)
print(flag)# GWHT{Just_Re_1s_Ha66y!}

FLAG:flag{Just_Re_1s_Ha66y!}

日期:2023.5.4

题目:[ACTF新生赛2020]easyre

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件后,通过查壳工具发现程序有加UPX壳

对其进行脱壳后将程序放入IDA中进行分析,找到关键的main函数,得知可以发现一个关键数组_data_start__。

由此可以推测,是将输入的字符的对应数值-1作为_data_start__数组的下标与v4进行比较,因此只需要找到v4中的值在_data_start__中的对应下标位置即可。脚本如下:

cipher = "*F'\"N,\"(I?+@"
flag = "ACTF{"
dist = "~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$# !\""
for i in range(len(cipher)):flag += chr(dist.index(cipher[i])+1)
print(flag+'}')# ACTF{U9X_1S_W6@T?}

FLAG:flag{U9X_1S_W6@T?}

题目:DASCTF Apr.2023 X SU战队2023开局之战 【简单】easyRE

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,根据附件图标可以猜测是python编写的exe文件,利用pyinstxtractor.py将其转成pyc文件,但根据信息发现,该程序所用的python版本为3.11,uncompyle6不支持这个python版本的反编译,当时在此陷入困境,发现自己还是太依赖工具了。

在后来,看到了官方WP后知晓了python的dis库和marshal库可以对pyc文件进行反编译,将其转成字节码。脚本如下:

import dis
import marshal
def main():file1 = open('easyRE.pyc','rb')code = marshal.loads(file1.read()[16:])print(dis.dis(code))
if __name__ == '__main__':main()

"file1.read()[16:]"是跳过pyc文件的文件头,以防止后续dis解析错误。执行脚本dump出pyc文件的字节码:

  0           0 RESUME                   01           2 LOAD_CONST               0 (0)4 LOAD_CONST               1 (None)6 IMPORT_NAME              0 (random)8 STORE_NAME               0 (random)3          10 PUSH_NULL12 LOAD_NAME                0 (random)14 LOAD_ATTR                1 (Random)24 LOAD_CONST               2 (322376503)26 PRECALL                  130 CALL                     140 STORE_NAME               2 (r)6          42 PUSH_NULL44 LOAD_NAME                3 (input)46 LOAD_CONST               3 ('Enter your flag: ')48 PRECALL                  152 CALL                     162 LOAD_METHOD              4 (encode)84 PRECALL                  088 CALL                     098 STORE_NAME               5 (pt)8         100 LOAD_CONST               4 (b'\x8b\xcck\xd3\xed\x96\xffFb\x06r\x085\x82\xbc \xb2\xde)p\x88Q`\x1bf\x18\xb6QUSw\x10\xcd\xd9\x13A$\x86\xe5\xcd\xd9\xff')102 STORE_NAME               6 (ct)10         104 BUILD_LIST               0106 STORE_NAME               7 (buf)12         108 LOAD_NAME                5 (pt)110 GET_ITER>>  112 FOR_ITER                46 (to 206)114 STORE_NAME               8 (b)13         116 LOAD_NAME                7 (buf)118 LOAD_METHOD              9 (append)140 LOAD_NAME                2 (r)142 LOAD_METHOD             10 (randint)164 LOAD_CONST               0 (0)166 LOAD_CONST               5 (255)168 PRECALL                  2172 CALL                     2182 LOAD_NAME                8 (b)184 BINARY_OP               12 (^)188 PRECALL                  1192 CALL                     1202 POP_TOP204 JUMP_BACKWARD           47 (to 112)15     >>  206 PUSH_NULL208 LOAD_NAME               11 (bytes)210 LOAD_NAME                7 (buf)212 PRECALL                  1216 CALL                     1226 LOAD_NAME                6 (ct)228 COMPARE_OP               2 (==)234 POP_JUMP_FORWARD_IF_TRUE     2 (to 240)236 LOAD_ASSERTION_ERROR238 RAISE_VARARGS            117     >>  240 PUSH_NULL242 LOAD_NAME               12 (print)244 LOAD_CONST               6 ('Correct!')246 PRECALL                  1250 CALL                     1260 POP_TOP262 LOAD_CONST               1 (None)264 RETURN_VALUE
None

大致能看出脚本流程,保险起见用ChatGPt辅助帮忙分析,得出程序:

import random
r = random.Random(322376503)
pt = input("Enter your flag:").encode()
ct = b'\x8b\xcck\xd3\xed\x96\xffFb\x06r\x085\x82\xbc \xb2\xde)p\x88Q`\x1bf\x18\xb6QUSw\x10\xcd\xd9\x13A$\x86\xe5\xcd\xd9\xff'
buf = []
for b in pt:buf.append(r.randint(0,255) ^ b)
if bytes(buf) == ct:print('Correct!')
else:None

到这里就轻松一些了,进行了异或运算,随机数种子为322376503,解密脚本如下:

import random
r = random.Random(322376503)
ct = b'\x8b\xcck\xd3\xed\x96\xffFb\x06r\x085\x82\xbc \xb2\xde)p\x88Q`\x1bf\x18\xb6QUSw\x10\xcd\xd9\x13A$\x86\xe5\xcd\xd9\xff'
flag = []
for b in ct:flag.append(r.randint(0,255) ^ b)for i in range(len(flag)):print(chr(flag[i]),end="")# flag{69858b56-4987-438f-a02c-5ab5c09e5138}

FLAG:flag{69858b56-4987-438f-a02c-5ab5c09e5138}

日期:2023.5.5

题目:findit

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,可以看出是一个apk文件,放入JEB中进行反编译,找到MainActivity函数,查看其中函数。

package com.example.findit;import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.MenuItem;
import android.view.View.OnClickListener;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;public class MainActivity extends ActionBarActivity {@Override  // android.support.v7.app.ActionBarActivityprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);this.setContentView(0x7F030018);  // layout:activity_mainButton btn = (Button)this.findViewById(0x7F05003D);  // id:widget3EditText edit = (EditText)this.findViewById(0x7F05003E);  // id:widget2TextView text = (TextView)this.findViewById(0x7F05003F);  // id:widget1btn.setOnClickListener(new View.OnClickListener() {@Override  // android.view.View$OnClickListenerpublic void onClick(View v) {char[] x = new char[17];char[] y = new char[38];for(int i = 0; i < 17; ++i) {if(new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] < 73 && new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] >= 65 || new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] < 105 && new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] >= 97) {x[i] = (char)(new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] + 18);}else if(new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] >= 65 && new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] <= 90 || new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] >= 97 && new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] <= 0x7A) {x[i] = (char)(new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] - 8);}else {x[i] = new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i];}}if(String.valueOf(x).equals(edit.getText().toString())) {for(int v1 = 0; v1 < 38; ++v1) {if(new char[]{'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'}[v1] >= 65 && new char[]{'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'}[v1] <= 90 || new char[]{'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'}[v1] >= 97 && new char[]{'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'}[v1] <= 0x7A) {y[v1] = (char)(new char[]{'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'}[v1] + 16);if(y[v1] > 90 && y[v1] < 97 || y[v1] >= 0x7A) {y[v1] = (char)(y[v1] - 26);}}else {y[v1] = new char[]{'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'}[v1];}}text.setText(String.valueOf(y));return;}text.setText("答案错了肿么办。。。不给你又不好意思。。。哎呀好纠结啊~~~");}});}@Override  // android.app.Activitypublic boolean onOptionsItemSelected(MenuItem item) {return item.getItemId() == 0x7F050040 ? true : super.onOptionsItemSelected(item);  // id:action_settings}
}

分析程序可知,对密文进行了凯撒加密,key值为10,找一个在线解密网站即可进行解密。

FLAG:flag{c164675262033b4c49bdf7f9cda28a75}

题目:DASCTF Apr.2023 X SU战队2023开局之战 【中等】gotots

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,根据题目名和题目介绍可以猜测是用go语言编写的程序,放入IDA中进行分析,但是找不到main函数,于是根据执行程序输出的字符串"Incorrect!"去查找字符串,想通过交叉引用去查找关键函数,可是找不到关键函数,陷入困境。

后来,看到其他师傅写的wp中是在"Incorrect!"这里下一个硬件断点进行查找或者是使用IDA Freeware 8.2,这里用了IDA Freeware 8.2进行查看,尝试着从官网IDA Free (hex-rays.com)下载过来,按原先思路进行交叉引用,终于找到了关键函数。

分析这个函数,函数进行了两个循环,第一个循环不清楚作用,第二个循环是在进行异或加密,将v11数组中的值依次与sub_327640函数的返回值进行异或加密。

__int64 __fastcall sub_327820()
{__int64 v0; // r14__int128 v1; // xmm15__int64 i; // rax__int64 v3; // rbx__int64 v4; // rax__int64 v5; // rcx__int64 j; // rdx__int64 v8; // [rsp+0h] [rbp-A8h]__int64 v9; // [rsp+8h] [rbp-A0h]__int64 j_1; // [rsp+10h] [rbp-98h]__int64 v11; // [rsp+38h] [rbp-70h]_QWORD *v12; // [rsp+40h] [rbp-68h]__int128 v13; // [rsp+48h] [rbp-60h] BYREFvoid *v14; // [rsp+58h] [rbp-50h]char **v15; // [rsp+60h] [rbp-48h]const char *v16; // [rsp+68h] [rbp-40h]_QWORD *v17; // [rsp+70h] [rbp-38h]_DWORD *v18; // [rsp+78h] [rbp-30h]__int128 v19; // [rsp+80h] [rbp-28h]__int128 v20; // [rsp+90h] [rbp-18h]if ( &v13 + 8 <= *(v0 + 16) )(sub_2EC3E0)();v12 = (runtime_newobject)();*v12 = 0LL;v16 = "\b";v17 = v12;fmt_Fscanln();                                // 输入v18 = v1;v19 = v1;v20 = v1;v18 = (runtime_makeslice)();*&v19 = 624LL;*(&v19 + 1) = 624LL;*v18 = 259598975;for ( i = 1LL; i < 624; ++i ){if ( v19 <= i - 1 )(sub_2EEA40)();if ( i >= v19 )(sub_2EEA40)();v18[i] = i + 1812433253 * (v18[i - 1] ^ (v18[i - 1] >> 30));}LODWORD(v20) = 1;*(&v20 + 1) = 0LL;v3 = *v12;v4 = (runtime_stringtoslicebyte)();v11 = v4;v8 = v3;v9 = v5;j = 0LL;while ( v3 > j ){j_1 = j;*(v11 + j) ^= sub_327640();                 // 异或加密j = j_1 + 1;v4 = v11;v5 = v9;v3 = v8;}if ( sub_292480(v4, v3, off_3E06D0, qword_3E06E0, v5) )// 估计是进行比较{*(&v13 + 1) = &off_364E68;                  // 输出"Incorrect!"}else{v14 = &unk_330540;v15 = &off_364E58;                          // 输出"Correct!"}return sub_31D6E0();
}

查看sub_327640函数,一看给愣住,这是啥算法啊?

__int64 __fastcall sub_327640()
{__int64 v0; // raxint v1; // edx_DWORD *v2; // rdxunsigned __int64 v3; // rcx__int64 i; // rbxunsigned __int64 v5; // rbxunsigned int v6; // ecxunsigned int v7; // ecx__int64 j; // rbxv1 = *(v0 + 24);*(v0 + 24) = v1 - 1;if ( v1 == 1 ){v2 = *v0;v3 = *(v0 + 8);*(v0 + 24) = 624;*(v0 + 32) = 0LL;for ( i = 0LL; i < 227; ++i ){if ( i >= v3 )sub_2EEA40();if ( v3 <= i + 1 )sub_2EEA40();if ( v3 <= i + 397 )sub_2EEA40();v2[i] = v2[i + 397] ^ -(v2[i + 1] & 1) & 0x9908B0DF ^ (((v2[i] ^ v2[i + 1]) & 0x7FFFFFFEu ^ v2[i]) >> 1);}for ( j = 227LL; j < 623; ++j ){if ( j >= v3 )sub_2EEA40();if ( v3 <= j + 1 )sub_2EEA40();v2[j] = v2[j - 227] ^ (((v2[j] ^ v2[j + 1]) & 0x7FFFFFFEu ^ v2[j]) >> 1) ^ -(v2[j + 1] & 1) & 0x9908B0DF;}if ( v3 <= 0x26F )sub_2EEA40();v2[623] = v2[396] ^ (((v2[623] ^ *v2) & 0x7FFFFFFEu ^ v2[623]) >> 1) ^ -(*v2 & 1) & 0x9908B0DF;}v5 = *(v0 + 32);if ( v5 >= *(v0 + 8) )sub_2EEA40();v6 = *(*v0 + 4 * v5);*(v0 + 32) = v5 + 1;v7 = v6 ^ (v6 >> 11) ^ (((v6 ^ (v6 >> 11)) & 0xFF3A58AD) << 7);return (v7 ^ ((v7 & 0xFFFFDF8C) << 15) ^ ((v7 ^ ((v7 & 0xFFFFDF8C) << 15)) >> 18)) >> 1;
}

询问了一下ChatGPt后得知,这是一个叫做"Mersenne Twister"的伪随机数算法,浅看了一下这个算法梅森旋转算法(Mersenne Twister)_weixin_30306905的博客-CSDN博客,大致知道了第一个循环是在进行算法的初始化。所以主要关注的就是第二个循环中的异或加密。

密文存放在off_3E06D0中,所以只需要知道依次异或了哪些值即可,用了一个有点硬核的办法,因为sub_327640函数的返回值会存放在eax寄存器中,并只取值的后八位进行异或,所以在"xor     ecx, eax"处下一个断点,执行到此处时eax值的后8位的值就是与密文异或的值,因为不知道怎么写脚本获取,只能一个个手动获取,之后若是学会使用脚本获取,再在后面补上。解密脚本如下:

def main():cipher = [  0x35, 0x8C, 0xEB, 0x85, 0x2C, 0xFA, 0x2D, 0xB1, 0x42, 0x82, 0x27, 0xD0, 0x10, 0xED, 0x06, 0x8E, 0x0D, 0xFE, 0xA8, 0x1E, 0x81, 0x3C, 0x8A, 0xBB, 0xB7, 0x0B, 0xF4, 0xF0, 0x7C, 0x6B, 0x70, 0x26, 0x71, 0x8B, 0x73, 0x7D  ]key = [0x57,0xb8,0x8e,0xbc,0x49,0x9b,0x4c,0x87,0x6f,0xe3,0x14,0xe0,0x26,0xc0,0x32,0xbd,0x6c,0xc7,0x85,0x26,0xe2,0x59,0xee,0x96,0xd1,0x6f,0x91,0x95,0x4f,0x5c,0x48,0x40,0x46,0xb8,0x45,0x1e]for i in range(len(key)):print(chr(cipher[i]^key[i]),end="")if __name__ == '__main__':main()# b4e9eaa6-a306-43a9-8ced-fdee378f736c

FLAG:flag{b4e9eaa6-a306-43a9-8ced-fdee378f736c}

2023.5.6添加注释

突然意识到不用脚本也可以比较方便拿到全部密钥,因为v4中存放的就是输入内容与密钥进行异或后的值,所以将断点断在进行比较的位置处,此时输入的内容已经全部加密,这样只需要将输入内容与异或加密后的内容再进行一个异或即可得到密钥。

查看v4,v4中的已经是加密后的输入内容。

接着即可写脚本获取全部密钥,脚本如下:

cipher = [ 0x66, 0x8A, 0xBD, 0x88, 0x7C, 0xAD, 0x7B, 0xBF, 0x56, 0xD3, 0x25, 0xD2, 0x15, 0xF4, 0x07, 0x8B, 0x5B, 0xFF, 0xBC, 0x16, 0xD3, 0x6B, 0xDD, 0xA2, 0xE4, 0x59, 0xA6, 0xAD, 0x76, 0x6C, 0x79, 0x72, 0x75, 0x8C, 0x70, 0x2 ]
input_value = "123456789012345678901234567890123456"
key = []
for i in range(0,len(input_value)):key.append(hex(ord(input_value[i]) ^ cipher[i]))
print(key)# key = ['0x57', '0xb8', '0x8e', '0xbc', '0x49', '0x9b', '0x4c', '0x87', '0x6f', '0xe3', '0x14', '0xe0', '0x26', '0xc0', '0x32', '0xbd', '0x6c', '0xc7', '0x85', '0x26', '0xe2', '0x59', '0xee', '0x96', '0xd1', '0x6f', '0x91', '0x95', '0x4f', '0x5c', '0x48', '0x40', '0x46', '0xb8', '0x45', '0x34']

日期:2023.5.6

题目:[ACTF新生赛2020]rome

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,32位可执行文件,无壳,放入IDA中进行分析,从main函数中找到一个func函数。查看func函数:

int func()
{int result; // eaxint v1[4]; // [esp+14h] [ebp-44h]unsigned __int8 v2; // [esp+24h] [ebp-34h] BYREFunsigned __int8 v3; // [esp+25h] [ebp-33h]unsigned __int8 v4; // [esp+26h] [ebp-32h]unsigned __int8 v5; // [esp+27h] [ebp-31h]unsigned __int8 v6; // [esp+28h] [ebp-30h]int v7; // [esp+29h] [ebp-2Fh]int v8; // [esp+2Dh] [ebp-2Bh]int v9; // [esp+31h] [ebp-27h]int v10; // [esp+35h] [ebp-23h]unsigned __int8 v11; // [esp+39h] [ebp-1Fh]char v12[29]; // [esp+3Bh] [ebp-1Dh] BYREFstrcpy(v12, "Qsw3sj_lz4_Ujw@l");printf("Please input:");scanf("%s", &v2);result = v2;if ( v2 == 'A' ){result = v3;if ( v3 == 'C' ){result = v4;if ( v4 == 'T' ){result = v5;if ( v5 == 'F' ){result = v6;if ( v6 == '{' ){result = v11;if ( v11 == '}' ){v1[0] = v7;v1[1] = v8;v1[2] = v9;v1[3] = v10;*&v12[17] = 0;while ( *&v12[17] <= 15 ){if ( *(v1 + *&v12[17]) > '@' && *(v1 + *&v12[17]) <= 'Z' )*(v1 + *&v12[17]) = (*(v1 + *&v12[17]) - 51) % 26 + 65;if ( *(v1 + *&v12[17]) > '`' && *(v1 + *&v12[17]) <= 'z' )*(v1 + *&v12[17]) = (*(v1 + *&v12[17]) - 79) % 26 + 97;++*&v12[17];}*&v12[17] = 0;while ( *&v12[17] <= 15 ){result = v12[*&v12[17]];if ( *(v1 + *&v12[17]) != result )return result;++*&v12[17];}return printf("You are correct!");}}}}}}return result;
}

可以看出是对输入内容中的小写字母和大写字母进行加密,再与密文进行比较。直接写脚本爆破即可。脚本如下:

import string
def main():dist = string.ascii_letterscipher = "Qsw3sj_lz4_Ujw@l"flag = "ACTF{"for i in range(len(cipher)):for d in dist:if ord(d) > 64 and ord(d) <= 90:v = chr((ord(d) - 51) % 26 + 65)elif ord(d) > 96 and ord(d) <= 122:v = chr((ord(d) - 79) % 26 + 97)if v == cipher[i]:flag += dbreakif d == dist[-1]:if v != cipher[i]:flag += cipher[i]print(flag + '}')
if __name__ == '__main__':main()# ACTF{Cae3ar_th4_Gre@t}

FLAG:flag{Cae3ar_th4_Gre@t}

题目:[FlareOn4]login

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,得到一个Description.txt和一个login.html,查看html文件,显示了一个输入框和一个按钮,猜测是输入flag进行判断。

按F12进行查看,发现一个疑似是密文的字符串,上一行是对输入内容进行加密,可以看出进行的是凯撒加密,key值为13。

用一个在线解密网站即可解出flag。

进行验证,flag正确。

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

题目:简单注册器

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,是一个apk文件,放进JEB中进行分析,查看MainActivity函数,可以很清晰地看出加密过程,将arr_c中的字符串按流程来进行加密即可。

脚本如下:

cipher = "dd2940c04462b4dd7c450528835cca15"
cipher = list(cipher)
cipher[2] = chr(ord(cipher[2]) + ord(cipher[3]) - 50)
cipher[4] = chr(ord(cipher[2]) + ord(cipher[5]) - 0x30)
cipher[30] = chr(ord(cipher[31]) + ord(cipher[9]) - 0x30)
cipher[14] = chr(ord(cipher[27]) + ord(cipher[28]) - 0x61)
for i in range(0,16):a = cipher[31-i]cipher[31-i] = cipher[i]cipher[i] = afor j in range(0,len(cipher)):print(cipher[j],end="")# 59acc538825054c7de4b26440c0999dd

FLAG:flag{59acc538825054c7de4b26440c0999dd}

日期:2023.5.7

题目:[WUSTCTF2020]level1

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,得到一个elf文件和一个txt文件,将elf文件放入IDA中,查看main函数,可以看出对打开一个flag文件,对其中内容进行了一个简单的加密,txt文件中存放的是加密后的密文。

int __cdecl main(int argc, const char **argv, const char **envp)
{int i; // [rsp+4h] [rbp-2Ch]FILE *stream; // [rsp+8h] [rbp-28h]char ptr[24]; // [rsp+10h] [rbp-20h] BYREFunsigned __int64 v7; // [rsp+28h] [rbp-8h]v7 = __readfsqword(0x28u);stream = fopen("flag", "r");fread(ptr, 1uLL, 0x14uLL, stream);fclose(stream);for ( i = 1; i <= 19; ++i ){if ( (i & 1) != 0 )printf("%ld\n", (ptr[i] << i));elseprintf("%ld\n", (i * ptr[i]));}return 0;
}
# output.txt
198
232
816
200
1536
300
6144
984
51200
570
92160
1200
565248
756
1474560
800
6291456
1782
65536000

可以直接写出解密脚本,脚本如下:

cipher = [198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000]
flag = ""
for i in range(0,len(cipher)):if (i & 1) == 0 :flag += chr(cipher[i] >> (i+1))else:flag += chr(cipher[i]//(i+1))
print(flag)# ctf2020{d9-dE6-20c}

FLAG:flag{d9-dE6-20c}

题目:[WUSTCTF2020]level2

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,查壳发现有UPX壳,对其进行脱壳。

脱壳后放入IDA中进行分析,查看main函数,发现什么也没有。

切换界面发现藏着的flag。

FLAG:flag{Just_upx_-d}

题目:[WUSTCTF2020]level3

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,放入IDA中进行分析,查看main函数,发现了对输入内容进行了base64加密,找到密文"d2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD==
",解密发现不是flag,猜测进行了base64换表。

int __cdecl main(int argc, const char **argv, const char **envp)
{const char *v3; // raxchar v5; // [rsp+Fh] [rbp-41h]char v6[56]; // [rsp+10h] [rbp-40h] BYREFunsigned __int64 v7; // [rsp+48h] [rbp-8h]v7 = __readfsqword(0x28u);printf("Try my base64 program?.....\n>");__isoc99_scanf("%20s", v6);v5 = time(0LL);srand(v5);if ( (rand() & 1) != 0 ){v3 = base64_encode(v6);puts(v3);puts("Is there something wrong?");}else{puts("Sorry I think it's not prepared yet....");puts("And I get a strange string from my program which is different from the standard base64:");puts("d2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD==");puts("What's wrong??");}return 0;
}

查看base64表发现表没有进行变化,猜测可能是在程序执行过程中进行更换。

注意到一个特别的函数O_OLookAtYou,查看O_OLookAtYou函数,发现该函数就是在对base64表进行修改。

__int64 O_OLookAtYou()
{__int64 result; // raxchar v1; // [rsp+1h] [rbp-5h]int i; // [rsp+2h] [rbp-4h]for ( i = 0; i <= 9; ++i ){v1 = base64_table[i];base64_table[i] = base64_table[19 - i];result = 19 - i;base64_table[result] = v1;}return result;
}

于是直接在main函数if语句判断处下一个断点,获取修改后的base64表。

获取到base64表后即可开始写解密脚本,脚本如下:

import base64
import stringstr1 = "d2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD=="string1 = "TSRQPONMLKJIHGFEDCBAUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"print(base64.b64decode(str1.translate(str.maketrans(string1,string2))))# b'wctf2020{Base64_is_the_start_of_reverse}'

FLAG:flag{Base64_is_the_start_of_reverse}

题目:[WUSTCTF2020]level4

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,放入IDA中进行分析,查看main函数,发现没有什么关键内容。

int __cdecl main(int argc, const char **argv, const char **envp)
{puts("Practice my Data Structure code.....");puts("Typing....Struct.....char....*left....*right............emmmmm...OK!");init();puts("Traversal!");printf("Traversal type 1:");type1(&qword_601290);printf("\nTraversal type 2:");type2(&qword_601290);printf("\nTraversal type 3:");puts("    //type3(&x[22]);   No way!");puts(&byte_400A37);return 0;
}

查看init函数,发现了一个疑似是密文的字符串。

unsigned __int64 init()
{int i; // [rsp+Ch] [rbp-34h]char v2[40]; // [rsp+10h] [rbp-30h] BYREFunsigned __int64 v3; // [rsp+38h] [rbp-8h]v3 = __readfsqword(0x28u);strcpy(v2, "I{_}Af2700ih_secTS2Et_wr");for ( i = 0; i <= 23; ++i )x[24 * i] = v2[i];qword_601298 = &unk_6011E8;qword_6011F0 = &unk_601260;qword_601268 = &unk_6010F8;qword_601100 = &unk_601110;qword_601108 = &unk_601140;qword_601270 = &unk_601230;qword_601238 = &unk_601158;qword_601240 = &unk_601098;qword_6010A0 = &unk_601200;qword_6010A8 = &unk_601188;qword_6011F8 = &unk_601170;qword_601178 = &unk_6011B8;qword_601180 = &unk_6010B0;qword_6010B8 = x;qword_6010C0 = &unk_601218;qword_6012A0 = &unk_601278;qword_601280 = &unk_6010E0;qword_601288 = &unk_6011A0;qword_6011B0 = &unk_601128;qword_601130 = &unk_6012A8;qword_601138 = &unk_6011D0;qword_6011D8 = &unk_601248;qword_6011E0 = &unk_6010C8;return __readfsqword(0x28u) ^ v3;
}

在return处下一个断点,发现按顺序查看unk内容就是flag。依次取出内容为ctf2020{This_IS_A_7reE}

FLAG:flag{This_IS_A_7reE}

日期:2023.5.8

题目:CrackRTF

刷题平台:BUUCTF

方向:REVERSE

Write UP:

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

int __cdecl main_0(int argc, const char **argv, const char **envp)
{DWORD v3; // eaxDWORD v4; // eaxchar Str[260]; // [esp+4Ch] [ebp-310h] BYREFint v7; // [esp+150h] [ebp-20Ch]char String1[260]; // [esp+154h] [ebp-208h] BYREFchar Destination[260]; // [esp+258h] [ebp-104h] BYREFmemset(Destination, 0, sizeof(Destination));memset(String1, 0, sizeof(String1));v7 = 0;printf("pls input the first passwd(1): ");scanf("%s", Destination);if ( strlen(Destination) != 6 ){printf("Must be 6 characters!\n");ExitProcess(0);}v7 = atoi(Destination);if ( v7 < 100000 )ExitProcess(0);strcat(Destination, "@DBApp");v3 = strlen(Destination);sub_40100A(Destination, v3, String1);if ( !_strcmpi(String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") ){printf("continue...\n\n");printf("pls input the first passwd(2): ");memset(Str, 0, sizeof(Str));scanf("%s", Str);if ( strlen(Str) != 6 ){printf("Must be 6 characters!\n");ExitProcess(0);}strcat(Str, Destination);memset(String1, 0, sizeof(String1));v4 = strlen(Str);sub_401019(Str, v4, String1);if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", String1) ){if ( !sub_40100F(Str) ){printf("Error!!\n");ExitProcess(0);}printf("bye ~~\n");}}return 0;
}

可以看出需要输入输入两段内容,每段内容长度为6,atoi函数是将第一段输入字符串转换成整型数,根据函数下面的if语句可以知道,第一段输入的字符串范围为100000~999999。

查看sub_40100A函数里的sub_401230函数,分析函数可以得知进行了SHA1加密。

int __cdecl sub_401230(BYTE *pbData, DWORD dwDataLen, LPSTR lpString1)
{DWORD i; // [esp+4Ch] [ebp-28h]CHAR String2[4]; // [esp+50h] [ebp-24h] BYREFBYTE v6[20]; // [esp+54h] [ebp-20h] BYREFDWORD pdwDataLen; // [esp+68h] [ebp-Ch] BYREFHCRYPTHASH phHash; // [esp+6Ch] [ebp-8h] BYREFHCRYPTPROV phProv; // [esp+70h] [ebp-4h] BYREFif ( !CryptAcquireContextA(&phProv, 0, 0, 1u, 0xF0000000) )return 0;if ( CryptCreateHash(phProv, 0x8004u, 0, 0, &phHash) ){if ( CryptHashData(phHash, pbData, dwDataLen, 0) ){CryptGetHashParam(phHash, 2u, v6, &pdwDataLen, 0);*lpString1 = 0;for ( i = 0; i < pdwDataLen; ++i ){wsprintfA(String2, "%02X", v6[i]);lstrcatA(lpString1, String2);}CryptDestroyHash(phHash);CryptReleaseContext(phProv, 0);return 1;}else{CryptDestroyHash(phHash);CryptReleaseContext(phProv, 0);return 0;}}else{CryptReleaseContext(phProv, 0);return 0;}
}

可以判断出第一段输入内容与"@DBApp"字符串进行拼接,再进行SHA1加密,密文为"6E32D0943418C2C33385BC35A1470250DD8923A9",由此我们可以写一个爆破脚本得出第一段字符串,脚本如下:

import hashlib
def main():cipher1 = "6E32D0943418C2C33385BC35A1470250DD8923A9"v2 = "@DBApp"for i in range(100000,1000000):v1 = str(i) + v2sha1 = hashlib.sha1(v1.encode())if sha1.hexdigest().upper() == cipher1:print(i)breakif __name__ == '__main__':main()# 123321

得出第一段字符串为"123321",接着继续往下解题,第二段字符串长度也是为6,但是不知道范围,继续往下看,sub_401019函数同样也是进行了一个哈希加密,再去查看sub_40100F函数中的sub_4014D0函数,函数去获取了程序中名为"AAA"的资源,最后经过一些操作后,会写入到一个名为"dbapp.rtf"的文件中。

char __cdecl sub_4014D0(LPCSTR lpString)
{LPCVOID lpBuffer; // [esp+50h] [ebp-1Ch]DWORD NumberOfBytesWritten; // [esp+58h] [ebp-14h] BYREFDWORD nNumberOfBytesToWrite; // [esp+5Ch] [ebp-10h]HGLOBAL hResData; // [esp+60h] [ebp-Ch]HRSRC hResInfo; // [esp+64h] [ebp-8h]HANDLE hFile; // [esp+68h] [ebp-4h]hFile = 0;hResData = 0;nNumberOfBytesToWrite = 0;NumberOfBytesWritten = 0;hResInfo = FindResourceA(0, 0x65, "AAA");if ( !hResInfo )return 0;nNumberOfBytesToWrite = SizeofResource(0, hResInfo);hResData = LoadResource(0, hResInfo);if ( !hResData )return 0;lpBuffer = LockResource(hResData);sub_401005(lpString, lpBuffer, nNumberOfBytesToWrite);hFile = CreateFileA("dbapp.rtf", 0x10000000u, 0, 0, 2u, 0x80u, 0);if ( hFile == -1 )return 0;if ( !WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0) )return 0;CloseHandle(hFile);return 1;
}

将程序放入ResourceHacker中,找到"AAA"资源,暂时不知道这些内容有何作用。

查看了一下sub_401005中的sub_401420函数,发现这个函数进行了一个异或,lpString中存放的实际就是第二串输入字符串、第一段输入字符串和"@DBApp"拼接而成的一个字符串,a2里存放"AAA"资源中的内容。

unsigned int __cdecl sub_401420(LPCSTR lpString, int a2, unsigned int a3)
{unsigned int result; // eaxunsigned int i; // [esp+4Ch] [ebp-Ch]unsigned int v5; // [esp+54h] [ebp-4h]v5 = lstrlenA(lpString);for ( i = 0; ; ++i ){result = i;if ( i >= a3 )break;*(i + a2) ^= lpString[i % v5];}return result;
}

由此就有思路了,因为首先开始参与异或的是第二串输入字符串,"AAA"资源前6位内容已知,只需要知道"dbapp.rtf"文件前6位内容即可,而rtf文件前六位内容为文件头部分的内容,只需查找或者自己创建rtf文件即可知道文件头。

由此即可写脚本,来得到第二串输入字符串。脚本如下:

key1 = "{\\rtf1"
key2 = [0x05,0x7D,0x41,0x15,0x26,0x01]
str2 = ""
for i in range(6):str2 += chr(ord(key1[i]) ^ key2[i])
print(str2)# ~!3a@0

获得第二串输入字符串"~!3a@0",最后拼接得出的字符串为"~!3a@0123321@DBApp",可以用这串字符串来与AAA资源中的内容进行异或得出flag。

str3 = "~!3a@0123321@DBApp"
value = [0x05,0x7D,0x41,0x15,0x26,0x01,0x6D,0x53,0x5D,0x40,0x5B,0x6D,0x21,0x2A,0x31,0x28,0x13,0x00,0x19,0x18,0x00,0x57,0x1C,0x54,0x54,0x54,0x55,0x03,0x6E,0x55,0x25,0x22,0x2E,0x20,0x1E,0x17,0x4F,0x11,0x00,0x52,0x1C,0x54,0x54,0x54,0x5F,0x52,0x5C,0x56,0x26,0x21,0x70,0x71,0x45,0x42,0x05,0x7D,0x55,0x0E,0x2E,0x44,0x45,0x50,0x5F,0x48,0x6E,0x57,0x70,0x18,0x24,0x2C,0x1F,0x14,0x1B,0x53,0x5D,0x3D,0x26,0x40,0x43,0x43,0x05,0x6F,0x54,0x52,0x28,0x25,0x30,0x32,0x15,0x04,0x4F,0x12,0x07,0x41,0x1C,0x17,0x52,0x50,0x6F,0x14,0x51,0x54,0x1C,0x63,0x21,0x22,0x2C,0x57,0x1B,0x14,0x08,0x1C,0x3D,0x3D,0x3B,0x49,0x6F,0x19,0x6E,0x56,0x25,0x2A,0x27,0x33,0x11,0x04,0x11,0x53,0x13,0x2C,0x33,0x56,0x45,0x57,0x57,0x5A,0x46,0x11,0x75,0x6A,0x76,0x70,0x5E,0x41,0x4B,0x0F,0x02,0x54,0x71,0x05,0x0A,0x4F,0x6F,0x45,0x5B,0x54,0x37,0x2F,0x2B,0x2F,0x14,0x44,0x22,0x54,0x50,0x50,0x1C,0x40,0x50,0x40,0x57,0x6F,0x5E,0x50,0x2E,0x23,0x70,0x71,0x45,0x42,0x22,0x47,0x03,0x3D,0x26,0x43,0x03,0x02,0x13,0x75,0x5E,0x50,0x27,0x18,0x39,0x0F,0x40,0x2F,0x33,0x11,0x41,0x04,0x1F,0x76,0x43,0x57,0x56,0x6C,0x70,0x44,0x27,0x37,0x1E,0x3C,0x2C,0x00,0x1F,0x53,0x3E,0x6B,0x3D,0x3D,0x3B,0x32]
for i in range(len(value)):print(chr((value[i]^ord(str3[i%len(str3)]))),end="")# {\rtf1\ansi\ansicpg936\deff0\deflang1033\deflangfe2052{\fonttbl{\f0\fmodern\fprq6\fcharset134 \'cb\'ce\'cc\'e5;}}
# {\*\generator Msftedit 5.41.15.1515;}\viewkind4\uc1\pard\lang2052\f0\fs20 Flag\{N0_M0re_Free_Bugs\}\par
# }

也可以按程序流程,依次输入"123321"、"~!3a@0",这样就能获得"dbapp.rtf"文件。flag已经被写入文件之中。

FLAG:flag{N0_M0re_Free_Bugs}

题目:[GUET-CTF2019]re

刷题平台:BUUCTF

方向:REVERSE

Write UP:

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

进行脱壳后,放入IDA中进行分析,因为找不到main函数,于是打开字符串窗口,根据执行文件后返回的"Wrong!"字符串,从而找到关键函数sub_400E28。

__int64 __fastcall sub_400E28(__int64 a1, int a2, int a3, int a4, int a5, int a6)
{int v6; // edxint v7; // ecxint v8; // r8dint v9; // r9d__int64 result; // rax__int64 v11[5]; // [rsp+0h] [rbp-30h] BYREFunsigned __int64 v12; // [rsp+28h] [rbp-8h]v12 = __readfsqword(0x28u);memset(&v11[1], 0, 24);sub_40F950("input your flag:", a2, a3, a4, a5, a6);sub_40FA80("%s", v11, v6, v7, v8, v9, 0);if ( sub_4009AE(v11) )sub_410350("Correct!");elsesub_410350("Wrong!");result = 0LL;if ( __readfsqword(0x28u) != v12 )sub_443550();return result;
}

程序逻辑很清晰,查看sub_4009AE函数。

_BOOL8 __fastcall sub_4009AE(char *a1)
{if ( 1629056 * *a1 != 166163712 )return 0LL;if ( 6771600 * a1[1] != 731332800 )return 0LL;if ( 3682944 * a1[2] != 357245568 )return 0LL;if ( 10431000 * a1[3] != 1074393000 )return 0LL;if ( 3977328 * a1[4] != 489211344 )return 0LL;if ( 5138336 * a1[5] != 518971936 )return 0LL;if ( 7532250 * a1[7] != 406741500 )return 0LL;if ( 5551632 * a1[8] != 294236496 )return 0LL;if ( 3409728 * a1[9] != 177305856 )return 0LL;if ( 13013670 * a1[10] != 650683500 )return 0LL;if ( 6088797 * a1[11] != 298351053 )return 0LL;if ( 7884663 * a1[12] != 386348487 )return 0LL;if ( 8944053 * a1[13] != 438258597 )return 0LL;if ( 5198490 * a1[14] != 249527520 )return 0LL;if ( 4544518 * a1[15] != 445362764 )return 0LL;if ( 3645600 * a1[17] != 174988800 )return 0LL;if ( 10115280 * a1[16] != 981182160 )return 0LL;if ( 9667504 * a1[18] != 493042704 )return 0LL;if ( 5364450 * a1[19] != 257493600 )return 0LL;if ( 13464540 * a1[20] != 767478780 )return 0LL;if ( 5488432 * a1[21] != 312840624 )return 0LL;if ( 14479500 * a1[22] != 1404511500 )return 0LL;if ( 6451830 * a1[23] != 316139670 )return 0LL;if ( 6252576 * a1[24] != 619005024 )return 0LL;if ( 7763364 * a1[25] != 372641472 )return 0LL;if ( 7327320 * a1[26] != 373693320 )return 0LL;if ( 8741520 * a1[27] != 498266640 )return 0LL;if ( 8871876 * a1[28] != 452465676 )return 0LL;if ( 4086720 * a1[29] != 208422720 )return 0LL;if ( 9374400 * a1[30] == 515592000 )return 5759124 * a1[31] == 719890500;return 0LL;
}

找到密文处,函数对输入值依次进行了判断,这里可以直接用z3来进行求解求出flag,脚本如下:

from z3 import *
def main():x = [BitVec("x%d"%i,16) for i in range(32)]s = Solver()s.add( 1629056 * x[0] == 166163712 )s.add( 6771600 * x[1] == 731332800 )s.add( 3682944 * x[2] == 357245568 )s.add( 10431000 * x[3] == 1074393000 )s.add( 3977328 * x[4] == 489211344 )s.add( 5138336 * x[5] == 518971936 )s.add( 7532250 * x[7] == 406741500 )s.add( 5551632 * x[8] == 294236496 )s.add( 3409728 * x[9] == 177305856 )s.add( 13013670 * x[10] == 650683500 )s.add( 6088797 * x[11] == 298351053 )s.add( 7884663 * x[12] == 386348487 )s.add( 8944053 * x[13] == 438258597 )s.add( 5198490 * x[14] == 249527520 )s.add( 4544518 * x[15] == 445362764 )s.add( 3645600 * x[17] == 174988800 )s.add( 10115280 * x[16] == 981182160 )s.add( 9667504 * x[18] == 493042704 )s.add( 5364450 * x[19] == 257493600 )s.add( 13464540 * x[20] == 767478780 )s.add( 5488432 * x[21] == 312840624 )s.add( 14479500 * x[22] == 1404511500 )s.add( 6451830 * x[23] == 316139670 )s.add( 6252576 * x[24] == 619005024 )s.add( 7763364 * x[25] == 372641472 )s.add( 7327320 * x[26] == 373693320 )s.add( 8741520 * x[27] == 498266640 )s.add( 8871876 * x[28] == 452465676 )s.add( 4086720 * x[29] == 208422720 )s.add( 9374400 * x[30] == 515592000 )s.add( 5759124 * x[31] == 719890500 )if s.check() == sat:a = s.model()for i in range(32):print(a[x[i]],end=",")else:print("NONE")flag = [102,108,97,103,123,101,0,54,53,52,50,49,49,49,48,98,97,48,51,48,57,57,97,49,99,48,51,57,51,51,55,125]for i in range(32):print(chr(flag[i]),end="")
if __name__ == '__main__':main()# flag{e65421110ba03099a1c039337}

但是因为缺少了a1[6],所以flag是不完整的,需要去猜一下a1[6]处的值。

FLAG:flag{e165421110ba03099a1c039337}

日期:2023.5.9

题目:[MRCTF2020]Transform

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,放入IDA中进行分析,查看main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{char Str[104]; // [rsp+20h] [rbp-70h] BYREFint j; // [rsp+88h] [rbp-8h]int i; // [rsp+8Ch] [rbp-4h]sub_402230(argc, argv, envp);sub_40E640("Give me your code:\n");sub_40E5F0("%s", Str);if ( strlen(Str) != 33 ){sub_40E640("Wrong!\n");system("pause");exit(0);}for ( i = 0; i <= 32; ++i ){byte_414040[i] = Str[dword_40F040[i]];byte_414040[i] ^= LOBYTE(dword_40F040[i]);}for ( j = 0; j <= 32; ++j ){if ( byte_40F0E0[j] != byte_414040[j] ){sub_40E640("Wrong!\n");system("pause");exit(0);}}sub_40E640("Right!Good Job!\n");sub_40E640("Here is your flag: %s\n", Str);system("pause");return 0;
}

分析后对程序做简要处理

int __cdecl main(int argc, const char **argv, const char **envp)
{char input[104]; // [rsp+20h] [rbp-70h] BYREFint j; // [rsp+88h] [rbp-8h]int i; // [rsp+8Ch] [rbp-4h]sub_402230(argc, argv, envp);printf("Give me your code:\n");scanf("%s", input);if ( strlen(input) != 33 ){printf("Wrong!\n");system("pause");exit(0);}for ( i = 0; i <= 32; ++i ){input_enc[i] = input[key[i]];input_enc[i] ^= LOBYTE(key[i]);}for ( j = 0; j <= 32; ++j ){if ( cipher[j] != input_enc[j] ){printf("Wrong!\n");system("pause");exit(0);}}printf("Right!Good Job!\n");printf("Here is your flag: %s\n", input);system("pause");return 0;
}

可以看出,程序以数组key中的值作为下标将输入值给打乱了,再跟key中值进行异或。分析清楚程序流程后就可以开始写解密脚本了,脚本如下:

cipher = [0x67, 0x79, 0x7B, 0x7F, 0x75, 0x2B, 0x3C, 0x52, 0x53, 0x79, 0x57, 0x5E, 0x5D, 0x42, 0x7B, 0x2D, 0x2A, 0x66, 0x42, 0x7E, 0x4C, 0x57, 0x79, 0x41, 0x6B, 0x7E, 0x65, 0x3C, 0x5C, 0x45, 0x6F, 0x62, 0x4D]
key = [9,10,15,23,7,24,12,6,1,16,3,17,32,29,11,30,27,22,4,13,19,20,21,2,25,5,31,8,18,26,28,14,0]
cipher2 = []
flag = ""
for i in range(len(cipher)):cipher2.append(chr(cipher[i]^key[i]))
for i in range(len(cipher2)):flag += cipher2[key.index(i)]
print(flag)# MRCTF{Tr4nsp0sltiON_Clph3r_1s_3z}

FLAG:flag{Tr4nsp0sltiON_Clph3r_1s_3z}

题目:[2019红帽杯]easyRE

刷题平台:BUUCTF

方向:REVERSE

Write UP:

获取题目附件,放入IDA中进行分析,因为找不到main函数,所以用老方法,打开字符串窗口,查找有没有关键的字符串 ,找到"You found me!!!"。

通过交叉引用找到关键函数。

__int64 sub_4009C6()
{__int64 result; // raxint i; // [rsp+Ch] [rbp-114h]__int64 v2; // [rsp+10h] [rbp-110h]__int64 v3; // [rsp+18h] [rbp-108h]__int64 v4; // [rsp+20h] [rbp-100h]__int64 v5; // [rsp+28h] [rbp-F8h]__int64 v6; // [rsp+30h] [rbp-F0h]__int64 v7; // [rsp+38h] [rbp-E8h]__int64 v8; // [rsp+40h] [rbp-E0h]__int64 v9; // [rsp+48h] [rbp-D8h]__int64 v10; // [rsp+50h] [rbp-D0h]__int64 v11; // [rsp+58h] [rbp-C8h]char v12[13]; // [rsp+60h] [rbp-C0h] BYREFchar v13[4]; // [rsp+6Dh] [rbp-B3h] BYREFchar v14[19]; // [rsp+71h] [rbp-AFh] BYREFchar v15[32]; // [rsp+90h] [rbp-90h] BYREFint v16; // [rsp+B0h] [rbp-70h]char v17; // [rsp+B4h] [rbp-6Ch]char v18[72]; // [rsp+C0h] [rbp-60h] BYREFunsigned __int64 v19; // [rsp+108h] [rbp-18h]v19 = __readfsqword(0x28u);qmemcpy(v12, "Iodl>Qnb(ocy", 12);v12[12] = 127;qmemcpy(v13, "y.i", 3);v13[3] = 127;qmemcpy(v14, "d`3w}wek9{iy=~yL@EC", sizeof(v14));memset(v15, 0, sizeof(v15));v16 = 0;v17 = 0;sub_4406E0(0LL, v15, 37LL);v17 = 0;if ( sub_424BA0(v15) == 36 ){for ( i = 0; i < sub_424BA0(v15); ++i ){if ( (v15[i] ^ i) != v12[i] ){result = 4294967294LL;goto LABEL_13;}}sub_410CC0("continue!");memset(v18, 0, 65);sub_4406E0(0LL, v18, 64LL);v18[39] = 0;if ( sub_424BA0(v18) == 39 ){v2 = sub_400E44(v18);v3 = sub_400E44(v2);v4 = sub_400E44(v3);v5 = sub_400E44(v4);v6 = sub_400E44(v5);v7 = sub_400E44(v6);v8 = sub_400E44(v7);v9 = sub_400E44(v8);v10 = sub_400E44(v9);v11 = sub_400E44(v10);if ( !sub_400360(v11, off_6CC090) ){sub_410CC0("You found me!!!");sub_410CC0("bye bye~");}result = 0LL;}else{result = 4294967293LL;}}else{result = 0xFFFFFFFFLL;}
LABEL_13:if ( __readfsqword(0x28u) != v19 )sub_444020();return result;
}

对程序分析后可以对程序中的一些函数加以重命名。

__int64 sub_4009C6()
{__int64 result; // raxint i; // [rsp+Ch] [rbp-114h]__int64 v2; // [rsp+10h] [rbp-110h]__int64 v3; // [rsp+18h] [rbp-108h]__int64 v4; // [rsp+20h] [rbp-100h]__int64 v5; // [rsp+28h] [rbp-F8h]__int64 v6; // [rsp+30h] [rbp-F0h]__int64 v7; // [rsp+38h] [rbp-E8h]__int64 v8; // [rsp+40h] [rbp-E0h]__int64 v9; // [rsp+48h] [rbp-D8h]__int64 v10; // [rsp+50h] [rbp-D0h]__int64 v11; // [rsp+58h] [rbp-C8h]char v12[13]; // [rsp+60h] [rbp-C0h] BYREFchar v13[4]; // [rsp+6Dh] [rbp-B3h] BYREFchar v14[19]; // [rsp+71h] [rbp-AFh] BYREFchar v15[32]; // [rsp+90h] [rbp-90h] BYREFint v16; // [rsp+B0h] [rbp-70h]char v17; // [rsp+B4h] [rbp-6Ch]char v18[72]; // [rsp+C0h] [rbp-60h] BYREFunsigned __int64 v19; // [rsp+108h] [rbp-18h]v19 = __readfsqword(0x28u);qmemcpy(v12, "Iodl>Qnb(ocy", 12);v12[12] = 127;qmemcpy(v13, "y.i", 3);v13[3] = 127;qmemcpy(v14, "d`3w}wek9{iy=~yL@EC", sizeof(v14));memset(v15, 0, sizeof(v15));v16 = 0;v17 = 0;read(0LL, v15, 37LL);v17 = 0;if ( strlen(v15) == 36 ){for ( i = 0; i < strlen(v15); ++i ){if ( (v15[i] ^ i) != v12[i] ){result = 4294967294LL;goto LABEL_13;}}printf("continue!");memset(v18, 0, 65);read(0LL, v18, 64LL);v18[39] = 0;if ( strlen(v18) == 39 ){v2 = base64_enc(v18);v3 = base64_enc(v2);v4 = base64_enc(v3);v5 = base64_enc(v4);v6 = base64_enc(v5);v7 = base64_enc(v6);v8 = base64_enc(v7);v9 = base64_enc(v8);v10 = base64_enc(v9);v11 = base64_enc(v10);if ( !compare(v11, off_6CC090) ){printf("You found me!!!");printf("bye bye~");}result = 0LL;}else{result = 4294967293LL;}}else{result = 0xFFFFFFFFLL;}
LABEL_13:if ( __readfsqword(0x28u) != v19 )sub_444020();return result;
}

可以看出for语句中将输入值与i进行异或后与v12中内容进行比较,可以先写出一个解密脚本。脚本如下:

cipher = "Iodl>Qnb(ocy\x7Fy.i" + "\x7F" + "d`3w}wek9{iy=~yL@EC"
for i in range(len(cipher)):print(chr(ord(cipher[i])^i),end="")# Info:The first four chars are `flag`

解密后是一段提示,告诉我们前四个字符是"flag",接着后面又读取了一次输入,而后将输入值进行了10次base64加密,无变表。密文放于off_6CC090中。于是又可以写出一个解密脚本。脚本如下:

import base64
def main():cipher = b"Vm0wd2VHUXhTWGhpUm1SWVYwZDRWVll3Wkc5WFJsbDNXa1pPVlUxV2NIcFhhMk0xVmpKS1NHVkdXbFpOYmtKVVZtcEtTMUl5VGtsaVJtUk9ZV3hhZVZadGVHdFRNVTVYVW01T2FGSnRVbGhhVjNoaFZWWmtWMXBFVWxSTmJFcElWbTAxVDJGV1NuTlhia0pXWWxob1dGUnJXbXRXTVZaeVdrWm9hVlpyV1hwV1IzaGhXVmRHVjFOdVVsWmlhMHBZV1ZSR1lWZEdVbFZTYlhSWFRWWndNRlZ0TVc5VWJGcFZWbXR3VjJKSFVYZFdha1pXWlZaT2NtRkhhRk5pVjJoWVYxZDBhMVV3TlhOalJscFlZbGhTY1ZsclduZGxiR1J5VmxSR1ZXSlZjRWhaTUZKaFZqSktWVkZZYUZkV1JWcFlWV3BHYTFkWFRrZFRiV3hvVFVoQ1dsWXhaRFJpTWtsM1RVaG9hbEpYYUhOVmJUVkRZekZhY1ZKcmRGTk5Wa3A2VjJ0U1ExWlhTbFpqUldoYVRVWndkbFpxUmtwbGJVWklZVVprYUdFeGNHOVhXSEJIWkRGS2RGSnJhR2hTYXpWdlZGVm9RMlJzV25STldHUlZUVlpXTlZadE5VOVdiVXBJVld4c1dtSllUWGhXTUZwell6RmFkRkpzVWxOaVNFSktWa1phVTFFeFduUlRhMlJxVWxad1YxWnRlRXRXTVZaSFVsUnNVVlZVTURrPQ=="for i in range(10):cipher = base64.b64decode(cipher)print(cipher)
if __name__ == '__main__':main()# b'https://bbs.pediy.com/thread-254172.htm'

解密后得到一个网址,访问网址后得知是一篇看雪论坛的文章,但文章中并未写有flag,虽然评论区中有写有flag,但实际flag并不是这样求得。

base64加密的密文下面发现还有一段密文。

通过交叉引用的方式,找到一个新的函数。

unsigned __int64 sub_400D35()
{unsigned __int64 result; // raxunsigned int v1; // [rsp+Ch] [rbp-24h]int i; // [rsp+10h] [rbp-20h]int j; // [rsp+14h] [rbp-1Ch]unsigned int v4; // [rsp+24h] [rbp-Ch]unsigned __int64 v5; // [rsp+28h] [rbp-8h]v5 = __readfsqword(0x28u);v1 = sub_43FD20(0LL) - qword_6CEE38;for ( i = 0; i <= 1233; ++i ){sub_40F790(v1);sub_40FE60();sub_40FE60();v1 = sub_40FE60() ^ 0x98765432;}v4 = v1;if ( (v1 ^ byte_6CC0A0[0]) == 'f' && (HIBYTE(v4) ^ byte_6CC0A3) == 'g' ){for ( j = 0; j <= 24; ++j )sub_410E90((byte_6CC0A0[j] ^ *(&v4 + j % 4)));}result = __readfsqword(0x28u) ^ v5;if ( result )sub_444020();return result;
}

可以看出v4就是key,"j%4"可以推测出取v4数组中的前4个元素与密文进行异或,根据if语句的判断和第一个脚本所解出的提示可以知道明文的前四个字符为"flag",又已知密文,于是可以得出key,再用key解出flag,脚本如下:

cipher = [0x40, 0x35, 0x20, 0x56, 0x5D, 0x18, 0x22, 0x45, 0x17, 0x2F, 0x24, 0x6E, 0x62, 0x3C, 0x27, 0x54, 0x48, 0x6C, 0x24, 0x6E, 0x72, 0x3C, 0x32, 0x45, 0x5B]
value = "flag"
key = []
for i in range(4):key.append(ord(value[i]) ^ cipher[i])
for i in range(len(cipher)):print(chr(cipher[i]^key[i%4]),end="")# flag{Act1ve_Defen5e_Test}

FLAG:flag{Act1ve_Defen5e_Test}

【2023.5.3~2023.5.9】CTF刷题记录相关推荐

  1. CTF 刷题记录(一) 白云新闻搜索(手动与自动化SQL注入)

    题目 给出的靶机如下: 解题思路 首先判断这是考察哪个知识点,只有一个输入框,题目中又说到入侵,首先考虑sql注入,下面介绍手工和自动化注入两种方式 (1)手工注入 先随便输入几个值,发现只有在值等于 ...

  2. CTF刷题记录CTFHub-RCE-命令注入

    ** CTFHub-RCE-命令注入 ** 1.无任何的过滤 一.解题思路 通过输入一些指令,利用某些特定的函数进行的操作,从而达到命令执行攻击的效果. 因为没有任何的过滤,那么我们可以直接使用分号( ...

  3. CTF刷题网站汇总(包括本地可以自己搭建的)(1)

    CTF刷题网站汇总(包括本地可以自己搭建的) CTF刷题平台汇总(欢迎各位师傅们补充) 第一个当然是CTFshow啦!https://ctf.show/ 攻防世界 https://adworld.xc ...

  4. CTF BugKu平台——Crypto篇刷题记录(后续更新)

    CTF BugKu平台--Crypto篇 前言 抄错的字符: /.- 聪明的小羊: ok: [+-<>]: 把猪困在猪圈里: 你喜欢下棋吗: 小山丘的秘密: EN-气泡: 你以为是md5吗 ...

  5. 力扣刷题记录--哈希表相关题目

    当遇到需要快速判断一个元素是否出现在集合里面的时候,可以考虑哈希法,牺牲一定的空间换取查找的时间. java常用的哈希表有HashMap.HashSet以及用数组去模拟哈希,这几种方法各有优劣. 数组 ...

  6. 攻防世界MISC进阶区刷题记录

    文章目录 攻防世界MISC进阶区刷题记录 Ditf 运用stegextract进行分离 glance-50 gif图片分离组合脚本 hit-the-core Test-flag-please-igno ...

  7. BUUCTF-2020寒假刷题记录

    BUUCTF-2020寒假刷题记录 Web [RoarCTF 2019]Easy Calc 打开源码,看到calc.php,打开看到源码. 在 num 前面加个空格即可绕过 ? num=phpinfo ...

  8. 攻防世界misc高手进阶区刷题记录

    攻防世界misc高手进阶区刷题记录 easycap 解压出来之后为一个pcap文件,使用wireshark打开 右键追踪TCP数据流即可获得flag flag:385b87afc8671dee0755 ...

  9. BUUCTF刷题记录(7)

    文章目录 web [NPUCTF2020]ezinclude [NPUCTF2020]ReadlezPHP [GXYCTF2019]BabysqliV3.0 非预期1 非预期2 预期 [NCTF201 ...

最新文章

  1. 多文多面阐述HMM很清晰
  2. 最近开发老遇到莫名其妙的问题,dialog自定义大小,setAttributes这个方法没反应是肿么一回事...
  3. HTML5与CSS3基础教程第八版学习笔记16-21章
  4. Java中四种访问修饰符的区别
  5. sklearn 决策树例子_决策树DecisionTree(附代码实现)
  6. .gitignore更新后如何生效
  7. 食物在人体内消化主要经过哪些步骤
  8. CCD的基本的基本知识介绍(转载)
  9. mfsort shell语法_8.10 shell特殊符号cut命令 8.11 sort_wc_uniq命令 8.12 tee_tr_split命令 8.13 shell特殊符号下...
  10. MD5碰撞,不同的原始数据,MD5后,值一样,出现碰撞
  11. 2019hbcpc部分题解
  12. 如何用matlab画超越方程组的图像,【求助】超越方程组的fsolve解法
  13. Numpy:两小时速成
  14. 【C++入门基础篇】---- 万字解析
  15. WCF技术剖析之十四:泛型数据契约和集合数据契约(上篇)
  16. 踩坑记-- UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0xa6 in position 17: illegal multibyte seque
  17. jenkins邮件模板配置
  18. vue中关于$emit及propos的用法
  19. img显示保存在服务器中的图片,img显示服务器图片不显示
  20. 简单 python 爬虫(一)

热门文章

  1. npm淘宝镜像安装和查看
  2. 【cocos shader 009】 受伤受击场景闪红特效
  3. Md2All,让公众号完美显示Latex数学公式
  4. java后端框架选型_后端语言选型浅谈
  5. 【三下乡】感悟文艺魅力,绽放绚丽青春——长江师范学院“青春星火筑梦团”开展“七彩课堂”活动
  6. android nfc 判断卡类型,NFC读卡判断卡类型
  7. 化學換膚chemical peels
  8. LeetCode第969题 煎饼排序
  9. stc32的Type-C接口识别不到
  10. 第二章 2.5 随机变量的函数的分布