- 最常见的行为特征
- 总结常见恶意行为
- 了解要查找的恶意代码种类
11.1 下载器和启动器
- 下载器:从互联网下载其他恶意代码,在本地系统运行,通常与漏洞利用打包在一起
- URLDownloadtoFileA
- WinExec
- 启动器:可执行文件,用来安装立即运行或将来秘密执行的恶意代码
11.2 后门
- 攻击者能通过后门远程访问受害机器
- 通信方式:常用80端口使用http协议,能够与其他流量混淆
- 后门常见功能:操作注册表、列举窗口、创建目录、搜索文件…
- 确定后门功能:查看后门使用和导入的windows函数
- 反向shell
- 定义:从被感染机器上发起一个连接,提供攻击者Shell访问被感染机器的权限
- 被感染的机器连接攻击者,请求要执行的命令
- 在反向shell中,攻击者能够如同在本地系统上 一样执行命令
- Netcat反向shell
- 可以从两台机器上运行Netcat创建反向shell
- 攻击者控制端(远程机器)执行nc命令监听端口,等待入站连接:nc -l -p 或 nc -l (-l:监听模式)
- 被控端(受害机器)向外连出,并使用-e参数指定连接成功后运行的程序:nc
-e cmd.exe - 建立连接后自动运行cmd.exe,并将该程序的标准输入输 出与套接字绑定,从而达到远程shell的功能
- windows反向shell
- 基础方法
- 调用CreateProcess并操纵STARTUPINFO 结构
- 创建一个套接字连接到远程服务器
- 然后绑定套接字与cmd.exe标准流(标准输入、 标准输出以及标准错误)
- 调用CreateProcess以隐藏窗口的方式创建cmd.exe,对受害者隐藏该进程
- 多线程技术
- 创建一个套接字、两个管道(CreatePipe)以及两个线程(CreateThread)
- CreatePipe:绑定一个管道的读写端,如标准输入(stdin)和标准输出(stdout)
- CreateProcess:绑定一个管道和标准流,产生两个线程,一个用来从标准输入管道读数据,并且向套接字写数据;另一个从套接字读数据,并且向一个标准输出管道写数据。通常这两个线程使用数据编码来篡改数据,通常逆向解密。
- 基础方法
- 远程控制工具(RAT)
- 作用: 隐蔽地运行在受害主机上并使得攻击者能够远程访问和控制该主机的工具,用于远程管理一台或多台主机
- 网络结构
- 服务端:运行在植入恶意代码的受害主机上
- 客户端:攻击者远程操控运行命令和控制的单元
- 服务端向客户端发起一个连接,并受客户端控制
- 越来越多的RAT使用80、443等常用端口进行通信
- 实例:Poison Ivy
- 僵尸网络
- 僵尸网络是被感染主机(也称僵尸主机) 的一个集合,由单一实体控制
- 僵尸主机(Bot)
- 僵尸控制器(Botmaster)
- 目标:尽可能更多地感染机器,来构建更大的僵尸网络,通过传播其他恶意代码或者发起分布式拒绝攻击来获利
- RAT和僵尸网络的区别
- Botnet包含许多主机,RAT控制很少的主机
- 所有僵尸同时被控制,RAT一个一个的控制受害者
- RAT用于针对性攻击,Botnet用于大规模攻击
- 僵尸网络是被感染主机(也称僵尸主机) 的一个集合,由单一实体控制
11.3 登录凭证窃密器
- 攻击者经常使用三种类型的恶意代码来窃取用户登录凭证
- 等待用户登录并窃取登录凭证
- 转储已存数据
- 击键记录程序
- GINA拦截
- winxp中,恶意代码使用图形识别和验证界面拦截技术来窃取用户登录凭证
- 设计用于第三方自定义登录过程,如指纹、无线射频标 签(RFID)、智能卡登录等,也有一些软件可以指定加载 商家自己开发的GINA,从而提供不同的Windows的登录界面
- GINA在msgina.dll中实现,这个dll在用户登录系统过程中由Winlogon可执行文件加载,WinLogon 也加载第三方自定义DLL,在 WinLogon 与 GINA之间加载第三方DLL
- HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GinaDLL注册表项 中包含将被WinLogon加载的第三方DLL
- 拦截方法:
- 一种是针对“欢迎屏幕”登录方式的木马,它模拟了Windows的欢迎界面。当用户输入密码后,就被木马程序所获取,而用户却全然不知。
- 另一种是针对“登录对话框”的GINA木马,其原理是在登录时加载,以盗取用户的账号和密码。该木马会屏蔽系统以“欢迎屏幕”方式登录和“用户切 换”功能,也会屏 蔽“Ctrl-Alt-Delete”的安全登录提示
- 中间人攻击:
- 实例:恶意文件fsgina.dll安装到上述注册表位 置,实现中间人攻击,拦截提交给系统的所有登陆凭证并记录到硬盘或发送出去(winlogon.exe——>fsgina.dll——>msgina.dll)
- 特点:为充当中间人,恶意DLL必须导出所有 msgina.dll真实导出的函数,具体而言,它必须导出超过15个函数且大部分以Wlx为前缀。通过这些就能判定分析的dll是不是GINA拦截起
- 实例:
- 1:利用Call_msgina_dll_function函数将登录信息传递给msgina.dll,即动态解析调用msgina.dll中的WlxLoggedOutSAS
- 2:将登陆凭证记录到文件 %SystemRoot%\system32\drivers\tcpudp.sys中
- 口令哈希转储
- 获取到口令哈希后,可以进行离线暴力破解或者执行Pass-the-Hash攻击,在无需获得明文密码的情况下,使用LM或NTLM哈希来通过远程主机的身份验证,从而获得访问权。(Pwdump 和 Pass-the-Hash (PSH)工具包)
- pwdump
- 从安全账户管理器(SAM)输出本地用户账户的LM和NTLM口令哈希
- 通过注入DLL到本地安全认证子系统服务(LSASS)进程进行攻击
- DLL注入:恶意代码在另外一个进程中运行DLL的一种方法,提供了DLL与被注入进程相同的权限
- 口令哈希转储工具通常针对lsass.exe进程,它拥有足够权限来访问许多有用的API函数
- 标准pwdump程序使用的DLL是lsaext.dll,一旦DLL在lsass.exe中运行,pwdump就会调用lsaext.dl导出的GetHash函数,目的是获取口令哈希,GetHash函数使用未公开的Windows函数调用枚举系统中的用户并获得每个用户的口令哈希
- 注意:Pwdump默认的导出函数是GetHash,但攻击者可以 改变 GetHash 函数的名字
- 因为多数API函数需要动态解析,口令转储导出函数中通常会多次调用GetProcAddress
- pwdump变种
- 1、2:通过LoadLibrary获得库samsrv.dll和advapi.dll的句柄
- samsrv.dll:包含容易访问SAM的API(Samxxxx)
- advapi.dll:获得没有被lsass.exe导入的函数
- samsrv.dll:
- SamIConnect:连接SAM;
- SamrQueryInformationUser:获取用户信息;
- SamIGetPrivationData:取哈希;
- advapi.dll
- SystemFunction025和SystemFunction027,用于解密哈希
- 1、2:通过LoadLibrary获得库samsrv.dll和advapi.dll的句柄
- PSH工具包
- 包含转储哈希表的程序
- whosthere-alt:注入一个dll到lsass.exe来转储SAM
- 1:动态导入secur32.dll并使用LsaEnumerateLogonSessions获 取本地唯一标志代码清单(LUIDs)。该清单包含用户名以及 每个登录用户的域
- 2:使用GetModuleHandleA查找lsass.exe内存空间中的 msv1_0.dll,使用该dll中的一个未公开函数 NlpGetPrimaryCredential来获取登陆凭证
- 击键记录
- 恶意代码记录用户击键操作
- 基于内核的击键记录器
- 通常作为Rootkit的一部分
- 作为键盘驱动程序,绕过用户空间应用程序和保护
- 用户空间的击键记录器
- 使用Windows API
- 通过挂钩或轮询的方式实现
- 挂钩(Hooking)
- 使用SetWindowsHookEx函数实现,每当一个键被按下便通知恶意代码
- 轮询(Polling)
- 使用GetAsyncKeyState与GetForegroundWindow不断的轮询键的状态
- GetAsyncKeyState:识别一个按键是按下还是弹起状态(先判断大写锁定键 or shift键是否被按下)
- GetForegroundWindow:告诉击键记录器当前哪个应用程序正在执行输入
- 通过字符串列表识别击键记录器
- 通过查看恶意代码的导入API/检查字符串列表来识别击键记录器的功能
11.4 存活机制(持久化机制)
- 持久化机制足够特别甚至能作为给定恶意代码的指纹
- 修改windows注册表
- RUN键
- AppInit_DLL
- AppInit_DLL中的dll在进程加载User32.dll时被加载
- 这个注册表键包含一个由空格分隔的DLL列表
- 由于很多进程都会加载User32.dll, 因此很多进程也会加 载AppInit_DLL
- 在执行攻击载荷前,恶意代码会调用 DLLMain来检测它在 哪个进程中
- AppInit_DLL中的dll在进程加载User32.dll时被加载
- Winlogon Notify
- 恶意代码编写者可以挂钩一个特殊的Winlogon事件,如登录、注销、关机以及锁屏,等等。这 甚 至可以允许恶意代码在安全模式下加载。
- HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\中
- 当winlogon.exe 产生一个事件时,Windows系统会检查Notify注册表键 来查找处理这个事件的 DLL程序
- SvcHost.dll
- 恶意代码经常作为一个服务安装,安装的恶意代码作为svchost.exe的DLL来存活,这使得恶意代码 可以与其他进程混淆,且更像标准的服务。
- 每个svchost实例包含一组服务,分组定义在 HKEY_LOCAL_MACHINE\ SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost 中(每个值代表一个不同的组)
- 服务定义在 HKEY_LOCAL_MACHINE\System\CurrentControlSet\ Services\ServiceName 中
- 所有 svchost.exe 的DLL包含一个参数为 ServiceDLL 键值,恶意代码设置 ServiceDLL 为恶意DLL位置
- 恶意代码通常将自身添加到一个已经存在的组或者覆盖一个无关紧要的服务(经常是 netsvcs服务组中很少使用的服务)
- 要识别这种技术,使用动态分析监视注册 表或者在反汇编中查找CreateServiceA,看恶意代码是否修改了敏感的注册表键
- RUN键
- 特洛伊木马化(Trojanized)系统二进制文件
- 恶意代码能够修改系统二进制文件,当被感染的二进制文件下次运行或加载时,会强制运行恶意代码
- DLL是最常见的目标
- 感染方法
- 通常修改入口函数跳到恶意代码,这些恶意代码会被插入到二进制文件一段空节中,插入的代码通常用来加载恶意代码
- 加载恶意代码后,代码会跳转回原始的DLL程序
- 和一般dll不同之处:木马化版本的程序在入口处会跳转到其他位置 (ljmp 长跳转)
- 实例:
- 1:前一句执行pusha,保存寄存器初始状态
- pop ecx:将返回地址给ECX,因为之后紧接着call
- 3:字符串在前面pusheax入栈
- 2:前一句执行popa,恶意代码运行结束恢复寄存器状态,popa之后执行原始函数指令
- dll加载顺序劫持
- 让windows加载恶意dll
- Windows中加载DLL的默认搜索顺序如下:
- 加载应用程序的目录
- 当前目录
- 系统目录(使用GetSystemDirectory函数获取的 路径,如:…/Windows/System32)
- Windows目录(使用GetWindowsDirectory函数获 取的路径,如 :…/Windows)
- PATH环境变量里面列出的目录
- KnownDll注册表键可以跳过DLL的加载过程,保护一些特定的dll位置列表,通常位于../Windows/System32目录下
- DLL 加载顺序劫持条件
- 可以被System32之外目录中的二进制文件利用
- 劫持未被KnownDLL保护的DLL
- 举例:
- explorer.exe位于/Windows目录
- 需要从System32加载ntshrui.dll
- 但是ntshrui.dll 不是knownDLL
- 遵循默认搜索顺序,/Windows目录中一个恶意的ntshrui.dll 被加载,代替了System32目录中的 ntshrui.dll
- KnownDLL机制也不能得到充分保护,因为许多DLL加载其他DLL,递归导入并以默认搜索顺序加载
11.6 用户态的rootkit
- rootkit:对用户隐藏生存机制和正在运行进程,隐藏恶意代码行为。Rootkit是在安装目标上隐藏自身及指定的文件、进程和
网络链接等信息的技术,常与恶意代码配合使用。大部分rootkit通过修改操作系统内部工作来工作。 - 处理用户态rootkit的策略:先确定挂钩位置,然后找出挂钩干了什么。
- IAT Hook
- 方法:修改导入表(IAT)或者导出表(EAT),隐藏本地系统中的文件、进程以及网络连接。
- 过时,用inline hook代替
- 方法:修改导入表(IAT)或者导出表(EAT),隐藏本地系统中的文件、进程以及网络连接。
- Inline Hook
- 方法:覆盖导入DLL中API函数的代码来实现的,必须等到dll加载后才能执行(修改了实际的函数代码)
- 用一个跳转指令替换函数的开始代码来执行Inline Hook。通过硬编码的方式向内核API的内存空间(通常是开始的一段字节,且一般在第一个call之前)写入跳转语句,这样该API只要被调用,程序就会跳转到钩子函数。
- 找位置——>填充rootkit