DASCTF-FATE-Reverse

DASCTF-FATE-Reverse

0x00-Crackme

考点

MFC逆向、反调试、Wincrypt

分析

看exe文件的图标是MFC,于是去网上搜了一下MFC逆向,发现了这篇文章

https://blog.csdn.net/Sanky0u/article/details/81568483

1000和1001对应两个输入框

能定位到输入框

对函数交叉引用发现找不到,因为这里使用的是this指针调用(可能)

MFC主函数是WinMain

然后动调半天看晕了

字符串搜索回显的字符串Wrong,直接明文存储

如果下次有机会出这样的题一定把回显字符串加密(

流程分析

这里都是一些API函数,就不过多介绍了

key加密

关键的是

不同的值对应了不同的加密

所以就是将我们输入的key分为两个长度为四的字符串,然后分别进行MD5和SHA1加密

最终的加密

flag加密

先把整段key进行md5加密

然后将加密后的key传入最终的加密函数中,生成MD5的哈希值,传入生成Key

看到这个参数,查了一下

https://docs.microsoft.com/zh-tw/windows/win32/seccrypto/alg-id?redirectedfrom=MSDN

发现对应AES-128,也就是生成AES-128的密钥

然后调用CryptEncrypt函数加密

反调试-ZwSetInformationThread

我们需要动态调试提取数据,但是在刚才的位置设置断点会发现输入后直接结束,应该是有反调试

https://ctf-wiki.org/reverse/windows/anti-debug/zwsetinformationthread/

对比各种反调试和去IMPORT找导入函数,最终确定是ZwSetInformationThread

反反调试在该文中也有介绍,就不再多说了

绕过后就可以提取数据进行解密了

得到key

MD5

SHA1

https://crackstation.net/

解密flag

这里直接提取数据拿去AES解密有问题(提取出来调用CryptDecrypt也不行),还是FallW1nd师傅强,想到直接模拟生成哈希值的过程,然后最后调用CryptDecrypt即可

EXP如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <windows.h>
#include <windef.h>
#include <wincrypt.h>
#include<stdio.h>
int main()
{
HCRYPTKEY phKey; // [esp+Ch] [ebp-10h] BYREF
HCRYPTPROV phProv; // [esp+10h] [ebp-Ch] BYREF
HCRYPTHASH phHash; // [esp+14h] [ebp-8h] BYREF
BOOL retValue;

BYTE flag_data[0x104] = { 0x5B, 0x9C, 0xEE, 0xB2, 0x3B, 0xB7, 0xD7, 0x34, 0xF3, 0x1B, 0x75, 0x14, 0xC6, 0xB2, 0x1F, 0xE8, 0xDE, 0x33, 0x44, 0x74, 0x75, 0x1B, 0x47, 0x6A, 0xD4, 0x37, 0x51, 0x88, 0xFC, 0x67, 0xE6, 0x60, 0xDA, 0x0D, 0x58, 0x07, 0x81, 0x43, 0x53, 0xEA, 0x7B, 0x52, 0x85, 0x6C, 0x86, 0x65, 0xAF, 0xB4 };
BYTE keyBuf[] = { 0x5c,0x53,0xa4,0xa4,0x1d,0x52,0x43,0x7a,0x9f,0xa1,0xe9,0xc2,0x6c,0xa5,0x90,0x90 };
DWORD dwDataLen = 0x10;
DWORD dwBufLen = 0x104;
DWORD dwDataLen_2;
DWORD* pdwDataLen = &dwDataLen_2;
*pdwDataLen = 0x20;


phProv = 0;
phHash = 0;
phKey = 0;

retValue = CryptAcquireContextA(&phProv, 0, 0, 0x18u, 0xF0000000);
if (retValue)
{
retValue = CryptCreateHash(phProv, 0x8003u, 0, 0, &phHash);
if (retValue)
{
retValue = CryptHashData(phHash, keyBuf, dwDataLen, 0);
if (retValue)
{
retValue = CryptDeriveKey(phProv, 0x660Eu, phHash, 1u, &phKey);
if (retValue)
retValue = CryptDecrypt(phKey, 0, 1, 0, flag_data, pdwDataLen);
}
}
}

if (phKey)
CryptDestroyKey(phKey);
if (phHash)
CryptDestroyHash(phHash);
if (phProv)
CryptReleaseContext(phProv, 0);

return retValue;

}

附录

还有这种调用加密,有兴趣可以去看看-http://ctf.hsc2019.site/challenges#DRIVER-58

0x01-FakePica

考点

安卓加壳、AES

分析

hgame-week3-re也有脱壳,这里把工具链接贴一下

https://github.com/CodingGay/BlackDex

具体分析加壳与脱壳直接看我之前写的文章

https://gift1a.github.io/2022/02/13/hgame2022-week3-re/?highlight=梆

加密分析

找到Mainactivity

数据提取

1
2
3
4
5
6
7
8
unsigned char content[] = {-114, 95, -37, 127, -110, 113, 41, 74, 40, 73, 19, 124, -57, -88, 39, -116, -16, -75, -3, -45, -73, -6, -104, -6, -78, 121, 110, 74, -90, -47, -28, -28};
unsigned char content1[] = {-40, 26, 95, -49, -40, -123, 72, -90, -100, -41, 122, -4, 25, -101, -58, 116};


for (int i = 0; i < 16; ++i)
{
printf("%X", content1[i] & 0xff);
}

解密直接去在线网站即可

get flag

0x02-奇怪的交易

考点

ELF-python打包、算法

分析

还好加了Lu1u师傅,刚好看到

https://lu1u.xyz/2022/03/28/RE_Challenge/

objcopy --dump-section pydata=pydata.dump 1

sudo snap install pyinstxtractor

pyinstxtractor pydata.dump

得到pyc文件,修补好文件头发现uncompyle6不了(因为是3.10的),寄,只能嗯读python字节码

翻译字节码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from cup import*
import dis
import libnum
pub_key=[12702192797044914024075774649965354105344232304099465264316470282606351700311177624703682814557100043599414982439635470829841890299241342602374578366076034128412992290094164613120745611751102797279925764448133764246126488845600641524814194290745105708735258127757986238766868988676022258542038318776640732920027324986285887310132372524224961045858183153047991881042129131551711617627844146600513830709959185824512201669420128585170924683844128155435146399996585220865423125338735154727569986267948480523307784641442521735105741341230032585576300299944879647981670048377150556292280650846158185797588466680532743801893,12680615221091469696163926483122992106481999501435284497098601343706982733487916553201934931961274845294041438909951977672521864927961654544622905443692482152403380984734291652023321187458458985625147422841102922314725726207365632256563373977251725785357590588556314671253970422319546403985257810950046085994573229162322957630767327089195523762665081311711474689269184996318744510300057603532953644164998953897411177604349567514705039306693117602798453972917348902600111420473965929048876821563646206875034926505783009957256212261250539005023918242209009676914632796839852778318989278092929214021282438144809708279435]
pp=[0]
dd=[54,54,54,54]
oo=[3532577106, 1472742623, 3642468664, 4193500461, 2398676029, 617653972, 1474514999, 1471783658, 1012864704, 3615627536, 993855884, 438456717, 3358938551, 3906991208, 198959101, 3317190635, 3656923078, 613157871, 2398768861, 97286225, 2336972940, 1471645170, 3233163154, 583597118, 2863776301, 3183067750, 1384330715, 2929694742, 3522431804, 2181488067, 3303062236, 3825712422, 145643141, 2148976293, 2940910035, 506798154, 994590281, 2231904779, 3389770074, 2814269052, 1105937096, 1789727804, 3757028753, 2469686072, 1162286478, 680814033, 2934024098, 2162521262, 4048876895, 2121620700, 4240287315, 2391811140, 3396611602, 3091349617, 3031523010, 2486958601, 3164065171, 1285603712, 798920280, 2337813135, 4186055520, 3523024366, 1077514121, 1436444106, 2731983230, 1507202797, 500756149, 198754565, 2382448647, 880454148, 1970517398, 3217485349, 1161840191, 560498076, 1782600856, 2643721918, 1285196205, 788797746, 1195724574, 4061612551, 103427523, 2502688387, 4147162188, 617564657, 978211984, 1781482121, 2205798970, 3939973102, 3826603515, 659557668, 2582884932, 1561884856, 2217488804, 1189296962, 169145316, 2781742156, 1323893433, 824667876, 408202876, 3759637634, 4094868412, 1508996065, 162419237, 3732146944, 3083560189, 3955940127, 2393776934, 2470191468, 3620861513, 481927014, 2756226070, 3154651143, 1261069441, 2063238535, 2222237213, 101459755, 3159774417, 1721190841, 1078395785, 176506553, 3552913423, 1566142515, 1938949000, 1499289517, 3315102456, 829714860, 3843359394, 952932374, 1283577465, 2045007203, 3957761944, 3767891405, 2917089623, 3296133521, 482297421, 1734231412, 3670478932, 2575334979, 2827842737, 3413631016, 1533519803, 4008428470, 3890643173, 272960248, 317508587, 3299937500, 2440520601, 27470488, 1666674386, 1737927609, 750987808, 2385923471, 2694339191, 562925334, 2206035395]



def ll():
pub_key = [
12702192797044914024075774649965354105344232304099465264316470282606351700311177624703682814557100043599414982439635470829841890299241342602374578366076034128412992290094164613120745611751102797279925764448133764246126488845600641524814194290745105708735258127757986238766868988676022258542038318776640732920027324986285887310132372524224961045858183153047991881042129131551711617627844146600513830709959185824512201669420128585170924683844128155435146399996585220865423125338735154727569986267948480523307784641442521735105741341230032585576300299944879647981670048377150556292280650846158185797588466680532743801893,
12680615221091469696163926483122992106481999501435284497098601343706982733487916553201934931961274845294041438909951977672521864927961654544622905443692482152403380984734291652023321187458458985625147422841102922314725726207365632256563373977251725785357590588556314671253970422319546403985257810950046085994573229162322957630767327089195523762665081311711474689269184996318744510300057603532953644164998953897411177604349567514705039306693117602798453972917348902600111420473965929048876821563646206875034926505783009957256212261250539005023918242209009676914632796839852778318989278092929214021282438144809708279435]
flag=input()
i = 0
m=libnum.s2n(flag)#字符串转为数字
c=str(pow(m,pub_key[1],pub_key[0]))#简单算法并且进行转为字符串
if i<len(c):
kk=0
for ii in c[slice(i,i+4)]:
kk=(kk<<8)+ord(ii)
pp.append(kk)
i+=4
if not i<len(c):
ww=len(pp)
res=encrypt(ww,pp,dd)
if pp==oo:
print("you are right!!")
else:
print("gg")
quit()

翻译出来大概是这样的

这里要关注跳转的条件是not还是true

encrypt函数是cup库里面的一个函数,当时我忽略了from cup import,导致一直识别不出来encrypt函数是什么*

过程差不多都可以读出来,那个for循环就是将每四个字符转为一个int,由于不会python,很多都是自己写代码试出来的(,剩下的蹲wp了

整个过程就是先进行RSA加密,然后调用encrypt函数加密

tip

看了https://blog.t0hka.top/index.php/archives/36/才知道可以使用在线工具

https://tool.lu/pyc/,效果差不多,不过还是需要自己修复一下

pyinstaller加密

https://bbs.pediy.com/thread-271253.htm

我们可以在解包的时候发现两个文件,一个是加密的密钥,一个是加密的过程

接下来只需要对PYZ文件解包(同样使用pyinxtxtractor),得到加密后的cup库即可

解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/env python3
import tinyaes
import zlib

CRYPT_BLOCK_SIZE = 16

# 从crypt_key.pyc获取key,也可自行反编译获取
key = bytes('0000000000000tea', 'utf-8')

inf = open('cup.pyc.encrypted', 'rb') # 打开加密文件
outf = open('cup.pyc', 'wb') # 输出文件

# 按加密块大小进行读取
iv = inf.read(CRYPT_BLOCK_SIZE)

cipher = tinyaes.AES(key, iv)

# 解密
plaintext = zlib.decompress(cipher.CTR_xcrypt_buffer(inf.read()))

# 补pyc头(最后自己补也行)
outf.write(b'\x6f\x0d\x0d\x0a\0\0\0\0\0\0\0\0\0\0\0\0')

# 写入解密数据
outf.write(plaintext)

inf.close()
outf.close()

反编译得到cup库的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
import libnum
from ctypes import *

def MX(z, y, total, key, p, e):
temp1 = (z.value >> 5 ^ y.value << 2) + (y.value >> 3 ^ z.value << 4)
temp2 = (total.value ^ y.value) + (key[p & 3 ^ e.value] ^ z.value)
return c_uint32(temp1 ^ temp2)


def encrypt(ᘗ, ᘖ, ᘘ):
ᘜ = 0x9E3779B9L
ᘛ = 6 + 52 // ᘗ
total = c_uint32(0)
ᘔ = c_uint32(ᘖ[ᘗ - 1])
ᘕ = c_uint32(0)
if ᘛ > 0:
total.value += ᘜ
ᘕ.value = total.value >> 2 & 3
ᘚ = c_uint32(ᘖ[0])
ᘖ[ᘗ - 1] = c_uint32(ᘖ[ᘗ - 1] + MX(ᘔ, ᘚ, total, ᘘ, ᘗ - 1, ᘕ).value).value
ᘔ.value = ᘖ[ᘗ - 1]
ᘛ -= 1
if not ᘛ > 0:
return

可以看出是xxtea加密

解密

得到rsa的密文c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <stdio.h>
#include <string.>


#define xxtea_DELTA 0x9e3779b9
#define xxtea_MX (((xxtea_z>>5^xxtea_y<<2) + (xxtea_y>>3^xxtea_z<<4)) ^ ((xxtea_sum^xxtea_y) + (xxtea_key[(xxtea_p&3)^xxtea_e] ^ xxtea_z)))
void xxtea(uint32_t* xxtea_origin, int xxtea_n, uint32_t const xxtea_key[4])
{
uint32_t xxtea_y, xxtea_z, xxtea_sum;
unsigned xxtea_p, xxtea_rounds, xxtea_e;
if (xxtea_n > 1) /* Coding Part */
{
xxtea_rounds = 6 + 52 / xxtea_n;
xxtea_sum = 0;
xxtea_z = xxtea_origin[xxtea_n - 1];
do
{
xxtea_sum += xxtea_DELTA;
xxtea_e = (xxtea_sum >> 2) & 3;
for (xxtea_p = 0; xxtea_p < xxtea_n - 1; xxtea_p++)
{
xxtea_y = xxtea_origin[xxtea_p + 1];
xxtea_z = xxtea_origin[xxtea_p] += xxtea_MX;
}
xxtea_y = xxtea_origin[0];
xxtea_z = xxtea_origin[xxtea_n - 1] += xxtea_MX;
} while (--xxtea_rounds);
}
else if (xxtea_n < -1) /* Decoding Part */
{
xxtea_n = -xxtea_n;
xxtea_rounds = 6 + 52 / xxtea_n;
xxtea_sum = xxtea_rounds * xxtea_DELTA;
xxtea_y = xxtea_origin[0];
do
{
xxtea_e = (xxtea_sum >> 2) & 3;
for (xxtea_p = xxtea_n - 1; xxtea_p > 0; xxtea_p--)
{
xxtea_z = xxtea_origin[xxtea_p - 1];
xxtea_y = xxtea_origin[xxtea_p] -= xxtea_MX;
}
xxtea_z = xxtea_origin[xxtea_n - 1];
xxtea_y = xxtea_origin[0] -= xxtea_MX;
xxtea_sum -= xxtea_DELTA;
} while (--xxtea_rounds);
}
}

int main()
{
//0x40CEA5BC,0xE7B2B2F4,0x129D12A9,0x5BC810AE,0x1D06D73D,0xDCF800DC
unsigned int enc[155] = { 3532577106, 1472742623, 3642468664, 4193500461, 2398676029, 617653972, 1474514999, 1471783658, 1012864704, 3615627536, 993855884, 438456717, 3358938551, 3906991208, 198959101, 3317190635, 3656923078, 613157871, 2398768861, 97286225, 2336972940, 1471645170, 3233163154, 583597118, 2863776301, 3183067750, 1384330715, 2929694742, 3522431804, 2181488067, 3303062236, 3825712422, 145643141, 2148976293, 2940910035, 506798154, 994590281, 2231904779, 3389770074, 2814269052, 1105937096, 1789727804, 3757028753, 2469686072, 1162286478, 680814033, 2934024098, 2162521262, 4048876895, 2121620700, 4240287315, 2391811140, 3396611602, 3091349617, 3031523010, 2486958601, 3164065171, 1285603712, 798920280, 2337813135, 4186055520, 3523024366, 1077514121, 1436444106, 2731983230, 1507202797, 500756149, 198754565, 2382448647, 880454148, 1970517398, 3217485349, 1161840191, 560498076, 1782600856, 2643721918, 1285196205, 788797746, 1195724574, 4061612551, 103427523, 2502688387, 4147162188, 617564657, 978211984, 1781482121, 2205798970, 3939973102, 3826603515, 659557668, 2582884932, 1561884856, 2217488804, 1189296962, 169145316, 2781742156, 1323893433, 824667876, 408202876, 3759637634, 4094868412, 1508996065, 162419237, 3732146944, 3083560189, 3955940127, 2393776934, 2470191468, 3620861513, 481927014, 2756226070, 3154651143, 1261069441, 2063238535, 2222237213, 101459755, 3159774417, 1721190841, 1078395785, 176506553, 3552913423, 1566142515, 1938949000, 1499289517, 3315102456, 829714860, 3843359394, 952932374, 1283577465, 2045007203, 3957761944, 3767891405, 2917089623, 3296133521, 482297421, 1734231412, 3670478932, 2575334979, 2827842737, 3413631016, 1533519803, 4008428470, 3890643173, 272960248, 317508587, 3299937500, 2440520601, 27470488, 1666674386, 1737927609, 750987808, 2385923471, 2694339191, 562925334, 2206035395 };
unsigned int key[4] = { (unsigned int)54,(unsigned int)54,(unsigned int)54,(unsigned int)54 };
xxtea(enc, -155, key);//长度为多少,解密时第二个参数就改为多长
for (int i = 0; i < 155; ++i)
{
printf("%c", (((enc[i]) & 0xff000000) >> 24));
printf("%c", ((enc[i]) & 0x00ff0000) >> 16);
printf("%c", ((enc[i]) & 0x0000ff00)>>8);
printf("%c", ((enc[i]) & 0xff));
}
return 0;
}

解RSA,怪我不是密码🤠,直接贴t0hka师傅的脚本了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import gmpy2
from Crypto.PublicKey import RSA
import ContinuedFractions, Arithmetic
from Crypto.Util.number import long_to_bytes


def wiener_hack(e, n):
# firstly git clone https://github.com/pablocelayes/rsa-wiener-attack.git !
frac = ContinuedFractions.rational_to_contfrac(e, n)
convergents = ContinuedFractions.convergents_from_contfrac(frac)
for (k, d) in convergents:
if k != 0 and (e * d - 1) % k == 0:
phi = (e * d - 1) // k
s = n - phi + 1
discr = s * s - 4 * n
if (discr >= 0):
t = Arithmetic.is_perfect_square(discr)
if t != -1 and (s + t) % 2 == 0:
return d
return False


def main():
pub_key = [
0x649EE967E7916A825CC9FD3320BEABF263BEAC68C080F52824A0F521EDB6B78577EC52BF1C9E78F4BB71192F9A23F1A17AA76E5979E4D953329D3CA65FB4A71DA57412B59DFD6AEDF0191C5555D3E5F582B81B5E6B23163E9889204A81AFFDF119FE25C92F4ED59BD3285BCD7AAE14824240D2E33C5A97848F4EB7AAC203DE6330D2B4D8FF61691544FBECD120F99A157B3D2F58FA51B2887A9D06CA383C44D071314A12B17928B96F03A06E959A5AFEFA0183664F52CD32B9FC72A04B45913FCB2D5D2D3A415A14F611CF1EAC2D6C785142A8E9CC41B67A6CD85001B06EDB8CA767D367E56E0AE651491BF8A8C17A38A1835DB9E4A9292B1D86D5776C98CC25,
0x647327833ACFEF1F9C83E74E171FC300FA347D4A6769476C33DA82C95120ACB38B62B33D429206FE6E9BB0BB7AB748A1036971BEA36EC47130B749C1C9FF6FE03D0F7D9FC5346EB0E575BDFA6C530AA57CD676894FC080D2DD049AB59625F4B9C78BCFD95CDCD2793E440E26E189D251121CB6EB177FEDB596409034E8B0C5BBD9BD9342235DBB226C9170EFE347FF0FD2CFF9A1F7B647CC83E4D8F005FD7125A89251C768AFE70BDD54B88116814D5030F499BCAC4673CCCC342FB4B6AC58EA5A64546DC25912B6C430529F6A7F449FD96536DE269D1A1B015A4AC6B6E46EE19DCE8143726A6503E290E4BAE6BD78319B5878981F6CFFDB3B818209341FD68B]
# 0->n,1->e

n = pub_key[0]
e = pub_key[1]
c = 10610336534759505889607399322387179316771488492347274741918862678692508953185876570981227584004676580623553664818853686933004290078153620168054665086468417541382824708104480882577200529822968531743002301934310349005341104696887943182074473298650903541494918266823037984054778903666406545980557074219162536057146090758158128189406073809226361445046225524917089434897957301396534515964547462425719205819342172669899546965221084098690893672595962129879041507903210851706793788311452973769358455761907303633956322972510500253009083922781934406731633755418753858930476576720874219359466503538931371444470303193503733920039
d = wiener_hack(e, n)
m = pow(c, d, n)
print(long_to_bytes(m)) # flag{You_Need_Some_Tea}


if __name__ == "__main__":
main()