Filer: Download challenge files

Writeup: Disk Encryption

Indledende Observationer

Jeg fik udleveret:

  • server.py

  • passwd.txt

Serveren:

  • Krypterede passwd.txt i memory med AES-XTS

  • Brugte nøgle = SHA512(flag) (64 bytes = to AES-256 nøgler)

  • Gav adgang til en ECB encryption oracle i debug-mode

  • Tillod restore af én vilkårlig ciphertext-blok

  • Printede flaget hvis en ikke-root bruger fik uid=0 og gid=0

Der var kun én integritetskontrol:

Usernames måtte ikke ændres.


Recon / Kortlægning

I server.py så jeg:

  • Hver 16-byte blok blev krypteret med XTS:

    1
    2
    
    T = E_k2(tweak)
    C = E_k1(P xor T) xor T
    
  • tweak = block_index.to_bytes(16, 'little')

Debug-funktionen gjorde:

1
2
print(cipher1.encrypt(pt1))  # under k1
print(cipher2.encrypt(pt2))  # under k2

Det betød, at jeg havde:

  • Oracle for E_k1(·)

  • Oracle for E_k2(·)

Restore-funktionen:

1
number contents

overskrev én ciphertext-blok i memory.


Noter:

  • AES-XTS brugt per 16-byte blok

  • Tweak = blokindeks (little-endian)

  • Debug gav ECB-oracle for både k1 og k2

  • Restore tillod overwrite af én ciphertext-blok

  • Flag printes hvis non-root bruger får uid=0,gid=0


Analyse

AES-XTS for én blok kan skrives som:

1
2
T = E_k2(tweak)
C = E_k1(P xor T) xor T

Hvis man har følgende:

  • E_k1(·) oracle

  • E_k2(·) oracle

kan man forge en gyldig ciphertext for vilkårligt plaintext.

Der var ingen MAC.
Der var ingen integritetsbeskyttelse.
Kun username-check.

Det betød at jeg kunne ændre UID/GID uden at ændre username.


Angrebet

1. Valg af target

I passwd.txt fandt jeg:

1
daemon:x:1:1:...

Jeg ændrede den til:

1
daemon:x:0:0:...

Det ændrede kun to bytes (1 -> 0) og holdt længden identisk.

Begge cifre lå i samme 16-byte blok.

Blok-index = 2.


2. Hent tweak-værdi

Tweak for blok 2:

1
02000000000000000000000000000000

Jeg sendte:

1
00000000000000000000000000000000 02000000000000000000000000000000

Serveren svarede:

1
2
59ef1f82d2959c119b42db7701b36052
f9e988b0b59a0541d57abe2cbf88340a

Anden linje var:

1
2
T = E_k2(tweak)
  = f9e988b0b59a0541d57abe2cbf88340a

3. Forge ønsket plaintext-blok

Ønsket plaintext-blok:

1
P' = b"daemon:x:0:0:dae"

Jeg beregnede:

1
2
X = P' xor T
  = 9d88eddddaf43f39ef4a841c85ec556f

Jeg sendte:

1
9d88eddddaf43f39ef4a841c85ec556f 02000000000000000000000000000000

Serveren svarede:

1
2
5e974a9a0cb78ba0d264927a9193840d
f9e988b0b59a0541d57abe2cbf88340a

Første linje var:

1
2
Y = E_k1(X)
  = 5e974a9a0cb78ba0d264927a9193840d

4. Konstruér forged ciphertext

1
2
C' = Y xor T
   = a77ec22ab92d8ee1071e2c562e1bb007

5. Restore blok 2

Jeg sendte:

1
2 a77ec22ab92d8ee1071e2c562e1bb007

Serveren dekrypterede filen igen.

Nu havde daemon:

1
2
uid = 0
gid = 0

Username var uændret.

Checken bestod.

Flaget blev printet.


Flaget

1
DDC{d1sk_3ncrypt10n_1s_w31rd}

Hvorfor det virkede

XTS beskytter kun mod mønstergenkendelse.
Det giver ingen autentificering.

Hvis man får adgang til:

  • E_k1 oracle

  • E_k2 oracle

kan man rekonstruere gyldige ciphertext-blokke.

Det reducerer XTS til en tweakbar ECB-konstruktion uden MAC.


Konklusion

Serveren brugte AES-XTS korrekt til disk-kryptering,
men kombinationen af:

  • ECB debug oracle

  • Restore-funktion

  • Manglende MAC

gjorde det muligt at forge ciphertext-blokke.

Jeg udnyttede dette til at ændre UID/GID på en systembruger
og opnåede dermed flaget:

1
DDC{d1sk_3ncrypt10n_1s_w31rd}