h1702ctf 2017 — Writeups

About 4 weeks ago, Hacker1 held their h1702ctf as a qualifier for the main h1702 event in Las Vegas later this month. The theme of this CTF was mobile applications, specifically applications on iOS and Android. I managed to be the 6th person to complete all the challenges. I managed to be invited to the actual event as a finalist, but am unfortunately unable to go.

As a bit of background of my experience, I mainly specialise in iOS and have barely touched on Android before.

iOS 1

I first dropped the binary into Hopper, and looked for strings that contained the word ‘flag’. The only relevant thing that was returned was “Level 1: The flag isn’t in the code!”.

I then moved on to checking if there were any assets that could be related to the flag. I used Asset Catalog Tinkerer to view the contents of the embedded Assets.car file. The first image that was in the file was titled ‘Matrix-Morpheus’, which contained the following image:

Image for post
Image for post

Flag: cApwN{y0u_are_th3_ch0sen_1}

iOS 2

Because one IPA was being used for 4 levels, I thought that now might be the time to install the application onto my device to see what the other levels. The UI for level 2 looked like below:

Image for post
Image for post

I then went to go see what happened when the button was pressed
(-[_TtC11IntroLevels20Level2ViewController buttonTouched:]), which lead me to sub_a930. The first check I noticed was whether the inputted text was 6 characters. I then noticed the string being MD5 hashed, and then a _swift_stdlib_memcmp being performed, but on what? It turns out I had forgot to turn off the ‘Remove potentially dead code’ option, which was hiding the important part, the target hash: 5b6da8f65476a399050c501e27ab7d91. Searching for this hash brought me to its value. Entering 424241 into the textfield generated the following output:

Image for post
Image for post

Flag: cApwN{0mg_d0es_h3_pr4y}

iOS 3

I went to level 3, and saw the following UI:

Pressing any of the buttons would show an alert saying that you had lost and that you had been reported to one of ‘their’ servers. I thought that if a request was being sent to a server, then there must be some sort of URL within the binary.

Using Hopper, I searched for ‘http’, and found ‘https://google.com’, which led me to sub_36cd8. The initial part of the function looked like some sort of obfuscation, but I decided to look at it later if I couldn’t get anything from the rest of the function. I discovered further below that an Alamofire request was being made with additional HTTP headers.

I used BurpSuite to capture any outgoing requests to ‘https://google.com’. Pressing a button and pressing OK, I went and saw Burp had got something. I saw an additional header, look at me i am a header, and its value was cApwN{1m_1n_ur_n00twork_tere3fik}, which was the flag.

iOS 4

I went to level4, and there was only a label present: ‘You got your flags, now do the thing…’ I remember seeing a class in Hopper called ZhuLi which had a method doTheThing:flag2:flag3.

I used Cycript to call this method (I had a jailbroken device). I called Cycript on the process, and ran the following command: [ZhuLi doTheThing:@”cApwN{y0u_are_th3_ch0sen_1}” flag2:@”cApwN{0mg_d0es_h3_pr4y}” flag3:@”cApwN{1m_1n_ur_n00twork_tere3fik}”]. This returned the flag: cApwN{f0h_sw1zzle_my_n1zzle}.

iOS 5

I first installed the application and opened it. It contained a cool GIF, and a button titled “Hammer time!”.

Pressing the button would crash the application. This seemed a bit suspicious, so I decided to look for the method in Hopper: -[_TtC10Level5Demo6DemoVC hammerTime:]. I had struggled a bit here, mainly because Hopper had skipped over marking some locations as subroutines. I manually marked these. The important subroutines were located at 0xa1a4 and 0xa2a8. In the first subroutine, a string “setmeinurkeychain” existed, and in the second, “youdidathing” was there. Additionally in the first subroutine, the custom KeychainThing class was being used with the string.

I decided to try and set the key-value pair into the keychain using Cycript. I used the following two lines:

var k = [[KeychainThing alloc] init]
[k createKeychainValue:@”youdidathing” forIdentifier:@”setmeinurkeychain”]

(formatting is hard D:)

I restarted the application, and pressed the button. This time, a view popped up with a grid and some squares filled up, with the shapes resembling letters. These letters created the flag: cApwN{i_guess_you_can_touch_this}.

iOS 6

Note 1: If you’ve read other h1702ctf writeups, you’ll notice that I went completely over the top with this one :) I was desperate…

Note 2: I started this problem before an update that fixed crashing on 32 bit devices was released (due to 64bit functions being used on 32bit). I had got around this problem by NOPing any calls to the functions using these 64bit functions.

I installed the application on to my device, and noticed a text box. I filled the text box in with some text, and got a series of 1’s and 0’s in return (upon pressing the button).

When the button was being pressed, the thing property was being used to generate the output. I looked into how this property, and it looked like it was some sort of binary tree structure.

I then looked into what was happening with this generated string. It seemed to be inputed into some sort of algorithm which was changing it. The output of that was being checked against a hard-coded value. Not knowing the algorithm, I decided to write a bruteforce to the original string to see what it actually was. You would know if the string is correct if the returned string was “That’s Right Morty!…” instead of the 1‘s and 0’s.

I did this bruteforce in 2 parts:

  1. Binary Patch: Yep, you read that right. I thought that it would take quite a long time to bruteforce all the combinations to find the generated string. What was happening when the check against the expected output was occurring was that it would check if the loop counter was less than or equal to 304. If it was true, it would continue comparing the expected output. Otherwise, it would go to the final handler. I thought that instead of comparing the counter to0x130, I would compare it to stack[2029], which had been used to convert the NSString to a char array. This involved two steps. The first was I modified the instruction above the loading of stack[2028], to load stack[2029] into a register. I then modified the cmp instruction to compare stack[2029] to stack[2028]. Finally, because I had modified the instruction above the loading of the loop counter, I had to modify any jumps to go to that instruction, rather than to the one below it. I tested this, and it seemed to work fine.

After all of this, I finally got the string: c5eg s I r Gr esatcn guc a toi oi osskl997ktakmeeeeeeeeeeeR. I had also managed to get the 1‘s and 0’s representation of it.

From that point, I wasn’t too sure where to go. I discovered the algorithm that was manipulating the text was a custom variant of Salsa20. I then tried to recreate the binary tree in Swift. When I had finished it, I had noticed that some of the values in the dictionary were different to those from the device itself. I wrote a simple function to find the appropriate character for the string, then shorten the string, etc. This returned the flag, cApwN{1m_mr_m33s33ks_l00k_at_meeeeeeeeeee}.

In case you’re interested, here’s the Swift playground I created: https://gist.github.com/ninjaprawn/1cd60999af50334d75855298e1288570

Android 1

I first decompiled the provided APK file using http://www.javadecompilers.com/apk. I then looked at the MainActivity.java file in com/h1702ctf/ctfone. After seeing nothing there, I went to TabFragment1.java, as I noticed in the MainActivity class references to tabs.

In there, I saw that input was being retrieved from the user. The program would then retrieve the file from the assets directory if the file existed, otherwise a random file would be returned. I went into the directory, and noticed a strange file called tHiS_iS_nOt_tHE_SeCrEt_lEveL_1_fiLE. I opened the file in Preview, and it displayed an image with the flag: cApwN{WELL_THAT_WAS_SUPER_EASY}.

Android 2

I opened up TabFragment2.java and noticed an onClick handler was being used. It seemed to be displaying the hash of some plaintext in a textfield. This method was being references from the InCryption class.

I looked within the hashOfPlainText, and noticed that some text was being decrypted. Upon further analysis, encryptedHex was being decrypted with the hex encoded key 0123456789ABCDEF0123456789ABCDEF using AES. I used CyberChef to do this, and got some hex encoded text. I decoded it, and got some text that started with ‘DASH DOT’. This looked to me like morse code. I replaced the words with the appropriate character, and used a morse code translator to get CAPWNBRACKETCRYP706R4PHYUNDERSCORE15UNDERSCOREH4RDUNDERSCOREBR0BRACKET. I replaced BRACKET with the appropriate brackets, and UNDERSCORE with _. This gave me a final flag of CAPWN{CRYP706R4PHY_15_H4RD_BR0}. I had struggled when trying to enter the flag because I thought that the CAPWN prefix was case sensitive across all flags.

Android 3

I went ahead and opened Level3Activity.java, as I thought that since I’m trying to complete level 3, the flag must be related to that. I didn’t see anything important, apart from references to the MonteCarlo class. Within that class, I thought that there again was nothing important to finding the flag for Level 3. However, I did notice a function functionnameLeftbraceOneCommaTwoCommaThreeCommaRightbraceFour, which I thought would be used for Level 4, as I thought that the Android problems would have a similar style to the iOS problems.

I noticed the Requestor.java file, and looked into it. I noticed that a function making a HTTP request to “https://h1702ctf.com/About". I noticed that the header name (hName) and value (hVal) were being retrieved from a function inside a native library. Not noticing any obvious use of the Requestor class, I decided to try and utilise the library in a custom made application.

When doing that, I learnt a couple of important things. The first was that the package name of the app had to be the same as the package the library is being used from, and that the class and function names have to be the same. After I had sorted that out, I called those functions in my custom application, and printed out the results. The full string was X-Level3-Flag: V1RCR2QyUXdOVGROVmpnd1lsWTVkV1JYTVdsTk0wcG1UakpvZVUxNlRqbERaejA5Q2c9PQo=. The value was base 64 encoded multiple times, which ended up with the flag cApwN{1_4m_numb3r_7hr33}.

Android 4

I remembered the native function in the MonteCarlo class that I had seen earlier called functionnameLeftbraceOneCommaTwoCommaThreeCommaRightbraceFour. Using a similar approach to level 3, I called the function within my custom app, using the previous flags as the arguments of the function. The result of this function was the flag: cApwN{w1nn3r_w1nn3r_ch1ck3n_d1nn3r!}.

Android 5

I first decompiled the APK and looked at the MainActivity.java file. I noticed that a native function was being used called flag. After not finding much else from a brief review of that file, I installed the APK onto my device. I noticed that there were 3 text boxes, and a label would pop up when you entered text. I also noticed a pink button at the bottom of the screen, which turned out to be a hint. The hint said “State the secret phrase (omit the oh ex)“. I believed I had to look for something that began with 0x, possibly some hex numbers.

I noticed the CruelIntentions.java file, and opened it. It didn’t seem much use, but I saw that the function one was being used. I decided to view what the function is doing by loading the library into Hopper. When looking through, I did some research, and discovered that it was some sort of anti-debugger check. However, I did notice 4 hex digits that looked like words: 0xbea7ab1e, 0xface1e55, 0xda7aba5e, and 0xdeadbabe. I tried entered the first 3, and got the flag cApwN{sPEaK_FrieNd_aNd_enteR!}.

Android 6

I first installed the APK to my device, and noticed a textfield and a button. Similar to iOS Level 5, if the incorrect text was entered, the application would crash. From this, I moved over to looking at the decompiled APK.

In MainActivity.java, a string comparison was made between the user input, and a certain string. If they were the same, the app would decrypt the something.jar file, and then call a function from a native library. I decrypted the jar file using the stored strings, and decompiled it. I found two classes: Pooper and IReallyHaveNoIdea. The Pooper class seemed to be used for decrypting another target file. I found the key and the IV, which were b1ahbl4hbl4hblop and mmhmthisdatgoods respectively. I found these by figuring out i was the position of the expected character.

I then went to the native library to figure out what was going on there. I realised that offsets were being used to call functions into the Java Runtime. I figured out that the secretasset file was being decrypted via the Pooper class, and then executed. I decrypted the the secretasset file myself, and discovered it was an ELF binary.

I dropped the binary into Hopper, and found that the binary was creating a socket and listening on it. There was lots of XOR obfuscation used, which I manually deobfuscated. I discovered that certain commands could be sent. I noticed in particular the \PRIVATE command which allowed a user to send messages to another user. This was handled in a separate function.

In this function, the first condition was to see whether the recipient was 1337. From this, the message would be iterated through, with a check being performed on it. I discovered that each character was MD5 hashed, and then checked with hardcoded values. I tried “decrypting” the hash, but I found nothing. I spend a lot of time trying to figure out what was happening to the hashes, whether they were being XOR’d or not. I looked more into the MD5 algorithm used, and it turns out 3 of the normal values had been modified slightly. I then generated all the hashes for each character, and the proceeded to find the flag, cApwN{d3us_d3x_my_4pk_is_augm3nted}.

Overall, this was an awesome CTF. I learned a whole bunch of stuff, and did pretty well :) Big thanks to the people at Hacker1 who made the challenges!

Written by

18, Security

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store