又是一年 Haclergame,今年又看了一些有趣的题目。

Hackergame 启动

录制声音后会检测相似率,大于 99.9 才可以,注意到提交后带参数 similarity=0,改一下就行了。

猫咪小测

  1. 看一下中科大西区图书馆介绍,要借外文书,需去十二楼;
  2. 简单机翻,搜索 “The upper limit on the density of chickens in the observable universe”,找到论文:《Nuggets of Wisdom: Determining an Upper Limit on the Number Density of Chickens in the Universe》,在 Abstract 中找到答案 23;
  3. 根据关键字 “linux compile tcp bbr” 找到 https://www.cyberciti.biz/cloud-computing/increase-your-linux-server-internet-speed-with-tcp-bbr-congestion-control/,找到编译选项 CONFIG_TCP_CONG_BBR
  4. 根据关键字 “make mypy infinite loop” 找到论文 《Python Type Hints are Turing Complete》,再根据论文找到 https://drops.dagstuhl.de/opus/volltexte/2023/18237/pdf/LIPIcs-ECOOP-2023-44.pdf,发布在 ECOOP 上。

更深更暗

获取 flag 的核心逻辑位于 main.js

    async function getFlag(token) {
        // Generate the flag based on user's token
        let hash = CryptoJS.SHA256(`dEEper_@nd_d@rKer_${token}`).toString();
        return `flag{T1t@n_${hash.slice(0, 32)}}`;
    }

在此处下一个断点,然后获取 flag 即可。

赛博井字棋

看上去下棋的地方没有 check,因此我们将断点下在发送的位置,将下棋的位置改为电脑的位置即可。

组委会模拟器

  • “检测到时空穿越”
  • “超过撤回时间”

简单来说它有一个 http://202.38.93.111:10021/api/getMessages 接口,分析里面的数据格式模拟消息撤回即可。

import time
import requests
from ast import literal_eval
import re
import json
 
with requests.Session() as s:
    res = s.get(
        "http://202.38.93.111:10021/api/checkToken?token="
    )
    res = s.post(
        "http://202.38.93.111:10021/api/getMessages"
    )
 
    delete_url = "http://202.38.93.111:10021/api/deleteMessage"
 
    text = literal_eval(res.text)
    old_time = time.time()
    for i, txt in enumerate(text['messages']):
        delay_time = txt['delay']
        print(f"delay_time: {delay_time}", flush=True)
        msg: str = txt['text']
        if re.search(
            "hack\[[a-z]+\]",
            msg
        ):
            while time.time() - old_time < delay_time:
                time.sleep(1)
            res = s.post(
                delete_url,
                json = {"id": i}
            )
            status = json.loads(res.text)
            print(f"delete id {i}: {msg}")
            if status['success'] != True:
                print(f"{res.text}", flush=True)
                exit(0)
        else:
            try:
                print(f"{msg}")
            except Exception as e:
                continue
 
    time.sleep(5)
    res = s.post(
        "http://202.38.93.111:10021/api/getflag"
    )
    print(f"{res.text}")

业余无线电

作为一名业余无线电爱好者,一眼想到 SSTV。ISS 的 SSTV 模式为 PD120,不过这一次的模式是 Scottie2。用 RX-SSTV 可解。

JSON ⊂ YAML?

一道yamljson 规范的题目

看 YAML 1.1 和 1.2 版本规范和 JSON 的不同。1.1 的很好找:

构造:{"text": 12345e999}

YAML 1.2 的要求是必须是合法的 YAML 1.1,那么只能看有哪些规定不合法了,参考 python yaml1.2 的库中实现,可以发现 Duplicate keys 是满足 YAML 1.1 但是在 1.2 中会出错的情况。

我觉得官方 wp 也非常有参考价值。

Git? Git!

一道git 命令题目

通过 git reflog 查看本地提交

ea49f0c (HEAD -> main) HEAD@{0}: commit: Trim trailing spaces
15fd0a1 (origin/main, origin/HEAD) HEAD@{1}: reset: moving to HEAD~
505e1a3 HEAD@{2}: commit: Trim trailing spaces
15fd0a1 (origin/main, origin/HEAD) HEAD@{3}: clone: from https://github.com/dair-ai/ML-Course-Notes.git

reset 到 505e1a3

git reset --hard 505e1a3

即可。

HTTP 集邮册

手动构造http 报文

200、400、404 比较好构造

505 HTTP Version Not Supported,修改 HTTP 协议

GET / HTTP/3.0\r\n
Host: example.com\r\n\r\n

405 Method Not Allowed,修改请求方法

DELETE / HTTP/1.1\r\n
Host: example.com\r\n\r\n

后面的内容摘自官方 wp

100 Continue,代表服务器希望客户端继续请求或者忽略。需要客户端发送 Expect: 100-continue

GET / HTTP/1.1\r\n
Host: example.com\r\n
Expect: 100-continue\r\n\r\n

206 Partial Content. 一个 HTTP 请求可以只请求部分内容,服务器也会返回部分内容。

GET / HTTP/1.1\r\n
Host: example.com\r\n
Range: bytes=1-2\r\n\r\n

416 Range Not Satisfiable. 上面的 Range 是一个合法的范围,那么不合法的范围呢?就是 416。

GET / HTTP/1.1\r\n
Host: example.com\r\n
Range: bytes=114514-1919810\r\n\r\n

304 Not Modified. 代表文件在指定条件下没有修改过,这里用 If-Modified-Since

GET / HTTP/1.1\r\n
Host: example.com\r\n
If-Modified-Since: Tue, 15 Aug 2023 17:03:04 GMT\r\n\r\n

412 Precondition Failed. 这个 payload 使用了 ETag + If-Match,ETag 和对应的 web 资源对应,用来区分对应资源不同的版本。客户端可以利用这个信息来节省带宽。这里 If-Match 则在尝试匹配这个 ETag,如果不匹配,那就返回 412。

GET / HTTP/1.1\r\n
Host: example.com\r\n
If-Match: "bfc13a64729c4290ef5b2c2730249c88ca92d82d"\r\n\r\n

413 Content Too Large. 不需要真正输入很大的 payload,把 Content-length 弄得很大就行:

GET / HTTP/1.1\r\n
Host: example.com\r\n
Content-length: 1145141919810\r\n\r\n

414 URI Too Long. 大概需要很长的 URI 路径(但是又不能太长,否则 web 界面本体不会允许这样的响应)。内容详见 414.txt

无状态码,为了保持和 http/0.9 的兼容性:

GET /\r\n

Docker for Everyone

docker

先看到 flag 软链接到了 /dev/shm/flag 上面,然后挂载之:

docker run -it -v /dev/shm/flag:/root/flag --rm alpine

惜字如金 2.0

根据 flag 的定位猜测添加的字符串位置,代码中给出了合适的 check 检查猜测是否正确,这是一道 Python 学习题目。

高频率星球

去翻一下 asciinema 的文档,可以通过 asciinema cat 命令讲所有屏幕上的输入重定向到文件,然后手动去除 shell 相关的命令和翻页命令即可。

🪐 小型大语言模型星球

参见小型大语言模型星球

为什么要打开 /flag 😡

  • LD_PRELOAD 可以用静态编译绕过
  • 看上去是通过竞争,但是没成功
    • 看了一下题解,感觉可能是没有用 musl 编译的原因

逆向工程不需要 F5

angr 一把梭,学习一下 wp:

import angr, monkeyhex, claripy
proj = angr.Project('no_need_for_F5/main.exe')
# 设置 flag 长度,32位内容+前后的 flag{ }
flag_chars = [claripy.BVS('flag_%d' % i, 8) for i in range(32)]
flag = claripy.Concat(*[claripy.BVV(b'flag{')]+flag_chars+[claripy.BVV(b'}\x00')])
 
# 设置初始状态
state = proj.factory.call_state(0x140001000)
input_addr = 0
 
# hook 输入函数
@proj.hook(0x140001093, length=5)
def get_input(state):
    global input_addr
    input_addr = state.regs.rdx
    state.memory.store(input_addr,flag)
    print('Input done')
 
# hook 打印函数
@proj.hook(0x140001079, length=5)
def printf(state):
    return
 
simgr = proj.factory.simgr(state)
simgr.explore(find=0x1400013A1, avoid=0x1400013B7)
simgr.found[0].solver.eval(flag).to_bytes(39,"big")

先写这么多吧,有一些题目可以拓展的,找个时间整理一下。