How I engineered #ieeesc2014

How I engineered #ieeesc2014

Disclaimer: Nothing of this was done with bad intentions, this has been transparent to most of the people named here. I consider it the “engineering approach”, which seems to be appropriate for the event.

The App and the Game

During the cocktail reception on Friday afternoon, I met Brenda from Region 6, who told me about the game built into the app for #ieeesc2014. It allows to collect points for certain actions in the app, e.g. adding each others contacts, and how good of an icebreaker it is to meet random people. And over the conversation, I found Jan H. to be leading the game with over 2000 points. Already! Over a beer he told me he liked such kind of game and invested some time weeks ahead of the conference to collect a few points. So I started to join the game and collected around 500pts the first evening.

The Question

The next morning, Jan lead the pack with more than 6000 points, adding ~4000 points on top of what he had the evening before. Quite irritating, the other 2000 points have taken weeks, as for what Jan told me. So I had to ask him how these 4000 extra points happened. His answer was very straight forward: “The app is buggy.”. He elaborated a bit more what he did: entering random codes for booths, ignite talks or sessions will eventually give you points.

The Idea

The codes were all announced after each session and ignite talk. So did I pay a bit more attention to this detail during the first session I attended on Saturday. The code was “4342“. It gave me 20 points after I entered it into the mobile app. And listening to Jan, I remember he tried random numbers. So I continued “4343“, “4344“, “4345“, etc. Obviously, I was too bored after only a few minutes. Reminding myself there was a webapp, I tried the same on-line.  To no surprise, what the app did, was POSTing the 4digit code to an URL. Along with my session cookie. Bang.

The Solution

Obviously, trying (brute forcing) all combinations is not too complex with 4 digit codes. And posting them to a website is neither. Hence, the software-engineer in me felt like trying it out. The result is about 50 lines of very imperative python script, to POST all 10000 combinations, building on the requests library.

Running the script took around 90 minutes and bought me ~6500 points

The price

Foremost, it was a lot of fun to battle Jan for the first place. Even though I collected most of the points through a script, he gave me a hard time to stay ahead. After almost 1.5 days, we agreed to win both in a tie. The price was an IEEE themed water bottle. Picture may follow.

The script

Jan asked me a few times whether he could get the script, and I promised to give to him after the event was over. Please note I tried to automate voting for the surveys too, and didn’t bother to clean up afterwards. It’s for sure not an example in software engineering. So, here it is:

import requests

import re


def urldecode(url):
    """
    Decode an encoded url.
    Usage:
    url = 'http://www.example.com/this%20is%20my%20test%20%26%20%23%24'
    decoded_url = urldecode(url)
    """
    if url.find(" ") == -1:
        url = url.replace("+", " ")

    p = re.compile("%(?=[0-9A-F]{2})")

    plist = p.split(url)

    if len(plist) > 1:
        for i in range(1, len(plist)):
            plist[i] = '%s%s' % (chr(int((plist[i])[:2], 16)), (plist[i])[2:])

        decoded_url = ''.join(plist)

        return decoded_url
    return url


# Fill in your details here to be posted to the login form.
payload = {
    'username': 'andreas@neumeier.org',
    'password': 'xxxxxxxxxx',
    'button': 'mySubmit',
}

cookies = {
    'PHPSESSID': 'data from real headers',
    'UDID': '53f898d9db950',
    'ci_session':'data from real headers',
    'lastUrl': 'login/index',
    'SessionId': 'xxxxxxxx',
    'express_session': 'data from real headers',
}

headers = {
    'Host': 'sc2014.quickmobile.com',
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'de,en;q=0.5',
    'Accept-Encoding': 'gzip, deflate',
    'Referer': 'https://sc2014.quickmobile.com/login/index',
    'Connection': 'keep-alive',
    'Content-Type': 'application/x-www-form-urlencoded',
}

# Use 'with' to ensure the session context is closed after use.
with requests.Session() as s:
    req = requests.Request('POST',
                           'https://sc2014.quickmobile.com/login/validate',
                           data=payload,
                           # cookies=cookies,
                           headers=headers
                           )
    prepped = s.prepare_request(req)
    resp = s.send(prepped)
    # print the html returned or something more intelligent to see if
    # it's a successful login page.

    # An authorised request.
    req = requests.Request('GET',
                           'https://sc2014.quickmobile.com/game/qrzones',
                           headers=headers
                           )
    prepped = s.prepare_request(req)
    resp = s.send(prepped)

    for i in range(9999, 10000):
        gamecode = ((u"%s" % (i)).zfill(4))
        qrcodedata = {
            'gameCode': gamecode,
            'activitycode': '',
            'Submit': 'Submit',
        }
        req = requests.Request('POST',
                               'https://sc2014.quickmobile.com/game/commitGameSubmit',
                               data=qrcodedata,
                               headers=headers,
                               )
        prepped = s.prepare_request(req)
        # resp = s.send(prepped)
        invalid = 'Invalid' in resp.text
        if invalid:
            print ("%s: %s contained 'Invalid'" % (resp.status_code, gamecode))
        else:
            print ("%s: %s appears to be good." % (resp.status_code, gamecode))

    pd1 = urldecode('SQ30YULJ%5B%5D')
    pd2 = urldecode('SQ37STPC%5B%5D')
    pd3 = urldecode('SQ41FRYL%5B%5D')
    pd4 = urldecode('SQ38WBJZ%5B%5D')
    pd5 = urldecode('SQ39ZUFJ%5B%5D')
    pd6 = urldecode('SQ40VCGW%5B%5D')
    pd7 = urldecode('SQ42MROG%5B%5D')

    data = {
        pd1: 'SA40CSYO',
        pd2: 'SA72UTMI',
        pd3: 'SA40CSYO',
        pd4: 'SA60SBZA',
        pd5: 'SA40CSYO',
        pd6: 'SA40CSYO',
        pd7: 'SAqmt1',
    }
    req = requests.Request('POST',
                           'https://sc2014.quickmobile.com/surveys/detail/0/SS313NTXJ/S39JNRY',
                           data=data,
                           headers=headers,
                           )
    prepped = s.prepare_request(req)
    resp = s.send(prepped)
    print resp.status_code
    print resp.text