【工具开发】Python批量web存活探测脚本
2023-4-23 19:14:0 Author: xz.aliyun.com(查看原文) 阅读量:21 收藏

本文仅限于技术研究与讨论,严谨用于非法用途,否则产生的一切后果自行承担
未经作者许可禁止转载

在平时的渗透任务里,经常会给到的情况是:上面给了一批目标,这里面的目标有的已经已经下线无法访问。所以在任务开始前期,会先对目标进行存活探测,判断有哪些目标系统可以访问。虽然有现成的工具可以使用,但最近刚学了python就想尝试自己编写一个批量存活探测脚本(其实我就是想自己造轮子)。

Python3.9

. 从文件读取URL并进行去重处理
. 对提取的URL重新构造“http://”“https://”请求协议
. 发送请求,通过响应状态码来判断请求结果
. 将请求结果保存的新的文件中

requests模块,用来发送请求和获取请求结果

文件的读写操作

在实现效果里我们写到需要从文件中读取URL并进去重处理以及对后面的请求结果建立新的文件来进行存储

  1. 文件读取URL并进行去重处理
    def File_Control():
     urls = set()
     with open('url.txt', 'r', encoding='utf-8') as f:
         for line in f:
             url = line.strip('\n')
             url = url.replace('http://', '')
             url = url.replace('https://', '')
             urls.add(url)
     return list(urls)
    
    这里我们定义里一个File_Control()函数,在里面我们打开需要存有目标URL的文件url.txt。同时我们对提取到的数据进行处理,去除换行符以及‘http://’或‘https://’。在对提取的数据完成处理后,我们将其存放到urls这个变量中。同时我们将urls设置成一个集合set(),这样做的目的是利用集合的去重特性来完成我们的去重操作。
    有的读者可能会有疑问为什么我们要在去除‘http://’‘https://’后再进行去重,这里举个例子:
    假设url.txt中存放了下面两条数据

    http://www.exapmle.com
    https://www.exapmle.com

这两条url其实就是同一个web,如果目标数量不多的情况下出现这种情况其实还好处理,但是假如在批量任务中存在许多类似的情况,这样将会加大我们后期渗透的一个工作量,所以我们选择去除‘http://’‘https://’后再进行去重。

  1. 请求结果建立新的文件来进行存储
    def Result_File(filename, url):
     with open(filename, 'a+', encoding='utf-8') as f:
         f.write(url)
         f.write('\n')
    
    这里我们建立一个Result_File()函数,同时我们使用“filename, url)”来接收外部传入的参数:

    filename:接收要用来存放结果的文件地址
    url:接收请求后的url

同时对于文件的操作,我们使用'a+',这让我们可以看存放路径下有无对应文件,如果没有没有就先创建对应文件后再进行写操作,否则就直接在文件末行进行追加新的内容。

web存活探测

在进行存活探测的时候,我们需要对目标发送请求然后获取响应结果来判断是否存活。对于向目标发送请求,我们需要用到python的requests模块。在正式开始存活探测函数编写前,我们先来简单了解一下requests模块。

  1. requests模块的简单使用
    在开始前,我想请问一下用python把大象放进冰箱需要几个步骤?
    答案是:三步。打开冰箱>把大象放进冰箱>关上冰箱
    同样的,对于requests模块的使用也分为三步:导入模块>发送请求>获取响应
    # 导入模块
    import requests
    # 发送请求
    respone = requests.get('http://www.baidu.com')
    # 获取响应数据
    print(respone.status_code)
    
    上面代码中我们对requests模块进行了简单使用,我们先导入了requests模块,然后通过get方式进行请求,最后通过status_conde属性来获取响应状态码。当然respone不只有status_conde属性,还有一下几个常见属性:

    respone.text:响应体str类型
    respone.encoding:二进制转换字符使用的编码
    respone.content:响应体bytes类型

以上只是对requests模块的一个简单使用,如果想详细了解还请去看相关文章

  1. 存活函数的编写
    ```python
    import requests

def Check_Url(url):
req = "http://" + url
try:
respone = requests.get(req, timeout=5)
print(f"响应状态码:{respone.status_code} -----> {req}")

except requests.exceptions.RequestException as e:
    req = "https://" + url
    try:
        respone = requests.get(req, timeout=5)
        print(f"响应状态码:{respone.status_code} -----> {req}")

    except requests.exceptions.RequestException as e:
        print(f"请求失败: {url}, 错误信息: {e}")
return url, respone.status_code
在这里我们创建了Check_Url()函数,并通过url来接收外部传入的参数。
Check_Url()的执行流程是:我们对外部传入的url先以`"http://"`的方式去进行请求访问,如果可以访问成功则打印出响应状态码和url;否则就改用`"https://"`的方式去进行请求访问。要是两种方式都无法访问就打印请求失败的信息。
在这里可能大家会想使用if语句来实现这个流程,但是由于requests在无法获取响应式会出现报错,所以我们使用try语句来实现这个流程,当无法获取响应式就进入下一个流程直到抛出异常,
## 完整的代码
前面我们完成了这个脚本所需要的功能,现在我们将这些功能整合到一起
```python
from concurrent.futures import ThreadPoolExecutor, as_completed
import requests
from tqdm import tqdm


def File_Control():
    urls = set()
    with open('url.txt', 'r', encoding='utf-8') as f:
        for line in f:
            url = line.strip('\n')
            url = url.replace('http://', '')
            url = url.replace('https://', '')
            urls.add(url)
    return list(urls)


def Check_Url(url, client="http://"):
    req = client + url
    try:
        respone = requests.get(req, timeout=5)
        if 200 <= respone.status_code < 300:
            Result_File('200.txt', url)
        elif 300 <= respone.status_code < 400:
            Result_File('300.txt', url)
        elif 400 <= respone.status_code < 500:
            Result_File('400.txt', url)
        else:
            Result_File('500.txt', url)

    except requests.exceptions.RequestException as e:
        req = "https://" + url
        try:
            respone = requests.get(req, timeout=5)
            if 200 <= respone.status_code < 300:
                Result_File('200.txt', url)
            elif 300 <= respone.status_code < 400:
                Result_File('300.txt', url)
            elif 400 <= respone.status_code < 500:
                Result_File('400.txt', url)
            else:
                Result_File('500.txt', url)

        except requests.exceptions.RequestException as e:
            print(f"请求失败: {url}, 错误信息: {e}")
            return url, None
    return url, respone.status_code


def Result_File(filename, url):
    with open(filename, 'a+', encoding='utf-8') as f:
        f.write(url)
        f.write('\n')


def Threadings(urls):
    with ThreadPoolExecutor(max_workers=40) as executor:
        futures = [executor.submit(Check_Url, i) for i in urls]
        # print(type(urls), urls)
        for future in as_completed(futures):
            req_url, status = future.result()
            # print(f"req: {req_url}, status_code: {status}")


if __name__ == '__main__':
    urls = File_Control()
    for j in tqdm(range(0, len(urls), 40)):
        Threadings(urls=urls[j:j + 40])

上面就是用python实现的web批量存活探测的完整脚本,在这里我们还是使用到了concurrent.futures模块以及tqdm模块。其中我们通过concurrent.futures模块来创建了40个线程来提高脚本的运行速度,而tqdm则是一个进度条模块,可以让我直观的看到脚本的运行进度。

以上就是就是用python实现的web批量存活探测的一个思路过程,当然在这个过程中还有一些需要完善的地方,比如请求的方式不够严谨,在确认‘http://’为存活的情况下我们就没有在使用`‘https://’进行存活探测。又或者我们还可以让脚本以命令的方式来运行等等。。。


文章来源: https://xz.aliyun.com/t/12470
如有侵权请联系:admin#unsafe.sh