Metadata-Version: 2.4
Name: exploit_utils
Version: 0.1.0
Summary: template code for exp
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fake-useragent>=2.2.0
Requires-Dist: pycryptodome>=3.23.0
Requires-Dist: tqdm>=4.67.1
Dynamic: license-file

# Exploit Utils

本项目的目标是封装编写 exp 时的样板代码, 加快 exp 的开发

功能主要通过实战进行积累, 会选取比较常用到的

作者主要进行 web 漏洞复现与编写批量攻击脚本, 受作者工作习惯影响, 可能有些本应包含的功能没有被封装

另外, 本项目引入的库可能过时, 本着能用就行的原则, 本项目可能不会使用最新的技术

> [!important]
> 
> 该项目针对 python3.12+ 版本设计，所以使用了 3.12 版本才引入的特性
>
> 依赖该库的 exp 需要在 python3.12+ 下运行

# 安装

使用 pip 安装

```sh
pip install exploit_utils
```

# 功能介绍

本项目各种功能设计得很"散装", 目的是让使用者能负担较小地替换某些模块

|文件|功能|
|--|--|
|args.py|命令行参数的相关功能|
|crypto.py|md5/sha1/aes 等常见加密方式的加解密操作|
|encode.py|base64/url/html 等常见编码的编解码操作|
|fs.py|封装了对于文件系统的操作|
|http.py|网络请求的相关功能|
|log.py|封装了日志相关的操作|
|misc.py|一些杂项|
|mt.py|封装了多线程有关的功能|
|rand.py|与"随机"相关的功能|
|sh.py|封装了执行系统命令相关的操作|

接下来介绍几个我认为能够明显提升开发效率的功能

## 配置命令行参数

每次写脚本时都要写一堆类似的样板代码:

```python
import argparse

parser = argparse.ArgumentParser()

# 几乎每个 exp 都会有的选项...
parser.add_argument("--url", "-u", help="目标 URL")
parser.add_argument("--file", "-f", help="从文件批量获取 URL")
parser.add_argument("--threads", "-t", type=int, default=5, help="线程数")
parser.add_argument("--output", "-o", help="输出文件")
parser.add_argument("--debug", action="store_true", help="开启 Debug 模式")

args = parser.parse_args()
```

现在你只需要:

```python
# step1. 引入 exploit_utils
import exploit_utils as exp

# step2. 使用 args 模块获取 Parser
parser = exp.args.Parser()

# step3. 使用预设, 一键配置常用选项
parser.load_args(exp.args.BASIC_PRESET + [exp.args.DEBUG])

# step4. 对于预设以外的自定义选项, 用原有的方式添加即可
parser.add_argument("--foo", action="store_true", help="foo")

# step5. 解析时也是使用原有方式
args = parser.parse_args()
```

你可以对 args 模块提供的选项进行细节上的修改

```python
import exploit_utils as exp

# 在预设的 --url 选项基础上添加 required=True 的属性, 以及修改 help 内容
url_option = exp.args.URL({"required": True, "help": "自定义的 url 选项"})

parser = exp.args.Parser()
parser.load_args([url_option])
```

## 创建多线程任务

经典多线程样板代码，从文件中读取 url 并创建 5 个线程进行攻击

```python
import threading
import queue

task_queue: queue.Queue[str] = queue.Queue()

def attack(url: str) -> None:
    ...

def task() -> None:
    while not task_queue.empty():
        url = task_queue.get()
        attak(url)

with open("urls.txt", "r", encoding="utf-8") as file:
    for url in file.readlines()
        task_queue.put(url.strip())

threads: list[threading.Thread] = []
for _ in range(5):
    t = threading.Thread(task)
    t.start()
    threads.append(t)
for t in threads:
    t.join()
```

python 提供了线程池，可以大大简化代码

```python
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import wait

def attack(url: str) -> None:
    ...

with open("urls.txt", "r", encoding="utf-8") as file:
    urls = [i.strip() for i in file.readlines()]

with ThreadPoolExecutor(max_worker=5) as pool:
    wait([pool.submit(attack, url) for url in urls])
```

现在你只需要:

```python
import exploit_utils as exp

def attack(url: str) -> None:
    ...

# 这条代码的作用见 "快速获取来自文件的输入"
urls: list[str] = exp.fs.parse_lines("urls.txt")

with exp.mt.ThreadPool(max_workers=5) as pool:
    exp.mt.wait([pool.submit(task, url) for url in urls])
    # 或者:
    # exp.mt.handle_fs([pool.submit(task, url) for url in urls])
```

## 获取来自文件的输入

写 exp 时经常有很多 `with open()... readlines()` 等重复代码

```python
with open("urls.txt", "r", encoding="utf-8") as file:
    for url in file.readlines():
        if url.strip():
            task_queue.put(url.strip())
```

现在你可以使用下面的方式快速获得来自文件的输入

```python
# step1. 引入 exploit_utils
import exploit_utils as exp

# step2. 直接使用封装好的函数
# 自动处理空行, 自动删除行尾换行符
for url in exp.fs.parse_lines("urls.txt"):
    task_queue.put(url)
```

`parse_lines` 能使用用户提供的 callback 自动处理数据, 例如

```python
def handler(data: str) -> str:
    if data[-1] != "/":
        data += "/"
    return data

urls: list[str] = exp.fs.parse_lines("urls.txt", parser=handler)
```

## 几乎免配置的实时日志系统

对 logging 进行了封装，现在能像 loguru 那样几乎不需要配置

原本要实现一个同时将日志输出到控制台和文件的 logger 要写非常多的样板代码

```python
import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

formatter = logging.Formatter("[%(levelname)s] %(message)s")

# 添加控制台输出
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)

# 添加文件输出
file_handler = logging.FileHandler("output.log")
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
```

现在你只需要:

```python
# step1. 引入 exploit_utils
import exploit_utils as exp

# step2. 通过 log 模块获取 logger
logger = exp.log.get_logger()

# step3. 使用 log 模块提供的方法一键添加输出文件
exp.log.add_outputfile("output.log")

# logger 自动拥有 ok 方法, 可以输出 SUCCESS 级别的日志
logger.ok("you did it!")
```

该日志系统是与 tqdm 兼容的, 无需额外代码即可与 tqdm 配合

```python
import exploit_utils as exp
import tqdm
import time

logger = exp.log.get_logger()

for i in tqdm.tqdm(range(100)):
    if i % 10 == 0:
        logger.info(f"{i=}")
    time.sleep(0.1)
```

## 自动获取常用 HTTP 配置支持

编写 exp 时经常需要使用随机 ua，也经常要对请求配置超时时间，以及忽略 SSL 证书

为了关闭警告我们还要引入 urllib3

于是一个简单的请求就变成了:

```python
import requests
import urllib3
from fake_useragent import UserAgent

# 禁用警告
urllib3.disable_warnings(urllib3.exceptions.HTTPWarning)

ua = UserAgent()
http = requests.Session()

http.get(
    url="http://example.com",
    # 随机 UA
    headers={"User-Agent": ua.random},
    # 设置超时
    timeout=5,
    # 忽略 SSL 证书
    verify=False,
)
```

现在你只需要:

```python
# step1. 引入 exploit_utils
import exploit_utils as exp

# step2. 通过 http 模块获取 session
http = exp.http.get_session()

# step3. 直接使用 http 模块提供的方法一键关闭警告
exp.http.no_warn()

# step4. 使用 session 发起请求
# 该请求自动获得随机 UA、5s超时时间、忽略 SSL 证书
http.get("http://example.com")
```

## 生成随机字符串

编写 exp 时经常会遇到需要生成指定长度的随机字符串的情景，例如生成 session id

```python
import random
import string

sessid = random.choices(string.ascii_letters, k=16)
```

现在你只需要:

```python
import exploit_utils as exp

# 随机单词 (由大小写字母组成), 长度为 16
a = exp.rand.rand_word(16)

# 随机 16 进制数字, 长度为 10
b = exp.rand.rand_digits(10, base=16)

# 如果你想让长度也随机化, 使用一个元组指定长度的上下界
# 随机单词, 长度为 1~3
c = exp.rand.rand_word((1, 3))
```

## 集成 log 的文件服务器

部分漏洞利用需要配合远程服务器提供的恶意文件

如 XXE 漏洞的 dtd 文件, 又如 curl 反弹 shell 的 sh 文件

使用 fs 模块中的 `FileServer` 类可以快速启动一个文件服务器

```python
import exploit_utils as exp

def attack(url: str) -> None:
    ...

# 在 0.0.0.0:5000 启动文件服务器
# 其根目录为脚本所在目录下的 files 文件夹
with exp.fs.FileServer("0.0.0.0", 5000, exp.fs.rget("files")):
    attack("http://example.com")
```

该文件服务器会使用 log 模块打印日志

当日志级别为 `INFO` 时会输出启动和停止消息

当日志级别为 `DEBUG` 时会输出所有连接信息

# 其他

## 使用建议

1. 将本项目的源码在 `exploit_utils` 文件夹, 可以提供给 AI 助手以帮助其生成代码  
如有必要, 可以将本项目的 `examples` 文件夹提供给 AI 助手以优化输出

2. 虽然怎样组织代码是您的自由, 但我还是建议编写 exp 时尽量使用类型注解

## 免责声明

本工具仅限于合法授权的场景中使用, 使用者在借助本工具编写漏洞利用脚本时, 需严格遵守当地法律法规
