[GWCTF 2019]pyre
这是一道py逆向的题目,放入在线的反编译的环境
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 = [
'\x1f',
'\x12',
'\x1d',
'(',
'0',
'4',
'\x01',
'\x06',
'\x14',
'4',
',',
'\x1b',
'U',
'?',
'o',
'6',
'*',
':',
'\x01',
'D',
';',
'%',
'\x13']
我们现在对这个函数进行解密
首先要异或回去
a ^ b = c (加密)
c ^ b = a
接着简化加密
num = (ord(input1[i]) + i) % 128
所以最后的脚本
# 给定的 code 列表
code = [
'\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4',
',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13'
]
# 转换 code 为整数列表
# code = [ord(c) for c in code]
# 逆向 XOR 还原原始的 num 列表
l = len(code)
for i in range(l - 2, -1, -1): # 从倒数第二个开始逆推
code[i] = chr(ord(code[i]) ^ ord(code[i + 1]))
# 逆向计算 input1
input1 = ''
for i in range(l):
char = chr((ord(code[i]) - i)%128)
input1 += char
print("flag:", input1)
findit
安卓逆向,在jadx中打开
package com.example.findit;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
/* loaded from: classes.dex */
public class MainActivity extends ActionBarActivity {
/* JADX INFO: Access modifiers changed from: protected */
@Override // android.support.v7.app.ActionBarActivity, android.support.v4.app.FragmentActivity, android.app.Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText edit = (EditText) findViewById(R.id.widget2);
final TextView text = (TextView) findViewById(R.id.widget1);
final char[] a = {'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'};
final char[] b = {'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', '}'};
((Button) findViewById(R.id.widget3)).setOnClickListener(new View.OnClickListener() { // from class: com.example.findit.MainActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View v) {
char[] x = new char[17];
char[] y = new char[38];
for (int i = 0; i < 17; i++) {
if ((a[i] < 'I' && a[i] >= 'A') || (a[i] < 'i' && a[i] >= 'a')) {
x[i] = (char) (a[i] + 18);
} else if ((a[i] < 'A' || a[i] > 'Z') && (a[i] < 'a' || a[i] > 'z')) {
x[i] = a[i];
} else {
x[i] = (char) (a[i] - '\b');
}
}
if (String.valueOf(x).equals(edit.getText().toString())) {
for (int i2 = 0; i2 < 38; i2++) {
if ((b[i2] < 'A' || b[i2] > 'Z') && (b[i2] < 'a' || b[i2] > 'z')) {
y[i2] = b[i2];
} else {
y[i2] = (char) (b[i2] + 16);
if ((y[i2] > 'Z' && y[i2] < 'a') || y[i2] >= 'z') {
y[i2] = (char) (y[i2] - 26);
}
}
}
text.setText(String.valueOf(y));
return;
}
text.setText("答案错了肿么办。。。不给你又不好意思。。。哎呀好纠结啊~~~");
}
});
}
@Override // android.app.Activity
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
看到这一大段代码,我们只需逆出这个就有flag了
嗯?提交错误?
我们来到另外一边
奇怪的东西
先把上面的扣下来
flag=[0x54,
0x68,
0x69,
0x73,
0x49,
0x73,
0x54,
0x68,
0x65,
0x46,
0x6c,
0x61,
0x67,
0x48,
0x6f,
0x6d,
0x65
]
a=len(flag)
fla=''
for i in range(a):
fla+=(chr(flag[i]))
print(fla)
得到
ThisIsTheFlagHome
下面的那段也这样试试
flag=[0x70,
0x76,
0x6b,
0x71,
0x7b,
0x6d,
0x31,
0x36,
0x34,
0x36,
0x37,
0x35,
0x32,
0x36,
0x32,
0x30,
0x33,
0x33,
0x6c,
0x34,
0x6d,
0x34,
0x39,
0x6c,
0x6e,
0x70,
0x37,
0x70,
0x39,
0x6d,
0x6e,
0x6b,
0x32,
0x38,
0x6b,
0x37,
0x35,
0x7d,]
a=len(flag)
b=''
for i in range(a):
b+=chr(flag[i])
print(b)
pvkq{m164675262033l4m49lnp7p9mnk28k75}
有点像了
放到随波逐流里面试试
得到正确flag
[ACTF新生赛2020]rome
脚本写半天,还写错了,我真菜啊
借用别人爆破的凯撒密码
#include <stdio.h>
int main()
{
char v12[] = "Qsw3sj_lz4_Ujw@l";
for (int i = 0;i < 17;i++)
{
for (int j = 32;j <= 126;j++)
{
int x = j;
if(x > '@' && x <= 'Z')
{
x = (x - 51) % 26 + 65;
}
if(x > '`' && x <= 'z')
{
x = (x - 79) % 26 + 97;
}
if(x == v12[i])
{
printf("%c", j);
}
}
}
}
[FlareOn4]login
直接在vscode中查看源码
<!DOCTYPE Html />
<html>
<head>
<title>FLARE On 2017</title>
</head>
<body>
<input type="text" name="flag" id="flag" value="Enter the flag" />
<input type="button" id="prompt" value="Click to check the flag" />
<script type="text/javascript">
document.getElementById("prompt").onclick = function () {
var flag = document.getElementById("flag").value;
var rotFlag = flag.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
if ("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz" == rotFlag) {
alert("Correct flag!");
} else {
alert("Incorrect flag, rot again");
}
}
</script>
</body>
</html>
加密的意思就是把字符串往后移动了13位,要是过了最后一位就+
/[a-zA-Z]/g 正则匹配
c.charCodeAt(0) + 13 字符串往后移动13
(c <= “Z” ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26 越界了就要回退
下面是解密脚本
def rot13(text):
result = ""
for char in text:
if 'A' <= char <= 'Z': # 处理大写字母
result += chr((ord(char) - ord('A') + 13) % 26 + ord('A'))
elif 'a' <= char <= 'z': # 处理小写字母
result += chr((ord(char) - ord('a') + 13) % 26 + ord('a'))
else:
result += char # 非字母字符保持不变
return result
encoded_flag = "PyvragFvqrYbtvafNerRnfl@syner-ba.pbz"
decoded_flag = rot13(encoded_flag)
print(decoded_flag)
rsa
思路来自[【BUUCTF-Reverse】0x13.rsa_buuctf rsa reverse-优快云博客](https://blog.youkuaiyun.com/weixin_44245267/article/details/143862420?ops_request_misc=%7B%22request%5Fid%22%3A%22fdc9d2209e3a0d2efee48abfa87614ea%22%2C%22scm%22%3A%2220140713.130102334…%22%7D&request_id=fdc9d2209e3a0d2efee48abfa87614ea&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-2-143862420-null-null.142v101pc_search_result_base2&utm_term=buuctf reverse rsa&spm=1018.2226.3001.4187)
离线时
from Crypto.PublicKey import RSA
f = open("D:\\Desktop\\41c4e672-98c5-43e5-adf4-49d75db307e4\\output\\pub.key",'rb')
public_key_data = f.read()
public_key = RSA.import_key(public_key_data)
n = public_key.n
e = public_key.e
print("n = ", n)
print("e = ", e)
接着我们再yafu的文件下面打开.\yafa-x64.exe factor()里面填入我们n进行分解
另外的文件用010打开
最后把获得到的值用010打开
[WUSTCTF2020]level1
给了两个文件,逆着写就行了
int __fastcall 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] BYREF
unsigned __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", (unsigned int)(ptr[i] << i));
else
printf("%ld\n", (unsigned int)(i * ptr[i]));
}
return 0;
}
flag=[198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000]
real_flag=''
for i in range(19):
if((i+1)&1!=0):
real_flag+=chr(flag[i]>>(i+1))
else:
real_flag+=chr(flag[i]//(i+1))
print(real_flag)
[GUET-CTF2019]re
先脱壳
点进去之后 ctrl+x
_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;
}
把乘换成除,没有第六个我们可以自己试试
a1 = [0]*32
a1[0]=chr(166163712//1629056)
a1[1] = chr(731332800 // 6771600)
a1[2] = chr(357245568 // 3682944)
a1[3] = chr(1074393000 // 10431000)
a1[4] = chr(489211344 // 3977328)
a1[5] = chr(518971936 // 5138336)
a1[7] = chr(406741500 // 7532250)
a1[8] = chr(294236496 // 5551632)
a1[9] = chr(177305856 // 3409728)
a1[10] = chr(650683500 // 13013670)
a1[11] = chr(298351053 // 6088797)
a1[12] = chr(386348487 // 7884663)
a1[13] = chr(438258597 // 8944053)
a1[14] = chr(249527520 // 5198490)
a1[15] = chr(445362764 // 4544518)
a1[16] = chr(981182160 // 10115280)
a1[17] = chr(174988800 // 3645600)
a1[18] = chr(493042704 // 9667504)
a1[19] = chr(257493600 // 5364450)
a1[20] = chr(767478780 // 13464540)
a1[21] = chr(312840624 // 5488432)
a1[22] = chr(1404511500 // 14479500)
a1[23] = chr(316139670 // 6451830)
a1[24] = chr(619005024 // 6252576)
a1[25] = chr(372641472 // 7763364)
a1[26] = chr(373693320 // 7327320)
a1[27] = chr(498266640 // 8741520)
a1[28] = chr(452465676 // 8871876)
a1[29] = chr(208422720 // 4086720)
a1[30] = chr(515592000 // 9374400)
a1[31] = chr(719890500 // 5759124)
for i in range(32):
if(i == 6):
continue
print(a1[i],end='')
经过1个个交flag,发现第6位是1
flag{e165421110ba03099a1c039337}
CrackRTF
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;
}
这题的flag由两个部分组成
我们来逆这个代码
v7 = atoi(Destination);
if ( v7 < 100000 )
ExitProcess(0);
strcat(Destination, "@DBApp");
v3 = strlen(Destination);
sub_40100A((BYTE *)Destination, v3, String1);
if ( !_strcmpi(String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )
我们要输入一个数,这个数字 要大于10000,小于99999,和后面的字符串拼接成一个进行加密,加密的及结果等于6E32D0943418C2C33385BC35A1470250DD8923A9
点开加密
int __cdecl sub_401230(BYTE *pbData, DWORD dwDataLen, LPSTR lpString1)
{
DWORD i; // [esp+4Ch] [ebp-28h]
CHAR String2[4]; // [esp+50h] [ebp-24h] BYREF
BYTE 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, 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;
}
}
看不懂,问了一下gpt,说是哈希加密,因为CryptCreateHash(phProv, 0x8004u, 0, 0, &phHash),0x8004 就是 SHA-1 的算法 ID!
所以可以直接写脚本暴力破解
import hashlib
target_hash = "6E32D0943418C2C33385BC35A1470250DD8923A9".lower() # 转换为小写匹配 Python 输出格式
for i in range(100000, 1000000): # 100000 ~ 999999
candidate = f"{i}@DBApp" # 拼接字符串
hash_value = hashlib.sha1(candidate.encode()).hexdigest() # 计算 SHA-1 哈希
if hash_value == target_hash:
print(f"找到密码: {i}")
break
这样,我们拿到了第一阶段的结果
后面哈希加密的部分因为标识符是0x8003,这个MD5爆破不了
看后面的函数
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;
}
sub_401005(lpString, (int)lpBuffer, nNumberOfBytesToWrite);
这上面这一段就是把AAA中读取的字符指针放到lpBuffer里面
unsigned int __cdecl sub_401420(LPCSTR lpString, int sourse, unsigned int length)
{
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 >= length )
break;
*(_BYTE *)(i + sourse) ^= lpString[i % v5];
}
return result;
}
点开函数,发现这个里面有个异或的加密,就是把我们输入的密码和AAA的文件异或得到result
用这个软件打开
在网上得知rtf文件的头部特征有“{\rtfl”
== (HANDLE)-1 )
return 0;
if ( !WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0) )
return 0;
CloseHandle(hFile);
return 1;
}
sub_401005(lpString, (int)lpBuffer, nNumberOfBytesToWrite);
这上面这一段就是把AAA中读取的字符指针放到lpBuffer里面
```c
unsigned int __cdecl sub_401420(LPCSTR lpString, int sourse, unsigned int length)
{
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 >= length )
break;
*(_BYTE *)(i + sourse) ^= lpString[i % v5];
}
return result;
}
点开函数,发现这个里面有个异或的加密,就是把我们输入的密码和AAA的文件异或得到result
用这个软件打开[外链图片转存中…(img-hKtmyRPf-1740997590540)]
在网上得知rtf文件的头部特征有“{\rtfl”