目录

  1. 1. 前言
  2. 2. Tutorial
    1. 2.1. 一眼盯帧
  3. 3. Web
    1. 3.1. Emoji Wordle
    2. 3.2. 逝界计划

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

PKU GeekGame 2023复现

2023/10/23 CTF线上赛
  |     |   总文章阅读量:

前言

北大的ctf,出的东西都好新,晚点再看看

yysy题目的梗含量爆炸,全是阿宅,太爽了(

官方wp:https://github.com/PKU-GeekGame/geekgame-3rd/tree/master/official_writeup

Tutorial

一眼盯帧

hint:实在不知道该给什么提示。因为只需要把 GIF 里每个帧里的字母拼起来,然后做个 ROT13 就解出来了。

用Photoshop打开gif图片,把里面每一帧的字符拼起来,得到synt{rawblgurtrrxtnzr}

猜测是凯撒加密,丢脚本跑一下

def caesar_decrypt(ciphertext, shift):
    """
    凯撒密码解密函数
    :param ciphertext: 密文
    :param shift: 移位数
    :return: 明文
    """
    plaintext = ""
    for char in ciphertext:
        if char.isalpha():
            # 将字母转换为ASCII码,并减去65或97,使得A或a的ASCII码为0
            ascii_code = ord(char) - shift
            # 处理超出字母表范围的ASCII码
            if char.isupper():
                if ascii_code < 65:
                    ascii_code += 26
            else:
                if ascii_code < 97:
                    ascii_code += 26
            # 将ASCII码转换回字符
            plaintext += chr(ascii_code)
        else:
            plaintext += char
    return plaintext


ciphertext = "synt{rawblgurtrrxtnzr}"
# ciphertext = ''.join([chr(i) for i in [86, 116, 128, 80, 98, 85, 139, 122, 134, 114, 125, 136, 117, 123, 129, 127, 128, 128, 142, 130, 140, 147, 127, 132, 131, 136, 151, 134, 152, 164]])
for i in range(1, 30):
    shift = i
    plaintext = caesar_decrypt(ciphertext, shift)
    print(plaintext)

得到flag:flag{enjoythegeekgame}


Web

Emoji Wordle

python爆破

Q:你能在规定的次数之内猜出由 64 个 Emoji 组成的 Wordle 吗?猜测结果正确就能拿到 Flag。

hint:

  • 本题使用了 Play Framework。这是一种无状态 Web 框架,其实服务器什么都没有存储。

  • 可以看看 它的 Session 实现,留意一下每次请求 Cookie 发生了什么变化。

  • 另外,输入框里面的 Placeholder 是从 128 个 Emoji 中随机(有放回)抽取 64 个,但是答案只会涉及 64 种 Emoji。在知道答案涉及的 64 种 Emoji 的前提下,可以用 64 次猜测得到答案

这题有点离谱,真就是在规定次数内拿脚本硬爆64个字符

level1~3均适用

import requests

def solve():
    cookie = requests.get("https://prob14.geekgame.pku.edu.cn/level1").cookies
    v = [0] * 64
    x = [
        chr(i + 0x1F410) for i in
        b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    ]
    for z in x:
        print(x.index(z))
        p = [
            ord(i) for i in requests.get(
                "https://prob14.geekgame.pku.edu.cn/level1?guess=" + z * 64,
                cookies=cookie).text.split()[28][14:-2]
        ]
        for j in range(64):
            if p[j] == 129001:
                v[j] = z
    return requests.get("https://prob14.geekgame.pku.edu.cn/level1?guess=" +
                        ''.join(v),
                        cookies=cookie).text

solve()

不过具体的思路应该是Gameover了可以用旧的cookie还原状态,但是这个硬爆还是挺离谱的


逝界计划

啤酒烧烤

题目描述

小帅在自己的电脑安装上 Home Assistant,惊叹道这个系统极为先进,在网页上点点鼠标就能自动控制智能设备、存储多媒体文件,甚至还能执行任意 Jinja 模版、用 nmap 扫描内网……既然这些功能都能做到,那读取服务器磁盘中的 /flag.txt 也不难做到,对吧?

题目源码给了个docker-compose.yml,意思是让我们本地自己调试

docker exec -it hass /bin/bash

hint:

  • 为了安全性,大多数与读写文件相关的集成都无法直接从Web界面添加。但是有一个集成看似与读写文件无关,却能顺便做到读写文件……

  • ……那就是大家都喜欢的 nmap 集成。

  • 你可能想用 nmap --script 执行任意脚本,但可惜它的 Docker 里没装完整的运行环境。试试别的方式吧。

这是一个项目,具有各种功能

  • 在 “开发者工具” 里面可以测试 Jinja 模板。一眼看上去就能执行任意代码,但实际上不行,因为它用了 Jinja 的 Sandbox,还挺安全的

    image-20231025215230537

  • 在 “媒体” 里面可以上传下载 /media 目录下的任意文件

    这里尝试传马,但是我好像连包都抓不到。。。

  • 在 “配置”>“备份” 里面可以打包下载 /config 目录。在 “配置”>“日志” 里面可以查看当前日志。

    下载下来也没有什么重要的信息,都是json和yaml文件

    image-20231025220042741

  • 在 “配置”>“设备与服务” 里面可以添加集成

    • 本地 IP 地址,顾名思义可以查看自己的 IP 地址
    • 通用摄像头,可以发起内网 RTSP 请求
    • 文件大小,可以查看本地任意文件的大小,但是对路径有限制
    • 正常运行时间,可以查看服务器的 uptime
    • ASUSWRT,可以 SSH 连接到内网
    • CPU 速度,可以……嗯……查看 CPU 速度
    • MQTT,可以发起内网 MQTT 请求
    • Nmap 跟踪器,可以运行 Nmap 命令
    • Profiler,可以输出各种各样的诊断信息
    • Scrape,可以发起内网 HTTP 请求
    • SQL,可以用 SqlAlchemy 执行任意 SQL 命令

    这些功能本身看起来都读不了文件内容,因此需要考虑能否通过滥用这些功能实现命令执行文件读取

    比如,让 Scrape 集成访问 file:/// 网址,让 SQL 集成通过某些神奇的 SQL 函数读取文件,让 Profile 集成泄露内存里的敏感信息

最后结合提示在nmap集成里可以发现扫描项能够传递任何命令行参数

image-20231025220351729

通过源码也可以确认它直接把这里配置的命令行参数直接传递给了nmap(arguments=options

def _run_nmap_scan(self):
   """Run nmap and return the result."""
   options = self._build_options()
   if not self._scanner:
       self._scanner = PortScanner()
   _LOGGER.debug("Scanning %s with args: %s", self._hosts, options)
   for attempt in range(MAX_SCAN_ATTEMPTS):
       try:
           result = self._scanner.scan(
               hosts=" ".join(self._hosts),
               arguments=options,
               timeout=TRACKER_SCAN_INTERVAL * 10,
           )
           break
       except PortScannerError as ex:
           if attempt < (MAX_SCAN_ATTEMPTS -
                         1) and NMAP_TRANSIENT_FAILURE in str(ex):
               _LOGGER.debug("Nmap saw transient error %s",
                             NMAP_TRANSIENT_FAILURE)
               continue
           raise
   _LOGGER.debug(
       "Finished scanning %s with args: %s",
       self._hosts,
       options,
   )
   return result

虽然很遗憾此处没有直接的命令注入,无法借机运行其他程序,但 nmap 的自身功能可是多了去了,足够让我们爽到。比如:

  • 读取任意文件(-iL /path/to/read
  • 写入任意文件(-oN /path/to/write
  • 执行任意命令(--script /path/to/exec.lua

要想解出此题,只需要利用 nmap 的前两个功能,在命令行参数里面输入

-iL /flag.txt -oN /media/log.txt.jpg

然后在媒体里面把结果下载下来即可(这个方法不知道怎么下载)

image-20231025221005313

或者输出到 /config 里面通过备份功能下载下来

-iL /flag.txt -oN /config/backups/log.txt

image-20231025221708752

flag:flag{sOOoo-MAny-LOoPhOLes-in-HOME-AsSistaNt}