本文仅限于技术研究与讨论,严谨用于非法用途,否则产生的一切后果自行承担
未经作者许可禁止转载
在平时的渗透任务里,经常会给到的情况是:上面给了一批目标,这里面的目标有的已经已经下线无法访问。所以在任务开始前期,会先对目标进行存活探测,判断有哪些目标系统可以访问。虽然有现成的工具可以使用,但最近刚学了python就想尝试自己编写一个批量存活探测脚本(其实我就是想自己造轮子)。
Python3.9
. 从文件读取URL并进行去重处理
. 对提取的URL重新构造“http://”
、“https://”
请求协议
. 发送请求,通过响应状态码来判断请求结果
. 将请求结果保存的新的文件中
requests模块,用来发送请求和获取请求结果
在实现效果里我们写到需要从文件中读取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)
‘http://’或‘https://’
。在对提取的数据完成处理后,我们将其存放到urls这个变量中。同时我们将urls设置成一个集合set(),这样做的目的是利用集合的去重特性来完成我们的去重操作。‘http://’
或‘https://’
后再进行去重,这里举个例子:
http://www.exapmle.com
https://www.exapmle.com
这两条url其实就是同一个web,如果目标数量不多的情况下出现这种情况其实还好处理,但是假如在批量任务中存在许多类似的情况,这样将会加大我们后期渗透的一个工作量,所以我们选择去除‘http://’
或‘https://’
后再进行去重。
def Result_File(filename, url): with open(filename, 'a+', encoding='utf-8') as f: f.write(url) f.write('\n')
filename:接收要用来存放结果的文件地址
url:接收请求后的url
同时对于文件的操作,我们使用'a+',这让我们可以看存放路径下有无对应文件,如果没有没有就先创建对应文件后再进行写操作,否则就直接在文件末行进行追加新的内容。
在进行存活探测的时候,我们需要对目标发送请求然后获取响应结果来判断是否存活。对于向目标发送请求,我们需要用到python的requests模块。在正式开始存活探测函数编写前,我们先来简单了解一下requests模块。
# 导入模块 import requests # 发送请求 respone = requests.get('http://www.baidu.com') # 获取响应数据 print(respone.status_code)
respone.text:响应体str类型
respone.encoding:二进制转换字符使用的编码
respone.content:响应体bytes类型
以上只是对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://’进行存活探测。又或者我们还可以让脚本以命令的方式来运行等等。。。