From 7b347366189c47a03a298fc782f4e3de2b2c5c42 Mon Sep 17 00:00:00 2001 From: sangge <2251250136@qq.com> Date: Wed, 15 Oct 2025 16:29:24 +0800 Subject: [PATCH] feat: finish p32 --- Cargo.lock | 14 ++++ problems/p32/Cargo.toml | 14 ++++ problems/p32/src/main.rs | 143 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 problems/p32/Cargo.toml create mode 100644 problems/p32/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index b85fbaa..c9ae358 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1052,6 +1052,20 @@ dependencies = [ "tokio", ] +[[package]] +name = "p32" +version = "0.1.0" +dependencies = [ + "anyhow", + "axum", + "common", + "hex", + "rand", + "reqwest", + "serde", + "tokio", +] + [[package]] name = "p33" version = "0.1.0" diff --git a/problems/p32/Cargo.toml b/problems/p32/Cargo.toml new file mode 100644 index 0000000..84839c1 --- /dev/null +++ b/problems/p32/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "p32" +version = "0.1.0" +edition = "2024" + +[dependencies] +reqwest = { workspace = true } +tokio = { workspace = true } +axum = { workspace = true } +serde = { workspace = true } +common = { path = "../../common/" } +hex = { workspace = true } +rand = { workspace = true } +anyhow = { workspace = true } diff --git a/problems/p32/src/main.rs b/problems/p32/src/main.rs new file mode 100644 index 0000000..61cdf23 --- /dev/null +++ b/problems/p32/src/main.rs @@ -0,0 +1,143 @@ +use std::time::{Duration, Instant}; + +use common::sha1; + +use anyhow::Result; +use axum::{Router, extract::Query, http::StatusCode, routing::get}; +use rand::Rng; +use serde::Deserialize; +use std::sync::LazyLock; +use tokio::time::sleep; + +static HMAC_KEY: LazyLock<[u8; 20]> = LazyLock::new(|| { + // 生成随机密钥 + let mut rng = rand::rng(); + let key: [u8; 20] = rng.random(); + key +}); + +#[derive(Deserialize)] +struct Params { + file: String, + signature: String, +} + +async fn verify_handler(Query(params): Query) -> StatusCode { + let my_signature = hmac_sha1(&*HMAC_KEY, params.file.as_bytes()); + + let provided_signature = match hex::decode(¶ms.signature) { + Ok(bytes) => bytes, + Err(e) => { + eprintln!("Hex decode error: {:?}", e); + return StatusCode::BAD_REQUEST; + } + }; + + match insecure_compare(&my_signature, &provided_signature).await { + true => StatusCode::OK, + false => StatusCode::INTERNAL_SERVER_ERROR, + } +} + +async fn insecure_compare(a: &[u8], b: &[u8]) -> bool { + if a.len() != b.len() { + return false; + } + for i in 0..a.len() { + if a[i] != b[i] { + return false; + } + sleep(Duration::from_millis(5)).await; + } + true +} + +fn hmac_sha1(key: &[u8], message: &[u8]) -> [u8; 20] { + let mut key = match key.len() { + 0..=64 => key.to_vec(), + _ => sha1(key).to_vec(), + }; + key.extend(vec![0; 64 - key.len()]); + let mut part_1 = key.iter().map(|x| x ^ 0x5c).collect::>(); + let mut part_2_input = key.iter().map(|x| x ^ 0x36).collect::>(); + part_2_input.extend(message); + let part_2 = sha1(&part_2_input); + part_1.extend(part_2); + sha1(&part_1) +} +#[test] +fn test_hmac_sha1() { + let output = hmac_sha1("123".as_bytes(), "helloworld".as_bytes()); + let output = hex::encode(output); + let correct = "8849fb5557760d35f19e2100aa250bfb97152bd9"; + assert_eq!(output, correct); +} + +async fn start_attack() -> Result<()> { + let mut signature = vec![0u8; 20]; + let mut pos = 0; + let mut last_max_time = Duration::from_millis(0); + let min_time_increase = Duration::from_millis(1); // 最小耗时增量阈值 + + while pos < 20 { + let mut max_time = Duration::from_millis(0); + let mut best_byte = 0u8; + + for byte in 0x00..=0xff { + signature[pos] = byte; + let url = format!( + "http://localhost:3000/verify?file={}&signature={}", + "helloworld", + hex::encode(&signature) + ); + let start = Instant::now(); + let status = reqwest::get(&url).await?.status(); + let elapsed = start.elapsed(); + + if status == StatusCode::OK { + println!("✓ 找到完整签名: {}", hex::encode(&signature)); + return Ok(()); + } + + if elapsed > max_time { + max_time = elapsed; + best_byte = byte; + } + } + + signature[pos] = best_byte; + println!( + "位置 {} 确定为: {:02x}, 耗时: {:?}", + pos, best_byte, max_time + ); + + // 检查耗时是否有足够增长 + if pos > 0 && max_time.saturating_sub(last_max_time) < min_time_increase { + println!("⚠ 耗时增长不足,回退1位重试",); + pos = pos.saturating_sub(1); + last_max_time = Duration::from_millis(0); // 重置基准 + continue; + } + + last_max_time = max_time; + pos += 1; + } + Ok(()) +} + +#[tokio::main] +async fn main() -> Result<()> { + let app = Router::new().route("/verify", get(verify_handler)); + + let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?; + + dbg!(hex::encode(*HMAC_KEY)); + + // 后台启动服务器 + tokio::spawn(async move { + axum::serve(listener, app).await.unwrap(); + }); + start_attack().await?; + Ok(()) +} +