The Sea Surfer – a Simple Tool for CSRF Vulnerability Detection and Proof-of-Concept Creation

Lately I have taken an interest in web application security, as covered by OWASP. One common vulnerability in web applications is to be sensitive to CSRF attacks. I have made a small tool in the form of a bookmarklet to detect CSRF vulnerabilities and create proof-of-concept exploits. It is very simple, but it does the job. There will probably be cases when it doesn’t work, but mostly it should. I guess there are similar tools out there already, and you can do this with Firebug for example (albeit that is a bit more cumbersome), but make not mistake: I’m in it for the code.

Installation

  • Add the jQuerify bookmarklet to your bookmarks (go to Learning jQuery to find it)
  • Add the Sea Surfer bookmarklet to your bookmarks (by dragging it to your bookmarks bar, for example)

Why do you need to install jQuerify? I was a little lazy and used jQuery in the code, and when I tried to use a jQuery Bookmarklet generator (that would include jQuery for me), Firefox blocked the popup. I am not exactly sure why, but it may have to do with that the window.open call doesn’t seem to originate from the click on the bookmarklet.

How to use

  • Choose a page with forms that you want to check
  • Run jQuerify by clicking it
  • Run the Sea Surfer by clicking it
  • In the resulting window or tab, all forms on the page will be displayed in text areas. Choose one that does not contain any CSRF tokens or similar, edit the inputs and then click “Test vulnerability”

An iframe will open and the form will be added to it. It will be submitted automatically. If the submit succeeded, you can use the edited form as a proof of concept when you report the vulnerability. I have only tested this in Firefox and Chrome (in Windows).

Source code

I have more or less hacked this together. Do not expect the highest code standards. Please modify it anyway you want to, though. Then make a bookmarklet of it, with a bookmarklet generator if you want to. I used the Bookmarklet Crunchinator. In the bookmarklet I’ve base64 encoded the code to be able to include the bookmarklet in this page (it broke the page layout, and I may have spent more on trying to fix that than on the code itself). This is not necessary if you convert the code to a bookmarklet yourself and just put it in your bookmarks.

    if (typeof jQuery === 'undefined') {
        alert('Run jQuerify first!');
    } else {
        var w = window.open();
        var body = jQuery(w.document.body);
        jQuery('form').each(function(i) {
            var clone = jQuery(this).clone();
            var inputs = clone.find('input,textarea,select');
            var area = jQuery('<textarea id=\'area' + i + '\' cols=120 rows=50>');
            var desc = '<h1>Form ' + i + '</h1><p>Edit the values and click \'Test vulnerability\' to try it out.</p>';
            var script = 'javascript:function insertAfter(newChild,refChild){refChild.parentNode.insertBefore(newChild,refChild.nextSibling);} var area = document.getElementById(\'area' + i + '\'); var iframe = document.getElementsByTagName(\'iframe\')[0]; if (!iframe) { iframe = document.createElement(\'iframe\'); insertAfter(iframe, area); }  iframe.contentDocument.write(area.value);';
            var a = document.createElement('a');
            a.href = clone.attr('action');
            clone.attr('action', a.href);
            clone.empty();
            clone.append(inputs);
            area.text(clone.wrap('<div>').parent().html().replace(/>/g, '>\n') + '<script>document.getElementsByTagName(\'form\')[0].submit();</script>');
            body.append(desc);
            body.append(area);
            body.append('<br/><input type=submit value="Test vulnerability" onclick="' + script + '"/><br/>');
        });
    }

Finally: the point of this is to find vulnerabilities in your own web apps and fix them, or in other web apps and report them.

Update

I noticed that there was a quite big short-coming in my code: I only included inputs in the forms, not textareas or selects. This is now fixed.