4

I am writing a server-backend for a conceptional problem that might be hosted on some CTF challenge. It will be hosted on Ubuntu 12.04 LTS, nginx 1.1.19, and uWSGI 1.0.3-debian which will handle Python 2.7.3.

The goal of the challenge is to exploit the JavaScript loaded on contestants' browsers to trigger a PyV8-defined function runThis() by successfully injecting the function call, quite alike XSS. The Python script described below will work as CGI and validate the contestants' input with PyV8, judging whether the XSS has succeeded or not.

However, it is a problem that this Python script is vulnerable to DoS attack (I suppose that some contestants may supply this script with "while(1){}")

I want to deal with this by setting a timeout to evalJavaScript(), so I've tried to adopt a solution which uses SIGALRM from https://stackoverflow.com/a/601168/1402144 this reference, but it's not working.

Here is the conceptional code (greatly simplified in order not to give away too much about the game, and to concentrate on the current problem about timeout):

#!/usr/bin/env python

import PyV8
import cgi, cgitb
import signal
from contextlib import contextmanager

# Timeout handler
class TimeoutException(Exception):
    pass

@contextmanager
def time_limit(seconds):
    def timeout(signum, frame):
        raise TimeoutException, "Timed out!"
    signal.signal(signal.SIGALRM, timeout)
    signal.alarm(seconds)
    try:
        yield
    finally:
        signal.alarm(0)
# end Timeout handler

# check JavaScript
class Global(PyV8.JSClass):
    def runThis(self):
        print "You have called this function via JavaScript."

def evalJavaScript(post_data):
    try:
        ctxt = PyV8.JSContext(Global())
        ctxt.enter()
        ctxt.eval(post_data)
        ctxt.leave()
    except Exception, e:
        print e
        print "Perhaps syntax error? Try again!"
# end JavaScript

# CGI
form = cgi.FieldStorage()

print 'Content-type: text/html'
print

try:
    with time_limit(5):
        evalJavaScript(form.getvalue('javascript'))
except TimeoutException, msg:
    print "Timed out!"

# end CGI
  • URL: http://localhost/validation.py?javascript=runThis()

    • Result: "You have called this function via JavaScript."
  • URL: http://localhost/validation.py?javascript=while(1){}

    • Result: Nginx timing out, while the Python script keeps running at 100% CPU usage. I also issued kill -ALRM ${pid} to the process but it had absolutely no influence to it.

I've also tested a very small script, which worked.

import signal
from time import sleep

def main():
    while 1:
        sleep(1)
        print "main"

def timeout_handler(signum, frame):
    raise Exception

signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(10)

try:
    main()
except:
    print "whoops"

Below are the references I've looked through so far:

Could you kindly give me a hint as to what I am doing wrong, or even better, suggest a better way to achieve the anti-DoS solution?

Community
  • 1
  • 1
  • I did not dig into the detailsof your specific problem, but http://stackoverflow.com/questions/18581174/max-execution-time-for-function-in-python-flask?rq=1 just saved my day ;). Maybe it helps for you, too. – OBu Oct 04 '13 at 06:52
  • Looks promising. If it works for CPython then it might also work for PyV8, as the V8 part of it is written in C++. Thanks for the info! – Christopher Smith Oct 06 '13 at 07:47
  • @ChristopherSmith: Any update on this issue? I'd be very interested in your solution. – Michel Müller Apr 01 '14 at 08:45
  • Btw. I've just stumbled upon this: https://github.com/taguchimail/taguchi-commonjs/blob/master/tagcommonjs/sandbox.py ; they also have quite a sane binary distribution, check out its stable branch for revision numbers of PyV8 / V8 that lead to less memory leaks. I'm thinking in terms of a DDoS you'd have to think about these as well btw. Since I couldn't find any version of PyV8 that is leak free, the only approach that works IMO is to have PyV8 running in a seperate process which is getting restarted when memory usage becomes too high. – Michel Müller Apr 01 '14 at 09:04

0 Answers0