“BLIND” Reversing – A Look At The BLIND iOS App

preface

“Blind is an anonymous community app for the workplace.” In other words, as an employee who has the intention of “speaking up” or anonymously bashing an employer or colleague (which is extremely common), Blind might be the place to go. This fun little app helps us see beyond the surface of things.

Scope and Environment

I focused on the app itself, so I signed up with a Linkedin account instead of a work email. This creates some access restrictions. Also, I didn’t take the time to learn all of the features, just a few components that I thought were core, so there were limitations.

Environment setup is as follows:

– Jailbroken iPhone 5S running iOS 9.3.3 -jtool -IDA pro-hopper -BurpSuite pro-frida

Escape detection

First, the app doesn’t have any jailbreak detection routines. I hold my tongue at your contempt for the time being. Nor do I initially see the lack of such checks as a security issue per se, but not from a broader, deeper defense point of view.

Certificate of fixed

The second observation is that the application does not check the authenticity of the remote endpoint through SSL certificate authentication (certificates are fixed), so it can listen and tamper with data through a man-in-the-middle (MiTM) attack. In fact, it’s not as bad as it sounds. The reasons are as follows: 1. The attacker must trick the user into installing a malicious certificate on the device. 2. The application encrypts the data sent to the backend.

On the other hand, attackers most often need to trick users into installing malicious certificates first. I agree, because tools do exist to simplify the process. Sensepost blog posts (sensepost.com/blog/2016/t…). Is a good example.

Finally, the application offers two login options: work email and LinkedIn authentication (see figure below). As mentioned above, I prefer the latter. The side effect is that an attacker can capture LinkedIn login credentials without the certificate being fixed, of course, if the malicious certificate is installed.

The login options

Get binaries

Once you’ve solved these problems, you can get the binaries and start working backwards. I use DumpDecrypted dylib, just SSH into the device and run the following code:

root@Jekyl (/var/root)# su mobile mobile@Jekyl (/var/mobile/Documents)# DYLD_INSERT_LIBRARIES=/var/root/dumpdecrypted.dylib /private/var/containers/Bundle/Application/3C411AB3-6018-4604-97D2-DC2A546EAB85/teamblind.app/teamblind mach-o decryption dumper DISCLAIMER: This tool is only meant for security research purposes, not for application crackers. [+] detected 64bit ARM binary in memory. [+] offset to cryptid found: @0x1000d4f28(from 0x1000d4000) = f28 [+] Found encrypted data at address 00004000 of length 7995392 bytes - type 1. [+] Opening /private/var/containers/Bundle/Application/3C411AB3-6018-4604-97D2-DC2A546EAB85/teamblind.app/teamblind for reading. [+] Reading header [+] Detecting header type [+] Executable is a plain MACH-O image [+] Opening teamblind.decrypted for writing. [+] Copying the not encrypted start of the file [+] Dumping the decrypted data into the  file [+] Copying the not encrypted remainder of the file [+] Setting the LC_ENCRYPTION_INFO->cryptid to 0 at offset f28  [+] Closing original file [+] Closing dump fileCopy the code

DYLD_INSERT_LIBRARIES=dumpdecrypted. Dylib kills the injected process on iOS 9.3.3 with root permission:

 root@Jekyl (/var/root)# DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /private/var/containers/Bundle/Application/3C411AB3-6018-4604-97D2-DC2A546EAB85/teamblind.app/teamblind  
 zsh: killed   DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib   
 root@Jekyl (/var/root)# 
Copy the code

The solution is to switch to the mobile phone first and then CD to the /var/mobile/Document above. Note also that we are able to inject our own dylib because Blind applications do not have __RESTRICT segments.

 LC_SEGMENT_64     Mem: 0x100008000-0x100008000     __RESTRICT  
      Mem: 0x100008000-0x100008000          __RESTRICT.__restrict 
Copy the code

This is a null segment (size 0) that tells DLYD not to trust any DLYD* environment variables.

To identify the endpoint

When I look at binaries, I typically dump strings and search for URL endpoints, then use that list to confirm Burpsuite traffic.

macho-reverser:BLIND macho-reverser$ jtool -d __TEXT.__cstring teamblind.decrypted | grep "http" Address : 0x1006dcfd0 = Offset 0x6dcfd0 0x1006df366: https://api.linkedin.com/v1/people/~:(id,email-address,first-name,last-name,headline,num-connections,industry,summary,sp ecialties,positions:(id,title,summary,start-date,end-date,is-current,company:(id,name,universal-name,type,size,industry, ticker,email-domains)),educations:(id,school-name,field-of-study,start-date,end-date,degree,activities,notes),associatio ns,interests,num-recommenders,date-of-birth,publications:(id,title,publisher:(name),authors:(id,name),date,url,summary), patents:(id,title,summary,number,status:(id,name),office:(name),inventors:(id,name),date,url),languages:(id,language:(na me),proficiency:(level,name)),skills:(id,skill:(name)),certifications:(id,name,authority:(name),number,start-date,end-da te),courses:(id,name,number),recommendations-received:(id,recommendation-type,recommendation-text,recommender),honors-aw ards,three-current-positions,three-past-positions,volunteer)?format=json 0x1006df80e: http://us.teamblind.com 0x1006e19ad: https://api.linkedin.com/v1/people/~:(id,email-address)?format=json 0x1006e75df: https://m.facebook.com/settings/email 0x1006e760c: https://www.linkedin.com/m/settings/email 0x1006ea5ec: https://docs.google.com/forms/d/e/1FAIpQLSc_J26TtkDL7HXcLeFXC2jy6lb1PmJSPnh51_ng7fr1638p_Q/viewform 0x1006ee9c3: https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=%@&scope=%@&state=%@&redirect_uri=%@ 0x1006f4865: https://krapi.teamblind.com 0x1006f4881: https://usapi.teamblind.com 0x1006f489d: http://kr.stage.teamblind.com:8080 0x1006f48c0: http://us.stage.teamblind.com:8080 0x1006f48e3: http://dev.teamblind.com:8080 0x1006f4901: http://us.dev.teamblind.com:8080 0x1006f4922: https://kr.teamblind.com 0x1006f493b: https://us.teamblind.com 0x1006f4954: https://krnotifier.teamblind.com 0x1006f4975: https://usnotifier.teamblind.com ----Copy the code

You can also use it to get lists of other potential targets. So start Burpsuite and check the traffic. As mentioned earlier, it doesn’t matter that the Blind application can fix the certificate because the application encrypts the data sent to the back end. The following figure shows an example of a common request.

Request samples

The only certainty is the link identified earlier. So we are effectively blind. But if the data is encrypted, how and where is the encryption key stored or generated? Can you see the plaintext data sent by the application to the server?

Extract the class

To answer these questions, first dump the class to see if there is anything valuable. A reference to Objective-C is found after listing the code snippet:

macho-reverser:BLIND macho-reverser$ jtool -l teamblind.decrypted   
 LC 00: LC_SEGMENT_64     Mem: 0x000000000-0x100000000     __PAGEZERO  
 LC 01: LC_SEGMENT_64     Mem: 0x100000000-0x1007a4000     __TEXT  
      Mem: 0x100007a90-0x100663f18          __TEXT.__text     (Normal)  
      Mem: 0x100663f18-0x10066723c          __TEXT.__stubs     (Symbol Stubs)  
      Mem: 0x10066723c-0x10066a560          __TEXT.__stub_helper     (Normal)  
      Mem: 0x10066a560-0x100671ec0          __TEXT.__const       
      Mem: 0x100671ec0-0x1006dcfc9          __TEXT.__objc_methname     (C-String Literals)  
      Mem: 0x1006dcfd0-0x10074ca58          __TEXT.__cstring     (C-String Literals)  
      Mem: 0x10074ca58-0x100754bb2          __TEXT.__objc_classname     (C-String Literals)  
      Mem: 0x100754bb2-0x100767daa          __TEXT.__objc_methtype     (C-String Literals)  
      Mem: 0x100767daa-0x100768e18          __TEXT.__ustring       
      Mem: 0x100768e18-0x100788c4c          __TEXT.__gcc_except_tab       
      Mem: 0x100788c50-0x10078b967          __TEXT.__swift3_typeref       
      Mem: 0x10078b968-0x10078c6a0          __TEXT.__swift3_capture       
      Mem: 0x10078c6a0-0x10078d720          __TEXT.__swift3_fieldmd       
      Mem: 0x10078d720-0x10078e67d          __TEXT.__swift3_reflstr       
      Mem: 0x10078e680-0x10078edc8          __TEXT.__swift3_assocty       
      Mem: 0x10078edc8-0x10078f3c8          __TEXT.__swift2_proto       
      Mem: 0x10078f3c8-0x10078f478          __TEXT.__swift2_types       
      Mem: 0x10078f478-0x10078f4dc          __TEXT.__swift3_builtin       
      Mem: 0x10078f4dc-0x1007a3d20          __TEXT.__unwind_info       
      Mem: 0x1007a3d20-0x1007a4000          __TEXT.__eh_frame       
 LC 02: LC_SEGMENT_64     Mem: 0x1007a4000-0x100980000     __DATA  
      Mem: 0x1007a4000-0x1007a4ba8          __DATA.__got     (Non-Lazy Symbol Ptrs)  
      Mem: 0x1007a4ba8-0x1007a6dc0          __DATA.__la_symbol_ptr     (Lazy Symbol Ptrs)  
      Mem: 0x1007a6dc0-0x1007a6e00          __DATA.__mod_init_func     (Module Init Function Ptrs)  
      Mem: 0x1007a6e00-0x1007cfd20          __DATA.__const       
      Mem: 0x1007cfd20-0x10080f300          __DATA.__cfstring       
      Mem: 0x10080f300-0x100811498          __DATA.__objc_classlist     (Normal)  
      Mem: 0x100811498-0x1008114d0          __DATA.__objc_nlclslist     (Normal)  
      Mem: 0x1008114d0-0x100811890          __DATA.__objc_catlist     (Normal)  
      Mem: 0x100811890-0x1008118e8          __DATA.__objc_nlcatlist     (Normal)  
      Mem: 0x1008118e8-0x1008123b0          __DATA.__objc_protolist       
      Mem: 0x1008123b0-0x1008123b8          __DATA.__objc_imageinfo       
      Mem: 0x1008123b8-0x10092bf38          __DATA.__objc_const       
      Mem: 0x10092bf38-0x100944b20          __DATA.__objc_selrefs     (Literal Pointers)  
      Mem: 0x100944b20-0x100944c88          __DATA.__objc_protorefs       
      Mem: 0x100944c88-0x100946ee0          __DATA.__objc_classrefs     (Normal)  
      Mem: 0x100946ee0-0x100948918          __DATA.__objc_superrefs     (Normal)  
      Mem: 0x100948918-0x10094ee80          __DATA.__objc_ivar       
      Mem: 0x10094ee80-0x100965188          __DATA.__objc_data  
 ------
Copy the code

We can dump classes and methods using the objC option of jtool -jcolor =1 jtool -v -d objc teamblind.decrypted.

Extract class information using Jtool

Also need to be clear, although in this paper, using IDA, the reader can completely according to their own need to use jtool disassembly, such as the study of a particular kind of input jtool UserControl – d: getSecretUserDefaultString: Teamblind decrypted.

Disassembly information

Decrypting encrypted value

Now, we have successfully intercepted traffic, but how to crack the encrypted traffic is a problem. Might as well find out the encryption implementation method first. As mentioned above, Blind allows you to log in through your work email or LinkedIn account. After logging in, you will see the option to create an account:

Login screen

Application Settings available in com. Teamblind. Blind. The lookup in the plist, Location in the/private/var/mobile/Containers/Data/Application / < app_id > / Library/Preferences/com. Tea mblind. Blind. Plist. At this point, an examination of the file reveals that it contains the clear text email and the company information entered when you logged in. You can use the plutil utility to read the files.

Plist code

Once you enter your password and username, click “Start” and it’s a different story.

Now, instead of being stored in clear text, your email is encrypted, with a password and a few other values. Never store sensitive information such as passwords in plist files. Keen readers will notice that I don’t hide the password_enc value. The key name ending in _enc indicates that the value might be encrypted, but is it? Also, note that this value is an essential part of the encryption process, for reasons explained below. Next, we’ll explore this value in more detail.

“Encryption password” is only a md5 hash value, can be seen in AuthCompleteViewController requestPassword.

Create a password hash

After obtaining the user-provided value at 0x000000010004EB50, calculate the MD5 hash value at 0x000000010004EB8C. To verify this, we use Python at the same plist value as above. Now, my super password is easy to see.

 >>> import hashlib  
 >>> m = hashlib.md5()  
 >>> m.update("password#1")  
 >>> print m.hexdigest()  
 5486b4af453c7830dcea12f347137b07  
 >>> 
Copy the code

Identify ViewControllers

To determine which classes to check, I first go to the account creation page and determine the ViewController appearance with Cycript:

Root @ Jekyl (/ var/root) # ps aux | grep blind mobile 4136 815696 59532 0.1 5.8?? Ss and PM 0:06. 85 / var/containers/Bundle/Application / 3 d2 c411ab3-6018-4604-97 - DC2A546EAB85 / teamblind app/teamblind root 4139 0.0 0.0 657104 212 s000 R+ 4:11pm 05:00.01 grep blind root@Jekyl (/var/root)# cycript -p 4136 cy# [[[UIWindow keyWindow] rootViewController] _printHierarchy].toString() "<UINavigationController 0x15615d000>, state: appeared, view: <UILayoutContainerView 0x157415a30>\n | <RootViewController 0x1570db260>, state: disappeared, view: <UIView 0x157337ab0> not in the window\n | <AuthCompleteViewController 0x155f587c0>, state: appeared, view: <UIView 0x155da07a0>" cy#Copy the code

Don’t forget that your email is encrypted. Encryption conventions are also presented in the requestPassword method. Your email is first retrieved via plist(NSUserDefaults) and then transmitted to the NSString ([NSString encryptHES256:]) encryptHES256 method.

Read user E-mail

The encryptHES256 method generates an encrypted secret key with a simple xor of the password and some “random” values before transiting to the AES256EncryptWithKey method, which covers the encryption process. From a technical point of view, this method calls another function, but the overall picture is becoming clearer and “random” is not hard to spot.

Frida

You can see this in action with a little help from Frida. For those of you who are not familiar with Frida, I strongly encourage you to add this tool to your Arsenal and check Frida CodeShare before using the Go script. Of course, a routine check before code runs is always a necessary step.

Using the Frida and CodeShare ObjC Method Observer scripts, we can observe the AES256EncryptWithKey method in action:

macho-reverser:BLIND macho-reverser$ frida -U --codeshare mrmacete/objc-method-observer -f com.teamblind.blind ____ / _ | Frida 10.6.15 - A world - class dynamic instrumentation framework | (_ | | > _ | Commands: /_/ |_| help -> Displays the help system . . . . object? -> Display information about 'object' . . . . exit/quit -> Exit . . . . . . . . More info at http://www.frida.re/docs/home/ Spawned `com.teamblind.blind`. Use %resume to let the main thread start executing! [iPhone::com.teamblind.blind]-> %resume [iPhone::com.teamblind.blind]-> observeSomething('*[* *AES256EncryptWithKey:*]'); (0x125fcdca0) -[NSData AES256EncryptWithKey:] AES256EncryptWithKey: password#1^0123456789abcdefghijk 0x1001b25cc teamblind! 0x11e5cc 0x1000e2c7c teamblind! 0x4ec7c ----Copy the code

Now, passwords and E-mail encryption are known. Basically, repeat the above steps to find additional encrypted values. Next, understand the actual traffic.

As described above, equipment outlet flow monitoring results show that all requests include a payload. After a search string in IDA found that most of the request parameters in [NetworkControl encRequestWithParams: showAlert: completionBlock: failBlock:] method in the Settings.

encRequestWithParams

This method first attempts to retrieve the previously generated encryption key and initialization vector (IV). If this fails, it calls the EncriptControl class makeKeyAndIvForEnc (-[EncriptControl makeKeyAndIvForEnc]) method. Yes, it’s Encript with IV. Or maybe it’s called cryptic security… 🙂

makeKeyAndIvForEnc

What’s interesting about this approach is that the encryption key is generated by combining the user password with a hard-coded value. Remember password_enc? The method first tries to retrieve it:

Generate another MD5 hash from the hard-coded value:

Generate static values

If user password retrieval is involved, then a hash value is regenerated:

Finally, the secret key is set and ends with the hash1+hash2 or hash1+password_enc combination.

Generate the actual secret key

In this case, the encryption key is md5(“QkdEhdk”) + md5(” password#1″), Thus, “C07bCDC2 3522ED81 fb76DB0c 0C4387CF 5486b4AF 453C7830 DCEA12F3 47137B07” is obtained.

The rest of the method sets the initial vector (IV) :

Generation IV

To break through the darkness

The NetworkControl class encRequestWithParams method sets up the encryption by calling EncriptControl class makeKeyAndIvForEnc. Set up after the class EncriptControl makePayloadDataWithJsonString encRequestWithParams method calls. This method calls CocoaSecurity aesEncryp with IV, using the encryption key mentioned earlier, and returns base64 encoded ciphertext, which is what Burp renders.

Encrypted payload

Jtool -d objc dump EncriptControl

Encript instance variable

After collecting all the clues, write a Frida script to get the instance variables, i.e., the encryption key, plaintext data, and corresponding ciphertext:

if(ObjC.available){ var makeKandIv = ObjC.classes.EncriptControl["- makePayloadDataWithJsonString:"]; Interceptor.attach(makeKandIv.implementation, { onEnter: function(args) { /* Get Class/Params */ var obj = ObjC.Object(args[0]); var params = ObjC.Object(args[2]); /* Get ivars */ var ivar = obj.$ivars; // Print ivars values console.log("-----------------------------------------------------------\n"); console.log("_encKey: " + ivar["_encKey"] + "\n"); console.log("_encIv: " + ivar["_encIv"] + "\n"); console.log("_encIvStr: " + ivar["_encIvStr"] + "\n"); console.log("_encKeyForDM: " + ivar["_encKeyForDM"] + "\n"); console.log("_encKeyForDM: " + ivar["_encIvForDM"] + "\n"); console.log("-----------------------------------------------------------\n"); console.log("PARAMS: " + params); }, onLeave: function onLeave(retval) { console.log("Encrypted Payload: " + new ObjC.Object(retval).toString() + "\n"); }}); }Copy the code

One encrypted BURP traffic

Now it becomes:

Plaintext data with encryption keys

In addition, the connection EncriptControl class convertDictionaryEncWithResultStr: method to print out the server response after clear. Consider using the Brida Burpsuite plug-in for other options.

conclusion

Ok, let’s call it a day. As mentioned above, I didn’t sign up for a Blind account and therefore couldn’t use the membership feature. But that’s fine. I’m only interested in some data from the Burp. Given the nature and requirements of the application, I intend to explore more. Therefore, no malicious traffic is sent to the Blind server.

Happy hacking!!!

This article can be used for further research around Blind applications. The blog assumes no responsibility for the use of the information provided.


This article was published by Seebug Paper. Address:paper.seebug.org/440/