Skip to content

Instantly share code, notes, and snippets.

@leveryd
Last active August 19, 2021 09:27
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leveryd/334b719e253261ffd0abfd161e499ae7 to your computer and use it in GitHub Desktop.
Save leveryd/334b719e253261ffd0abfd161e499ae7 to your computer and use it in GitHub Desktop.
# coding:utf-8
""" 管理后台、未授权的管理后台 """
import unittest
from urllib2 import urlparse
from bs4 import BeautifulSoup
from bs4.element import Tag
from poc_common.utils import get_hostname_port_url
from poc_common.utils import c_requests as requests
from scripts.poc_common.misinformation import is_valid
info = {
"tag": u"web_poc,external_scan,sensitive_file,forbidden_internal_scan",
"script_desc": u"管理后台",
"fingerprint_query_condition": "service:http",
"vuln_version": "",
"vuln_level": "",
"vuln_type": "",
"big_alarmtype": u"应用漏洞",
"small_alarmtype": u"敏感信息泄漏"
}
def is_in_white_list(hostname, port, white_list):
"""
:param hostname:
:param port:
:param white_list:
:return:
"""
e = hostname + ":" + str(port)
if e in white_list:
return True
return False
def bad_location(location):
"""
跳转的location host是否在白名单中
:param location:
:return:
"""
domain_white_list = [
"open.weixin.qq.com"
]
host = urlparse.urlparse(location)[1]
if host in domain_white_list:
return False
return True
def poc(args):
"""
:param args:
:return:
"""
manage_word_list = ['admin', 'login', 'manage', 'manager', 'backend', 'monitor']
(domain, port, base_url) = get_hostname_port_url(args)
# 无法消除的误报、白名单
white_list = [
]
if is_in_white_list(domain, port, white_list):
return False
# 域名中包含关键词,直接当作后台管理系统
if any([i in domain for i in manage_word_list]):
return base_url
for suffix in ["/"]:
req_url = base_url + suffix
r = requests.get("{0}".format(req_url), allow_redirects=False)
if r.status_code in [301, 302]:
for keyword in manage_word_list:
if r.headers.get('Location', '').find(keyword) >= 0:
if not bad_location(r.headers.get('Location')):
continue
if is_valid(r):
return req_url
if r.status_code in [301, 302]:
r = requests.get("{0}".format(req_url))
if "<table>" in r.text and str(r.status_code).startswith("2"):
if is_valid(r):
return req_url
# vue框架写的cms
soup = BeautifulSoup(r.text, 'html.parser')
if soup.body is not None:
# https://www.cnblogs.com/yoyoketang/p/6931209.html
# descendants 孙节点, contents 字节点
tmp = list(soup.body.descendants)
tags = [i for i in tmp if isinstance(i, Tag)]
if len(tags) == 0:
return False
# body下所有的元素,只能有script/div/noscript标签,必须有script/div标签
if all([i.name in ["script", "div", "noscript"] for i in tags]):
if any([i.name == "script" for i in tags]) and any([i.name == "div" for i in tags]):
return req_url
return False
@leveryd
Copy link
Author

leveryd commented Jul 12, 2021

def is_valid(response):
    """
    敏感文件类探测专用,其他POC判断是否误报不要直接使用此函数

    1.判断是否误报,页面和404页面 页面结构、内容是否相同
        1. 响应和404页面响应内容完全相等时,误报
        2. 响应去除干扰因素后,和404页面响应内容完全相等时,误报
            去除响应中path部分
        3. 不稳定的报警
    2.响应如果为200,内容过短,则误报

    3.响应是403直接判定为误报
    4.响应命中关键词

    特殊场景:
    1. 访问404探测url时, xxx.com/x 每次访问同一个url时,会有类似时间戳之类的动态内容

    处理逻辑:
    1. 针对404 url发送两次探测包,形成规则xxxx{{dynamic}}yyyy,payload响应能匹配上规则,则判断成404页面 【暂不实现】
    2. 将报警的url第二次重放,和第一次响应完全相等时报警 【已实现】
    :param response: requests库的response对象
    :return:
    """
    global r

    # 存在30x跳转时
    if len(response.history) > 0:
        response = response.history[0]

    url = response.url
    r = custom_404(url)

    # 去除误报,403页面
    if str(response.status_code) == "403":
        return False

    if response.text == r.text:
        return False

    if int(r.status_code) == 999:
        return False

    if is_equal_response(response, r) is True:
        return False

    # 特殊case:去掉缓存,二次确认。
    # r_old = r
    r = None
    url = response.url
    r = custom_404(url)

    if is_equal_response(response, r) is True:
        return False

    # 404页面不稳定时,将报警的url第二次重放,和第一次响应完全相等时报警
    # if r_old.text == r.text:
    h = {
        "Cache-Control": "no-cache"
    }
    second_alarm_response = requests.get(url, headers=h)

    # 第二次发送请求和第一次发送请求可能不同,allow_redirects参数不同
    if response.status_code != second_alarm_response.status_code:
        pass
    elif response.text != second_alarm_response.text:
        return False

    if str(response.status_code) == "200" and len(response.text) <= 2:
        return False

    return True

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment