So, my
dear Firefox and Explorer fanboys :) I have something special today for Opera
users only. I'm pretty excited by Opera's Userscripts that allow you to write
Javascript files that are far richer than greasemonkey Userscripts -which is
also supported by Opera- I've written a security plugin for Opera last night,
that attempts to mitigate various Javascript attack vectors. But, one problem
for writing a security plugin is that we usually need to process a script
before it gets rendered by the browser. Otherwise, it is already to late to
block a dangerous request or script instance. This is particularly useful to
mitigate CSRF and XSS.
For instance, the Opera event listeners can process inline or remote Javascript
and other page events before and after
it gets executed. What a marvelous idea, I am really stunned when I read about
it. It's exactly what I wanted for Opera! It really gives absolute user control
over the page. Bare with me, it is written in a couple of hours with a few
ideas I had at the moment. I will be working on it some more when I find the
time for it. I gave the script the name Arioso, as an appreciation for Opera.
Arioso's features I created:
-Arioso enumerates all links inside a website looking for dangerous URI schemes
-Arioso blocks remote JS files that are not coming from the same-domain (strict
SOP)
-Arioso scans remote and same-origin Javascript before it gets rendered and
kills the script if needed.
-When it is done, it creates a bar in the browser alerting the issue at hand.
Arioso source can be loaded into Opera. To enable user JavaScript, use Tools
> Preferences > Advanced > Content > JavaScript options, and select
the directory where you will put your User JavaScript files. Opera will load
all files in the specified directory whose names end with .js and will use them
as User JavaScript files.
/*
~~~
Opera Arioso! ~~~
by
rvdh, 0x000000.com
*/
// Ariosos magic (ghost)
varibales
window.opera.defineMagicVariable('arioso_links',
function() {}, null);
window.opera.defineMagicVariable('arioso_sanitize_xss',
function() {}, null);
// Arioso variables
var arioso_links =
document.links;
var arioso_sanitize_xss =
true;
var bad_arioso_schemes = '';
// Arioso arrays
var arioso_schemes =
["chrome:", "file:", "opera:", "res:",
"data:", "telnet:", "about:",
"resource:", "view-source:", "acrobat:",
"mms:", "localhost", "loopback"];
// Arioso link enumerator
detecting bad schemes
for (var i = 0; i <
arioso_links.length;++i) {
for (j =
0; j < arioso_schemes.length;++j) {
if (arioso_links[i].toString().match(arioso_schemes[j])) {
bad_arioso_schemes += arioso_schemes[j] + ' | ';
}
}
}
// Arioso evil JS blocker
window.opera.addEventListener('BeforeScript',
function(e) {
//
prevent heap spraying, denial of service
if
(e.element.text.match(/for\s*\(\s*[a-z]\s*\=\s*[0-9]\s*;\s*[a-z]\s*(<|>|<=|>=|<==|>==)\s*[0-9]{3,}\s*;\s*/gim))
{
arioso_alert = 'Possible heapspraying or denial of service vector found and
blocked';
e.preventDefault();
// prevent heap spraying, stack/heap overflows
}
if
(e.element.text.match(/(while|for|space|block|memory).*unescape\(("|')%([0-9]|\\x|\\u)([a-z]|[0-9])("|')\)/gim))
{
arioso_alert = 'Possible heapspraying or denial of service vector found and
blocked';
e.preventDefault();
// VBinjection
}
if
(e.element.text.match(/String\(\s*[0-9]{6,},\s*"[a-z]"\)/gim)) {
arioso_alert
= 'VBInjection vector found and blocked';
e.preventDefault();
// prevent JS cookie stealing
}
if
(e.element.text.match(/http:\/\/.*\?.*=.*(\+|concat|join).*document\.cookie/gim))
{
arioso_alert = 'Cookie stealing attempt blocked';
e.preventDefault();
// prevent non-same origin bad URI sourcing
}
if
(e.element.text.match(/(src|href|location)\s*=.*(localhost|loopback|telnet:|file:|res:|resource:|about:|javascript:|data:)/gim))
{
arioso_alert = 'Prevented non-same origin URI sourcing';
e.preventDefault();
// prevent keycode logging
}
if
(e.element.text.match(/(\.charCode|\.keyCode))/gim)) {
arioso_alert = 'Prevented keylogging';
e.preventDefault();
// Arioso self protection, not really needed because of the 'ghost' variables.
}
if
(e.element.text.match(/(bad_arioso_schemes|arioso_links|arioso_schemes|arioso_sanitize_xss))/gim))
{
e.preventDefault();
}
}, false);
// Arioso strict non-same
origin JS blocker (think: ads, and cookie stealers)
window.opera.addEventListener('BeforeExternalScript',
function(e) {
// If JS
is not on the same domain, block it
if
(!e.element.getAttribute('src').match(document.location)) {
e.preventDefault();
}
}, false);
document.addEventListener('load',
function(e) {
if
(bad_arioso_schemes) {
arioso_message = 'found and blocked unsafe URI hyperlink schemes.\r\nSchemes
found and blocked: | ' + bad_arioso_schemes;
} else if
(arioso_alert) {
arioso_message = arioso_alert;
}
if
(arioso_message) {
var ary = document.createElement('div');
ary.style.position = 'fixed';
ary.style.top = '0px';
ary.style.left = '0px';
ary.style.width = '100%';
ary.style.border = '1px solid #999';
ary.style.padding = '3px';
ary.style.font = 'small-caps bold 10pt
sans-serif';
ary.style.backgroundColor = '#fffff0';
ary.style.color = '#000';
ary.appendChild(document.createTextNode('ARIOSO: ' + arioso_message))
document.body.appendChild(ary);
} else {
return true;
}
}, false);
List of useful userscript events:
BeforeExternalScript
Fired when a SCRIPT element with a SRC attribute is encountered. The script
element is available as the element attribute of the UserJSEvent. If cancelled,
the external source is not loaded and the script element is not executed. In
addition, if it is cancelled, the BeforeScript event will not fire.
BeforeScript
Fired before a SCRIPT element is executed. The script element is available as
the element attribute of the UserJSEvent. The content of the script is
available as the text property of the script element, and is also writable:
UserJSEvent.element.text = UserJSEvent.element.text.replace(/!=s*null/,'');
The BeforeScript event is fired for inline scripts as well as external scripts,
including scripts with a type that Opera normally does not execute (such as
VBScript). If cancelled, the script element is not executed.
AfterScript
Fired after a SCRIPT element has finished executing. The script element is
available as the element attribute of the UserJSEvent.
BeforeEvent
Fired before a regular event is fired, regardless of whether such an event
would be handled by any event handlers. The regular event is available as the
event attribute of the UserJSEvent. If cancelled, the regular event is not
fired, its default action is performed, and any associated BeforeEventListener
events are not fired.
BeforeEvent.type
Like BeforeEvent, but fired only for events of the specified type (for example,
BeforeEvent.click). In Opera 8, if any listeners are registered for a matching
BeforeEvent.type event, no BeforeEvent event is fired. In Opera 9, both will
fire.
AfterEvent
Fired after a regular event has been fired and handled but before its default
action has been performed. The regular event is available as the event
attribute of the UserJSEvent. If cancelled, any attempts by a regular event
handler to cancel the regular event will be ignored. The UserJSEvent object
will also have the eventCancelled property, that will be set to true if any regular
event handlers have cancelled the event.
AfterEvent.type
Like AfterEvent, but fired only for events of the specified type (for example,
AfterEvent.click). In Opera 8, if any listeners are registered for a matching
AfterEvent.type event, no AfterEvent event is fired. In Opera 9, both will
fire.
BeforeEventListener
Fired before a listener for a regular event is called. The regular event is
available as the event attribute of the UserJSEvent, and the listener to be
called is available as the listener attribute of the UserJSEvent. If cancelled,
the regular event listener will not be called.
BeforeEventListener.type
Like BeforeEventListener, but fired only for events of the specified type (for
example, BeforeEventListener.click). In Opera 8, if any listeners are
registered for a matching BeforeEventListener.type event, no
BeforeEventListener event is fired. In Opera 9, both will fire.
AfterEventListener
Fired after a listener for regular events is called. The regular event is
available as the event attribute of the UserJSEvent, and the listener to be
called is available as the listener attribute of the UserJSEvent. If cancelled,
any attempts by a regular event handler to cancel the regular event propagation
will be ignored. The UserJSEvent object will also have the propagationStopped
property, that will be set to true if any regular event handlers have cancelled
the event propagation.
AfterEventListener.type
Like AfterEventListener, but fired only for events of the specified type (for
example, AfterEventListener.click). In Opera 8, if any listeners are registered
for a matching AfterEventListener.type event, no AfterEventListener event is
fired. In Opera 9, both will fire.
BeforeJavascriptURL
Fired before a javascript: URL is executed. The JavaScript code to be executed
(everything after the 'javascript:' in the URL) is available as the source
attribute of the UserJSEvent, and is also writable. If cancelled, the
javascript: URL is not executed.
AfterJavascriptURL
Fired after a javascript: URL is executed. The JavaScript code that was
executed (everything after the 'javascript:' in the URL) is available as the
source attribute of the UserJSEvent, and any value returned by that code is
available as the returnValue attribute of the UserJSEvent. The returnValue is
also writable. If cancelled, any returned value will not be used as the source
of a new page.
[Ph4nt0m Security Team]
Email: ax...@ph4nt0m.org
=== V3ry G00d, V3ry Str0ng ===
=== Ultim4te H4cking ===
=== XPLOITZ ! ===
=== #_# ===
#If you brave,there is nothing you cannot achieve.#