【2023.5.3~2023.5.9】CTF刷题记录

目录

日期: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}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/19286.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅尝Transformer和LLM

文章目录 TransformerTransformer的衍生BERTPre-trainingBERT与其他方法的关系怎么用BERT做生成式任务&#xff1f; GPTPre-trainingFine-Tuning Transformer工具开源库特点 LLM系列推理服务 大语言模型势不可挡啊。 哲学上来说&#xff0c;语言就是我们的一切&#xff0c;语言…

【stable diffusion原理解读通俗易懂,史诗级万字爆肝长文,喂到你嘴里】

文章目录 一、前言&#xff08;可跳过&#xff09;二、stable diffusion1.clip2.diffusion modelforward diffusion &#xff08;前向扩散&#xff09;逆向扩散&#xff08;reverse diffusion&#xff09;采样图阶段小结 3.Unet modeltimestep_embedding采用正余弦编码 三、sta…

旋转的base,你见过吗wp

一、题目 前几天在ctfshow的qq交流群里看到有个师傅在问一道名为“旋转的base&#xff0c;你见过吗”的题目&#xff08;但这道题不是ctfshow平台上的啦&#xff0c;后来听说好像是个比赛题&#xff09;&#xff0c;题目给出了一串编码过的字符串&#xff0c;但看题目名也能知…

OtterCTF—内存取证wp

目录 前言 一、工具说明 二、题目解析 1.What the password? 2.General Info 3.Play Time 4.Name Game 5.Name Game 2 6.Silly Rick 7.Hide And Seek 8.Path To Glory 9.Path To Glory 2 10.Bit 4 Bit 11.Graphics For The Weak 12.Recovery 13.Closure 总结 前言 前几天有幸…

电商打工人的饭碗,AIGC还端不走

文 | 螳螂观察 作者 | 鲸胖胖 以ChatGPT、Midjourney、文心一言等为代表的AIGC产品&#xff0c;已经在全球掀起新一轮的AI技术变革新浪潮&#xff0c;再度刷新了人们对AI的认知&#xff0c;多个行业的商业模式和生态必然在未来会被彻底重构。 前不久&#xff0c;36氪就测使用…

巴比特 | 元宇宙每日必读:用虹膜信息换基本收入?OpenAI创始人顶着质疑声为其Web3项目Worldcoin再寻1亿美元融资...

摘要&#xff1a;据元宇宙日爆报道&#xff0c;OpenAl的CEO要为他两年前创办的币圈项目worldcoin再寻1亿美元融资&#xff0c;该项目于5月8日面向全球推出加密钱包WorldApp&#xff0c;要给“无条件为全民空投代币”&#xff0c;此外&#xff0c;项目方还为这款钱包的推出发行了…

类 ChatGPT 开源软件,开发者用的上吗?

声明&#xff1a;本文是 Preethi Cheguri 所著文章《ChatGPT Equivalent Is Open-Source, But it Is of No Use to Developers》的中文译文。 原文链接&#xff1a;https://www.analyticsinsight.net/chatgpt-equivalent-is-open-source-but-it-is-of-no-use-to-developers/ 类…

【原创】运维工程师涨薪计划,chatGPT帮你做规划

文章目录 1、运维工程师怎么涨薪呢&#xff1f;a&#xff09;加大深度b&#xff09;加大广度 2、运维工程师何处去呢&#xff1f;3、chatGPT告诉你3年、5年、10年运维和开发的现状&#xff1b;有运维经验的工程师&#xff0c;搞开发好吗薪资会有显著提升吗以数据证明&#xff0…

计算机视觉实战--OpenCV进行红绿灯识别

前言&#xff1a; Hello大家好&#xff0c;我是Dream。 OpenCV是一个开源的计算机视觉库&#xff0c;可以用于实现各种图像和视频处理任务&#xff0c;包括红绿灯识别。可以帮助自动驾驶汽车、智能交通系统等设备准确地识别红绿灯的状态&#xff0c;以便做出正确的决策。今天&a…

时隔 3 年,全新 Linux QQ 正式开启公测!

出品 | OSC开源社区&#xff08;ID&#xff1a;oschina2013) 2019 年&#xff0c;腾讯低调发布了 Linux QQ 的更新&#xff0c;目前版本停留在 2.0 Beta2。 时隔 3 年&#xff0c;QQ for Linux 基于 NT 技术架构迎来全新升级。今日&#xff08;12 月 7 日&#xff09;起&#x…

USG防火墙------内外网用户通过外网IP访问内部服务器(NAT)

实现需求&#xff1a;用户通过内外网用户通过公网IP访问内部服务器。 一、局域网配置&#xff1a;交换机(SW7)、防火墙&#xff08;FW3&#xff09;、服务器&#xff08;Server1&#xff09;、客户端&#xff08;Client1&#xff09; 二、配置思路 1、配置防火墙接口和IP地址…

趋势交易策略的买卖点选择,几种趋势介绍

这一篇来给大家说说顺势而为的趋势里面的交易策略。 清晰流畅的趋势都是比较难得的。那样的趋势一旦出现了&#xff0c;股价的运行 就会表现出一定的规律&#xff0c;即在上升趋势中表现出“更高的高点和更高的低点”&#xff0c;在下跌趋势中 表现出“更低的高点和更低的低点…

近期的热点风险事件都与这些内容相关

今天是母亲节&#xff0c;您辛苦了&#xff01;愿妈妈们被岁月温柔以待图片 2022年青山伦镍事件&#xff0c;上演了一出《生死时速》大片&#xff0c;国际金融市场的猎杀、逼仓、巨亏等戏码&#xff0c;作为普通吃瓜群众可能只是当成饭后茶余的谈资&#xff0c;但其背后蕴藏着…

iBox系统源码分享,ibox的核心源码

iBox系统核心源码分享 from IBOX import IBOX_ART import json# https://etherscan.io/tx/0xbede5e44cc631303a22d066cc269f989469742b5bb6d9a74185e146dab9211e4 # https://mainnet.infura.io/v3/8a264f274fd94de48eb290d35db030ab # contract address is0x0632aDCab8F12edD3…

政策利好,元宇宙从概念到产业的行动

今年7月&#xff0c;《上海市培育“元宇宙”新赛道行动方案&#xff08;2022-2025年&#xff09;》&#xff08;以下简称《行动方案》&#xff09;公布。《行动方案》明确&#xff0c;到2025年&#xff0c;上海“元宇宙”相关产业规模将达3500亿元&#xff0c;培育10家以上具有…

有趣并不能拯救 Web3 游戏

游戏玩家和Web3游戏开发者&#xff0c;你们好&#xff1a; 我的名字是Nick Metzler。我是Framework Ventures的代币经济学和治理设计师&#xff0c;也是一个获奖的、终身的游戏设计师。我曾经设计过世界各地都在玩的Jumanji和Hail Hydra等棋盘游戏&#xff0c;为CBS的节目Surv…

十连跌!这个一线城市的房价到底怎么了?

自2016年房价快速上涨开始&#xff0c;北京和上海两大城市一路创新高&#xff0c;即使在2016年10月份开始的新一轮限购政策开始和2017年地产新政策不断加码下&#xff0c;这两大城市房价也仅有个别月份有所回落&#xff0c;其余绝大多数时间都处于上涨中。 然而&#xff0c;自2…

在空投之后,Blur能否颠覆OpenSea的主导地位?

Mar. 2023, Daniel 数据源&#xff1a; NFT Aggregators Overview & Aggregator Statistics Overview & Blur Airdrop 一年前&#xff0c;通过聚合器进行的NFT交易量开始像滚雪球一样增长&#xff0c;有时甚至超过了直接通过市场平台的交易量。 虽然聚合器的使用量从10…

股票交易记录第2天

实盘交易记录第 2天。 收盘&#xff0c;初始资金50万。 90后游资北京炒家&#xff0c;2018年20万起步&#xff0c;历时五年&#xff0c;目前资金5800多万。 我50万起步&#xff0c;每天实盘&#xff0c;看看资金能做到多少万&#xff0c;关注我&#xff0c;一起来见证。 之前…

炒股记录第1天

股票实盘交易记录第 1 天。 收盘&#xff0c;初始资金50万&#xff0c;今天总资金是 50万。累计盈利 0万。 90后游资北京炒家&#xff0c;2018年20万起步&#xff0c;历时五年&#xff0c;目前资金5800多万。 我50万起步&#xff0c;每天实盘&#xff0c;看看资金能做到多少万&…