
취약한 코드와 멀티스레드 트리거를 통해 메모리 손상 및 코드 실행 가능성을 보여주는 웹 서버의 Rust use-after-free 취약점을 시연합니다.
// uaf_server.rs - Vulnerable Rust HTTP server with use-after-free
use std::sync::{Arc, Mutex};
use std::thread;
use std::io::prelude::*;
use std::net::{TcpListener, TcpStream};
struct SharedBuffer {
data: Vec<u8>,
}
impl SharedBuffer {
fn new() -> Self { SharedBuffer { data: vec![0; 1024] } }
}
fn handle_client(mut stream: TcpStream, buffer: Arc<Mutex<SharedBuffer>>) {
// Simulate reading request and writing response.
let mut buf = [0; 512];
stream.read(&mut buf).unwrap();
let b = buffer.lock().unwrap();
let ptr = b.data.as_ptr() as *mut u8; // raw pointer
// Drop the lock early? In unsafe block we might send the pointer to another thread.
// Here we simulate a bug: the SharedBuffer is dropped, but we later use the pointer.
drop(b);
// After lock is released, another thread could replace the Vec, freeing the old allocation.
// Unsafe write through the dangling pointer.
unsafe {
*ptr = 42; // use after free!
}
stream.write(b"HTTP/1.1 200 OK\r\n\r\nHello").unwrap();
}
fn main() {
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
let buffer = Arc::new(Mutex::new(SharedBuffer::new()));
for stream in listener.incoming() {
let stream = stream.unwrap();
let buf_clone = Arc::clone(&buffer);
thread::spawn(move || {
handle_client(stream, buf_clone);
});
}
}
Rust 웹 서버는 스레드 간에 버퍼를 공유하기 위해 unsafe 코드를 사용합니다. 경쟁 조건(race condition)으로 인해 use‑after‑free가 발생하여 메모리 손상이나 정보 노출로 이어질 수 있습니다.
Vec에서 원시 포인터를 가져온 후 잠금을 해제하고, 다른 스레드가 벡터를 교체하여 포인터가 여전히 사용되는 동안 메모리를 해제합니다.rustc uaf_server.rs
./uaf_server
python trigger_uaf.py