Deadline: 21.11.2022, ora 23:59
12.11.2022 - Am adăugat cerința și scheletul pentru exercițiul 2.
Capture-the-flag: Doriți să capturați flagul unui server care este protejat sub un cont administrativ. Va trebui să obțineți un tag valid de administrator. Serverul ne oferă și un cont de guest care însă nu are access la acest flag. Din fericire, ați reușit să extrageți codul sursă de pe server, dar se pare că nu conține flagul secret.
(secret)
}”
Acest exercițiu vă va testa capacitatea de a înțelege construcții criptografice, analizând codul sursă și folosirea de criptanaliză pentru a demonstra că un cipher este nesigur. În final, va fi nevoie să construiți un proof-of-concept care demonstrează un atac eficient, executând atacul împotriva unui server.
Recomandare de rezolvare:
Codul sursă care rulează și pe server:
#!/usr/bin/python3 from Crypto import Random from Crypto.Cipher import AES import base64 as b64 from secretz import * options_txt = """Options: 1. Get guest token 2. Login 3. Exit Input:""" welcome_txt = """Welcome to SRY, most confidential platform with top-notch integrity. To get public data login as guest.""" GUEST_NAME = b"Anonymous" AES_KEY_SIZE = 16 def byte_xor(txt, rnd): return bytes(a ^ b for a, b in zip(txt, rnd)) class Crypt: def __init__(self): KEY = Random.get_random_bytes(AES_KEY_SIZE) self.IV = Random.get_random_bytes(AES_KEY_SIZE) self.C = AES.new(KEY, AES.MODE_ECB) self.INTEGRITY = AES.new(KEY, AES.MODE_ECB) def getIntegrity(self, plain): return self.INTEGRITY.encrypt(b'\x00' * (AES_KEY_SIZE - len(plain)) + plain)[0:INTEGRITY_LEN] def encrypt(self, plain): rnd = self.C.encrypt(self.IV) cipher = byte_xor(plain, rnd) + SERVER_PUBLIC_BANNER + self.getIntegrity(plain) return cipher def decrypt(self, input): rnd = self.C.encrypt(self.IV) secret_len = INTEGRITY_LEN + len(SERVER_PUBLIC_BANNER) cipher, secret, tag = input[:-secret_len], input[-secret_len:-INTEGRITY_LEN], input[-INTEGRITY_LEN:] plain = byte_xor(cipher, rnd) if secret != SERVER_PUBLIC_BANNER: return -1 if self.getIntegrity(plain) != tag: return None return plain def get_guest_token(): global C token = C.encrypt(GUEST_NAME) print(b64.b64encode(token).decode('raw_unicode_escape')) def login(): global C try: s = input("Token:") # Python3. Don't get funny RCE ideas cipher = b64.b64decode(s) if(len(cipher) > 16): print("Tokens must be smaller than 16 bytes!") plain = C.decrypt(cipher) if plain == -1: print("Wrong server secret!") elif plain == None: print("Failed integrity check!") elif plain == GUEST_NAME: print("Secret:", "No secrets for anonymous") elif plain == b"Ephvuln": print("Secret:", FLAG) else: print("I don't have an answer for", plain.decode('utf-8')) except: print("No h3k1ng allowed") exit() def invalid(): print("! Invalid option.") def menu(): global C C = Crypt() print(welcome_txt) while True: print(options_txt, end='') switch = { "1": get_guest_token, "2": login, "3": exit } func = switch.get(input(), invalid) func() print() if __name__ == "__main__": menu()
Serverul se găsește la adresa: 141.85.224.117:1337
nc 141.85.224.117 1337
Pentru interacțiunea automată cu serverul, aveți la dispoziție următorul schelet de cod, care necesită pachetul pwntools. Pentru instalare:
pip3 install pwntools
from pwn import * import base64 as b64 from time import sleep def byte_xor(ba1, ba2): return bytes([_a ^ _b for _a, _b in zip(ba1, ba2)]) LOCAL = True # Local means that you run binary directly if LOCAL: # Complete this if you want to test locally r = process("<PATH_TO_PYTHON_CHALLENGE>") else: r = remote("141.85.224.117", 1337) # Complete this if changed def read_options(): """Reads server options menu.""" r.readuntil(b"Input:") def get_token(): """Gets anonymous token as bytearray.""" read_options() r.sendline(b"1") token = r.readline()[:-1] return b64.b64decode(token) def login(tag): """Expects bytearray. Sends base64 tag.""" r.readline() read_options() r.sendline(b"2") # sleep(0.01) # Uncoment this if server rate-limits you too hard r.sendline(b64.b64encode(tag)) r.readuntil(b"Token:") response = r.readline().strip() return response # TODO: Solve challenge # .. # .. # .. # .. # response = login(payload).decode('utf-8') # if "CTF" in response: # print("[*] Found flag:",response) # r.close()
Descrierea task-ului se poate găsi în fișierul tema2022_ex2.pdf, iar scheletul de la acest exercițiu este diponibil în skel2022_ex2.zip.
Rezolvarea trebuie trimisă într-o arhivă pe Moodle [1] care să conțină câte un folder pentru fiecare task în care să aveți un script care rulează tema și un fișier README în care descrieți pe scurt abordarea voastra. Puteți avea și fișiere adiționale pe lângă script-ul principal, dar trebuie să scrieți în README cum trebuie rulată soluția.