HackTheBox-Challenges SPG Writeup
Exploitation 首先題目附給我們 source.py
以及 output.txt
,其中程式的主邏輯如下:
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 randomimport stringfrom base64 import b64encodefrom hashlib import sha256from Crypto.Cipher import AESfrom Crypto.Util.Padding import padfrom secret import FLAG, MASTER_KEYALPHABET = string.ascii_letters + string.digits + "~!@#$%^&*" def generate_password (): master_key = int .from_bytes(MASTER_KEY, "little" ) password = "" while master_key: bit = master_key & 1 if bit: password += random.choice(ALPHABET[: len (ALPHABET) // 2 ]) else : password += random.choice(ALPHABET[len (ALPHABET) // 2 :]) master_key >>= 1 return password def main (): password = generate_password() encryption_key = sha256(MASTER_KEY).digest() cipher = AES.new(encryption_key, AES.MODE_ECB) ciphertext = cipher.encrypt(pad(FLAG, 16 )) with open ("output.txt" , "w" ) as f: f.write( f"Your Password : {password} \nEncrypted Flag : {b64encode(ciphertext).decode()} " ) if __name__ == "__main__" : main()
我們來分析一下上面做了些什麼,首先他有一個 generate_password()
的函式把引入的 MASTER_KEY 來生成一組密碼。他先把 MASTER_KEY 用 little_endian 的格式轉成整數,接著從最低位開始若 bit 為 1 則從自定義的字母表前半部分挑一個字符加入 password,反之,若 bit 為 0 就從後半部挑一個字符,然後往高位移動一個重複前面的操作。再來 main 使用 MASTER_KEY 通過 SHA-256 雜湊算法生成加密金鑰 encryption_key,sha256(MASTER_KEY).digest()
會產生一個 256 位的摘要,這會用於之後 AES 加密的密鑰。 接著我們會使用生成的 encryption_key 初始化 AES 加密器,並選擇 ECB 模式。然後把 flag padding 到 16 位確保 AES 可以正常運作,然後執行加密後輸出 password 跟 flag。
那分析完後首先我們會想先想辦法得到 master_key,那根據他字母表的建立方式我們可以知道前半跟後半分別是:abcdefghijklmnopqrstuvwxyzABCDEFGHI
,JKLMNOPQRSTUVWXYZ0123456789~!@#$%^&*
,所以我們可以透過 password 的每一位在前半或是後半知道 master_key 的每一個 bit 是 0 還是 1 如此就可以得到 master_key,接著就是正常的 AES 操作。
Exploit 最後按照剛剛的邏輯把腳本實現如下:
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 import stringfrom base64 import b64decodefrom hashlib import sha256from Crypto.Cipher import AESfrom Crypto.Util.number import long_to_bytesfrom Crypto.Util.Padding import unpadalph = string.ascii_letters + string.digits + "~!@#$%^&*" first_half, second_half = set (alph[:len (alph) // 2 ]), set (alph[len (alph) // 2 :]) def load_data (): with open ("output.txt" ) as f: password = f.readline().split(" : " )[1 ].strip() enc_flag = b64decode(f.readline().split(" : " )[1 ].strip()) return password, enc_flag def recover_master_key (password ): bits = ['1' if p in first_half else '0' for p in password] return int ('' .join(bits[::-1 ]), 2 ) def decrypt_flag (master_key, enc_flag ): encryption_key = sha256(long_to_bytes(master_key)[::-1 ]).digest() cipher = AES.new(encryption_key, AES.MODE_ECB) return unpad(cipher.decrypt(enc_flag), 16 ).decode() def pwn (): password, enc_flag = load_data() master_key = recover_master_key(password) flag = decrypt_flag(master_key, enc_flag) print (f"Decrypted FLAG: {flag} " ) pwn()
1 2 ╰─ python solve.py ─╯ Decrypted FLAG: HTB{m4ll34bl3_p4ssw0rd_g3n3r4t0r!}
Pwned !!!
References