From 9ae53e12fd60d4ab876763ce95f192c40f4fe37d Mon Sep 17 00:00:00 2001 From: 0xalivecow Date: Wed, 6 Nov 2024 23:38:54 +0100 Subject: [PATCH] feat: Initial padding oracle working. Pending check for special case. The initial padding oracle attack is working. More tests need to be added and there needs to be a check for the special case of the 02 01, 02 02 padding case --- src/tasks/mod.rs | 7 ++ src/tasks/tasks01/mod.rs | 1 + src/tasks/tasks01/pad_oracle.rs | 136 ++++++++++++++++++++++++++++++++ src/utils/mod.rs | 1 + src/utils/net.rs | 1 + test_json/padding_oracle.json | 13 +++ 6 files changed, 159 insertions(+) create mode 100644 src/tasks/tasks01/pad_oracle.rs create mode 100644 src/utils/net.rs create mode 100644 test_json/padding_oracle.json diff --git a/src/tasks/mod.rs b/src/tasks/mod.rs index 6c003b2..0fa72d6 100644 --- a/src/tasks/mod.rs +++ b/src/tasks/mod.rs @@ -10,6 +10,7 @@ use tasks01::{ block2poly::block2poly, gcm::{gcm_decrypt, gcm_encrypt}, gfmul::gfmul_task, + pad_oracle::padding_oracle, poly2block::poly2block, sea128::sea128, xex::{self, fde_xex}, @@ -75,7 +76,13 @@ pub fn task_deploy(testcase: &Testcase) -> Result { Ok(json) } + "padding_oracle" => { + let plaintext = padding_oracle(args)?; + let out_plain = BASE64_STANDARD.encode(&plaintext); + let json = json!({"plaintext" : out_plain}); + Ok(json) + } _ => Err(anyhow!( "Fatal. No compatible action found. Json data was {:?}. Arguments were; {:?}", testcase, diff --git a/src/tasks/tasks01/mod.rs b/src/tasks/tasks01/mod.rs index d1f3e99..479fe47 100644 --- a/src/tasks/tasks01/mod.rs +++ b/src/tasks/tasks01/mod.rs @@ -1,6 +1,7 @@ pub mod block2poly; pub mod gcm; pub mod gfmul; +pub mod pad_oracle; pub mod poly2block; pub mod sea128; pub mod xex; diff --git a/src/tasks/tasks01/pad_oracle.rs b/src/tasks/tasks01/pad_oracle.rs new file mode 100644 index 0000000..31b739c --- /dev/null +++ b/src/tasks/tasks01/pad_oracle.rs @@ -0,0 +1,136 @@ +use anyhow::Result; +use base64::prelude::*; +use serde_json::Value; +use std::io::prelude::*; +use std::net::TcpStream; +use std::time::Duration; +use std::{thread, usize}; + +pub fn padding_oracle(args: &Value) -> Result> { + let hostname: String = serde_json::from_value(args["hostname"].clone())?; + + let port_val: Value = serde_json::from_value(args["port"].clone())?; + let port: u64 = port_val.as_u64().expect("Failure in parsing port number"); + + let iv_string: String = serde_json::from_value(args["iv"].clone())?; + let iv: Vec = BASE64_STANDARD.decode(iv_string)?; + + let cipher_text: String = serde_json::from_value(args["ciphertext"].clone())?; + let ciphertext: Vec = BASE64_STANDARD.decode(cipher_text)?; + + // Initialise tracker to adapt correct byte + let byte_counter = 15; + eprintln!("byte_counter is: {}", byte_counter); + + let mut plaintext: Vec = vec![]; + eprintln!("Ciphertext: {:002X?}", ciphertext); + + let cipher_chunks: Vec<&[u8]> = ciphertext.chunks(16).rev().collect(); + let mut chunk_counter = 0; + + for chunk in &cipher_chunks { + let mut stream = TcpStream::connect(format!("{}:{}", hostname, port))?; + stream.set_nonblocking(false)?; + + // Track value sent to server + let mut attack_counter: Vec = vec![0; 16]; + + // Amount of q blocks to send to server. + // TODO:: May be increased via function + let q_block_count: u16 = 255; + + //Send the first ciphertext chunk + eprintln!("Sending Ciphertext chunk: {:002X?}", chunk); + stream.flush()?; + stream.write_all(&chunk)?; + stream.flush()?; + + for i in (0..=15).rev() { + // Craft length message + // FIXME: Assignment is redundant for now + // TODO: Goal is to maybe add speed increase in the future + let l_msg: [u8; 2] = q_block_count.to_le_bytes(); + //eprintln!("Sending l_msg: {:02X?}", l_msg); + stream.write_all(&l_msg)?; + stream.flush()?; + //eprintln!("L_msg sent"); + + // Generate attack blocks + for j in 0..q_block_count { + // Next byte + //eprintln!("Sending attack block: {:02X?}", attack_counter); + + //thread::sleep(Duration::from_millis(1000)); + stream.write_all(&attack_counter)?; + stream.flush()?; + attack_counter[i as usize] += 1; + } + + // Read server response + let mut buf = [0u8; 0xFF]; + stream.read_exact(&mut buf)?; + //eprintln!("{:02X?}", buf); + + // extract valid position + let valid_val = buf.iter().position(|&r| r == 0x01).expect("No valid found") as u8; + //eprintln!("Valid value found: {:02X?}", valid_val); + + // Craft next attack vector padding; 0x01, 0x02, ... + attack_counter[i as usize] = valid_val; + + if chunk_counter + 1 < cipher_chunks.len() { + eprintln!("XOR Next Ciph block"); + plaintext.push( + cipher_chunks[chunk_counter + 1][i] + ^ (attack_counter[i as usize] ^ (15 - i as u8 + 1)), + ); + } else { + eprintln!("XOR IV"); + + plaintext.push(iv[i] ^ (attack_counter[i as usize] ^ (15 - i as u8 + 1))); + } + //eprintln!("Attack counter after set: {:02X?}", attack_counter); + for pos in i..=15 { + //eprintln!("i is: {:02X?}", i); + //eprintln!("i + 1 is: {:02X?}", ((16 - i) as u8).to_le()); + /* + eprintln!( + "attack_counter[pos as usize]: {:02X?}", + attack_counter[pos as usize] + ); + eprintln!( + "attack_counter[pos as usize] ^ 0x02 {:02X?}", + attack_counter[pos as usize] ^ (15 - i as u8 + 1) + ); + */ + let intermediate = attack_counter[pos as usize] ^ (15 - i as u8 + 1); + + attack_counter[pos as usize] = intermediate ^ ((15 - i as u8 + 1) + 1); + } + stream.flush()?; + + // Write plaintext + //eprintln!("{:02X?}", plaintext); + } + chunk_counter += 1; + stream.flush()?; + // break; + drop(stream); + } + + plaintext.reverse(); + + eprintln!("{:02X?}", BASE64_STANDARD.encode(&plaintext)); + Ok(plaintext) +} // the stream is closed here + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn test_connection() -> Result<()> { + Ok(()) + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 2f12ed4..298415b 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,5 +1,6 @@ pub mod ciphers; pub mod field; pub mod math; +pub mod net; pub mod parse; pub mod poly; diff --git a/src/utils/net.rs b/src/utils/net.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/utils/net.rs @@ -0,0 +1 @@ + diff --git a/test_json/padding_oracle.json b/test_json/padding_oracle.json new file mode 100644 index 0000000..c837963 --- /dev/null +++ b/test_json/padding_oracle.json @@ -0,0 +1,13 @@ +{ + "testcases": { + "254eaee7-05fd-4e0d-8292-9b658a852245": { + "action": "padding_oracle", + "arguments": { + "hostname": "localhost", + "port": 1337, + "iv": "AAAAAAAAAAAAAAAAAAAAAA==", + "ciphertext": "QENCRURHRklIS0pNTE9OUQAAAAAAAAAASUlJSUlJSUk=" + } + } + } +}