neraliu / tainted-phantomjs

Tainted PhantomJS
BSD 3-Clause "New" or "Revised" License
53 stars 12 forks source link

Real web application pentest use case - REST API #8

Open andresriancho opened 10 years ago

andresriancho commented 10 years ago

This week I'm working on a WAPT, and I wanted to test the target site using tpjs, but found a couple of limitations that I would like to point out and potentially help fix. Please wait until the end to comment, since it will make more sense then ;)

Another way to do this might be using the --webdriver= feature in phantomjs, but with that other tools that want to "forward traffic to phantomjs for analysis" would have to implement the webdriver protocol (I'm sure that most languages have libs for it, but it might not be the best thing to do).

If you want to chat, I'm __apr__ at the #w3af IRC channel http://w3af.org/community

andresriancho commented 10 years ago

There are various examples from which we could build the REST API:

andresriancho commented 10 years ago

Another solution, instead of a proxy server (which might be complex to code due to SSL, etc.) is to expose a REST API:

POST /domxss HTTP/1.1
...
{"url": "http://target.com", "headers": {"Cookie": "session-cookie-abc"}}

HTTP/1.1 200 OK
...
uuid4-unique-task-id

Then, to retrieve the run output:

GET /domxss/<uuid4-unique-task-id> HTTP/1.1
...

HTTP/1.1 200 OK
...
{"vulnerable": true, "output": ...}

The beauty of this architecture is that if the results are stored in a central location (Redis for example) there can be N tpjs REST API servers receiving POST/GET requests and processing the queries.

andresriancho commented 10 years ago

The taint information is available in the document object, read the source code of domxss-common.js:page.onLoadFinished = function(status) { to get the format.

Only read the following if you want to lose some time.

In order for almost any wrapper like these to work, we'll need to capture the output. I'm mostly interested in the lines prepended with [CONSOLE] [TRACE]:

[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] --------------------
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] TEST #2000: domxss-db.js(<img src="" onerror="alert(0)">)
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] TEST URL: http://dmitris.github.io/domxsstest/document_write_hash.html?1396896801601&#%3Cimg%20src%3D%22%22%20onerror%3D%22alert(0)%22%3E
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] =================
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] source,1,jsLocationHref,location.href,http://dmitris.gith
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] source,2,jsLocationHash,location.hash,#%3Cimg%20src%3D%22
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] source,3,jsLocationHref,location.href,http://dmitris.gith
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] =================
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] sink,2,jsHTMLDocumentPrototypeFunctionWrite,document.write,#%3Cimg%20src%3D%22
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] sink,2,documentWrite,document.write/writeln,#%3Cimg%20src%3D%22
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] =================
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] propagate,3,stringProtoFuncToLowerCase,String.LowerCase,http://dmitris.gith
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] propagate,3,stringProtoFuncReplace::exec,RegExp.exec,http://dmitris.gith
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] propagate,3,regExpProtoFuncExec,RegExp.exec,http://dmitris.gith
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] propagate,3,JSString,String._manipulation,http://dmitris.gith
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] =================
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] =================
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [CONSOLE] [TRACE] reset,0,globalFuncEncodeURIComponent,encodeURIComponent,%3Cimg%20src%3D%22%
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [RESULT] document.tainted? true
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [RESULT] document.onAlert? false
[Mon, 07 Apr 2014 18:53:21 GMT] [TPJS] [RESULT] document.domxss.vulnerable? true|false
[Mon, 07 Apr 2014 18:53:23 GMT] [TPJS] --------------------

Is there a programatic way to get those? The ideal scenario would be to have that output there after the page loads and tests are finished, like:

page.tpjs_result = {"document.tainted": true, ...}

I know I could somehow intercept/mock console.log and get the messages from there... but that's not nice ;)

andresriancho commented 10 years ago

Finally decided that exposing a REST API is the best (and easiest) path to follow.

Starting the REST API server

phantomjs examples/domxss-api.js

The code for the script will be very similar to the examples that expose a web server. The web server API is documented here.

Sending work to the API

POST /domxss HTTP/1.1
...
{"url": "http://target.com", "headers": {"Cookie": "session-cookie-abc"}}

HTTP/1.1 200 OK
...
uuid4-unique-task-id

This will add a new task to a Queue that we'll keep in memory. There will be a thread consuming tasks from the queue and saving results to a dictionary. The results will be stored in JSON format, and will be based on the taint information stored in the document object.

The test_domxss function would have to be modified in order to:

Retrieving results from the API

GET /domxss/<uuid4-unique-task-id> HTTP/1.1
...

HTTP/1.1 200 OK
...
{"vulnerable": true, "output": ...}

This will have a really simple handler. It should go to the results dict, retrieve the value (result) associated with the uuid4-unique-task-id (which already is in JSON format), and return it as the response body.

DELETE results from the API

Once the consumer has processed the result, he should DELETE the result from the REST API in order to reduce memory usage:

DELETE /domxss/<uuid4-unique-task-id> HTTP/1.1
...

HTTP/1.1 200 OK
...
{}
yukinying commented 10 years ago

+1

andresriancho commented 10 years ago

Do we want to wait for @neraliu's +1 to start working on this? I would like it to be merged into the repository so that all can benefit from it.

dmitris commented 10 years ago

+1 - exposing a REST API and documenting it with use cases / recipes would be very useful

iriusrisk commented 10 years ago

+1 REST API would be very useful.

andresriancho commented 10 years ago

Asked a question on the phantomjs mailing list about Long running tasks in webserver request handler, will wait for a response there to start.

The programming environment provided by phantomjs scripting is rather limited and poorly documented, and I might end up doing something with web workers to solve the issue explained above.

Another option would be to use an external javascript library like this one

Webserver module documentation: "There is currently a limit of 10 concurrent requests; any other requests will be queued up."

neraliu commented 10 years ago

i am focusing on the 64 bit compilation issue. i will make this after that as planned.

andresriancho commented 10 years ago

@neraliu no need to work on this yourself, I'll do it.

neraliu commented 10 years ago

if u wanna to get the json result, try to put the "gryffin" into the $VERBOSE, not yet document back, enjoy

${TPJS_HOME}bin/phantomjs ${TPJS_HOME}share/phantomjs/domxss.js "${URL}" $COOKIE_FILE $TIMEOUT 1 $RENDERING_PATH $VERBOSE

neraliu commented 10 years ago

for the authentication, i guess phantomjs should support it. let me check later.

andresriancho commented 10 years ago

We don't care about auth when doing REST API, since the crawler will handle that, and then phantomjs/tpjs will just get all the headers used by the crawler in the POST, and re-send them to be authenticated.