代码注入技术之Shellcode注入
2019-11-29 12:29:06 Author: www.4hou.com(查看原文) 阅读量:201 收藏

代码注入是指在应用程序中注入任意外部代码的行为,有两种类型的代码注入:

1.注入易受攻击的程序;

2.注入不易受攻击的程序;

如果代码注入是在易受攻击的应用程序中完成的,则可以通过利用在处理无效数据时发生的漏洞来实现。在这种情况下,代码注入的程度就取决于应用程序中的错误,我们也将其称为“漏洞”。但问题在于,应用程序应该具有可以被利用来获得代码执行的漏洞。

本系列针对第二种情况,即不希望或不需要该应用程序具有漏洞。正如所预料的那样,这为应用程序提供了一个非常广泛的领域,同时也为滥用操作系统提供了机会。

恶意软件通常使用此方法,因为执行代码注入之前不需要满足任何条件,并且操作系统本身也完全支持该方法。所有主要的操作系统都提供ABI和API,以与其他进程进行交互,控制它们后,在其他程序的进程空间中读写内存。

通过CreateRemoteThread API进行代码注入

CreateRemoteThread是Win32 API提供的用于在另一个进程中创建线程的函数。在另一个应用程序中创建线程之前,必须满足两个条件:

1.试图在另一个进程中创建线程的进程必须具有创建线程的权限,简单地说,这意味着与受害进程(目标是指我们要在其中创建线程的进程)具有相同或更高的权限。

2.两个进程(目标进程和攻击者进程)必须驻留在同一个会话中,如果会话标识符不匹配,将不会创建线程。

如果上述任何一个条件不满足,则操作系统本身将拒绝代码注入过程。

但这不并是Windows OS体系结构中的安全漏洞,而是由操作系统提供的功能。由于我们无法修改具有比我们更高的权限的进程,因此不会跨越安全边界。

算法

为了通过CreateRemoteThread API实现代码注入,我们必须遵循以下算法:

1.选择一个进程作为受害者进程;

2.使用带有参数PROCESS_ALL_ACCESS的OpenProcess函数获得对进程的访问权限,以便能够执行所需的操作;

3.如果OpenProcess失败,请退出;

4.使用VirtualAllocEx函数在受害者进程的进程空间中分配内存;

5.如果VirtualAllocEx失败,请退出;

6.将shellcode写入VirtualAllocEx分配的内存位置;

7.如果Shellcode写入失败或只有部分写入Shellcode,请退出;

8.编写完shellcode后,请使用必要的参数调用CreateRemoteThread,将shellcode的地址指向LPTHREAD_START_ROUTINE。

运行环境

就本文的示例而言,必须具备以下环境设置:

1.Visual Studio 2019;

2.Windows 10 RS6(x64);

注意:可以从我的github存储库访问代码。

代码注入

访问远程进程

要对任何进程执行内存操作,我们必须能够访问它。可以使用函数OpenProcess来获得它,该函数的原型为:

1.png

它包含三个参数:

1.dwDesiredAccess:它根据受害者进程的安全令牌进行检查,不过你可以指定一些所需的访问值,但是指定PROCESS_ALL_ACCESS包含该进程的所有可能的访问权限。

2.bInheritHandle:这是一个布尔值,指示该进程创建的进程是否将继承此句柄。

3.dwProcessId:这是受害者进程的进程标识符;

这个进程返回其他进程的句柄(成功时),其他API函数可以使用它来操作受害进程的内存。如果失败,则返回NULL。

为Shellcode分配空间

一旦获得了受害进程的句柄,我们就可以在受害进程内存中为shell代码分配空间,这是通过使用VirtualAllocEx API调用实现的。

VirtualAllocEx的原型为:

2.png

它包含五个参数:

1.hProcess:处理要在其中分配内存的进程;

2.lpAddress:指向受害者进程内存中指定地址的指针,如果将参数指定为NULL,则该函数自动选择要分配给的内存页;

3.dwSize:要分配的内存区域的大小,它是以字节为单位指定的。

4.flAllocationType:指定要分配的内存类型,该参数必须包含以下三个值之一:MEM_COMMIT,MEM_RESERVE,MEM_RESET,MEM_RESET_UNDO。

5.flProtect:指定分配的内存保护。出于我们的目的,由于它将包含要执行的代码,并且希望其具有可读性和可写性,因此将其设置为PAGE_EXECUTE_READWRITE。

该函数在成功时返回分配的基地址,而在失败时返回NULL。至此,我们已经成功地在受害进程中分配了可执行内存。

在远程进程中编写Shellcode

现在,我们需要在分配的区域中编写我们的shellcode。为此,我们有一个称为WriteProcessMemory的函数。

WriteProcessMemory是一种由调用者将数据写入指定进程的内存区域的函数,需要注意的是,整个内存区域必须是可写的,否则该函数将会失败,这就是为什么我们将内存分配为可写的,以及可读和可执行的原因。

WriteProcessMemory的原型为:

3.png

WriteProcessMemory具有五个参数:

1.hProcess:处理要向其中写入数据的进程;

2.lpBaseAddress:我们要在其中写入数据的地址(以指针的形式);

3.lpBuffer:指向必须写入的数据的指针,该指针必须是const指针。

4.nSize:必须写入的数据量(以字节为单位);

5.* lpNumberOfBytesWritten:指向SIZE_T的指针,该指针将存储在该目标中写入的字节数。

如果函数由于某种原因而失败,它将返回false;如果成功,则将返回true。

至此,所有设置都已准备就绪,只需要在远程进程中创建一个线程并运行它即可。

执行shellcode

为了在远程进程中创建线程,我们使用Win32 API提供的函数CreateRemoteThread。

1.CreateRemoteThread是一个用于创建在另一个进程的虚拟空间中运行的线程的函数。 2.CreateRemoteThread提供的功能有限,并且可以访问可以为线程指定的扩展属性,可以使用CreateRemoteThreadEx,但在本文的示例下,前者就足够了。

CreateRemoteThread的原型为:

4.png

CreateRemoteThread有七个参数,其中只有三个对我们有用。其余的可以具有默认值,尽管通过调整它们可以对新创建的线程进行更多控制。

我们感兴趣的参数是:

hProcess:受害者进程的句柄,我们希望在其中创建线程。

lpStartAddress:它是指向THREAD_START_ROUTINE的指针,THREAD_START_ROUTINE是线程一旦创建即将从其开始执行代码的位置。

lpParameters:指向LPTHREAD_START_ROUTINE所需参数的指针。由于在本例中,它是一个简单的shellcode,因此不需要任何参数,因此,我们将其保留为NULL,该参数在DLL注入中有重要意义。

演示

演示视频中,你可以看到我使用了一个Shellcode在Windows 10 RS6 (x64)上启动cal .exe(使用msfvenom生成)。

该方法的优势

与其他代码注入技术相比,使用CreateRemoteThread进行代码注入具有多个优势,比如:

1.最容易实现;

2.不需要对库函数进行地址解析;

3.不需要等待事件的发生;

4.不需要操作内存中的文件结构;

该方法的缺点

该方法除了优点之外,还有一些缺点,这些缺点使其无法成为流行的代码插入技术,比如:

1.只能注入二进制代码;

2.更改Shellcode时需要进行大量更改;

3.使用shellcode可以实现的数量有限。


文章来源: https://www.4hou.com/web/21784.html
如有侵权请联系:admin#unsafe.sh