Share this post on:

作为pwn,确实是很基础的堆题,就是用rust写的有点恶心人。。。

分析

F5随便搜一搜,可以发现有后门函数,对后门函数分析后(才学rust两天,很多都不知道全靠猜。。。),存在UAF可以利用

image-20230504102859099

运行程序发现是标准菜单题,注意到这儿可以show(泄露地址),edit(改fd/bk)

image-20230504103350102

而且这个题是libc2.27,思路就很简单了,放一个unsortedbin的chunk,通过UAF泄露mainarena拿到libcbase,然后edit可以改fd为free_hook(因为这儿有delete)为system,然后写binsh(本来想改成onegadget的,但为什么就是打不通???)

其他的点

  • 由于是rust写的,所以ida打开几乎不能看,但是这个题可能出于人道主义给了符号表,可以在动调调试的时候结合f5的结果来重新整理一下程序

源码

赛后wp出题人还很贴心的给出了源码

官方wp:https://xz.aliyun.com/t/12485#toc-28

use anyhow::Result;
use std::io::{self, Read, Write};
use std::vec::Vec;
use nix::unistd::alarm;

const MAX_HOUSE: usize = 8;

struct HouseTbl {
    houses: [Option<Vec<u8>>; MAX_HOUSE],
}

fn show_menu() -> Result<()> {
    println!("1. add a house");
    println!("2. show a house");
    println!("3. edit a house");
    println!("4. delete a house");
    println!("5. exit");
    print!(">>> ");
    io::stdout().flush()?;
    Ok(())
}

fn add(tbl: &mut HouseTbl) -> Result<()> {
    let mut i = 0;
    for x in tbl.houses.iter() {
        if !x.is_none() {
            i += 1;
        } else {
            break;
        }
    }

    if i == MAX_HOUSE {
        println!("full!");
        return Ok(());
    }

    println!("idx is {}", i);
    print!("now the size: ");
    io::stdout().flush()?;

    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer)?;
    let size = buffer.trim().parse::<usize>()?;
    if size >= 0x200 {
        println!("too large");
        return Ok(());
    }
    let mut content: Vec<u8> = vec![0xcc as u8; size];
    // let mut content: Vec<u8> = Vec::with_capacity(size);
    print!("next the content: ");
    io::stdout().flush()?;

    io::stdin().read_exact(&mut content)?;

    tbl.houses[i] = Some(content);

    Ok(())
}

fn show(tbl: &mut HouseTbl) -> Result<()> {
    print!("house index: ");
    io::stdout().flush()?;
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer)?;
    let index = buffer.trim().parse::<usize>()?;

    if index >= MAX_HOUSE {
        println!("invalid!");
        return Ok(());
    }

    match tbl.houses[index].as_ref() {
        Some(house) => io::stdout().write_all(house)?,
        None => println!("no house"),
    }
    Ok(())
}

fn edit(tbl: &mut HouseTbl) -> Result<()> {
    print!("house index: ");
    io::stdout().flush()?;
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer)?;
    let index = buffer.trim().parse::<usize>()?;

    if index >= MAX_HOUSE {
        println!("invalid!");
        return Ok(());
    }

    match tbl.houses[index].as_mut() {
        Some(house) => {
            print!("content(size {}): ", house.len());
            io::stdout().flush()?;
            io::stdin().read_exact(house)?;
        }
        None => println!("no house"),
    }

    Ok(())
}

fn backdoor(tbl: &mut HouseTbl, i: i32)  {
    let idx = i - 1953723762;
    if  idx < MAX_HOUSE as i32 && idx >= 0 {
        if let Some(house) = tbl.houses[idx as usize].as_mut() {
            unsafe {
                let _ = Vec::from_raw_parts(house.as_mut_ptr(), house.len(), house.capacity());
            }
        }
    }
}

fn delete(tbl: &mut HouseTbl) -> Result<()> {
    print!("house index: ");
    io::stdout().flush()?;
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer)?;
    let index = buffer.trim().parse::<usize>()?;

    backdoor(tbl, index as i32);

    if index >= MAX_HOUSE {
        println!("invalid!");
        return Ok(());
    }

    match tbl.houses[index].take() {
        Some(_) => println!("success"),
        None => println!("no house"),
    }

    Ok(())
}

fn main_process() -> Result<()> {
    let mut tbl = HouseTbl {
        houses: Default::default(),
    };
    loop {
        show_menu()?;
        let mut choose = String::new();
        io::stdin().read_line(&mut choose)?;
        let choose_number = choose.trim().parse::<u8>();
        _ = match choose_number {
            Ok(1) => add(&mut tbl),
            Ok(2) => show(&mut tbl),
            Ok(3) => edit(&mut tbl),
            Ok(4) => delete(&mut tbl),
            Ok(5) => break,
            _ => {
                println!("invalid!");
                Ok(())
            }
        };
    }
    println!("Bye~");
    Ok(())
}

fn main() {
    alarm::set(60);
    _ = main_process();
}
Share this post on:

Leave a Comment

您的电子邮箱地址不会被公开。 必填项已用 * 标注