Python 实战:内网渗透中的信息收集自动化脚本(9)
用途限制声明,本文仅用于网络安全技术研究、教育与知识分享。文中涉及的渗透测试方法与工具,严禁用于未经授权的网络攻击、数据窃取或任何违法活动。任何因不当使用本文内容导致的法律后果,作者及发布平台不承担任何责任。渗透测试涉及复杂技术操作,可能对目标系统造成数据损坏、服务中断等风险。读者需充分评估技术能力与潜在后果,在合法合规前提下谨慎实践。
这次我们使用python来编写一个跨平台的批量用户密码修改工具,支持 Windows 和 Linux 系统。它能够根据配置批量修改符合条件的用户密码,同时具备权限检查、用户信息备份、操作日志记录和模拟运行(不实际修改密码)等功能,适用于系统管理员批量管理用户密码的场景。
import platform
import logging
import subprocess
import ctypes
import os
from typing import List, Dict, Optional# 配置日志:记录操作详情(成功/失败/时间),支持文件和控制台输出
logging.basicConfig(level=logging.INFO,format="%(asctime)s - %(levelname)s - %(message)s",handlers=[logging.FileHandler("password_change.log"), # 日志文件备份logging.StreamHandler() # 控制台输出]
)
logger = logging.getLogger(__name__)class PasswordChanger:def __init__(self, config: Dict):"""初始化配置参数"""self.target_users = config.get("target_users", []) # 目标用户列表(支持正则)self.new_password = config.get("new_password") # 新密码self.backup_enabled = config.get("backup_enabled", True) # 是否备份用户信息self.dry_run = config.get("dry_run", False) # 模拟运行(不实际修改)self._validate_config() # 校验配置合法性def _validate_config(self) -> None:"""校验配置参数合法性"""if not self.target_users:raise ValueError("目标用户列表不能为空,请配置target_users")if not self.new_password:raise ValueError("新密码不能为空,请配置new_password")if len(self.new_password) < 8:logger.warning("密码长度小于8位,可能不符合安全策略")def _is_admin(self) -> bool:"""检查当前用户是否有管理员/root权限(修改密码必需)"""try:if platform.system() == "Windows":return ctypes.windll.shell32.IsUserAnAdmin() != 0else: # Linux/Unixreturn os.geteuid() == 0except Exception as e:logger.error(f"权限检查失败: {str(e)}")return Falsedef _backup_user_info(self, username: str) -> None:"""备份用户信息(用于回滚)"""if not self.backup_enabled:returntry:if platform.system() == "Windows":# Windows: 备份用户基本信息到文件with open(f"user_backup_{username}.txt", "w") as f:f.write(f"Backup for {username} at {platform.system()}\n")# 可扩展:通过WMI获取更多用户属性(如SID、创建时间等)else:# Linux: 备份/etc/shadow中该用户的记录with open("/etc/shadow", "r") as shadow, \open(f"shadow_backup_{username}.txt", "w") as f:for line in shadow:if line.startswith(f"{username}:"):f.write(line)breaklogger.info(f"已备份用户 {username} 信息")except Exception as e:logger.warning(f"备份用户 {username} 信息失败: {str(e)}")def _match_user(self, username: str) -> bool:"""判断用户是否符合修改条件(支持精确匹配和正则)"""import refor pattern in self.target_users:if re.fullmatch(pattern, username): # 支持正则表达式匹配return Truereturn Falsedef set_windows_password(self, username: str) -> bool:"""Windows系统修改密码(优化错误处理)"""try:from win32com import adsifrom pywintypes import com_error # 捕获ADSI相关异常ads_path = f"WinNT://localhost/{username},user"ads_obj = adsi.ADsGetObject(ads_path)ads_obj.Getinfo()if not self.dry_run:ads_obj.SetPassword(self.new_password)logger.info(f"[Windows] 用户 {username} 密码修改成功({'模拟' if self.dry_run else '实际'}操作)")return Trueexcept com_error as e:error_msg = f"[Windows] 用户 {username} 密码修改失败: {e.excepinfo[2]}"logger.error(error_msg)return Falseexcept Exception as e:logger.error(f"[Windows] 处理用户 {username} 时发生未知错误: {str(e)}")return Falsedef set_linux_password(self, username: str) -> bool:"""Linux系统修改密码(使用subprocess增强安全性,避免shell注入)"""try:# 构造密码输入(两次输入新密码)input_data = f"{self.new_password}\n{self.new_password}\n".encode()# 使用subprocess避免os.system的安全风险,不启用shellresult = subprocess.run(["passwd", username], # 命令参数列表化,防止注入input=input_data,stdout=subprocess.PIPE,stderr=subprocess.PIPE,text=False # 二进制输入输出)if result.returncode == 0:logger.info(f"[Linux] 用户 {username} 密码修改成功({'模拟' if self.dry_run else '实际'}操作)")return Trueelse:error_msg = result.stderr.decode(errors="ignore")logger.error(f"[Linux] 用户 {username} 密码修改失败: {error_msg}")return Falseexcept Exception as e:logger.error(f"[Linux] 处理用户 {username} 时发生未知错误: {str(e)}")return Falsedef run(self) -> None:"""主执行逻辑"""# 权限检查if not self._is_admin():logger.error("错误:修改用户密码需要管理员/root权限,请以管理员身份运行")return# 按系统类型处理if platform.system() == "Windows":self._process_windows_users()else:self._process_linux_users()def _process_windows_users(self) -> None:"""处理Windows用户"""try:import wmiw = wmi.WMI()for user in w.Win32_UserAccount():username = user.Nameif self._match_user(username):logger.info(f"发现符合条件的用户: {username}")self._backup_user_info(username)self.set_windows_password(username)except ImportError:logger.error("处理Windows用户失败:请安装wmi模块(pip install wmi)")except Exception as e:logger.error(f"Windows用户处理逻辑出错: {str(e)}")def _process_linux_users(self) -> None:"""处理Linux用户(优化用户筛选逻辑)"""try:import pwd# 筛选有效用户(排除系统用户,可配置uid范围)min_uid = 1000 # 普通用户起始UID(可配置)for p in pwd.getpwall():if p.pw_uid == 0 or (p.pw_uid >= min_uid and p.pw_uid < 65534):username = p.pwd_nameif self._match_user(username):logger.info(f"发现符合条件的用户: {username}")self._backup_user_info(username)self.set_linux_password(username)except Exception as e:logger.error(f"Linux用户处理逻辑出错: {str(e)}")if __name__ == "__main__":# 配置示例(可迁移到外部配置文件,如JSON/YAML)config = {"target_users": ["testuser", "user1", "dev_.*"], # 支持正则(如匹配dev_开头的用户)"new_password": "StrongPass@2024", # 强密码(实际使用中建议从环境变量读取)"backup_enabled": True, # 启用备份"dry_run": False # 设为True可先模拟运行,不实际修改密码}try:changer = PasswordChanger(config)changer.run()except Exception as e:logger.critical(f"程序执行失败: {str(e)}", exc_info=True)
1. 导入模块与日志配置
import platform # 判断操作系统类型
import logging # 日志记录
import subprocess # 执行系统命令(如Linux的passwd)
import ctypes # Windows权限检查
import os # 系统操作(如文件、权限)
from typing import List, Dict, Optional # 类型提示,增强代码可读性# 配置日志:同时输出到文件和控制台,记录操作时间、级别和内容
logging.basicConfig(level=logging.INFO,format="%(asctime)s - %(levelname)s - %(message)s",handlers=[logging.FileHandler("password_change.log"), # 日志保存到文件logging.StreamHandler() # 日志打印到控制台]
)
logger = logging.getLogger(__name__) # 创建日志实例
- 导入的模块覆盖了跨平台判断、日志、系统命令执行等核心需求。
- 日志配置确保所有操作(成功 / 失败 / 时间)都被记录,方便后续审计和问题排查。
2. 核心类 PasswordChanger
该类封装了密码修改的所有逻辑,通过配置参数初始化,支持灵活定制。
2.1 初始化与配置校验
class PasswordChanger:def __init__(self, config: Dict):"""初始化配置参数"""self.target_users = config.get("target_users", []) # 目标用户列表(支持正则)self.new_password = config.get("new_password") # 新密码self.backup_enabled = config.get("backup_enabled", True) # 是否备份用户信息self.dry_run = config.get("dry_run", False) # 模拟运行(不实际修改)self._validate_config() # 校验配置合法性def _validate_config(self) -> None:"""校验配置参数合法性"""if not self.target_users:raise ValueError("目标用户列表不能为空,请配置target_users")if not self.new_password:raise ValueError("新密码不能为空,请配置new_password")if len(self.new_password) < 8:logger.warning("密码长度小于8位,可能不符合安全策略")
__init__
从配置中读取核心参数:目标用户、新密码、备份开关、模拟运行开关。_validate_config
确保配置合法:必须指定目标用户和新密码,同时警告短密码(可能不符合安全策略)。
2.2 权限检查
def _is_admin(self) -> bool:"""检查当前用户是否有管理员/root权限(修改密码必需)"""try:if platform.system() == "Windows":return ctypes.windll.shell32.IsUserAnAdmin() != 0 # Windows管理员判断else: # Linux/Unixreturn os.geteuid() == 0 # root用户判断(euid=0)except Exception as e:logger.error(f"权限检查失败: {str(e)}")return False
- 修改用户密码需要高权限(Windows 管理员 / Linux root),该方法提前检查权限,避免后续操作失败。
2.3 用户信息备份
def _backup_user_info(self, username: str) -> None:"""备份用户信息(用于回滚)"""if not self.backup_enabled:returntry:if platform.system() == "Windows":# Windows:备份用户基本信息到文本文件with open(f"user_backup_{username}.txt", "w") as f:f.write(f"Backup for {username} at {platform.system()}\n")# 可扩展:通过WMI获取更多属性(如SID、创建时间)else:# Linux:备份/etc/shadow中该用户的密码记录(用于密码回滚)with open("/etc/shadow", "r") as shadow, \open(f"shadow_backup_{username}.txt", "w") as f:for line in shadow:if line.startswith(f"{username}:"):f.write(line)breaklogger.info(f"已备份用户 {username} 信息")except Exception as e:logger.warning(f"备份用户 {username} 信息失败: {str(e)}")
- 开启备份时,会保存用户关键信息(Linux 的
/etc/shadow
记录包含密码哈希,Windows 保存基本信息),便于密码修改出错时回滚。
2.4 用户匹配逻辑
def _match_user(self, username: str) -> bool:"""判断用户是否符合修改条件(支持精确匹配和正则)"""import refor pattern in self.target_users:if re.fullmatch(pattern, username): # 正则全匹配(如"dev_.*"匹配dev开头的用户)return Truereturn False
- 支持通过正则表达式匹配用户(如配置
["dev_.*"]
可匹配所有dev_
开头的用户),灵活筛选目标用户。
2.5 密码修改实现(分系统)
def set_windows_password(self, username: str) -> bool:"""Windows系统修改密码"""try:from win32com import adsi # 操作Windows AD服务接口from pywintypes import com_error # 捕获ADSI相关异常ads_path = f"WinNT://localhost/{username},user" # 用户ADSI路径ads_obj = adsi.ADsGetObject(ads_path)ads_obj.Getinfo()if not self.dry_run: # 非模拟运行时才实际修改ads_obj.SetPassword(self.new_password)logger.info(f"[Windows] 用户 {username} 密码修改成功({'模拟' if self.dry_run else '实际'}操作)")return Trueexcept com_error as e:error_msg = f"[Windows] 用户 {username} 密码修改失败: {e.excepinfo[2]}"logger.error(error_msg)return Falseexcept Exception as e:logger.error(f"[Windows] 处理用户 {username} 时发生未知错误: {str(e)}")return Falsedef set_linux_password(self, username: str) -> bool:"""Linux系统修改密码(避免shell注入风险)"""try:# 构造密码输入(passwd命令需要两次输入新密码)input_data = f"{self.new_password}\n{self.new_password}\n".encode()# 使用subprocess调用passwd,参数列表化(防止shell注入)result = subprocess.run(["passwd", username], # 命令参数拆分,避免注入input=input_data,stdout=subprocess.PIPE,stderr=subprocess.PIPE,text=False # 二进制输入输出)if result.returncode == 0: # 命令执行成功(返回码0)logger.info(f"[Linux] 用户 {username} 密码修改成功({'模拟' if self.dry_run else '实际'}操作)")return Trueelse:error_msg = result.stderr.decode(errors="ignore")logger.error(f"[Linux] 用户 {username} 密码修改失败: {error_msg}")return Falseexcept Exception as e:logger.error(f"[Linux] 处理用户 {username} 时发生未知错误: {str(e)}")return False
- Windows:通过
win32com.adsi
操作 Windows 用户对象,调用SetPassword
修改密码。 - Linux:通过
subprocess
调用系统passwd
命令,参数列表化避免 shell 注入风险(安全最佳实践)。 - 均支持
dry_run
(模拟运行):仅日志记录,不实际修改密码,方便测试。
2.6 主执行逻辑
def run(self) -> None:"""主执行逻辑"""# 权限检查:无权限则退出if not self._is_admin():logger.error("错误:修改用户密码需要管理员/root权限,请以管理员身份运行")return# 按系统类型处理用户if platform.system() == "Windows":self._process_windows_users()else:self._process_linux_users()def _process_windows_users(self) -> None:"""处理Windows用户:获取所有用户,筛选并修改密码"""try:import wmi # Windows管理接口,用于获取用户列表w = wmi.WMI()for user in w.Win32_UserAccount(): # 遍历所有本地用户username = user.Nameif self._match_user(username): # 匹配目标用户logger.info(f"发现符合条件的用户: {username}")self._backup_user_info(username) # 备份信息self.set_windows_password(username) # 修改密码except ImportError:logger.error("处理Windows用户失败:请安装wmi模块(pip install wmi)")except Exception as e:logger.error(f"Windows用户处理逻辑出错: {str(e)}")def _process_linux_users(self) -> None:"""处理Linux用户:筛选普通用户,修改密码"""try:import pwd # Linux用户信息模块min_uid = 1000 # 普通用户起始UID(排除系统用户,如root是0)for p in pwd.getpwall(): # 遍历所有用户# 筛选有效用户:root(uid=0)或普通用户(uid 1000-65533)if p.pw_uid == 0 or (p.pw_uid >= min_uid and p.pw_uid < 65534):username = p.pwd_nameif self._match_user(username): # 匹配目标用户logger.info(f"发现符合条件的用户: {username}")self._backup_user_info(username) # 备份信息self.set_linux_password(username) # 修改密码except Exception as e:logger.error(f"Linux用户处理逻辑出错: {str(e)}")
run
:主入口,先检查权限,再根据操作系统调用对应处理方法。_process_windows_users
:通过wmi
模块获取 Windows 本地用户,筛选符合条件的用户并执行备份和密码修改。_process_linux_users
:通过pwd
模块获取 Linux 用户,排除系统用户(保留 root 和普通用户),再执行后续操作。
3. 主程序入口
if __name__ == "__main__":# 配置示例(可迁移到外部配置文件,如JSON/YAML)config = {"target_users": ["testuser", "user1", "dev_.*"], # 目标用户(支持正则)"new_password": "StrongPass@2024", # 新密码(建议从环境变量读取,避免硬编码)"backup_enabled": True, # 启用备份"dry_run": False # 模拟运行开关(True:不实际修改)}try:changer = PasswordChanger(config)changer.run()except Exception as e:logger.critical(f"程序执行失败: {str(e)}", exc_info=True) # 记录致命错误及堆栈
- 定义配置示例,创建
PasswordChanger
实例并执行密码修改流程。 - 捕获全局异常,确保程序崩溃时记录详细错误信息(便于排查)。
提示:此python脚本需要在管理员权限进行运行。