ztgrace / changeme

A default credential scanner.
GNU General Public License v3.0
1.44k stars 248 forks source link

Issue while adding default credential detection for Aruba's ClearPass #79

Closed mzet- closed 5 years ago

mzet- commented 5 years ago

First of all: thanks for excellent tool. Just found it so haven't used during the testing engagement but it has potential to save huge amount of time during the testing and skip most mundane activity during pen tests of large networks: walking thru all the web consoles for yet another (and another, ...) device/appliance and try out default creds manually.

That being said, during my pen test I've recently found instance of Aruba ClearPass (https://www.arubanetworks.com/products/security/network-access-control/) and guess what default credentials admin:eTIPS123 worked perfectly :).

After finding changeme I've decided to add ClearPass to it. The authentication to ClearPass is straightforward and could be summed up with following curl invocations:

Failed authn:

curl -x 127.0.0.1:8080 -v -k --url https://<ip>/tips/tipsLoginSubmit.action -d 'username=admin&password=badpass'

# Response:
< HTTP/1.1 200 OK
< Date: Thu, 23 May 2019 16:35:18 GMT
...

Successful authn:

curl -x 127.0.0.1:8080 -v -k --url https://<ip>/tips/tipsLoginSubmit.action -d 'username=admin&password=eTIPS123'

# Response:
< HTTP/1.1 302 Found
< Date: Thu, 23 May 2019 16:37:28 GMT
....
(empty body)

So the HTTP status code 200 vs 302 differentiate successful vs failed authn.

Fingerprinting:

curl -s -x 127.0.0.1:8080 -k --url https://<ip>/tips/tipsLogin.action | grep '<title>ClearPass Policy Manager - Aruba Networks</title>'

# Response:
<title>ClearPass Policy Manager - Aruba Networks</title>

So I've prepared (with --mkcred) following yaml file for changeme:

auth:
  credentials:
  - password: eTIPS123
    username: admin
  headers: []
  post:
    password: password
    username: username
  sessionid: JSESSIONID
  success:
    body:
    - ""
    status: 302
  type: post
  url:
  - /tips/tipsLoginSubmit.action
category: general
contributor: mzet
default_port: 443
fingerprint:
  body:
  - <title>ClearPass Policy Manager - Aruba Networks</title>
  status: 200
  url:
  - /tips/tipsLogin.action
name: ClearPass
protocol: http
ssl: true

Unfortunately default creds aren't identified:

clearpass

What I've missed? Or mybe yaml file is wrong?

Best, mzet

ztgrace commented 5 years ago

Glad you found it and hopefully it saves you some time. Your use case is exactly why I wrote it. I wanted to do a thorough job of assessing default creds on a large network. The initial credentials came from manual findings I discovered via Eyewitness.

Thanks for the detailed write-up, it really helps debugging. Looking at the output, you're fingerprinting correctly so that stage is good.

The credentials aren't successful. My hunch is that you've set the status to 302. The way that changeme uses python requests is the default behavior of following redirects. In your curl command, you get the 302 response code because you're not providing the -L argument which would follow the redirect and mimic the chanageme behavior. I need to update the documentation to note this behavior.

For reference: https://2.python-requests.org/en/master/user/quickstart/#redirection-and-history

>>> import requests
>>> res = requests.get('http://github.com')
>>> res.status_code
200
>>> res.history
[<Response [301]>]

Why don't you try setting the status to 200 in the response code and finding a unique string on the successfully logged in page, I like the to find the HTML surrounding the logout button/link, and see if that fixes the issues.

If the above suggestion doesn't fix the issue, I would suggest is running your curl commands with the --proxy option through an intercepting proxy like burp. Then run changeme through the same proxy and compare the request differences. I've seen some embedded devices like printer require some funky header or request sequence that might not be obvious until you compare the two.

Hope that helps and looking forward to your PR!

mzet- commented 5 years ago

@ztgrace , thanks for prompt response.

Yeah, this would be most clean solution to expect HTTP 200 and I've already tried it (expecting: Logout</a> string) - however the issue here is that the ClearPass app after providing valid credentials (used Burp Repeater) does three redirects and then finally redirects to some kind of (still) pre-authn page so to differentiate those two states I've opted to the solution with detecting redirect 302 (but in case changeme by default follows redirects this obviously won't work).

To summarize, what exactly happens when logging in (valid vs invalid creds):

valid creds -> 302 -> 302 -> 302 -> 200 (siteX) invalid creds -> 200 (almost the same siteX but with string Invalid Username or Password specified)

So the solution (based on the html content inspection) would be to have negative condition, i.e. page does not contain string Invalid Username or Password specified. Is it doable in changeme?

ztgrace commented 5 years ago

Hey @mzet-

I added additional criteria to the check_success method to look for the existence of a redirect history and match based on the status code of the first redirect. Please test this out when you have a chance to see if this will work for your scenario.

https://github.com/ztgrace/changeme/blob/development/changeme/scanners/http_get.py#L93

Thanks, Zach

mzet- commented 5 years ago

Thanks for adding support for such case. Had to rewrite your line a little bit (as res is not defined):

if success.get('status') == self.response.status_code or self.response.history and self.response.history[0].status_code == success.get('status'):

and seems to work smoothly now:

w.

When your change will land in master I will send PR with clearpass.yml.

Best, mzet

ztgrace commented 5 years ago

good catch, I missed self context for the response. Go ahead and make a PR with both this change and the yaml file to the development branch and I'll merge them into master.

Thanks! Zach

mzet- commented 5 years ago

Hi @ztgrace,

I think that we can now close this issue.