Pwn
1. Hello pwner

Flag: W1{welcome_to_assembly}
Crypto
2. Substitution
Tải file, giải nén và mở chall lên:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| KEY = {
'A': 'Q', 'B': 'W', 'C': 'E', 'D': 'R', 'E': 'T', 'F': 'Y', 'G': 'U', 'H': 'I', 'I': 'O',
'J': 'P', 'K': 'A', 'L': 'S', 'M': 'D', 'N': 'F', 'O': 'G', 'P': 'H', 'Q': 'J', 'R': 'K',
'S': 'L', 'T': 'Z', 'U': 'X', 'V': 'C', 'W': 'V', 'X': 'B', 'Y': 'N', 'Z': 'M',
'a': 'q', 'b': 'w', 'c': 'e', 'd': 'r', 'e': 't', 'f': 'y', 'g': 'u', 'h': 'i', 'i': 'o',
'j': 'p', 'k': 'a', 'l': 's', 'm': 'd', 'n': 'f', 'o': 'g', 'p': 'h', 'q': 'j', 'r': 'k',
's': 'l', 't': 'z', 'u': 'x', 'v': 'c', 'w': 'v', 'x': 'b', 'y': 'n', 'z': 'm',
}
def hehe(data, key):
return ''.join(key.get(char, char) for char in data)
def encrypt(plaintext):
substituted = hehe(plaintext, KEY)
return substituted
if __name__ == "__main__":
plaintext = "W1{???????????????}"
encrypted = encrypt(plaintext)
with open("encrypted.txt", "w") as f:
f.write(encrypted)
|
Phân tích:
1
2
| def hehe(data, key):
return ''.join(key.get(char, char) for char in data)
|
Hàm hehe
lấy data
và chuyển đổi từng ký tự trong dữ liệu đó sang ký tự tương ứng bằng danh sách của KEY
.
1
2
3
| def encrypt(plaintext):
substituted = hehe(plaintext, KEY)
return substituted
|
Hàm encrypt
có mục đich là sử dụng hàm hehe để mã hóa dữ liệu.
Giải:
Để lấy được plaintext
thì ta cần giải mã encrypted
, nghĩa là phải đảo ngược lại quá trình chuyển đổi ký tự trong danh sách của KEY
1
| KEY_rev = {i : v for v, i in KEY.items()}
|
Rồi sử dụng hàm hehe
chuyển đổi tiếp 1 lần nữa để được data
ban đầu.
1
2
| def hehe(data, key):
return ''.join(key.get(char, char) for char in data)
|
Script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| KEY = {
'A': 'Q', 'B': 'W', 'C': 'E', 'D': 'R', 'E': 'T', 'F': 'Y', 'G': 'U', 'H': 'I', 'I': 'O',
'J': 'P', 'K': 'A', 'L': 'S', 'M': 'D', 'N': 'F', 'O': 'G', 'P': 'H', 'Q': 'J', 'R': 'K',
'S': 'L', 'T': 'Z', 'U': 'X', 'V': 'C', 'W': 'V', 'X': 'B', 'Y': 'N', 'Z': 'M',
'a': 'q', 'b': 'w', 'c': 'e', 'd': 'r', 'e': 't', 'f': 'y', 'g': 'u', 'h': 'i', 'i': 'o',
'j': 'p', 'k': 'a', 'l': 's', 'm': 'd', 'n': 'f', 'o': 'g', 'p': 'h', 'q': 'j', 'r': 'k',
's': 'l', 't': 'z', 'u': 'x', 'v': 'c', 'w': 'v', 'x': 'b', 'y': 'n', 'z': 'm',
}
KEY_rev = {i : v for v, i in KEY.items()}
def hehe(data, key):
return "".join(key.get(char, char) for char in data)
def decrypt(plaintext):
substituted = hehe(plaintext, KEY_rev)
return substituted
if __name__ == "__main__":
encrypted = "V1{lxwlzozxzogf}"
decrypted = decrypt(encrypted)
print(decrypted)
|
Flag: W1{substitution}
3. Hix
Tải file, giải nén và mở chall lên:
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
| import hashlib
import random
methods = ['md5', 'sha256', 'sha3_256', 'sha3_512', 'sha3_384', 'sha1', 'sha384', 'sha3_224', 'sha512', 'sha224']
def random_encrypt(x) :
method = random.choice(methods)
hash_obj = hashlib.new(method)
hash_obj.update(x.encode())
return hash_obj.hexdigest()
def main() :
message = open("./../private/flag.txt", "r").read()
enc = []
for char in message :
x = (ord(char) + 20) % 130
x = hashlib.sha512(str(x).encode()).hexdigest()
x = random_encrypt(x)
enc.append(x)
with open('encrypted_memory.txt', 'w') as f :
f.write("ct = " + str(enc))
if __name__ == "__main__" :
main()
|
Phân tích:
1
| methods = ['md5', 'sha256', 'sha3_256', 'sha3_512', 'sha3_384', 'sha1', 'sha384', 'sha3_224', 'sha512', 'sha224']
|
Đây là các thuật toán được sử dụng cho hàm băm.
1
2
3
4
5
| def random_encrypt(x) :
method = random.choice(methods)
hash_obj = hashlib.new(method)
hash_obj.update(x.encode())
return hash_obj.hexdigest()
|
Hàm random_encrypt
dùng để mã hóa một chuỗi x bằng cách sử dụng một thuật toán băm bất kì có sẵn trong methods
.
1
2
3
4
5
| for char in message :
x = (ord(char) + 20) % 130
x = hashlib.sha512(str(x).encode()).hexdigest()
x = random_encrypt(x)
enc.append(x)
|
Lấy từng kí tự trong message
, sau đó lấy giá trị của ký tự đó trong ASCII rồi cộng 20 và lấy modulo 130. Tiếp theo, chuyển nó về một chuỗi rồi băm bằng SHA-512. Đến cuối thì sử dụng hàm random_encrypt
.
Giải:
Ý tưởng: Vì x nằm trong đoạn từ 0 đến 129 (là một số nhỏ) nên ta có thể brute-force từng giá trị x khi thử với mỗi phương pháp băm để tìm ra các x tương ứng với từng giá trị của ct
một cách dễ dàng.
1
2
3
4
5
6
7
8
9
10
11
| def reverse_encrypt(enc_hash):
for method in methods:
try:
for x in range(130):
test_input = hashlib.sha512(str(x).encode()).hexdigest()
hash_obj = hashlib.new(method)
hash_obj.update(test_input.encode())
if hash_obj.hexdigest() == enc_hash:
return x
except:
continue
|
Sau đó, với từng giá trị trong ct
, ta dùng hàm reverse_encrypt
và truy ngược lại giá trị x ban đầu bằng các phép toán và đổi sang dạng ASCII để giải mã nó bằng hàm sau:
1
2
3
4
5
6
7
| def decrypt():
decrypted_message = ""
for ct_hash in ct:
x = reverse_encrypt(ct_hash)
original_ascii = (x - 20) % 130
decrypted_message += chr(original_ascii)
return decrypted_message
|
Script:
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
| ct = ['f189636f8eef640b55d03387864fd17efd324453cc9276be5ff6bd4da88b13fca72438daaab00830a6d14330d37c0f7bee1e7c32d5dda0541a171f66a2343dc1', '1388cafa58065fa0c04372ce57f303cc4ec9fe62', 'f6266e2849bf8b8575701814cc3f3eb5369e887db54b34e85b1e4608b4fbf5e5', '31f33ac191e818db784cf8321d70f84763db2b2e599f90cf65868eec85a10f20ae0e23aa1cd48c2f13eec355b2975089490761a291ac2a1bcf33f5fbecead431', '981e4bce5dede3faa51a936f650e2c1d64169493860c67d68a1ffbbfa32f58598e7869f3f11aefc1620ee8d3ebe4e5f5', 'f06ffaaa6290bf47d26ba2c09c28dddd8f5bcad6ac464ec17fea48040acf1214d10bc109b7c47cffddb6bccd6b61b61a9e629a8f47ab26b80593f29c8c297489', 'a7d95b3bbde885b4eaa76afc6572e18e4483351005f637fe1f5a7bc0b000fe1f', '85245de371c327440a5f343f27d6df361225806e679950bab3a5a336', 'ea1923e909de3c3c3384ad9ae7696d73', '21df20aab35967470aada32375f535d4a735789bf0789fd421f85163c4d75c6e', 'b9491ae1a9de40d30a86c00139bd7d6f496f5bf4ce013bc2d5a43a97', '03f061f60f3527b15ff31d31dcce0761', '981e4bce5dede3faa51a936f650e2c1d64169493860c67d68a1ffbbfa32f58598e7869f3f11aefc1620ee8d3ebe4e5f5', 'f2a1a7e9dd5e6363050b0cdb0579ebfebdc5e348ab538bdcf47616139351cf2b9f92cb4d14446b3ad8bf182875b81e75', '24aaafc58a2b897aed5829b2e96d73b1de7cd680d76a1143cdc8baef', '6d80d11e5f1161ef86619dcdb186852b5218d6ac224b81b63555fe73741631c36ae0bcb5b3228fbed796c22dedeed587c9d65ddb825aee4fae92b6619e7ffd8f', '6f8b39550106044625102ee0cabf9fe1393f0013388633d5742fcc7e8df7708793a96885b9d18b795a2b0d9014704b9f', 'ddf3c543be9cac44f3af078583fe5fddb64104d93308c146c23f52ff25b2a6e23606c42dc0060a4dd9b11b446759cb5de1844471eb3d6d25c43c6fcc0d8d60c4', '95f2739053cf64555b0c0662b5e2d63822433f7fcac6960de6d57efda427461a58c6e2ffac6da6f4caa9407df10cc0be', 'a1bd4e0efc7ce8bd1d63433a0baa87e3a486fbfe2729d73d1dbf7d2822d201ee8726c6d94da1f09f1a53554e440ad6041ecab545b2085dc28c6f6849f0fcea23', 'a7d95b3bbde885b4eaa76afc6572e18e4483351005f637fe1f5a7bc0b000fe1f', '2b4561a521a82af6a26dfb76078ca97ba53a720f7ee67d923a6d3a13', 'b21ed1f3d501a8a842ef1b26ed3863cf10cf8231ee23a079f749cfa322702c8e', 'd798a32b52384219f8779dccf8b2173f4b73f075cbeb4507ee83c94e', 'b863fa3492fb87edcdef766f38a508ed', '9f876db4b58c1b7e499f35cdbd533a810060a0c8250bfc5421e0f42b2715b027', '4b14748ba0f3da581ddd7ec49dac41d34ea1ee6dae90818333b11501', '85153b2a5f8dea7f5488906cb65d61e9ac0666057636ff6b356dd4d8d0fc5d20', '6b91d6259827176bcb3f312a8faca297e56c7e627235b930cf8163b3e7a5328b', 'b21ed1f3d501a8a842ef1b26ed3863cf10cf8231ee23a079f749cfa322702c8e', '4c8740f90af1055f194a4c8e1b69522da228812465eb72b82b35c927bc48bf9d', 'b248b6b2f2c9365aa9a0e9b37a8057effd29bb2f34c79ec0b40124d08986832b5d227db95cb97b176541589985762d9a', '7260f9b5d1c58d0609523114ed324f396335d940f852dba558461b34c5a53630', 'a1bd4e0efc7ce8bd1d63433a0baa87e3a486fbfe2729d73d1dbf7d2822d201ee8726c6d94da1f09f1a53554e440ad6041ecab545b2085dc28c6f6849f0fcea23', '1077caf3ed754ed8fbd49c76134906e8', 'f3565219d115ec74a85056997cc25e98e3e4912a31c858c1e45b841047698e93', '83315b8fa07a35b12e3f47ebb365268b4a4a8ef2', '64c008d6460c2b98aba616b1d0d11a06b9df564b87d3aeedda83b36aacd3d0c160465109eb06c62e86e360cf026faa27a616dbbf2bec269be9ad128af96073bb', '60bbd94b3ac3ea7149fc6cd850d72d4f1750601275832815dd9a23d4c3757d84aca29d716da5dd72a0045f15ff969925', '94327e8c8321421e72f52cd726336e824630ec7dda31b07ce83f11b8234aea7a', 'a69ef62254280226cc4223a2341c727afcd7ce4e3ffd3f2f1c57d9d3cd30659b52b1c2b56f911a7157041b5f0ff8176f', '3c904622c8d8d79c6704d50ae0175b049b3a5708705ecdce932fe426b9f46f1bd6585b8288c1d38f6301c31af5feac02', 'a3939bf491ffd9824056e249d6e355d8423855f0']
import hashlib
methods = ['md5', 'sha256', 'sha3_256', 'sha3_512', 'sha3_384', 'sha1', 'sha384', 'sha3_224', 'sha512', 'sha224']
def reverse_encrypt(enc_hash):
for method in methods:
try:
for x in range(130):
test_input = hashlib.sha512(str(x).encode()).hexdigest()
hash_obj = hashlib.new(method)
hash_obj.update(test_input.encode())
if hash_obj.hexdigest() == enc_hash:
return x
except:
continue
def decrypt():
decrypted_message = ""
for ct_hash in ct:
x = reverse_encrypt(ct_hash)
original_ascii = (x - 20) % 130
decrypted_message += chr(original_ascii)
return decrypted_message
if __name__ == "__main__":
flag = decrypt()
print(flag)
|
Flag: W1{are_you_trying_to_predict_randomness@_@}
4. DH
Tải file, giải nén và mở chall lên:
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
| from Crypto.Util.number import isPrime, long_to_bytes, getPrime
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from random import randint
from hashlib import sha256
FLAG = b"W1{fake-flag}"
class DH:
def __init__(self):
self.gen_params()
def gen_params(self):
self.r = getPrime(512)
while True:
self.q = getPrime(42)
self.p = (2 * self.q * self.r) + 1
if isPrime(self.p):
break
while True:
self.h = getPrime(42)
self.g = pow(self.h, 2 * self.r, self.p)
if self.g != 1:
break
self.a = randint(2, self.p - 2)
self.b = randint(2, self.p - 2)
self.A, self.B = pow(self.g, self.a, self.p), pow(self.g, self.b, self.p)
self.ss = pow(self.A, self.b, self.p)
def encrypt(self, flag_part):
key = sha256(long_to_bytes(self.ss)).digest()[:16]
cipher = AES.new(key, AES.MODE_ECB)
ct = cipher.encrypt(pad(flag_part, 16)).hex()
return f"encrypted = {ct}"
def get_params(self):
return f"p = {self.p}\ng = {self.g}\nA = {self.A}\nB = {self.B}"
def main():
dh = DH()
print(dh.get_params())
print(dh.encrypt(FLAG))
if __name__ == "__main__":
main()
p = 85013941328859365232686230728938372320812319905627686919070637645614632817039920673725615375841158719310596592903101914818137738460649589340349796188816568005092757847
g = 20033344683527080232439150682925185454003164954955126339094967675384779782733210350757021743656898625398860187361281262413493941502725149445995471514781822892886669776
A = 76548721461171533747911417838852759206858825205673491250696441734297318615226024320798706656529038703728631231084155790148283919370554345818139818854112841655270107839
B = 2103083080159597422706551446020625757109756570951674830166998494220734179439318911618156966499109201221652320384817270671579741987575328177442670242481963924501204498
encrypted = "240e7b7678aaaa0dcbe06de7c5598a1ca0be7e2ae584bc7dfd2388cdb1d4fb6a37ceb94556757afc293999cbe5a5a2dbb4071ebf6cfd4332088555f9b2de1922"
|
Phân tích:
Trong class DH, có:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| def gen_params(self):
self.r = getPrime(512)
while True:
self.q = getPrime(42)
self.p = (2 * self.q * self.r) + 1
if isPrime(self.p):
break
while True:
self.h = getPrime(42)
self.g = pow(self.h, 2 * self.r, self.p)
if self.g != 1:
break
self.a = randint(2, self.p - 2)
self.b = randint(2, self.p - 2)
self.A, self.B = pow(self.g, self.a, self.p), pow(self.g, self.b, self.p)
self.ss = pow(self.A, self.b, self.p)
|
Hàm gen_params
tạo một bộ khóa Diffie-Hellman.
1
2
| def get_params(self):
return f"p = {self.p}\ng = {self.g}\nA = {self.A}\nB = {self.B}"
|
Khi lấy hàm get_params
thì sẽ trả về các giá trị p, g, A, B.
1
2
3
4
5
| def encrypt(self, flag_part):
key = sha256(long_to_bytes(self.ss)).digest()[:16]
cipher = AES.new(key, AES.MODE_ECB)
ct = cipher.encrypt(pad(flag_part, 16)).hex()
return f"encrypted = {ct}"
|
Ngoài ra, còn có hàm encrypt
lấy giá trị ss
từ hàm gen_params
để tạo key cho thuật toán mã hóa AES chế độ ECB, cuối cùng dùng nó để mã hóa FLAG
.
Giải:
Để tìm ra FLAG
thì ta cần lấy được key
để giải mã cipher
1
2
3
| key = sha256(long_to_bytes(ss)).digest()[:16]
cipher = AES.new(key, AES.MODE_ECB)
flag = cipher.decrypt(encrypted)
|
Do đó, ta phải tìm ra giá trị ss
để tạo được key
.
Ta có các phương trình sau:
$A≡g^a$ (mod p); $B≡g^b$ $⇒ss≡A^b≡(g^a )^b≡g^{ab}≡(g^b )^a≡B^a$ (mod p)
Ta đã có p, g, A, vậy ta chỉ cần có thêm b là có thể tìm ra ss
. Tới đây, tôi sử dụng thuật toán Pohlig-Hellman để tìm b qua công thức $B≡g^b$ (mod p) bằng công cụ Alpetron.

Set k = 0, lấy được b = exp và tính được ss
. Sau đây là script cho thử thách:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| from Crypto.Util.number import long_to_bytes
from Crypto.Cipher import AES
from hashlib import sha256
p = 85013941328859365232686230728938372320812319905627686919070637645614632817039920673725615375841158719310596592903101914818137738460649589340349796188816568005092757847
g = 20033344683527080232439150682925185454003164954955126339094967675384779782733210350757021743656898625398860187361281262413493941502725149445995471514781822892886669776
A = 76548721461171533747911417838852759206858825205673491250696441734297318615226024320798706656529038703728631231084155790148283919370554345818139818854112841655270107839
B = 2103083080159597422706551446020625757109756570951674830166998494220734179439318911618156966499109201221652320384817270671579741987575328177442670242481963924501204498
encrypted = "240e7b7678aaaa0dcbe06de7c5598a1ca0be7e2ae584bc7dfd2388cdb1d4fb6a37ceb94556757afc293999cbe5a5a2dbb4071ebf6cfd4332088555f9b2de1922"
encrypted = bytes.fromhex(encrypted)
b = 2891401095038
ss = pow(A, b, p)
key = sha256(long_to_bytes(ss)).digest()[:16]
cipher = AES.new(key, AES.MODE_ECB)
flag = cipher.decrypt(encrypted)
print(flag.decode())
|
Flag: W1{so_you_know_about_the_Diffie-Hellman-key_exchange}
Reverse
5. GiacMoTrua2
Tải file về và phiên dịch mã giả bằng IDA, ta có:

Chương trình yêu cầu ta nhập một chuỗi bí mật và đem chuỗi đó so sánh với flag sau khi qua hàm Lookthis
được mã hóa thành: “W1{live_speels_a5_NoOn_4v4ry_emit!}”

Hàm swap
dùng để đổi hai kí tự cho nhau. Hàm Lookthis
có 3 vòng lặp riêng biệt trên từng khoảng với nhiệm vụ đổi ký tự tương ứng. Như vậy, ta chỉ cần viết script đảo ngược lại và đổi ký tự thì sẽ cho ra được flag
ban đầu:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| def reverse_lookthis(flag):
for k in range(32, 28, -1):
if k < (61 - k):
flag[k], flag[61 - k] = flag[61 - k], flag[k]
for j in range(13, 7, -1):
if j < (21 - j):
flag[j], flag[21 - j] = flag[21 - j], flag[j]
for i in range(6, 2, -1):
if i < (9 - i):
flag[i], flag[9 - i] = flag[9 - i], flag[i]
return flag
fake_flag = [ord(c) for c in "W1{live_speels_a5_NoOn_4v4ry_emit!}"]
real_flag = reverse_lookthis(fake_flag)
flag = "".join(chr(c) for c in real_flag)
print(flag)
|
Flag: W1{evil_sleeps_a5_NoOn_4v4ry_time!}
6. Easy Flag Checker
Tải file và phiên dịch mã giả bằng IDA, có:

Qua hàm main, chương trình yêu cầu ta nhập một chuỗi 20 ký tự, sau đó thực hiện vòng lặp kiểm tra với mỗi ký tự thứ 4*i+32 XOR với 0x38. Sau đó lấy ký tự đó so sánh ngay với dword_4020
thứ i. Chúng ta sẽ truy cập thử vào dword_4020
:

Ở đây, các giá trị trong unk_4020
là các byte đã được mã hóa. Do đó, ta sẽ lấy các giá trị khác 0 để thực hiện phép XOR và nối lại tạo thành flag.
Sau đây là script cho thử thách:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| def reverse_lookthis(flag):
for k in range(32, 28, -1):
if k < (61 - k):
flag[k], flag[61 - k] = flag[61 - k], flag[k]
for j in range(13, 7, -1):
if j < (21 - j):
flag[j], flag[21 - j] = flag[21 - j], flag[j]
for i in range(6, 2, -1):
if i < (9 - i):
flag[i], flag[9 - i] = flag[9 - i], flag[i]
return flag
fake_flag = [ord(c) for c in "W1{live_speels_a5_NoOn_4v4ry_emit!}"]
real_flag = reverse_lookthis(fake_flag)
flag = "".join(chr(c) for c in real_flag)
print(flag)
|
Flag: W1{v3ry_34sy_r1gh7?}
7. GiacMoTrua1
Ta thấy tệp thử thách có định dạng .pyc. Sau khi thử tìm kiếm thì tôi biết được đây là một tệp đầu ra được biên dịch được tạo từ mã nguồn được viết bằng ngôn ngữ lập trình Python. Do đó tôi sử dụng PyLingual – một công cụ online để dịch ngược và khôi phục mã nguồn Python:

Tải file python này về, ta nhận được thử thách như sau:
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
| dic = [0] * 85
dic[0] = 33
dic[1] = 35
dic[2] = 36
dic[3] = 37
dic[4] = 38
dic[5] = 40
dic[6] = 41
dic[7] = 42
dic[8] = 43
dic[9] = 44
dic[10] = 45
dic[11] = 46
dic[12] = 47
dic[13] = 48
dic[14] = 49
dic[15] = 50
dic[16] = 51
dic[17] = 52
dic[18] = 53
dic[19] = 54
dic[20] = 55
dic[21] = 56
dic[22] = 57
dic[23] = 58
dic[24] = 59
dic[25] = 60
dic[26] = 61
dic[27] = 62
dic[28] = 63
dic[29] = 64
dic[30] = 65
dic[31] = 66
dic[32] = 67
dic[33] = 68
dic[34] = 69
dic[35] = 70
dic[36] = 71
dic[37] = 72
dic[38] = 73
dic[39] = 74
dic[40] = 75
dic[41] = 76
dic[42] = 77
dic[43] = 78
dic[44] = 79
dic[45] = 80
dic[46] = 81
dic[47] = 82
dic[48] = 83
dic[49] = 84
dic[50] = 85
dic[51] = 86
dic[52] = 87
dic[53] = 88
dic[54] = 89
dic[55] = 90
dic[56] = 91
dic[57] = 97
dic[58] = 98
dic[59] = 99
dic[60] = 100
dic[61] = 101
dic[62] = 102
dic[63] = 103
dic[64] = 104
dic[65] = 105
dic[66] = 106
dic[67] = 107
dic[68] = 108
dic[69] = 109
dic[70] = 110
dic[71] = 111
dic[72] = 112
dic[73] = 113
dic[74] = 114
dic[75] = 115
dic[76] = 116
dic[77] = 117
dic[78] = 118
dic[79] = 119
dic[80] = 120
dic[81] = 121
dic[82] = 122
dic[83] = 123
dic[84] = 125
flag = input("Let me help you check your flag: ")
length = len(flag)
ans = [0] * length * 2
for i in range(length):
ans[i] = dic[ord(flag[i]) ^ 112]
for i in range(length, length * 2):
ans[i] = ans[i - length]
fin = ""
for i in range((23 * length + 16) % length, (23 * length + 16) % length + length):
fin += chr(ans[i])
if fin == "R8Abq,R&;j%R6;kiiR%hR@k6iy0Ji.[k!8R,kHR*i??":
print("Rightttt!")
print("Heyy you are really lovely, i promise!")
else:
print("Think more....")
|
Phân tích:
Flag được nhập vào và qua một số bước biến đổi trở thành một đoạn mã hóa cho trước là: “R8Abq,R&;j%R6;kiiR%hR@k6iy0Ji.[k!8R,kHR*i??”
Đầu tiên, chúng ta lấy từng giá trị của flag
dạng thập phân ở hệ Unicode để XOR với 112 rồi lấy đó làm chỉ số để tra bảng dic
và gán vào dãy ans
, tiếp theo lấy ans
thêm vào sau để tạo thành 1 dãy có độ dài gấp đôi flag
.
1
2
3
4
| for i in range(length):
ans[i] = dic[ord(flag[i]) ^ 112]
for i in range(length, length * 2):
ans[i] = ans[i - length]
|
Sau đó lập thành dãy fin
mà ta đã biết trước bằng cách lấy i trong khoảng từ (23*length+16) % length
tới (23*length+16) % length + length
và lấy đó làm chỉ số với ans
để chuyển nó về dạng Unicode và thêm vào fin
.
1
2
3
| fin = ""
for i in range((23 * length + 16) % length, (23 * length + 16) % length + length):
fin += chr(ans[i])
|
Giải:
Nhận thấy, fin
có độ dài bằng length và lớn hơn 16 nên:
$23×length+16≡16$ (mod length)
Do đó, ans
sẽ được tính từ chỉ số 16 của fin
tăng dần và quay ngược lên 15.
Sau đó, ta phải đảo ngược bảng giá trị dic
cùng với việc thực hiện phép XOR với 112 để truy ngược lại giá trị ban đầu của flag.
Đây là script cho thử thách:
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
| dic = [0] * 85
dic[0] = 33
dic[1] = 35
dic[2] = 36
dic[3] = 37
dic[4] = 38
dic[5] = 40
dic[6] = 41
dic[7] = 42
dic[8] = 43
dic[9] = 44
dic[10] = 45
dic[11] = 46
dic[12] = 47
dic[13] = 48
dic[14] = 49
dic[15] = 50
dic[16] = 51
dic[17] = 52
dic[18] = 53
dic[19] = 54
dic[20] = 55
dic[21] = 56
dic[22] = 57
dic[23] = 58
dic[24] = 59
dic[25] = 60
dic[26] = 61
dic[27] = 62
dic[28] = 63
dic[29] = 64
dic[30] = 65
dic[31] = 66
dic[32] = 67
dic[33] = 68
dic[34] = 69
dic[35] = 70
dic[36] = 71
dic[37] = 72
dic[38] = 73
dic[39] = 74
dic[40] = 75
dic[41] = 76
dic[42] = 77
dic[43] = 78
dic[44] = 79
dic[45] = 80
dic[46] = 81
dic[47] = 82
dic[48] = 83
dic[49] = 84
dic[50] = 85
dic[51] = 86
dic[52] = 87
dic[53] = 88
dic[54] = 89
dic[55] = 90
dic[56] = 91
dic[57] = 97
dic[58] = 98
dic[59] = 99
dic[60] = 100
dic[61] = 101
dic[62] = 102
dic[63] = 103
dic[64] = 104
dic[65] = 105
dic[66] = 106
dic[67] = 107
dic[68] = 108
dic[69] = 109
dic[70] = 110
dic[71] = 111
dic[72] = 112
dic[73] = 113
dic[74] = 114
dic[75] = 115
dic[76] = 116
dic[77] = 117
dic[78] = 118
dic[79] = 119
dic[80] = 120
dic[81] = 121
dic[82] = 122
dic[83] = 123
dic[84] = 125
fin = "R8Abq,R&;j%R6;kiiR%hR@k6iy0Ji.[k!8R,kHR*i??"
length = len(fin)
ans = [ord(fin[i - 16]) for i in range(length)]
reverse_dic = {v: i for i, v in enumerate(dic)}
flag = "".join(chr(reverse_dic[ans[i]] ^ 112) for i in range(length))
print(flag)
|
Flag: W1{H3pe_y3U_w1ll_enJ9y_th2s_ch311_s0_m3c1!}