background

在某次内部赛中遇见的的题,我打了一天都没做出来。整场就一道web,给我整不会了,60人平台带不动,只能给两个环境题,一道web一道pwn,sb平台不能限制用户启动容器的数量,真tm无语……

题目简述

上来就是一个请输入用户名的页面,输入完成后跳转到商品页面。点击商品详情就显示“hello XXX,这件商品的价格是XXX”
点击buyflag提示money money money
抓包分析发现就是通过session来进行鉴权的,session不对就会跳转到一个页面
一开始不知道也没想那么多,jwt解了一下发现是hs256,扫了目录没发现私钥就直接和jwt杠上了,改none这些都没用,然后就执着的跑key,rockyou跑完了,各种常见字典都跑了,还生成了4位数所有密码的排列组合,都无效。

后面想到了hello**,于是才想起来考点可能在ssti(当时比赛的时候有师傅说这题是xss,没毛病,确实有xss,hhhhh),49,{77}都直接报错了。接下来就是常规操作,但是一直报错,给我整到怀疑人生了。
在报错页面我看到了部分源码的我发现了代码里面写的commodity.name,commodity.money这类的字眼,于是我{commodity.name},这样确实解析了。{commodity.name.__class__.__bases__}这样也ok了
2023-05-08T01:12:02.png
正当我以为要上高速的时候,又是报错,给我整到怀疑人生了。
{commodity.name.__class__.__bases__.__subclasses__()}
这其实是正常,因为format函数无法执行__subclasses__()这样的方法,所以这题也压根不能rce

我在想:这是啥环境{{"".__class__}}这种为啥都能报错?难道删掉了空字符串?不可能吧,他到底是怎么限制我的。

后面看了wp才知道过滤了{{{%,匹配到了就抛出异常,然后考点就是利用format格式化字符串的漏洞去打出flask的key,然后伪造jwt.以下是wp内容
2023-05-08T01:24:21.png
2023-05-08T01:33:07.png

format格式化字符串漏洞

这里属实是我知识盲区了,格式化字符串漏洞一直以为只有在pwn里才会有。这里先看一下python的格式化字符串方法,我知道的有三种

%格式化

这是Python中旧式的字符串格式化方式,它使用百分号字符作为占位符。例如,%s表示字符串占位符,%d表示整数占位符。

name = "w3lkin"
age = 18
print("My name is %s and I'm %d years old." % (name, age))

#my name is w3lkin and I'm 18 years old.

str.format()

这是Python 2.6引入的一种新式字符串格式化方法,它使用花括号{}来表示占位符。例如,{0}表示第一个参数,{1}表示第二个参数。

name = "w3lkin"
age = 18
print("My name is {} and I'm {} years old.".format(name, age))

#my name is w3lkin and I'm 18 years old.

不带数字默认按顺序填充,也可以使用数字来指定填充位置

name = "w3lkin"
age = 18
print("My name is {1} and I'm {0} years old.".format(name, age))

#My name is 18 and I'm w3lkin years old.

还可以使用参数的形式来填充

print("My name is {name} and I'm {age} years old.".format(name="w3lkin",age=18))

#my name is w3lkin and I'm 18 years old.

f-strings

这是Python 3.6引入的一种新式字符串格式化方法,它使用前缀f和花括号{}来表示占位符。例如,{name}表示名为name的变量。

name = "w3lkin"
age = 18
print(f"My name is {name} and I'm {age} years old.")

#My name is 18 and I'm w3lkin years old.

string.Template

使用标准库中的模板字符串类进行字符串格式化。

from string import Template
myname = 'w3lkin'
t = Template('Hey, $name!')
print(t.substitute(name=myname))

#Hey, w3lkin!

其中最安全的是f-strings方法