Python 实战:内网渗透中的信息收集自动化脚本(9)
主要解释通过python脚本来修改系统账户密码
·
用途限制声明,本文仅用于网络安全技术研究、教育与知识分享。文中涉及的渗透测试方法与工具,严禁用于未经授权的网络攻击、数据窃取或任何违法活动。任何因不当使用本文内容导致的法律后果,作者及发布平台不承担任何责任。渗透测试涉及复杂技术操作,可能对目标系统造成数据损坏、服务中断等风险。读者需充分评估技术能力与潜在后果,在合法合规前提下谨慎实践。
这次我们使用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() != 0
else: # Linux/Unix
return os.geteuid() == 0
except Exception as e:
logger.error(f"权限检查失败: {str(e)}")
return False
def _backup_user_info(self, username: str) -> None:
"""备份用户信息(用于回滚)"""
if not self.backup_enabled:
return
try:
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)
break
logger.info(f"已备份用户 {username} 信息")
except Exception as e:
logger.warning(f"备份用户 {username} 信息失败: {str(e)}")
def _match_user(self, username: str) -> bool:
"""判断用户是否符合修改条件(支持精确匹配和正则)"""
import re
for pattern in self.target_users:
if re.fullmatch(pattern, username): # 支持正则表达式匹配
return True
return False
def set_windows_password(self, username: str) -> bool:
"""Windows系统修改密码(优化错误处理)"""
try:
from win32com import adsi
from 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 True
except com_error as e:
error_msg = f"[Windows] 用户 {username} 密码修改失败: {e.excepinfo[2]}"
logger.error(error_msg)
return False
except Exception as e:
logger.error(f"[Windows] 处理用户 {username} 时发生未知错误: {str(e)}")
return False
def 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的安全风险,不启用shell
result = 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 True
else:
error_msg = result.stderr.decode(errors="ignore")
logger.error(f"[Linux] 用户 {username} 密码修改失败: {error_msg}")
return False
except Exception as e:
logger.error(f"[Linux] 处理用户 {username} 时发生未知错误: {str(e)}")
return False
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
w = wmi.WMI()
for user in w.Win32_UserAccount():
username = user.Name
if 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_name
if 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/Unix
return 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:
return
try:
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)
break
logger.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 re
for pattern in self.target_users:
if re.fullmatch(pattern, username): # 正则全匹配(如"dev_.*"匹配dev开头的用户)
return True
return 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 True
except com_error as e:
error_msg = f"[Windows] 用户 {username} 密码修改失败: {e.excepinfo[2]}"
logger.error(error_msg)
return False
except Exception as e:
logger.error(f"[Windows] 处理用户 {username} 时发生未知错误: {str(e)}")
return False
def 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 True
else:
error_msg = result.stderr.decode(errors="ignore")
logger.error(f"[Linux] 用户 {username} 密码修改失败: {error_msg}")
return False
except 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.Name
if 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_name
if 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脚本需要在管理员权限进行运行。
更多推荐



所有评论(0)