iCTF 2010 was again wicked sick this year, with a lot of new ideas. As usual, I picked the broken service that didn't respond for half the time, yet was easy to do: ccstore. We started our analysis before the network was up, since the ccstore service source & binaries were distributed ahead of time via LityaLeaks.
The Java service was distributed in source form and contained a threaded TCP server, that would accept one line on the connection, write save it to a file and then read back the first line of this file to the socket:
this.clientSocket.setSoTimeout(1000);
out = new PrintWriter(this.clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
String ccinfo;
ccinfo = in.readLine();
filename = this.storeToTemp(ccinfo);
System.out.println(filename);
if ((filename == null) || (filename.length() == 0)) {
throw new Exception("CC data cannot be stored");
}
BufferedReader tmpfile = new BufferedReader(new FileReader(filename));
line = tmpfile.readLine();
if (line != null) {
out.println(line);
}
else {
out.println("No CC data");
}
Judging from the names, this service would store dumped credit card data. The storeToTemp function was given in the Java source like this:
public String storeToTmp(String text) {
try {
BufferedWriter out = new BufferedWriter(new FileWriter("tempfile.cc"));
out.write(text);
out.close();
return new String("tempfile.cc");
} catch (Exception e) {
return null;
}
However, the file declared the function native after a lot of blank lines:
public native String storeToTemp(String text);
Which was already hinted at by loading a native library upon startup:
System.loadLibrary("c-lamp");
Reversing the c-lamp library was straightforward, it only implemented the necessary JNI stuff for giving a native x86 implementation of storeToTemp.
This native function expected to be the input string a 4-tuple of space separated character strings, of which the third tuple was passed to the native sub-function
verify. Just before that, it created a temporary dropzone file, it would write to:
The verify function expected a 0Ch - 13h characters input string of all digits and would return success or failure for verifying the input. Given the name
of the service, I guessed at the public credit card validation algorithm, but never verified. Simply playing with gdb a little, I came up with a very easy, valid input:
12300000000000. Might as well have tried my real credit card number. The implementation was using shifts, loops etc. but I really didn't care anlysing that:
If the verify check failed, the function would just exit. Otherwise, it would use a loop on a copy of the input line to replace all spaces with 2Ch, a comma.
The function would then build a new Java string from the C string on the stack which contains the filename, it wrote to and return. Therefore, we saw the expected behavior
that was similiar to the Java sourcecode (just spaces replaced with commata):
Interestingly, the code protects against buffer overflows with strncpy(.., .., 100h). However, the code fails to add a trailing zero byte, if the string exceeds this length. The code subsequently uses an unprotected strcpy call to copy the input to a temporary buffer for replacing the spaces. This temporary buffer resides
directly before the filename buffer on the stack:
Therefore, we can provide a large input line longer than 100h bytes and a copy of s1 (which is the first part of the 4-typle parsed with sscanf) will overwrite the filename buffer. This allows us to influence the return value to the Java code, which will open this file and give us the first line for us. The exploit for this is trivial:
sckt.send(filename + ' a 12300000000000 ' + ('A' * 256))
Note that it sends more As than required, as only the total length must be 256 (or longer).
Analyzing this was almost trivial and I was a little disappointed by this year's iCTF for a lack of real binary exploitation in services (friends told me later, there was
one nice 64bit local linux challenge though). So why didn't we get out first place (I played on 0ldEur0pe)? We had the exploit working before the network was up, so we
theoretically could have been earning leetness points during the whole time. Except that I didn't listen to the initial briefing and did not know, what file to read. I tried
guessing tmpnam names, but failed (as did bruteforcing of course). Closer to the end, one of the organizers told me that there would be a file called "secrets.txt" and I started earning points right away... -.-

