一緒に迷子やろうよ 战队WriteUp
一、 战队信息
战队名称:一緒に迷子やろうよ 战队
战队成员:Lwrzgo、Annms_、laingxi、ABCcookie
战队得分:800
二、 解题情况
# | 题目情况 | 解题队员 | 题目类别 | 获得分数 | 解题排名 | 解题时间 |
---|---|---|---|---|---|---|
1 | Webshell_pro | Annms_ | Misc | 200 | 211 | 2024-03-24 17:53:57 |
2 | world.execute.me | Lwrzgo | Misc | 200 | 56 | 2024-03-24 16:03:18 |
3 | Minecraft:SEED | Lwrzgo | Misc | 200 | 104 | 2024-03-23 19:12:39 |
4 | signin | laingxi | Misc | 200 | 47 | 2024-03-23 08:02:28 |
三、 解题过程
signin 解题步骤:
登录签到
Minecraft:SEED 解题步骤:
作为十多年 MC 牢玩家,可谓是最信手拈来的一题了(自信满满),先读题,一眼就是登录服务器,然后找服务器种子
首先想到的是多年前在 MCBBS 上看到的通过遗迹和村庄逆推种子的帖子,但是最近 MCBBS 寄了(哭),去百度有没有其他方法
不搜不知道,原来科技发展了这么多年了,连自动找种子的 mod 都有了
小声 bb :当初在服务器找服主要种子盖史莱姆农场,服主死活不给 qwq
具体方法也是通过遗迹反推种子,登录服务器,刚刚好有片海,撸树,坐船,跑图!
种子出来力!然后指令获取 flag 就行了(没截图,找 log 去了)
world.execute.me 解题步骤:
读题:
看来就是要找这个 secrets.Heart 值了,但是如何找?
翻看脚本代码可以注意到
读完可以发现,这段代码就是提取问题和提取答案的部分,然后就使用 eval 命令执行了ANSWER变量中的命令
兜底数据规则具体解释如图
结果就是,我们需要发一个 issue ,要使得 Answer 执行命令获取 HEART 的值
得到!
Webshell_Pro 解题步骤:
拿到题目,是一个pcapng包
显然这是一道流量分析题,且只涉及到ICP和HTTP协议
猜测大概率是考HTTP
过滤如下:
观察可发现疑似为BASE32的字符串,解码试试:
(按顺序)
上面的解码后都是正常的操作流,但在解密序号为35的字符串的时候发现了不对劲的地方:
看起来像是base64字串,遂解密得到:
hmmm…
得到了一个不知道干什么的密码,先暂时放着不管(其实是试过了不是flag才继续的)
继续往下,得到了一个以base64加密的脚本:
import base64
import libnum
from Crypto.PublicKey import RSA
pubkey = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK/qv5P8ixWjoFI2rzF62tm6sDFnRsKsGhVSCuxQIxuehMWQLmv6TPxyTQPefIKufzfUFaca/YHkIVIC19ohmE5X738TtxGbOgiGef4bvd9sU6M42k8vMlCPJp1woDFDOFoBQpr4YzH4ZTR6Ps+HP8VEIJMG5uiLQOLxdKdxi41QIDAQAB
-----END PUBLIC KEY-----
"""
prikey = """-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIr+q/k/yLFaOgUjavMXra2bqwMWdGwqwaFVIK7FAjG56ExZAua/pM/HJNA958gq5/N9QVpxr9geQhUgLX2iGYTlfvfxO3EZs6CIZ5/hu932xTozjaTy8yUI8mnXCgMUM4WgFCmvhjMfhlNHo+z4c/xUQgkwbm6ItA4vF0p3GLjVAgMBAAECgYBDsqawT5DAUOHRft6oZ+//jsJMTrOFu41ztrKkbPAUqCesh+4R1WXAjY4wnvY1WDCBN5CNLLIo4RPuli2R81HZ4OpZuiHv81sNMccauhrJrioDdbxhxbM7/jQ6M9YajwdNisL5zClXCOs1/y01+9vDiMDk0kX8hiIYlpPKDwjqQQJBAL6Y0fuoJng57GGhdwvN2c656tLDPj9GRi0sfeeMqavRTMz6/qea1LdAuzDhRoS2Wb8ArhOkYns0GMazzc1q428CQQC6sM9OiVR4EV/ewGnBnF+0p3alcYr//Gp1wZ6fKIrFJQpbHTzf27AhKgOJ1qB6A7P/mQS6JvYDPsgrVkPLRnX7AkEAr/xpfyXfB4nsUqWFR3f2UiRmx98RfdlEePeo9YFzNTvX3zkuo9GZ8e8qKNMJiwbYzT0yft59NGeBLQ/eynqUrwJAE6Nxy0Mq/Y5mVVpMRa+babeMBY9SHeeBk22QsBFlt6NT2Y3Tz4CeoH547NEFBJDLKIICO0rJ6kF6cQScERASbQJAZy088sVY6DJtGRLPuysv3NiyfEvikmczCEkDPex4shvFLddwNUlmhzml5pscIie44mBOJ0uX37y+co3q6UoRQg==
-----END PRIVATE KEY-----
"""
pubkey = RSA.import_key(pubkey)
prikey = RSA.import_key(prikey)
n = pubkey.n
def enc_replace(base64_str: str):
base64_str = base64_str.replace("/", "e5Lg^FM5EQYe5!yF&62%V$UG*B*RfQeM")
base64_str = base64_str.replace("+", "n6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8W")
return base64_str.replace("=", "JXWUDuLUgwRLKD9fD6&VY2aFeE&r@Ff2")
def encrypt(plain_text):
\# 私钥加密
cipher_text = b""
for i in range(0, len(plain_text), 128):
part = plain_text[i:i+128]
enc = libnum.n2s(pow(libnum.s2n(part), prikey.d, n))
cipher_text += enc
return enc_replace(base64.b64encode(cipher_text).decode())
if __name__ == '__main__':
m = b"-RSA-" * 30
print(f"原始数据: {m}")
c = encrypt(m)
print(f"加密数据: {c}")
仔细阅读代码,猜测其是一个加密脚本,原理是将输入的字符串进行base64,RSA和分段拆分操作完成加密。
结合上面所解密出来的操作流,不难猜测这一段应该是在对flag进行加密,那么此时只要继续在该步操作的前后文进行寻找,就可以找到flag的蛛丝马迹
意料之中。
结合上文找到的解密脚本,不难猜测加密后的flag就在这附近了
使用GPT获得解密脚本
在测试脚本能跑之后,使用脚本对附近的shell进行解密:
得到密文:
U2FsdGVkX1+SslS2BbHfe3c4/t/KxLaM6ZFlOdbtfMHnG8lepnhMnde40tNOYjSvoErLzy0csL7c5d4TlMntBQ==
看起来有点像base,但其实不是,这时候我们就要用到上文最开始解出的password了:
Password-based-encryption
其实到这一步理论上是已经拿到flag了,但不知道为什么随波逐流一直抽风,导致一开始AES没得到结果
导致走了不少弯路,到后面甚至开始胡思幻想是不是要以某种手段拆分密文:
卡了很久后决定转用在线解密,在巨大巨量n把在线梭后在一开始排除掉的AES处解出了flag…
所以为什么同样都是AES,有的能解有的不能啊