diff options
author | metamuffin <metamuffin@disroot.org> | 2022-09-26 17:33:56 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2022-09-26 17:33:56 +0200 |
commit | ce7538d74742d0ed92829906853bc6a3607c8b79 (patch) | |
tree | 4676cd0310a71d8d958eb242eb97b6ae2a42fe8b | |
parent | 5316b954323a4d7bee492a3997bae35dd107e44a (diff) | |
download | metamuffin-blog-ce7538d74742d0ed92829906853bc6a3607c8b79.tar metamuffin-blog-ce7538d74742d0ed92829906853bc6a3607c8b79.tar.bz2 metamuffin-blog-ce7538d74742d0ed92829906853bc6a3607c8b79.tar.zst |
improve readability some more
-rw-r--r-- | content/articles/2022-09-25-ductf-file-magic.md | 41 |
1 files changed, 24 insertions, 17 deletions
diff --git a/content/articles/2022-09-25-ductf-file-magic.md b/content/articles/2022-09-25-ductf-file-magic.md index 267a707..b0bc560 100644 --- a/content/articles/2022-09-25-ductf-file-magic.md +++ b/content/articles/2022-09-25-ductf-file-magic.md @@ -1,10 +1,12 @@ # DownUnderCTF 2022: File Magic -A short writeup about my favorite challenge from DUCTF. +A short writeup about my favorite challenge from DUCTF. It took me approximatly +0.5 days to solve. I found it was the most creative and challenging one that i +solved. ## Task -The challenge consists of a python script and an ip-port-pair which appears to +The challenge consists of a python script and an ip-port pair which appears to be running that script. Also the path of the flag is given: `./flag.txt` ```py @@ -50,10 +52,13 @@ So for a anything to make it past these check and be executed it must: 1. be a valid 13x37 JPEG image with the pixel at 7,7 set to #070707 2. be a valid ELF binary that reads `./flag.txt` after decrypting with AES CBC, - fixed key and the provided IV + fixed key (`downunderctf2022`) and the provided IV 3. The IV must contain `DUCTF` -## 1. AES CBC +During the competition I discovered the information the next three headings in +parallel but internally in-order. + +## 1. AES CBC "flaw" We need to generate a file that is a sort-of polyglot with JPEG and ELF, converted with AES CBC. @@ -74,13 +79,12 @@ IV--->XOR ,---------->XOR ,--------->XOR ,---- ... ___ciphertext___|___ciphertext___|___ciphertext___|... ``` -For decryption we can just flip the diagram and replace AES with reverse AES -(`AES'`). +For decryption we can just flip the diagram and replace AES with reverse AES. ``` ___ciphertext___|___ciphertext___|___ciphertext___|... v---, v---, v---, - AES | AES | AES | + ∀EZ | ∀EZ | ∀EZ | v | v | v | IV--->XOR '---------->XOR '--------->XOR '---- ... v v v @@ -101,7 +105,7 @@ AES^{-1}(c) = m \oplus IV \\ AES^{-1}(c) \oplus m = IV $$ -All blocks after the first are now "uncontrollable" as ciphertext because IV and +All blocks in ciphertext after the first are now "uncontrollable" because IV and plaintext are set. ## 2. JPEG @@ -120,7 +124,7 @@ The comment segment is perfect for embedding our ELF binary into JPEG. We can first generate a JPEG image, then insert a _comment_ somewhere containing any data we want. -## 3. ELF +## 3. ELF Payload The binary needs to be super small so creating it "manually" was required. I followed a the guide @@ -156,7 +160,8 @@ I was able to produce a 207 byte long executable. ## 4. _magic!_ Here is how we align the files now (single quotes `'` indicate ASCII -representation for clarity): +representation for clarity, question marks `?` represent data that is implicitly +defined): ``` ciphertext: 7f 'E 'L 'F 02 01 01 00 00 00 00 00 00 00 00 00 @@ -164,17 +169,18 @@ iv: ?? ?? ?? ?? ?? ?? 'D 'U 'C 'T 'F 00 00 00 00 00 plaintext: ff d8 ff fe {len} ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ``` -This scenario is a little more complicated because in places we define cipertext -and plaintext and in some we define ciphertext and IV. This is not a problem -though, because XOR operates on every byte individually. +This scenario is a little more complicated because in some places we define +cipertext and plaintext and in some we define ciphertext and IV. This is not a +problem though, because XOR operates on every byte individually. -All-in-all the file looks like this now: +All-in-all, the file looks like this now: -- First block +- First block: - overlapping headers (6 bytes) - `DUCTF` string (5 bytes) - padding (5 bytes) - Rest of the ELF binary +- _end of the jpeg comment_ - Rest of the JPEG image All this information should be enough to solve this challenge. @@ -203,6 +209,7 @@ while payload.len() % 16 != 0 { assert!(payload.len() % 16 == 0); let prefix_len = 6; +// write the JPEG headers to start a comment buf.put_u16(0xffd8); buf.put_u16(0xfffe); buf.put_u16(payload.len() as u16 + 2 /*seg len*/ - prefix_len as u16); @@ -231,8 +238,8 @@ for i in 1..buf.len() / 16 { key.encrypt_block(GenericArray::from_mut_slice(&mut buf[block_range(1)])); } -// append the rest of the image -buf.put(&imgbuf.into_inner()[2..]); // skip "header" (first segment) +// append the rest of the image, stripping the first segment +buf.put(&imgbuf.into_inner()[2..]); // pad the final buffer again because the image might not be aligned while buf.len() % 16 != 0 { |