The problem
You are in the plane, 11000 meters above the sea level, traveling 900kmh. And suddenly (usually after a bottle of wine) you have this brilliant idea about a bug in the browser, new way to filter some data or really anything that just requires writing a webapp. But you are in the plane, having the company machine running the OS_of_not_so_much_your_choice. Not always you have an Apache server wit PHP running on your laptop (well, you really should not have), VMplayer/VMFusion/anyVM is probably even less common. So, maybe you can use Django or Ror (or J2EE+Tomcat+JBoss - and if you say yes to it this is not the blog you are looking for). Anyway, you still want to code something.So, here comes the Bottle. Repeating after web page - Bottle is a fast, simple and lightweight WSGI micro web-framework for Python. It is distributed as a single file module and has no dependencies other than the Python Standard Library.
Those two sentences neatly summarize all the things I like in it - just one file, no much of a setup needed and development effort is reduced to minimum. Thanks to that you can spent time solving real problems, not struggling with weird Apache vhost config file and wondering why the hell mod_php is not working.
Crash course
I know - talk is cheap, so show me the code. Instead of just pasting some code from the tutorial we can try solving some semi-real problem. Let's get back to my previous post - Using burp in a smart way where we were trying to figure it out how to fuzz for XSS vulnerabilities. To see how Burp behaves in different situation we would need some vulnerable script.
#!/usr/bin/env python import re import traceback try: from bottle import run, request, template, route except: print traceback.format_exc().splitlines()[-1] head = "<html><title>Simple search interface</title><body>" footer = "</body></html>" filters = [r'!.*',r'[^a-zA-z0-9]*'] @route('/show') def show_patterns(): t="" for p in patterns: t+="<p>"+p+"</p>" return head+t+footer @route('/search/:id') def index(id): q = request.query.q t = "<p>You have searched for {{!query}} " t+= "and I've applied following filter - {{filter}}</p>" t+= "<p>Sadly, nothing was returned</p>" try: f = filters[int(id)] except: f = filters[0] return template(t, filter=f, query=re.sub(f,'',q)) run(host='localhost', port=8000)
Idea - application echoing back user search query and simple switch that will either show regexp patterns used to filter it or apply one of them.
I'll explain it in more details.
try: from bottle import run, request, template, route except: print traceback.format_exc().splitlines()[-1]First, import couple of functions from bottle framework - for this small program you will need only some functions to route request, get parameters from query, run template and run test webserver. Bear i mind that this is very simple web server and it's not suited to be exposed to the world.
You can safely ignore try..except block construction - I'm just trying to inform you, that you are missing bottle library.
Let's handle our first request:
@route('/show') def show_patterns(): t="" for p in patterns: t+="<p>"+p+"</p>" return head+t+footerMost important thing here is a function decorator @route. I hope you are familiar with python function decorators - if not this is simply a function which wraps around other function - (over)simplifying you can treat it as a condition upon which the inside function will run (for all CS degree people - I don't care for formal decorator definition).
So, if we make an request to URL /show the function show_patterns() will run. Inside this function we only enumerate filters inside our script - we glue it together with header and footer then spit it out by return function.
That was really easy. Now time to analyze next function.
@route('/search/:id') def search(id): q = request.query.qAgain, important thing is our @route decorator. Take a look at this :id thing - it just an element that will be matched dynamically - whatever you put after /search/ will get translated into argument for your function. Of course we need to grab argument from the query string (be careful, it's bit tricky - GET parameters are in requst.query, but POST requests are in request.forms), hence the q assignment.
Now, let's construct main body of the template file
t = "<p>You have searched for {{!query}} " t+= "and I've applied following filter - {{filter}}</p>" t+= "<p>Sadly, nothing was returned</p>" [..] return template(t, filter=f, query=re.sub(f,'',q))Bottle can use multiple template engines, but by default it uses Simple Template Engine. Two important things here - first, take a look at {{filter}} - it tells you that this is a place where you are going to put data while rendering template (by template() function). Second thing - template engine by default escapes all dangerous HTML characters - probably we don't want that, so precede it with ! character to disable that feature.
Being practical
I was using this program (well, actually I was not - I wrote it during 15 minutes break on the conference) writing previous article about burp fuzzing - you can use it as a testbed for both, testing some filters (still not perfect, but I can make better version later) and learn how to fuzz looking things with burp. Currently I'm using Bottle for both - writing small vulnerable things if I need to test some concept/attacks but also for some more serious projects - but let's save it for the next entry.