Is there a phantomJS injection vulnerability in page.evaluate()? - javascript

Using PhantomJS you can execute code in the browser by doing page.evaluate(). Are we opening ourselves up to an attack vector if we allow users to specify code which could be executed in that browser context? Is there a way to escape from the browser context into the phantomJS environment thereby executing commands on our servers?
Here's an example:
page.open(options.url, function(status) {
var test = function() {
return page.evaluate(function() {
return eval({{USER JAVASCRIPT STRING}});
});
});
var interval = setInterval(function() {
if (test()) {
clearInterval(interval);
// take screenshot, do other stuff, close phantom
}
}, 250);
});
From my understanding, the eval() occuring inside the page.evaluate() prevents them from ever escaping the context of the page which was opened. The user javascript string is passed as a string (it is not "compiled" into a single javascript file). It appears to me that it is no different then a user browsing to a site with a browser and attempting to hack away through their favorite Javascript console. Thus, this usage does not represent a security vulnerability. Is this correct?
Update
To provide a little more clarity about the exact use case. The basic gist is that someone will go to a url, http://www.myapp.com/?url=http://anotherurl.com/&condition={{javascriptstring}}. When a worker is available, it will spin up a phantom instance, page.open the URL provided, and then when condition is met, it will take a screenshot of the webpage. The purpose for this is that some pages, especially those with massive amounts of async javascript, have bizarre "ready" conditions that aren't as simple as DOM ready or window ready. In this way the screenshot won't be taken until a javascript condition is true. Examples include $(".domNode").data("jQueryUIWidget").loaded == true or $(".someNode").length > 0.

I'm not very familiar with PhantomJS, but eval is inherently unsafe when it comes to running unknown code. It would be very easy to escape the intended context:
return page.evaluate(function() {
return eval({{javascriptstring}});
});
http://example.com/?url=http://anotherurl.com/&condition={{javascriptstring}}
How about where {{javascriptstring}} equals:
console.log('All your script are belong to us');
I'm not sure what kind of nasty things you could do with PhantomJS, but it's an example of a user being able to run any code they want, so this doesn't sound like a good idea. The user string could literally be an entire program.
To clarify, the injection vulnerability is not in page.evaluate(), it's in the eval in your code.

Yes, this is DOM based XSS. This is a vulnerability that can be used to hijack user's (or administrative) sessions and expose users to other attacks.
If the input comes from a GET/POST or Fragment or part of the URL then its very easy to exploit. If the input comes from the UI, then it can be exploited with clickjacking.

Related

Javascript redirect not working in Edge browser when opened with android ActionView intent, but working after manual reload

Situation
In our Android app (Xamarin), we open a web page using an ActionView intent. The code looks like this:
Intent intent = new Intent((string)Intent.ActionView, Android.Net.Uri.Parse(args.url));
intent.AddFlags(ActivityFlags.NewTask);
The opened page at some point does a JS redirect, with a line like this:
window.location = '...';
We tried many different variations of that line, including window.location.href = '...', window.location.assign('...'); and some more. All show the same behavior.
Problem
This has worked fine for years now, in all browsers - but now we ran into a problem, when the browser on the android device is the Edge browser:
When the browser tab is initially opened by the intent, the window.location = '...' line in Javascript is just ignored by the browser. No error message - just ignored.
However, if that same browser tab with exactly the same URL is opened manually (either by reloading or by copying and pasting the URL), the JS redirect is executed just fine.
Question
How do we fix this, how do we make the JS redirect reliably work?
My guess is that we are running into a security feature, which prevents JS redirects in browser tabs that the user has never interacted with.
Is there something (maybe an intent flag?) to circumvent this? We already tried the flag GrantWriteUriPermission, but it did not help.
Possible duplicates
Android Browser Facebook Redirect Does Not Always Trigger Intent for URL :
The proposed situation of setting the URL on a link and faking a click on it did not work.
Microsoft Edge security
Microsoft Edge recently fixed an issue regarding XSS Targeting Non-Script Elements (June 24, 2021).
The vulnerability was found by two researcher when they visited a website in another language via the Microsoft Edge browser and attempted to translate the page. The goal of the recent fix by Microsoft is to avoid vulnerability regarding accessing dynamically to a content from a third party application and specifically in the case of browser redirection. They need to act quickly because the vulnerability is quite huge.
In order to mitigate a large class of potential cross-site scripting issues, the Microsoft Edge Extension system has incorporated the general concept of Content Security Policy (CSP)
Ok, but ... is there any solution?
Maybe you can find a solution to solve your issue here, in particular the part concerning the <button onclick="...">.
Inline code is considered harmful in concept of CSP and microsoft recommend some good practices :
1 - The clickHandler definition must be moved into an external JavaScript
2 - The inline event handler definitions must be rewritten in terms of addEventListener and extracted into your external js file. If you are currently starting your program using code like <body onload="main();">, consider replacing it by hooking into the DOMContentLoaded event of the document, or the load event of the window, depending on your requirements. Use the former, since it generally triggers more quickly.
3 - Function inside onclick call must be rewritten to avoid converting the string of function into JavaScript for running.
The code exemple of the external .js file cited in the documentation look like this :
function awesome() {
// Do something awesome!
}
function totallyAwesome() {
// do something TOTALLY awesome!
}
function awesomeTask() {
awesome();
totallyAwesome();
}
function clickHandler(e) {
setTimeout(awesomeTask, 1000);
}
function main() {
// Initialization work goes here.
}
// Add event listeners once the DOM has fully loaded by listening for the
// `DOMContentLoaded` event on the document, and adding your listeners to
// specific elements when it triggers.
document.addEventListener('DOMContentLoaded', function () {
document.querySelector('button').addEventListener('click',
clickHandler);
main();
});
Hope it's helps

Solving code injection in JavaScript

I've been given a task to deal with security vulnerabilities. I've ran a test on all custom JavaScript files in our project using DefenseCode ThunderScan and found several high threat vulnerabilities, all of them associated with 'code injection'. Example of piece of code where the vulnerability was found:
setTimeout(function () {
window.location.href = Urls.getHuhnScaleIndexDataUrl.replace('ResidentId',
model.residentId()).replace('SessionVal', true);
}, 2000);
window.open(urlReport, '_blank');
What exactly poses a vulnerability in these code examples?
Using windows.open is considered bad practice because the new windows retains a reference to the parent one and can then try to inject / code into it.
The new window has an opener field which points to the former window with unrestricted access, which means you can delete the body of the parent or steal tokens embedded in forms...
Reference: https://dev.to/ben/the-targetblank-vulnerability-by-example

Phantomjs disable javascript in page but enable included javascript

I am using phantomjs to retrieve CSS information from a page without execute its javascript. For example here is the code snippet.
page.settings.javascriptEnabled = false;
page.open('file:///home/sample.html', function(status) {
if (status !== 'success') {
console.log('Unable to access network');
} else {
page.includeJs("file:///home/sample.js", function() {
var class = page.evaluate(function() {
return document.querySelector('body').className;
});
console.log(class);
});
}
}
If I disabled the javascript, the evaluate function always return null. But when I tried to enable the javascript, the evaluate function will return some value. Is there any idea to disable the javascript in the page, but my included javascript have to work ?
No
page.evaluate() executes JavaScript on the page. If you disable JavaScript in PhantomJS, then you effectively can't use page.evaluate() anymore. And with it goes every way of accessing DOM elements. page.includeJs() will also not work, because it the script cannot be executed on the page.
You can still access page.content which provides access to the current page source (computed source). You may try to use some DOM library to parse the source into a DOM object1 or if the task is simple, you may try to use Regular Expressions.
1 Note that PhantomJS and node.js have different execution environments, so most node.js modules that deal with the DOM won't work
As suggested by Artjom, there is no way to disable execution of the target website JavaScript without disabling PhantomJS ability to execute JavaScript on the page. However, there is a simple way to ensure that no scripts are executed by the target website (which achieves the same result, at the end).
Create a HTTP proxy that intercepts all requests.
Detect responses with Content-Type: text/html.
Remove all <script> tags from the document.
You can configure phantomjs to use proxy using --proxy configuration.
Use http-proxy to create a proxy server.
Use cheerio to remove, comment out, or otherwise invalidate the <script> tags.

HTML 5 Worker "threads" , spawn on Function

I have been reading up on HTML 5 worker threads but all the samples i have seen seem to require the javascript be in its own file.
so im basicly wondering if its posible to start a worker work directly towards a function.
The end goal here being something along the lines of:
function AllJavascriptIsLoaded()
{
if(gWorkersSupported)
{
var Worker = new Worker(MyFunc)
Worker.Start();
}
else
{
// Horrible user experience incomming.
MyFunc();
}
}
function MyFunc()
{
// Complex and time consuming tasks
}
To my knowledge, this is not allowed for security reasons. I'd assume that a child object, or any JS script in the same file, would potentially have access to the parent DOM window, which Web Workers are not allowed to access.
So, we're stuck with posting messages to other files unless someone finds a nicer way to do it ;)
You can use something called inline-worker.
Basically you create a script resource via dataURI or BlobURL for the worker script. Given that the content of the script can be generated, you can use Function.toString() to build the content of the worker.
Example use BlobURL: http://www.html5rocks.com/en/tutorials/workers/basics/
Example use both technique: https://github.com/jussi-kalliokoski/sink.js/blob/master/src/core/inline-worker.js
Jeffrey is right about the security restriction of WebWorker. The code running in the worker cannot access the DOM, so it should only be used for calculation heavy tasks. If you try to access the DOM inside worker's code it would raise an error.
vkThread plugin helps you to implement exactly what you requested.
take a look at http://www.eslinstructor.net/vkthread/
there are examples for different kind of functions: regular function, function with context, with dependencies, anonymous, lambda.

How to manipulate Javascript websites in Perl

I have been asked to automate the logging into a webapp(what I assume to be one, that runs a lot of .aspx and .js scripts) that, currently, can only run in IE. Now i am programming in Perl and have tried to use Win32::IE::Mechanize to run the IE browser and log in. What i did was try an extract all the forms from the webapp, and given the users information, fill out the required forms, but this is where the problem arises, when I try and run the subroutine no forms appear......
So then I transitioned into WWW::Mechanize and used the post subroutine(from LWP::UserAgent) which solved the problem for the most part. Now i've run into a problem in the response, from the server, I get this script as the content of the response and I don't know what to do with it.
So my question is: Using Perl how can I go about to manipulate a Javascript functions in a website? Would that even be a valid solution to the problem?
I am open to writing this in other programming languages as well. Thanks in advance for the help!
(So that I can fully log in to the webapp)
Update: The content of the response:
var msgTimerID;
var strForceLogOff = "false";
function WindowOnLoad(){
if ("false" == "true" && "false" == "false")
MerlinSystemMsg("",64);
if ("false"=="true")
msgTimerID = window.setInterval("MerlinSystemMsg(10095,64)", 300000,'javascript');
}
function MyShowModal(){
showModalDialog("", window, strFeatures);}
function clearMsgInterval(){
window.clearInterval(msgTimerID);
}
function WindowOnUnLoad(){
if(top.frames(0).document.getElementById("OPMODE").value =="LOGOFF"){
strFeatures = "width=1,height=1,left=1000,top=1000,toolbar=no,scrollbars=no,menubar=no,location=no,directories=no,status=yes,resizable=1";
window.open("ForceLogOff.aspx","forcelogout",strFeatures);
}
}
window.onbeforeunload = WindowOnUnLoad;
window.onload = WindowOnLoad;
There is also this Frame Title that has the src:
FRAME TITLE="Service Desk Express Navigator" SRC="options_nailogo.aspx" MARGINWIDTH=0 MARGINHEIGHT=0 NORESIZE scrolling=no
Trying to emulate the browser with a fully functioning JS engine is going to be a mighty big task. Instead, I'd suggest that you just try to emulate the actual interaction with the web site and not care what HTML/JS is actually sent back. Your server side code doesn't care how the HTTP submissions take place, only that they do. Admittedly this is more fragile if the forms change a lot, but at least you're not trying to implement a full browser.
So look at modules like LWP::UserAgent, HTTP::Request and HTTP::Response.
I'm copying and pasting my answer to your other duplicate question here
(You should consider deleting one of these?)
That content is the website source :)
How WWW::Mechanize deals with FRAME SRC as a link:
Note that <FRAME SRC="..."> tags are parsed out of the the HTML and
treated as links so this method works with them.
You'll want to use follow_link on that link.
As far as dealing with Javascript, there is support for a Firefox Add-on called MozRepl that you can use in conjunction with WWW::Mechanize::Firefox that I have used in the past to call Javascript code while crawling a page.

Categories

Resources