犬戎's Writeup for Hackergame 2024
看了官方 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
截取这个部分进行谷歌识图
第一条直接是这个
不能说很像,简直就是一模一样
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}")