[TOC]

签到

简单做法

在 Windows 系统中使用 Edge 浏览器,直接在下面两行分别双击,选中整行,然后复制到浏览器地址栏即可得到对应的明文。然后将明文按照原有顺序上下排序,即可得到 FLAG

被坑做法

题目刚放出来的时候我用的 Mac 电脑。。。正如第二阶段提示,Safari 和 Mac系统自带的预览 都无法完整复制整行,导致我卡了一下午没做出签到题,心态差点炸掉2333

当时使用 strings 命令看到 PDF 中有下面这种花体字符的字体名是Wingdings-Regular

于是在网上下载了这个字体,挨个比对,发现和复制出来的没啥区别,心态爆炸+1

小北问答

题目答案
15
2407
32021-07-11T08:49:53+08:00
4OOO{this_is_the_welcome_flag}
52933523260166137923998409309647057493882806525577536
6submits
7AS59201
8区域光纤通信网与新型光通信系统国家重点实验室
  1. 利用高德地图搜索 北京大学理科 会看到 理科1号楼、理科2号楼和理科5号楼,(震惊🤯贵校竟然有理科5号楼,我呆了5年了才知道),发现没有4和6号楼,于是利用百度搜索,发现4号楼是生科、3号楼是毅夫2楼,并且没搜到6号楼。
  2. 我首先查看了第零届的 Github 仓库 但很遗憾在仓库里并没有找到总注册人数,只有前100的榜单。于是想到这种东西应该可以用来彰显成绩,在宣传的时候应该会用到,于是翻了翻信科的公众号找到推送 https://mp.weixin.qq.com/s/voAN7LX655Hy5w3_cZmraA 里写着共407人注册、有效参与人数334人。
  3. 印象中有个网站能看某个域名签发的所有免费证书,找了好久才找到这个网站,https://crt.sh/ ,然后搜索 geekgame.pku.edu.cn 即可看到历史签发

    可以看到4362003382 这个的过期时间和下一个没有接上,再转换一下时间格式即可。
  4. 第四题找了好久,主要是一开始没搜对关键词。。一开始用的https://rayhan0x01.github.io/ctf/2020/08/08/defcon-redteamvillage-ctf-tunneler-1,2,3,4,5,7,9.html 这个FLAG,结果做完其他的发现只对了6个,再次查找才找到 DEFCON 的官方 Pre-qualifier 网站, 然后进入DC28Quals 点击上方 Challenges 下载第一个动图中的 txt 即可
  5. 这问卡了好久,甚至尝试手动计算公式,再考虑到斜边的多种复杂情况后决定放弃,继续搜索。找到答案后对世界数学大师感到非常震撼。。。他给了一个(m,n) 棋盘上解个数的公式,利用python把 ^幂运算换成**然后直接计算即可。
  6. 肯定要找题目源码,利用第2问中提到的 第零届的 Github 仓库 ,找到对应的 源码 ,当时其实找了一会儿,主要是不知道 小北问答 的英文名是哪道题。。。
  7. 利用 ipip.net 查询计算中心的 IP 地址找到 3个ASN,随便点进第一个发现 Org Name 不是 PKU,在 Down Streams 中找到一个 Org Name 为 PKU 的
  8. 翻遍信科的所有机构,列了个表,找出最长的是区域光纤通信网与新型光通信系统国家重点实验室

共享的机器

打开题目,获得反编译代码如下:

def storage:
  stor0 is addr at storage 0
  stor1 is uint256 at storage 1
  stor2 is uint256 at storage 2
  stor3 is uint256 at storage 3

def _fallback() payable: # default function
  revert

def unknown7fbf5e5a(uint256 _param1, uint256 _param2) payable: 
  require calldata.size - 4 >= 64
  if stor0 != caller:
      if stor0 != tx.origin:
          if stor1 != sha3(caller):
              if stor1 != sha3(tx.origin):
                  revert with 0, 'caller must be owner'
  stor2 = _param1
  stor3 = _param2

def unknownded0677d(uint256 _param1) payable: 
  require calldata.size - 4 >= 32
  idx = 0
  s = 0
  while idx < 64:
      idx = idx + 1
      s = s or (Mask(256, -4 * idx, _param1) >> 4 * idx) + (5 * idx) + (7 * Mask(256, -4 * idx, stor2) >> 4 * idx) % 16 << 4 * idx
      continue 
  if stor3 != 0:
      revert with 0, 'this is not the real flag!'
  return 1

可以看到就是对输入的数据和stor2进行运算后再与stor3 比对。

这里遇到不知道是不是坑,上面的反编译是 etherscan.io 上的,和其他工具得到的反编译代码有微小差别,我做题时是用的其他工具的结果。

首先使用 web3.py 得到 store2store3

import web3
from web3 import Web3

w3 = Web3(Web3.HTTPProvider("https://ropsten.infura.io/v3/83ebfc92383e429a9ea26572d16ba7b9"))

print(w3.eth.get_storage_at("0xa43028c702c3B119C749306461582bF647Fd770a", 0))
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00MR\x00\xa3W\x13\x91\xf3\xe6T\xdf\x15bq\xbf/\x01\xc0\xc5'

print(w3.eth.get_storage_at("0xa43028c702c3B119C749306461582bF647Fd770a", 1))
b"\xdai\x86\x8c\xde'\xbd\x8f2X\t\x8c\xce\xb1\xd0\x9ds\xd5\xc8P\x17V\xee;\\\xb2\xe7x*\xd7M\x98"

print(w3.eth.get_storage_at("0xa43028c702c3B119C749306461582bF647Fd770a", 2))
b'\x15\xee\xa4\xb2U\x1f\x0c\x96\xd0*]b\xf8L\xac\x81\x12i\rh\xc4{\x16\x81N"\x1b\x8a7\xd6\xc4\xd3'

print(w3.eth.get_storage_at("0xa43028c702c3B119C749306461582bF647Fd770a", 3))
b')>\xde\xa6acZ\xab\xcdm\xeb\xa6\x15\xab\x81:v\x10\xc1\xcf\xb9\xef\xb3\x1c\xccR$\xc0\xe4\xb3sr'

然后再将反编译代码翻译为 python 进行求解,这里卡了一段时间,主要是想从 store3store2 直接反推出 _param1 但由于中间是按位或,导致倒推很困难,基本上很难得到。。。

然后想到每次运算时会比上次多右移4位,所以可以从低位开始每4位爆破,每次只需从0到15依次测试即可,代码如下:


s2 = b'\x15\xee\xa4\xb2U\x1f\x0c\x96\xd0*]b\xf8L\xac\x81\x12i\rh\xc4{\x16\x81N"\x1b\x8a7\xd6\xc4\xd3'
s3 = b')>\xde\xa6acZ\xab\xcdm\xeb\xa6\x15\xab\x81:v\x10\xc1\xcf\xb9\xef\xb3\x1c\xccR$\xc0\xe4\xb3sr'


s2 = int.from_bytes(s2, "big")
s3 = int.from_bytes(s3, "big")

def func_0089(arg0, maxvar1):
    var0 = 0x00
    print(bin(arg0))
    for var1 in range(0, maxvar1):
        var0 = var0 | (((arg0 >> var1 * 0x04) + var1*0x05 + (s2>>var1*0x04)*0x07&0x0f)<<var1*0x04)
        print(f"var: {var0 & ((1<<4*(var1+1))-1)}\ns3: {s3 & ((1<<4*(var1+1))-1)}")
        if var0 & ((1<<4*(var1+1))-1) != s3 & ((1<<4*(var1+1))-1):
            return False
    return True
def calc():
    ans = 0

    for i in range(0, 64):
        print(f"calc i : {i}")
        for tmp in range(0, 16):
            if func_0089(ans + (tmp<<4*i), i+1):
                ans = ans + (tmp<<4*i)
                print(f"ans: {bin(ans)}")
                break
        else:
            print("error")
            exit(-1)
    return ans

ans = calc()
ans = ans.to_bytes((ans.bit_length()+7)//8, "big")

print(ans)

翻车的谜语人

FLAG1

利用 Wireshark 打开流量包,搜索 flag 字样,找到一个 JSON 格式的 HTTP 请求

{
    "name": "Untitled.ipynb", 
    "path": "Untitled.ipynb", 
    "last_modified": "2021-11-06T07:42:40.600988Z", 
    "created": "2021-11-06T07:42:40.600988Z", 
    "content": {
        "cells": [
            {
                "cell_type": "code", 
                "execution_count": 13, 
                "metadata": {
                    "trusted": true
                }, 
                "outputs": [ ], 
                "source": "import zwsp_steg
from Crypto.Random import get_random_bytes"
            }, 
            {
                "cell_type": "code", 
                "execution_count": 14, 
                "metadata": {
                    "trusted": true
                }, 
                "outputs": [ ], 
                "source": "import binascii"
            }, 
            {
                "cell_type": "code", 
                "execution_count": 15, 
                "metadata": {
                    "trusted": true
                }, 
                "outputs": [ ], 
                "source": "def genflag():
    return 'flag{%s}'%binascii.hexlify(get_random_bytes(16)).decode()"
            }, 
            {
                "cell_type": "code", 
                "execution_count": 16, 
                "metadata": {
                    "trusted": true
                }, 
                "outputs": [ ], 
                "source": "flag1 = genflag()
flag2 = genflag()"
            }, 
            {
                "cell_type": "code", 
                "execution_count": 17, 
                "metadata": {
                    "trusted": true
                }, 
                "outputs": [ ], 
                "source": "key = get_random_bytes(len(flag1))"
            }, 
            {
                "cell_type": "code", 
                "execution_count": 18, 
                "metadata": {
                    "trusted": true
                }, 
                "outputs": [
                    {
                        "data": {
                            "text/plain": "b'\\xc4\\x07[\\xe5zy}b3\\x1aM\\xed\\t\\x14\\x1c\\xea\\x8f\\xfb\\xe52\\\\\\x80\\xb1\\x98\\x8a\\xb4\\xa6\\xdd;\\x92X\\x81\\xcd\\x86\\x86\\xc4\\xe0v'"
                        }, 
                        "execution_count": 18, 
                        "metadata": { }, 
                        "output_type": "execute_result"
                    }
                ], 
                "source": "key"
            }, 
            {
                "cell_type": "code", 
                "execution_count": 19, 
                "metadata": {
                    "trusted": true
                }, 
                "outputs": [ ], 
                "source": "def xor_each(k, b):
    assert len(k)==len(b)
    out = []
    for i in range(len(b)):
        out.append(b[i]^k[i])
    return bytes(out)"
            }, 
            {
                "cell_type": "code", 
                "execution_count": 20, 
                "metadata": {
                    "trusted": true
                }, 
                "outputs": [ ], 
                "source": "encoded_flag1 = xor_each(key, flag1.encode())
encoded_flag2 = xor_each(key, flag2.encode())"
            }, 
            {
                "cell_type": "code", 
                "execution_count": 22, 
                "metadata": {
                    "trusted": true
                }, 
                "outputs": [ ], 
                "source": "with open('flag2.txt', 'wb') as f:
    f.write(binascii.hexlify(encoded_flag2))"
            }
        ], 
        "metadata": {
            "kernelspec": {
                "display_name": "Python 3 (ipykernel)", 
                "language": "python", 
                "name": "python3"
            }, 
            "language_info": {
                "codemirror_mode": {
                    "name": "ipython", 
                    "version": 3
                }, 
                "file_extension": ".py", 
                "mimetype": "text/x-python", 
                "name": "python", 
                "nbconvert_exporter": "python", 
                "pygments_lexer": "ipython3", 
                "version": "3.8.3rc1"
            }
        }, 
        "nbformat": 4, 
        "nbformat_minor": 4
    }, 
    "format": "json", 
    "mimetype": null, 
    "size": 2502, 
    "writable": true, 
    "type": "notebook"
}

整理后得到一个 .ipynb 文件中的代码,进行还原

from Crypto.Random import get_random_bytes

import binascii

def genflag():
    return "flag{%s}"%binascii.hexlify(get_random_bytes(16)).decode()

flag1=genflag()
flag2=genflag()

key = get_random_bytes(len(flag1))

key = b'\x1e\xe0[u\xf2\xf2\x81\x01U_\x9d!yc\x8e\xce[X\r\x04\x94\xbc9\x1d\xd7\xf8\xde\xdcd\xb2Q\xa3\x8a?\x16\xe5\x8a9'

def xor_each(k, b):
    out = []
    for i in range(len(b)):
        out.append(b[i]^k[i])
    return bytes(out)

encode_flag2 = xor_each(key, flag2.encode())


with open('flag2.txt') as f:
    encode_flag2 = f.write()

注意,上面的 key 和截图中的不一致,主要是由于这个数据比较老,在流量中还能找到新的 Untitled.ipynb 文件,这个 key 是从新的文件中提取出来的。

然后继续在流量中找 flag1

可以得到 flag1.txt 的内容,然后计算即可。

flag1="788c3a1289cbe5383466f9184b07edac6a6b3b37f78e0f7ce79bece502d63091ef5b7087bc44"

key = b'\x1e\xe0[u\xf2\xf2\x81\x01U_\x9d!yc\x8e\xce[X\r\x04\x94\xbc9\x1d\xd7\xf8\xde\xdcd\xb2Q\xa3\x8a?\x16\xe5\x8a9'

def xor_each(k, b):
    out = []
    for i in range(len(b)):
        out.append(b[i]^k[i])
    return bytes(out)

flag1 = xor_each(key, bytes.fromhex(flag1))
print(flag1)

FLAG2

在流量中搜索 flag2 可以看到一个 HTTP 传输的压缩包,保存下来后解压发现有密码,继续在流量中搜索 flag2 发现了 websocket

在里面看到了压缩包是如何生成的,还原密码为

Wakarimasu! \`date\` \`uname -nom\` \`nproc\`

markdown 好难写这个密码,还是看截图吧

date 是当时的日期时间,在流量包中找到该压缩包的生成时间为2021-11-06T07:44:16,我在 wsl2 虚拟机上将时间调整到 6 号执行 date 命令得到如下格式Sat 6 Nov 2021 21:10:11 CST

uname -nom 得到 vm x86_64 GNU/Linux 其中 vm 是我的虚拟机名,在 websocket 包中可以找到 You 酱的虚拟机名,第二项是处理器架构,现在应该都是64位机,第三项是系统相关。

nproc 是处理器线程数,在 websocket 包中可以看到 You 酱的虚拟机是 8线程的

于是得到密码为 Wakarimasu! Sat 6 Nov 2021 07:44:16 CST you-kali-vm x86_64 GNU/Linux 8 改动的地方只有秒位需要,结果尝试了很久都无法解压成功,一度怀疑是压缩包有问题,还尝试了修复压缩包。。。

直到第二阶段提示放出后,才知道是 date 部分错了,正确的密码是Wakarimasu! Sat 06 Nov 2021 03:44:15 PM CST you-kali-vm x86_64 GNU/Linux 8

解压后得到一个 .wav 文件,通过 websocket 包得知,该文件是用 stegolsbflag2.txt 隐写进去得到的

于是使用命令stegolsb wavsteg -r -i xxx.wav -o encode_flag2.txt -n 1 -b 76 其中的 -n 参数和 -b 参数是在 websocket 包中得到的。

重复 FLAG1 中的解密步骤即可得到 FLAG2

在线解压网站

通过分析源码可以看到,当访问路径是文件时,会返回该文件对应的内容。而 FLAG 藏在根目录下,于是猜测是否可以利用Linux下的软链接读取flag,

touch /flag
ln -s /flag ./test

然后压缩 test 文件再上传至服务器,确实能得到 FLAG

早期人类的聊天室

第一阶段未解出来但分析了很多,第二阶段看到提示后即解。

首先分析源码发现可以任意读取文件,只需要在参数上拼接足够的../即可访问到根目录,尝试直接读取 flag 失败,应该是没有权限。

利用 linux 上的 /proc 目录读取自身的 cmdline 得到 uwsgi 配置文件路径,访问该文件发现服务器的进程的权限是 nobody ,这时想着能否提权,尝试了很多办法都不行,卡住。。。

在卡住的过程中,我遍历了 pid 得知服务器是用 supervisor 启动的,于是想到能否更改 uwsig 配置文件,然后重启 uwsgi 进程就能提权,但迫于无法写入 uwsgi 配置文件,且无法执行命令,卡住。。。

第二阶段看到提示后,才知道要利用 uwsgi 的 rce ,啊这🤯,用了好几年的 uwsgi 都不知道有漏洞。。。

于是使用服务器发送消息页面,将地址改为 127.0.0.1:3031 ,这个端口号是上面通过读取 uwsgi 配置文件得到的。

然后使用 uwsgi_exp.py 构造 payload, 首先修改 uwsgi 配置文件

echo '[uwsgi]
socket = :3031
chdir = /usr/src/ufctf
manage-script-name = true
mount = /=app:app
master = true
uid = root
gid = root
workers = 2
buffer-size = 65535
enable-threads = true
pidfile = /tmp/uwsgi.pid
' >/tmp/uwsgi-ctf.ini

由于 uwsgi 进程权限很低,创建新进程还是 nobody 所以只能考虑重启 uwsgi 进程,尝试了uwsgi --reload /tmp/uwsgi.pid 发现并没有提权成功,于是使用 uwsgi --stop /tmp/uwsgi.pid (我自己停止我自己总行了吧),借助于 supervisor 这个进程管理器成功得到新的 root 权限的 uwsgi 进程,然后直接读取 /flag 即可。

Flag 即服务

Flag0

卡了很久,主要是搜到了 RFC 3986, 以为浏览器和各种发送请求的工具都会遵循,后来偶然发现 Postman 并没有遵循该标准。。。于是利用 Postman 访问 /api/../package.json 得到 package.json 文件,从文件中得到 jsonaas-backend 的下载链接,从而得到源码。

阅读源码,发现对 FLAG0 有特殊约束

FLAG0===`flag{${0.1+0.2}$}`

在浏览器中执行 0.1+0.2 即可得到 FLAG0

FLAG1 和 FLAG2

尝试了很多方法都不行,简单说下自己尝试过的思路。

FLAG2 应该是 vm 沙盒逃逸,而且由于代码中只是在文件系统中 unlinkflag2.txt 所以还是可以用其他方法读取的。

FLAG1 尝试了 session 伪造,发现行不通;尝试构造 req.query 绕过验证失败。

静待大神们的 WP

诡异的网关

这题我应该是非预期解😊

打开软件后随便点点发现有个用户名叫 flag 且密码以星号表示,于是在网上找了个能用的星号查看器,然后就得到了 FLAG

静待大神们的 WP

密码学实践

这题出的太好了!

FLAG1

阅读代码发现和 Richard 谈话时, FLAG1 会直接拼接在已知明文后再加密发送给我们,于是查看加密算法,手推加密循环发现,密文和明文之间关系较为简单。

如果已知明文和密文,可以倒推出加密使用的key,然后再利用得到的key,解密 FLAG 部分的密文。

代码如下:

from Crypto.Util.number import bytes_to_long, long_to_bytes


def get(mess: bytes, oristr: bytes):
    pmess = mess[0:32]
    a0 = bytes_to_long(pmess[0:8])
    b0 = bytes_to_long(pmess[8:16])
    c0 = bytes_to_long(pmess[16:24])
    d0 = bytes_to_long(pmess[24:32])

    o0 = bytes_to_long(oristr[0:8])
    o1 = bytes_to_long(oristr[8:16])
    o2 = bytes_to_long(oristr[16:24])
    o3 = bytes_to_long(oristr[24:32])

    ka = c0 ^ a0 ^ o0
    kb = d0 ^ b0 ^ o1
    kc = a0 ^ o2
    kd = b0 ^ o3

    ori = b""
    for it in range(32, len(mess), 32):
        pmess = mess[it:it+32]
        a1 = bytes_to_long(pmess[0:8])
        b1 = bytes_to_long(pmess[8:16])
        c1 = bytes_to_long(pmess[16:24])
        d1 = bytes_to_long(pmess[24:32])
        a, b, c, d = c1^a1^ka, d1^b1^kb, a1^kc, b1^kd

        a = long_to_bytes(a, 8)
        b = long_to_bytes(b, 8)
        c = long_to_bytes(c, 8)
        d = long_to_bytes(d, 8)

        ori += a+b+c+d
        print(ori)


def pad(msg):
    n = 32 - len(msg) % 32
    return msg + bytes([n]) * n


enc = bytes.fromhex("f5b658a1fa3f7740e0c0a8bc67077fd1aaebaec98bfddb0f3a5e32b9fd3f8fa7f1ab14a4a9623e50e981b6a854423af589b3e8ccd6ebc1707f2227adcf3cead1ddbe5a92950f584b8de8d9db1a2f03aebee38cc9e58480320b4d4be4ef52899c")

get(enc, pad("Hello, Alice! I will give you two flags. The first is: ".encode("utf-8")))

FLAG2

原理应该是选择密文攻击

阅读代码,我们发现 God 会对我们的 name 和 key 加密返回 cert,而 Richard 会验证我们的 cert 当 name 是 Alice 时给我们发送 FLAG2。但 God 已经加密过 name 是 Alice 的,所以如果我们输入 name 是 Alice 会被拒绝。

由于 Richard 只验证 name ,于是我们考虑制造 name 为 Alice,key 随意的明文对应的密文。

观察 God 签发过程,首先会将 name 和 key 进行 packmess 然后拼接起来再使用 rsa 加密。

我们考虑最简单的情况,即我们想要的是 Alice\x00\x05\x00\x00 这样的明文对应的 cert,于是我们考虑发送给God的 name 为空,这样 God 发送的 cert 的明文就是 key 和 key的长度 拼接起来。

$$ 我们需要\ C\ 使得\ M=C^e\mod N \\ 其中\ M=Alice\backslash x00\backslash x05\backslash x00\backslash x00 \\ 我们选择任意的\ X 与\ N 互素(为了简单可以选 X=3 \ )\\ 我们计算\ Y=M*X^e\mod N \\ 将\ Y\ 发送给服务器计算\ Z=Y^d\mod N=M^d * X^{e*d}\mod N=C*X \mod N \\ 现在我们知道Z、X,计算C只需要使得 (Z+iN)\%X==0 即可 $$

注意⚠️:在构造出 Y 后,我们需要保证 Y 转换成 bytes 的长度减去2要小于 Y 的bytes的最后两个字节转换成的数字大小,且发送给服务器的 Y 应是 Y 转化成 bytes 后的前

代码如下:

from re import T
from pwn import *
from Crypto.Util.number import bytes_to_long,long_to_bytes
import binascii
from rsa import *
import gmpy2

r = connect("prob08.geekgame.pku.edu.cn", 10008)
r.sendlineafter(b"Please input your token:\n", b"Your Token")

print(r.recvline())  # What do you want to do?
print(r.recvline())  # 0. Talk to God.
print(r.recvline())  # 1. Talk to Richard.
r.sendline(b"0")
N = int(r.recvline().split()[-1].decode("utf-8"))  # My RSA N is: 
e = int(r.recvline().split()[-1].decode("utf-8"))  # My RSA e is: 
print("N: ", N)
print("e: ", e)

p = int.from_bytes(b"Alice\x00\x05\x00\x00", "big")
print(f"p: {p}")
x = 3
while True:
    tmp = p*pow(x, e, N) % N
    y = tmp.to_bytes((tmp.bit_length()+7)//8, "big")
    rlen = int.from_bytes(y[-2:], "big")
    if len(y)-2 > rlen:
        x+=1
        continue
    else:
        print(f"x:{x} y:{y}")
        break

y = b'\x00'*(rlen-len(y)+2) +y
y = y[-(2+rlen):-2]

print(r.recvline())  # What is your name?
r.sendline(b"")
print(b"")
print(r.recvline())  # What is your key?
r.sendline(y.hex().encode("utf-8"))
print(y)
print(r.recvline())  # Your certificate is:
fakecert = r.recvline().strip()
print(fakecert)
fakecert = int(fakecert.decode("utf-8"))
mess=pow(fakecert,e,N)
mess=mess.to_bytes((mess.bit_length()+7)//8,'big')
print("mess: ", mess)

i = 0
while True:
    tmp = fakecert + N*i
    if tmp % x == 0:
        break
    i += 1

C = (fakecert + N*i) // x
print(f"C: {C}")
mess=pow(C,e,N)
messm=mess.to_bytes((mess.bit_length()+7)//8,'big')
print(f"Hacked! {messm}")



print(r.recvline())  # What do you want to do?
print(r.recvline())  # 0. Talk to God.
print(r.recvline())  # 1. Talk to Richard.

r.sendline(b"1")
flag1enc = r.recvline() # Hello, Alice! I will give you two flags. The first is: 
notice_mess_enc =  r.recvline()  # Sorry, I forget to verify your identity. Please give me your certificate.

r.sendline(str(C).encode("utf-8"))

flag2enc = r.recvline() # I can give you the second flag now. It is: 
print(flag2enc)
# print(get_flag2(flag2enc))


r.close()

叶子的新歌

套娃心态炸掉。。

首先下载下来,在mac上会自动播放发现没啥东西,使用音频分析软件也没发现什么,耽误了好久,后来在windows上播放时发现右上角有提示Secret in Album Cover ,于是使用 potplayer 提取出封面图片,然后使用 stegosolove 找出使用 lsb 隐写进去的一个 png 文件,该 png 文件长得类似二维码,卡住。。。然后在linux 下使用 binwalk 发现有个压缩包,使用 binwalk -e 处理后得到一个 MIPSEL-BE ECOFF executable stripped -version 0.0 的文件,尝试使用 qemu 运行无果,卡住。。。

Q 小树洞的一大步

在使用了现代化框架 React 后的网站找 XSS 真难啊。。。尝试了很多方法都无法在网页上构建 XSS。

第二阶段看到提示后,又尝试了很多方法,还是行不通。我甚至逐行比对了 Q小树洞和 PKU树洞现在的 js 文件,还是没有任何发现。

审计代码中发现访问 /hole/#//setflag flag1=content 会将 LocalStorage 中的 flag1 设置为 content ,但并不会触发代码执行,且由于会弹出一个提示框,将导致 XSSBOT 无法继续执行。。

还发现 LocalStorage 中的 APPSWITCHER_ITEMS 中有一项 fix 会被 eval 语句执行,但由于跨域要求,无法在其他站点修改这个值,无法利用这个点。

静待大神们的 WP

射手鱼

.debug 文件完全不懂,静待大神们的 WP

字符串转义

第一阶段想到了计算 canary,然后调用print_flag但没动力做,之前完全没做过😮‍💨,静待大神们的 WP

最强大脑

不知道为什么进入compile_code() 编译的区域后会segment fault ,静待大神们的 WP

电子游戏概论

看着没人做出来,就没看,静待大神们的 WP

扫雷

练了一个 Qlearning 但效果不行,不太想调参,放弃,静待大神们的 WP

龙珠模拟器

应该是考察 java 里的 Random 类,对 java 不熟对算法也不熟,放弃,静待大神们的 WP

最后修改:2022 年 04 月 16 日
如果觉得我的文章对你有用,请随意赞赏