FinalEncrypt
题目给了3个附件,分别是FindEncrypt和flag.md,Encryption.exe.enc
1.查看代码主要功能
先看FindEncrypt文件,
主要思路就是一个指令FindEncrypt,有一些参数,加密,解密,获取key等操作,输入FindEncrypt -h会给出用法提示:
所以.enc就是加密后的文件,需要进行解密enc文件,解密需要密钥,密钥由时间戳作为种子生成的伪随机数来生成,加密和解密用同一个密钥,所以就要找到给这两个enc文件加密的时间是什么时候
2.获取文件修改时间戳
使用指令tar --atime-preserve -xvf encrypted.tar.xz
保持文件的修改时间不变,解压文件
使用stat
查看文件的修改时间,如下
Encryption.exe.enc和flag.md.enc的文件修改时间分别为2024-05-08 16:20:22.000000000 +0800
,2024-05-08 16:21:59.000000000 +0800
进行时间戳的转换,将时间改为Unix时间戳(时间戳(Unix timestamp)转换工具 - 在线工具 (tool.lu)),分别为1715127622
,1715127719
3.修改随机数种子为文件修改时间,获取密钥
主要思路是调试修改随机数种子为文件的修改时间,这样得到的密钥就是文件加密时的密钥,用这个密钥解密,就能得到正确的解密文件(之前没往这边想,只知道随机数种子是时间戳,不知道怎么处理这些
可以用gdb调试
使用指令:gdb --args ./FinalEncrypt -re test.txt
其中 --args :此选项告诉gdb
将后续参数直接传递给正在调试的程序
./FinalEncrypt:表示要调试的程序
-re test.txt:表示参数
(没安装pwndbg一直调试不了,pwndbg是gdb的一个插件,在ctf比赛中调试pwn程序用处很大
注意:需要安装pwndbg,(安装中有很多问题,在执行命令r时候出现libc.so.6: version ‘GLIBC_2.34‘ not found
问题,可以参考如下文章:问题:libc.so.6: version ‘GLIBC_2.34‘ not found 高效解决办法-CSDN博客
)
(出现这种,需要使用指令chmod +x 文件
,给文件提权
程序运行到这里,能看到调用eax
中的数据当作种子,然后调用scrand
函数,所以我们要修改的就是eax
的值,使用set $rax=1715156422
,修改rax的值,按c
接着执行,获取到key507CD82354B1A821ED46A45FAF06D53D0F941C24E085D511F244410B2666056462E126287107616B308DDB193B62036C89C7112C8E713828BC8E8C5079ED221A
A768B85A09DB4A2066AA416CFFE7E0356B54682DD29EDF279D2D851AA25F631915FBD95364FB5337CA383573A66D744BB7731C2C587F5A048CE2484984DE772C
4.用获取到的密钥解密文件
使用指令:FinalEncrypt -d Encryption.exe.enc -k 507CD82354B1A821ED46A45FAF06D53D0F941C24E085D511F244410B2666056462E126287107616B308DDB193B62036C89C7112C8E713828BC8E8C5079ED221A
密文:e07816e1dba1da61536634bef2c3b6346d533cc3b6b834e3beb634c80264143c34e36400bb4daa6902ff643414e3b8344dff6634b8b66db6bbc33834143461ab147e04
生成的密码表是随机数,需要获取随机数的种子,因为flag形式是DASCTF{}并且v8表所有值都不超过0xff(动调可以看到),v8[0]=rand(),所以尝试去爆破种子
写脚本爆破得到种子为35,然后求解flag即可
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <windows.h>
__int64 __fastcall __ROR1__(unsigned __int8 a1, char a2)
{
return ((a1 >> a2) | (a1 << (8 - a2)));
}
int main()
{
unsigned int v3; // eax
char Str[8]; // [rsp+20h] [rbp-60h] BYREF
char v6[56]; // [rsp+28h] [rbp-58h] BYREF
int v7; // [rsp+60h] [rbp-20h]
unsigned char v8[256]; // [rsp+70h] [rbp-10h] BYREF
int v9; // [rsp+174h] [rbp+F4h]
int v10; // [rsp+178h] [rbp+F8h]
int v11; // [rsp+17Ch] [rbp+FCh]
int v12; // [rsp+180h] [rbp+100h]
int v13; // [rsp+184h] [rbp+104h]
int v14; // [rsp+188h] [rbp+108h]
int v15; // [rsp+18Ch] [rbp+10Ch]
int v16; // [rsp+190h] [rbp+110h]
char v17; // [rsp+195h] [rbp+115h]
char v18; // [rsp+196h] [rbp+116h]
char v19; // [rsp+197h] [rbp+117h]
int i; // [rsp+198h] [rbp+118h]
unsigned __int8 v21; // [rsp+19Ch] [rbp+11Ch]
char v22; // [rsp+19Dh] [rbp+11Dh]
char v23; // [rsp+19Eh] [rbp+11Eh]
char v24; // [rsp+19Fh] [rbp+11Fh]
memset(v8, 0, 0x100L);
// v3 = time(0L);
// for (int i = 0; i < 256; i++)
// {
srand(35);
do
v19 = rand();
while (!v19);
memset(v8, 0, 0x100L);
v8[0] = v19;
v22 = 1;
v21 = 1;
do
{
if (v22 < 0)
v24 = 27;
else
v24 = 0;
v22 ^= v24 ^ (2 * v22);
v18 = (2 * v21) ^ (4 * ((2 * v21) ^ v21)) ^ v21;
v17 = v18 ^ (16 * v18);
if (v17 < 0)
v23 = 9;
else
v23 = 0;
v21 = v23 ^ v17;
v16 = (v23 ^ v17);
v16 = __ROR1__(v23 ^ v17, 7);
v15 = v16 ^ (v21 ^ v8[0]);
v14 = v21;
v14 = __ROR1__(v21, 6);
v13 = v15 ^ v14;
v12 = v21;
v12 = __ROR1__(v21, 5);
v11 = v13 ^ v12;
v10 = v21;
v10 = __ROR1__(v21, 4);
v9 = v11 ^ v10;
v8[v22] = v11 ^ v10;
} while (v22 != 1);//下面是用于爆破的代码,得到种子值为35
// if (v8[68] == 0xE0 && v8[65] == 0x78 && v8[83] == 0x16 && v8[67] == 0xe1 && v8[84] == 0xdb && v8[70] == 0xa1)
// {
// printf("%d", i);
// }
//}
int a[] = {224, 120, 22, 225, 219, 161, 218, 97, 83, 102, 52, 190, 242, 195, 182, 52, 109, 83, 60, 195, 182, 184, 52, 227, 190, 182, 52, 200, 2, 100, 20, 60, 52, 227, 100, 0, 187, 77, 170, 105, 2, 255, 100, 52, 20, 227, 184, 52, 77, 255, 102, 52, 184, 182, 109, 182, 187, 195, 56, 52, 20, 52, 97, 171, 20, 126, 4};
for (int j = 0; j < 67; j++)
for (int k = 0; k < 256; k++)
{
if (v8[k] == a[j] && k < 126 && k > 47)
printf("%c", k);
}
return 0;
}
拿到flag