buuctf re wp部分合集
1.reverse2
将文件用IDA打开,shift+f12找到字符串
转入主函数
从主函数可以看出,for循环中将flag中的‘i'和‘r'转换为字符’1‘,然后判断输入的字符串和flag是否相同,然后找到flag所存字符串
按上述方式变换字符后,即得到flag{hack1ng_fo1_fun}
题目reverse1同理
2.新年快乐
先查壳,发现有upx壳
使用工具脱壳后,用IDA搜索字符串
根据题目提示,此字符串即为flag
3.xor
将文件拖入IDA
函数要将输入的字符串逐位异或后与 global 进行比对
查找global
编写EXP进行反异或
得到flag{QianQiuWanDai_YiTongJiangHu}
4.reverse3
拖入IDA中查看主函数
主要部分是将输入的字符串的每个字符加上其所在位置的数字来进行简单的加密
查询字符串
根据此猜测字符串使用了base64加密
然后编写EXP将str2进行解密
得到flag{i_l0ve_you}
5.helloworld
.apk文件,安卓逆向,使用JEB
6.不一样的Flag
查看主函数中有上下左右信息,还有一串01字符串,推测为迷宫,#为终点。
可以得到flag{222441144222}
7.SimpleRev
主要函数依据key字符串对v2进行加密操作,得到的str2与上面操作所得text相同,所以需要写解密的EXP。
在IDA中找到变量代表的字符串
src与v10是由16进制直接转换为字符,本质是小端存储的十六进制,解密时应将src与v10字符串倒置再拼接
#出现的变量 key1 = 'ADSFK' key3 = 'kills' src = 'SLCDN' v10 = 'wodah' #LODWORD(v0) = join(key3, &v10) v0 = key3 for i in range(len(v10)-1, -1, -1): v0 += v10[i] print(v0) #strcat(key, src) key = key1 for i in range(len(src)-1, -1, -1): key += src[i] print(key) #第一个循环:key大写转化为小写 tmp = '' for i in key: value = ord(i) + 32 tmp += chr(value) key = tmp print(key) #第二个循环,逆向求出flag str2 = text = v0 flag = '' for i in range(len(str2)): value1 = ord(str2[i]) value1 -= 97 value2 = -ord(key[i]) value2 += 97 value2 -= 39 value = value1 - value2 while True: if value > ord('Z'): value -= 26 elif value < ord('A'): value += 26 else: break flag += chr(value) print(flag)
8.luck_guy
64位程序,拖入IDA,惯例shift+f12
找到疑似指向flag字符串
跟进后ctrl+x
找到函数后F5进入反汇编
可以看到s是由f1和f2拼接而成,f1可以跟进,得到一半flag---GXY{do_not_
另一半则是f2进行case5操作得到,写EXP
f1 = 'GXY{do_not_' f2 = [0x7F, 0x66, 0x6F, 0x60, 0x67, 0x75, 0x63, 0x69][::-1] flag = '' for i in range(8): if i % 2 == 1: f2[i] -= 2 else: f2[i] -= 1 f1 += chr(f2[i]) print(f1)
得到flag{do_not_hate_me}
9.java逆向
将文件拖入jd gui中
函数操作就是先将输入的字符数组每个字符的ASCII值+64,再与0x20异或,最后与KEY比较是否相同
写EXP
KEY = [180, 136, 137, 147, 191, 137, 147, 191, 148, 136,133, 191, 134, 140, 129, 135, 191, 65] flag = '' for i in range(0, len(KEY)): value = KEY[i] value ^= 0x20 value -= 64 flag += chr(value) print(flag)
得到flag{This_is_the_flag_!}
10.刮开有奖
拖入IDA查看字符串
可疑字符串,跟进后ctrl+x查看交叉引用然后f5反汇编
找到疑似flag字符串和一个函数
可以猜测flag为8个字符,然后跟进sub_4010F0函数
把伪代码直接改写成c语言代码(伪代码是地址寻址,比如a1 + i*4 代表的就是a1[i] *4是因为int型占四个字节,如果是char型就不需要 *4)
#include <stdio.h> int sub_4010F0(char *a1, int a2, int a3) { int result; // eax int i; // esi int v5; // ecx int v6; // edx result = a3; for (i = a2; i <= a3; a2 = i) { v5 = i; v6 = a1[i]; if (a2 < result && i < result) { do { if (v6 > a1[result]) { if (i >= result) break; ++i; a1[v5] = a1[result]; if (i >= result) break; while (a1[i] <= v6) { if (++i >= result) goto LABEL_13; } if (i >= result) break; v5 = i; a1[result] = a1[i]; } --result; } while (i < result); } LABEL_13: a1[result] = v6; sub_4010F0(a1, a2, i - 1); result = a3; ++i; } return result; } int main() { char str[] = "ZJSECaNH3ng"; sub_4010F0(str, 0, 10); printf("%s\n", str); getchar(); return 0; }
运行得到加密后的字符串
3CEHJNSZagn
看下一部分
跟进函数,发现是个很复杂的函数,但是还有个可跟进函数
根据主要函数
推测是将v4和v5经过base64加密的到ak1w和V1Ax,解密后得到
v4 = jMp v5 = WP1
最后看最后部分,写个EXP
string = '3CEHJNSZagn' flag = '' flag += chr(ord(string[0]) + 34) flag += string[4] flag += chr(((ord(string[2]) * 3) + 141) // 4) flag += chr(((ord(string[7]) // 9) * 2) * 4) print(flag)
得到结果
UJWP //前四个字符
因为flag长度为8,所以WP应该是直接重叠拼进去
得到flag{UJWP1jMp}
11.简单注册器
.apk文件,拖入JEB,主函数tab反汇编
找到主要函数,很简单的加密,写个EXP
arr1 = 'dd2940c04462b4dd7c450528835cca15' arr = list(arr1) arr[2] = chr(ord(arr[2]) + ord(arr[3]) - 50) arr[4] = chr(ord(arr[2]) + ord(arr[5]) - 0x30) arr[30] = chr(ord(arr[0x1F]) + ord(arr[9]) - 0x30) arr[14] = chr(ord(arr[27]) + ord(arr[28]) - 97) for i in range(16): a = arr[0x1F - i] arr[0x1F - i] = arr[i] arr[i] = a arr1 = ''.join(arr) print(arr1)
得到flag{59acc538825054c7de4b26440c0999dd}
12.[ACTF新生赛2020]easyre
查壳,UPX壳,32位程序
脱壳后拖入IDA
找到main函数反汇编
从for循环看出flag应该是12位,循环内容就是以flag的ASCII值-1为索引在byte_402000数组中搜索字符与v4字符串数组比较是否相同
写EXP,反向一下for循环
v4 = [0x2A, 0x46, 0x27, 0x22, 0x4E, 0x2C, 0x22, 0x28, 0x49, 0x3F, 0x2B, 0x40] string = '~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(' + chr( 0x27) + '&%$# !"' flag = '' for i in v4: for j in range(1, len(string)): if i == ord(string[j]): flag += chr(j + 1) print("flag{" + flag + "}")
13.[GWCTF 2019]pyre
使用反编译
#!/usr/bin/env python # visit https://tool.lu/pyc/ for more information # Version: Python 2.7 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) % 128 code += num for i in range(l - 1): code[i] = code[i] ^ code[i + 1] print code code = [ '%1f', '%12', '%1d', '(', '0', '4', '%01', '%06', '%14', '4', ',', '%1b', 'U', '?', 'o', '6', '*', ':', '%01', 'D', ';', '%', '%13']
然后将加密逆向
code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13'] flag = '' length = len(code) for i in range(length): code[i] = ord(code[i]) for i in range(length - 1, 0, -1): code[i - 1] = code[i] ^ code[i - 1] for i in range(length): code[i] = code[i] - i if code[i] <= 0: code[i] += 128 flag += chr(code[i]) print(flag)
得到flag{Just_Re_1s_Ha66y!}
14.findit
.apk用JEB反汇编
得到函数,下面的if函数的循环中字符串疑似flag有关,直接放IDEA运行
public class Main { public static void main(String[] args) { char[] y = new char[38]; for (int i = 0; i < 38; ++i) { 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', '}'}[i] >= 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', '}'}[i] <= 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', '}'}[i] >= 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', '}'}[i] <= 0x7A) { y[i] = (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', '}'}[i] + 16); if (y[i] > 90 && y[i] < 97 || y[i] >= 0x7A) { y[i] = (char) (y[i] - 26); } } else { y[i] = 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', '}'}[i]; } } System.out.println(y); } }
直接得到结果flag{c164675262033b4c49bdf7f9cda28a75}
这道题其实是个凯撒加密,将字符串整体偏移10后也可以得到flag
15.[ACTF新生赛2020]rome
32位程序,拖入IDA,找到主要加密函数部分
最主要的就是加密部分
对大小写字母分别处理,写EXP把加密逆向
v1 = ['Q', 's', 'w', '3', 's', 'j', '_', 'l', 'z', '4', '_', 'U', 'j', 'w', '@', 'l'] flag = '' for i in range(len(v1)): if 64 < ord(v1[i]) <= 90: v1[i] = ord(v1[i]) - 65 + 51 while v1[i] < 65: v1[i] += 26 v1[i] = chr(v1[i]) elif 96 < ord(v1[i]) <= 122: v1[i] = ord(v1[i]) - 97 + 79 while v1[i] < 97: v1[i] += 26 v1[i] = chr(v1[i]) flag += v1[i] print("flag{"+flag+"}")
得到flag{Cae3ar_th4_Gre@t}
16.rsa
什么是RSA加密
RSA加密是对明文的E次方后除以N求余数的过程
公钥 = (E,N)
密文 = 明文^E modN
RSA解密
对密文进行D次方后除以N的余数就是明文
私钥 = (D,N)
明文 = 密文^D modN
总结
公钥 | (E,N) |
---|---|
私钥 | (D,N) |
密钥对 | (E,D,N) |
加密 | 密文=明文^E modN |
解密 | 明文 = 密文^D modN |
开始解题
在网站中解析RSA密钥得到公钥
得到E和N
将E拆解成p和q
p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463
写EXP
import gmpy2 import rsa e = 65537 n = 86934482296048119190666062003494800588905656017203025617216654058378322103517 p = 285960468890451637935629440372639283459 q = 304008741604601924494328155975272418463 lll = (q - 1) * (p - 1) d = gmpy2.invert(e, lll) key = rsa.PrivateKey(n, e, int(d), p, q) with open("C:\\Users\\12611\\Desktop\\re\\rsa\\output\\flag.enc", "rb+") as f: f = f.read() print(rsa.decrypt(f, key))
得到flag{decrypt_256}
17.[FlareOn4]login
html文件,打开以后直接f12
找到关键加密函数
/[a-zA-Z]/g是正则匹配,匹配字符串中所有的字母
charCodeAt(0)是返回当前字符的Unicode 编码
String.fromCharCode返回Unicode对应的字符串
所以加密的意思就是先匹配大小写字母的上限,然后将字符+13与上限比较,如果超过上限就-26,是一个明显的凯撒加密,向右位移13位
写EXP
a = 'PyvragFvqrYbtvafNerRnfl@syner-ba.pbz' flag = '' for i in a: if 'a' <= i <= 'z': i = chr(ord(i) - 13) if i < 'a': i = chr(ord(i) + 26) elif 'A' <= i <= 'Z': i = chr(ord(i) - 13) if i < 'A': i = chr(ord(i) + 26) flag += i print("flag{" + flag + "}")
得到flag{ClientSideLoginsAreEasy@flare-on.com}
18.[WUSTCTF2020]level1
用IDA,找主要函数
加密是从文件中读取字符并进行下面操作,
i & 1 //按位运算,i为偶数时为0,i为奇数时为1 << //按位操作符,比如0001会变成0010
写个EXP
a = [0, 198, 232, 816, 200, 1536, 300, 6144, 984, 51200, 570, 92160, 1200, 565248, 756, 1474560, 800, 6291456, 1782, 65536000] flag = '' for i in range(1, 20): if i & 1: flag += chr(a[i] >> i) else: flag += chr(a[i] // i) print(flag)
要注意的是题目中i是从1开始的,所以把列表[0]的位置随便加一个字符
19.[GUET-CTF2019]re
查壳,发现有upx壳,用upx官方工具脱壳
拖IDA找到关键函数
一个简单的运算,EXP
from z3.z3 import * s = Solver() a1 = [0] * 32 for i in range(32): a1[i] = Int('a1[' + str(i) + ']') s.add(1629056 * a1[0] == 166163712) s.add(6771600 * a1[1] == 731332800) s.add(3682944 * a1[2] == 357245568) s.add(10431000 * a1[3] == 1074393000) s.add(3977328 * a1[4] == 489211344) s.add(5138336 * a1[5] == 518971936) s.add(7532250 * a1[7] == 406741500) s.add(5551632 * a1[8] == 294236496) s.add(3409728 * a1[9] == 177305856) s.add(13013670 * a1[10] == 650683500) s.add(6088797 * a1[11] == 298351053) s.add(7884663 * a1[12] == 386348487) s.add(8944053 * a1[13] == 438258597) s.add(5198490 * a1[14] == 249527520) s.add(4544518 * a1[15] == 445362764) s.add(3645600 * a1[17] == 174988800) s.add(10115280 * a1[16] == 981182160) s.add(9667504 * a1[18] == 493042704) s.add(5364450 * a1[19] == 257493600) s.add(13464540 * a1[20] == 767478780) s.add(5488432 * a1[21] == 312840624) s.add(14479500 * a1[22] == 1404511500) s.add(6451830 * a1[23] == 316139670) s.add(6252576 * a1[24] == 619005024) s.add(7763364 * a1[25] == 372641472) s.add(7327320 * a1[26] == 373693320) s.add(8741520 * a1[27] == 498266640) s.add(8871876 * a1[28] == 452465676) s.add(4086720 * a1[29] == 208422720) s.add(9374400 * a1[30] == 515592000) s.add(5759124 * a1[31] == 719890500) s.check() print(s.model())
a1 = [0]*32 a1[23] = 49 a1[26] = 51 a1[24] = 99 a1[11] = 49 a1[0] = 102 a1[30] = 55 a1[21] = 57 a1[1] = 108 a1[16] = 97 a1[18] = 51 a1[3] = 103 a1[13] = 49 a1[20] = 57 a1[7] = 54 a1[31] = 125 a1[29] = 51 a1[10] = 50 a1[4] = 123 a1[2] = 97 a1[8] = 53 a1[12] = 49 a1[25] = 48 a1[14] = 48 a1[28] = 51 a1[22] = 97 a1[17] = 48 a1[15] = 98 a1[19] = 48 a1[9] = 52 a1[5] = 101 a1[27] = 57 a1[6] = 49 for i in range(32): print(chr(a1[i]), end='')
其中a[6]作者没给,可以用burp爆破出等于1,图个方便exp直接写了
得到flag{e165421110ba03099a1c039337}
20.CrackRTF
查壳,无壳
ida f5主函数
int __cdecl main_0(int argc, const char **argv, const char **envp) { DWORD v3; // eax DWORD v4; // eax char Str[260]; // [esp+4Ch] [ebp-310h] BYREF int v7; // [esp+150h] [ebp-20Ch] char String1[260]; // [esp+154h] [ebp-208h] BYREF char Destination[260]; // [esp+258h] [ebp-104h] BYREF memset(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((BYTE *)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((BYTE *)Str, v4, String1); if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", String1) ) { if ( !(unsigned __int8)sub_40100F(Str) ) { printf("Error!!\n"); ExitProcess(0); } printf("bye ~~\n"); } } return 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");
上面这一块说明第一部分是6位,并且把@DBApp接在第一部分后面,第一部分字符串化整形要大于100000
sub_40100A((BYTE *)Destination, v3, String1);
这个是个加密函数,跟进去
int __cdecl sub_401230(BYTE *pbData, DWORD dwDataLen, LPSTR lpString1) { DWORD i; // [esp+4Ch] [ebp-28h] char String2[4]; // [esp+50h] [ebp-24h] BYREF char v6[20]; // [esp+54h] [ebp-20h] BYREF DWORD pdwDataLen; // [esp+68h] [ebp-Ch] BYREF HCRYPTHASH phHash; // [esp+6Ch] [ebp-8h] BYREF HCRYPTPROV phProv; // [esp+70h] [ebp-4h] BYREF if ( !CryptAcquireContextA(&phProv, 0, 0, 1u, 0xF0000000) ) return 0; if ( CryptCreateHash(phProv, 0x8004u, 0, 0, &phHash) ) { if ( CryptHashData(phHash, pbData, dwDataLen, 0) ) { CryptGetHashParam(phHash, 2u, (BYTE *)v6, &pdwDataLen, 0); *lpString1 = 0; for ( i = 0; i < pdwDataLen; ++i ) { wsprintfA(String2, "%02X", (unsigned __int8)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; } }
有很多不知道的函数,查询后是哈希加密函数
学习了一下hashlib库的用法,根据0x8004确定加密方式是sha1
因为有位数,又得出六位都是数字,所以直接爆破
import hashlib a = '@DBApp' for i in range(100000, 1000000): b = str(i) + a c = hashlib.sha1(b.encode('utf-8')) d = c.hexdigest() if d == "6e32d0943418c2c33385bc35a1470250dd8923a9": print(b) break ''' 123321@DBApp '''
然后看接下来的部分
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((BYTE *)Str, v4, String1);
依然是六位,然后进行了拼接操作,然后依然是进行hash加密,但是没有可用条件了
继续往下看,在比较后还有个sub_40100F
函数,跟进
char __cdecl sub_4014D0(LPCSTR lpString) { LPCVOID lpBuffer; // [esp+50h] [ebp-1Ch] DWORD NumberOfBytesWritten; // [esp+58h] [ebp-14h] BYREF DWORD 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, (LPCSTR)0x65, "AAA"); if ( !hResInfo ) return 0; nNumberOfBytesToWrite = SizeofResource(0, hResInfo); hResData = LoadResource(0, hResInfo); if ( !hResData ) return 0; lpBuffer = LockResource(hResData); sub_401005(lpString, (int)lpBuffer, nNumberOfBytesToWrite); hFile = CreateFileA("dbapp.rtf", 0x10000000u, 0, 0, 2u, 0x80u, 0); if ( hFile == (HANDLE)-1 ) return 0; if ( !WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0) ) return 0; CloseHandle(hFile); return 1; }
没见过的函数
HRSRC FindResourceA( HMODULE hModule, LPCSTR lpName, LPCSTR lpType ); FindResourceA function Determines the location of a resource with the specified type and name in the specified module. 确定具有指定类型和名称的资源在指定模块中的位置。 hModule:处理包含资源的可执行文件的模块。NULL值则指定模块句柄指向操作系统通常情况下创建最近过程的相关位图文件。 lpName:指定资源名称。 lpType:指定资源类型。 返回值:如果函数运行成功,那么返回值为指向被指定资源信息块的句柄。为了获得这些资源,将这个句柄传递给LoadResource函数。如果函数运行失败,则返回值为NULL。 SizeofResource表示该函数返回指定资源的字节数大小。 LoadResource 检索一个句柄,该句柄可用于获取指向内存中指定资源的第一个字节的指针。
三个函数,查找字符,计算大小,返回指定资源的第一个字节的指针
用resource hacker看这个文件
看不出什么信息,继续往下看,有个sub_401005
函数
unsigned int __cdecl sub_401420(LPCSTR lpString, int a2, unsigned int a3) { unsigned int result; // eax unsigned 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; *(_BYTE *)(i + a2) ^= lpString[i % v5]; } return result; }
就是资源中的每一个字符与密码循环异或
跳出后生成一个rtf文件,将异或后的结果写进去
所以这个资源的前六位与密码异或后的结果就是rtf文件的前六位
而rtf文件前六位是'{\rtf1'
所以反向异或
A = [0x05, 0x7D, 0x41, 0x15, 0x26, 0x01] a = '' for i in A: a += chr(int(i)) rtf = "{\\rtf1" for i in range(0, 6): print(chr(ord(a[i]) ^ ord(rtf[i])), end='') ''' ~!3a@0 '''
得到密码,将两次密码输入进去后,得到rtf文件
Flag{N0_M0re_Free_Bugs}
21.[WUSTCTF2020]level2
查壳,有upx壳,用官方工具脱壳
然后ida
查到字符串得到flag
22.[SUCTF2019]SignIn
无壳,拖ida
通过字符串找到关键函数
rsa加密,推测十六进制串为密文,下一个十进制串为n
在网站分解p和q
要素齐全,写EXP
import gmpy2 import binascii c = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35 n = 103461035900816914121390101299049044413950405173712170434161686539878160984549 e = 65537 p = 282164587459512124844245113950593348271 q = 366669102002966856876605669837014229419 d = gmpy2.invert(e, (p-1)*(q-1)) m = gmpy2.powmod(c, d, n) print(binascii.unhexlify(hex(m)[2:]).decode(encoding='utf-8'))
得到flag{Pwn_@_hundred_years}
23.[ACTF新生赛2020]usualCrypt
IDA找主函数
先看下面这个关键函数
跳转
根据经验是一个base64加密,但是开头多进行了一个函数
进入字符串以后是以下两个字符串,刚开始还疑惑了一会,第一个字符串并没有15那么长怎么运算,后来发现 内存空间本身就是连在一起的,伪代码只是为了好表示字符的起点将字符串分割成两个部分,实际运算还是一个空间。
所以得知上面函数就是i从6到14,a[i]与a[i+10]互换
解决了这个函数,再看结尾的返回函数
很明显是个大小写互换函数
随后就是比较
然后逆推flag就好,写EXP
import base64 a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' flag = '' dict = {} for i in range(len(a)): dict[a[i]] = a[i] for i in range(6, 15): dict[a[i]], dict[a[i + 10]] = dict[a[i + 10]], dict[a[i]] s = 'zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9'.swapcase() for i in range(len(s)): flag += dict[s[i]] flag = base64.b64decode(flag) print(flag)
得到flag{bAse64_h2s_a_Surprise}
24.[HDCTF2019]Maze
查壳,upx壳,脱
ida,题目maze,迷宫题
进来看见这个,网上了解一下,这个是花指令导致的反汇编错误
解决方法:将call这一行第一个字节改为90(就是nop)
把红色部分选中摁P,然后f5
flag是一个14位的字符串,wasd就是移动
初始位置(7,0)然后到(5,-4)
字符串找迷宫
发现是70个字符,根据初始位置猜是个10*7的迷宫
flag{ssaaasaassdddw}
25.[MRCTF2020]Xor
拖入ida,发现反汇编错误
解决方法:找到报错地址,发现是个call函数,把跳转过去的函数先反汇编成函数,然后再回来f5就能反汇编了
很简单一个函数,就是把输入和角标异或与给的字符串比较
写EXP
byte_41EA08 = 'MSAWB~FXZ:J:`tQJ"N@ bpdd}8g' flag = '' for i in range(len(byte_41EA08)): flag += chr(i ^ ord(byte_41EA08[i])) print(flag)
其实这道题也可以直接看汇编
开头这个框里能看出这个push的4212c0就是输入的字符串
这个操作一直在edx自增,test也是在找输入字符串的结尾,因为ecx存的是edx+1的地址,所以sub以后edx就是字符串长度,可以看到是1B
进行eax清零操作后,把每个字符与角标(al)进行异或然后和给定字符串比较,再进行eax自增,如果比较不相等就跳出错误信息,否则到了字符串长度后就跳出正确信息。
得到flag{@_R3@1ly_E2_R3verse!}
26.[MRCTF2020]hello_world_go
go语言,放ida,查字符串,发现特别多,ctrl+f搜flag
一眼真
27.[2019红帽杯]easyRE
放ida,第一步查字符串
上来就是这个,base64没跑,开始破解,结果发现是10次base64加密
得到一个网址https://bbs.pediy.com/thread-254172.htm
名为主动防御,看完发现,应该是被错误引导了
后面又找到个函数加密
从v12和v13、v14的地址来看,这三个空间是连在一起的,加密也是简单的异或
写个码解一下
a = 'Iodl>Qnb(ocy\x7Fy.i\x7Fd`3w}wek9{iy=~yL@EC' a = list(a) flag = '' for i in range(len(a)): a[i] = chr(ord(a[i]) ^ i) flag = ''.join(a) print(flag) ''' Info:The first four chars are `flag` '''
结果是告诉你前四个字符是flag,又找到了只有一点用的信息。
后面在很长的base64加密后面的交叉引用的地方找到了一个字符串
跟进去是这样的
前面看不明白,但是后面有个v4=v1,v1还是int8,也就是一个字节
根据之前的推测,以及这个函数的加密部分,这个v1就是个四字节的key,四个字节应该是分别与key异或得到flag这四个字符,然后反向异或就得到key,加密就是与key中字符循环异或
a = [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] v = [0] * 4 flag = '' v[0] = a[0] ^ ord('f') v[1] = a[1] ^ ord('l') v[2] = a[2] ^ ord('a') v[3] = a[3] ^ ord('g') for i in range(len(a)): a[i] = chr(a[i] ^ v[i % 4]) flag = ''.join(a) print(flag) ''' flag{Act1ve_Defen5e_Test} '''
本文作者:yee-l
本文链接:https://www.cnblogs.com/yee-l/p/18233898
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性