Android
参考链接:https://aadityapurani.com/2019/03/07/bsidessf-ctf-2019-mobile-track/#weather
感谢大佬分享。
拿到apk,在JEB中打开,找到MainActivity,先看一下全局的逻辑。
在上图中,v6_1这个StringBuilder()拼接成了一个json字符串,然后和上面的v2、v3一起走到下面的代码段里,最终组成一个URL地址。
1 2 3
| URL v1_3 = ((g)v1_1).a(c.a(v2, v3).a(), TimeUnit.DAYS, new com.b.c.c.g$a[]{com.b.c.c.g$a.a(com.b.b.b.i.a(new ByteArrayInputStream(v6_1.toString().getBytes())))});
String v4 = v1_3.toString();
|
接上面的代码继续往下看,使用v1_3这个URL去打开一个网络连接,然后在v2_1中取得响应内容【v1_4.getInputStream()】并输出,最终函数a()的返回值v0为网络请求的响应内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| private String a(){ ......省略此处代码...... try{ ......省略此处代码......
URLConnection v1_4 = v1_3.openConnection(); v1_4.connect(); v1_4.getContentLength(); BufferedReader v2_1 = new BufferedReader(new InputStreamReader(v1_4.getInputStream())); StringBuffer v1_5 = new StringBuffer(); while(true) { v0 = v2_1.readLine(); if(v0 == null) { break; }
v1_5.append(v0 + "\n"); }
v0 = v1_5.toString(); } catch(IOException v1_2) { v1_2.printStackTrace(); }
if(v4 != null) { Log.d("Background url", "Background URL in progress"); }
return v0; }
|
然后从响应里取数据,并在应用上显示
大体逻辑分析清楚了,接下来要关注的就是上面提到的v6_1这个json字符串里到底是什么内容。
用到的函数在Utils()里
可以看到,分别是Base64解码,int转char,BigInteger转Hex以及三个native层的函数。
为了方便,使用frida框架去hook对应的函数,上传frida server到root的手机设备里,
运行
setenforce 0
关闭SELinux机制,然后运行frida server,并编写hook脚本,这里直接使用参考链接里大佬的脚本。
代码的第一部分使用了android hook时绕过SSL Pinning的一种方法,实际测试时发现删除了也可以hook。相关绕过方法的链接
第二部分是hook java String类中的toString()方法,完美展示了frida万物皆可hook的强大功能。为什么hook这个函数是因为前面代码里有个将URL toString()的操作,把通过各种编码加密处理后的内容呈现出来。
第三部分则是将hook到的toString()打印出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| Java.perform(function(){ var array_list = Java.use("java.util.ArrayList"); var ApiClient = Java.use('com.android.org.conscrypt.TrustManagerImpl');
ApiClient.checkTrustedRecursive.implementation = function(a1, a2, a3, a4, a5, a6) { var k = array_list.$new(); return k; } console.log("Hooking Java"); const StringBuilder = Java.use('java.lang.StringBuilder'); StringBuilder.$init.overload('java.lang.String').implementation = function (arg) { var partial = ""; var result = this.$init(arg); console.log('new StringBuilder("' + result + '");') return result; } console.log("Hooking new StringBuilder(java.lang.String)");
StringBuilder.toString.implementation = function () { var result = this.toString(); console.log('StringBuilder.toString(); => ' + result) return result; } console.log("Hooking StringBuilder.toString() hooked"); }, 0);
|
将上述脚本保存为hook.js
在Android 8.0的Nexus 6P上运行这个应用,使用如下命令开始hook:
frida -U -f com.example.myapplication -l D:\Learning\Android\CTF\hook.js
稍等片刻,即可得到下面的内容。
这段json格式的字符串其实就是Google Cloud Storage里使用服务账号进行授权的密钥文件(json格式),https://cloud.google.com/sdk/docs/authorizing#authorizing_with_a_service_account。
我是第一次听到Google Cloud Storage这个词。。
从网上了解到这个密钥文件的格式后,将上图的hook内容整理(注意\n的使用)如下并保存为key.json文件:
1 2 3 4 5 6 7 8 9 10 11 12
| { "type": "service_account", "project_id": "bsides-sf-ctf-2019", "private_key_id": "6dd7fc48a8b1d49edf7f03f74bc47713bec7d989", "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCbNaJX7qZ2Sec4\n5W4ir+yYXJ3IwjZ8fwyw0PZSoiTb/iJqTcKk/ltjP61TrJHB5MqKm6Vz/WGw7GSm\nnd21xMFqclwuG8N7f+zhIK0XuvRBrS+cMEhw0RbHNUbcO3ZaghKffaLThzPY4x2r\nHh/N8lUYi4TB8WAGaAzCJH3pUi9rTG4+ucxO6pMNz3/ENzyOSmihR9Xb5OkMY/Aq\n7NJ7BAwH8oSWRlTllaC8Chl8wDdun6fKWgYYmmcBWXSjropu8f6MR7vMM3F0PEua\nYBz1ZpxVvYc1iiMS0WiNtAa1ZBuWhRenAiTfwOCt4rISfbgYSqCTSoK5tOWS52tM\ntuzt/OVjAgMBAAECggEAC9T230UuI25W1huHXdWTb7n/vUIw7SSyTvhfDsWVkb+5\n1+i9od5SESrVh79sDR/n4NEkt8blH5ulwJ3gPO8W34qARHORX2TNJgxbpad231rY\nekuj+hW2atFA6aEO0K+Bw+7L7twrs6j8pgLR4d1LZ2ebYz2HWHWuI06s2pCNVNyM\nSMn593YgfmzNotaoJ3dHAwKG8PuNRHh0qDqqLnu0574dXkTFkEePcedyzza007Iy\nCoNTUYJxDO7aJbTQPVyqm7mOewh1SYUdHSofcfALlC9eT2nn6+c9qRgGO3AwbC8V\ns9TmMR9+DWfHrUmPN8AKB4YKov/QGUv29svI0d8YwQKBgQDTobsDSI96xm2s+NnE\nPabZ+W76sg/1o1dPU4w4+/0u/RUT+vJoumsvwf5n7KUXVAP8npu6LYouNlHz9+zV\nThTINxyTrrA5VamFhoEpeY8OFboNVltxKj9nFvbS2jw2GLZQLapN0XIYE0axRNJs\nCSyc2LDYVVj0abjzx0CCFc0S+QKBgQC7v7kpSMJmIwl7FpJm/T9oakdvyZNzt3ZU\n+DTRmPXh/WM5c6j9vdzGKq3IlmHV/SSzVUfwQaxF8VzQlAi69fru/DStT8h7CpGd\nLEz8S0qq7ubbs7gODK/ZrwSQhv8doegZGu0ntURfaVL7AnyKGJVq2SLheVhMhJeZ\nm94mGME2OwKBgFXFSWcGRGhM/WxKGvAG0JWtGwZtnjw+rAcRZFZAApfFqIJFhXNe\ngkyDwhjadvpiaY87tP+ar1MVXteS1qCImbGfbGyKMw+5oQ/luHlXs9vQgGwhYMQX\njES6sOQ54IdIMrOCHnCVfzk0rsTvkJyKh1M2G05CIOBF7NiYG5PdRBT5AoGABEwT\nFNrReDz9DpApsanCNcWY9PoMIe3lC3TS4Kk7l3yRNNNs3sHlt7NqXtjyTE+K83/U\nMa+PHdq0YSHCQWU35RhorD7TO922D37gFDY080ychBLM96VasQTMefJdDHSUN17i\nZrJDaluixpP7/b0qTlPB9J8uYjH2tlFW+FBAu9kCgYBch8VvyBzlGay5r07joRju\ncdnVfrGAUdZRLxA5hrIaKvKFy28CaaKV/lZNI9NmdZntj6aIQ0rzUWidOQsmj2o4\n7VcArl5UNurhx4uhg2GClcUIHY5YdExHfEujBu6uMQdZjBpX87uoaggC7jwJanQC\nlApTPc3478g/mho9S5eDMw==\n-----END PRIVATE KEY-----\n", "client_email": "weather-companion-service-acco@bsides-sf-ctf-2019.iam.gserviceaccount.com", "client_id": "116037946827001874660", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url" : "https://www.googleapis.com/robot/v1/metadata/x509/weather-companion-service-acco%40bsides-sf-ctf-2019.iam.gserviceaccount.com" }
|
但是在安装Google Cloud SDK(安装过程中需要断开shadowsocks,要求使用python2.7.9+)后使用
gcloud auth activate-service-account --key-file=key.json
却被告知invalid_grant,一度怀疑是json格式没整理好的原因,纠结蛮久的。结果后面发现是主办方把这道题的项目或者密钥删了。。
为了搞清楚什么情况,我决定动手生成一个自己的服务账号密钥。
通过下面的网址进入服务账号界面:
https://console.cloud.google.com/iam-admin/serviceaccounts?_ga=2.264695759.-1360606619.1552115951
创建一个服务账号后,Google Cloud Platform的菜单栏里选择"API和服务",然后就看图操作。
下面是我创建的服务账号密钥,用于测试。
1 2 3 4 5 6 7 8 9 10 11 12
| { "type": "service_account", "project_id": "l-project-6598", "private_key_id": "44ce83da2a92a53255bc0549c7516ec0f51532d1", "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDOgpO10EsII69Y\n3VMI7a90sv+rpedkl2lIyWWwDjz9//f6qtpY7OKg3me0qR7MeN6VnP9E51A6RFVT\nt+x9GEEFIfeh4FAawOg97lcmRNcAqoDx9T4mIGQkY5Ynrz6hNc1NIVgXSSceUP4r\nHJgElOhzTE5W9lsr7D6+MOaabuqZWLVODBz8adBdwMW0386yWRwxK/hdJ3k0Vkkh\nWCsXypaMUMJiw9yLy2wP6T4Me0tA4poP2uMv7fA38YY3KQTiL5obNtqg5VMo8UGJ\nvdVF7vGMjxUZ28+ZcF3KgRyVlhMzZ8kkJhlihSzqEIgiKRbULtCZ8bABznZaJ4LQ\nUT5VapERAgMBAAECggEAYuE7AM9fXeJYT2CKJbhJTsN2kCW8CfpFu0hTnFz071nk\nzu2H5xRl30ketu5ThOxLB7BIuiFX1M5rXM6wOaWnXGHLRIM3V9gOW7kHmZdUq0j4\nvOIEhBT2XkYg25eZkW9Fgiz5FQ094dI+IT5ru6XhN3PN/u2u8fUIheC8Si3ZvtpR\nsbQCH8mJdzWMRKbHNpvxI9pvv5jNqs297MyNqgaGmM2UfAnaZogWOWklnagm2oda\nUTzN6SHreOJA/58PQ+zjh8E7sHhDuvq2xcaYvlJXEIZpoAjdOqE38fb/VmUMxmm7\nTGFGxlBuuCPNLhEC/PFT0fk8YfIe00zEGG9eJOw00QKBgQD8VTyeYLKpVJStgh+M\nOS4L+s7tREOiSbmn4cPJrVz1d4iVNQIs464HXPSIP+Sd7c8FDaUwC9FrVS22Prly\nRwNDQpRx5byq1l1VzzlL08ONJilAotdoN3Dcm5+kZtWuyynnnsTBpGHb3CTlpt+t\nAs8FF05GTNHlPhiig9Ogj8IfrwKBgQDRgt0aht2/B+AAGQMPGU0y3pYOHY1J2baR\nCsKqZJ4/Bti15QhpuP9+/QlGwuo+e8iWFKd2dj+HT3Lm1JKQQ9C+tZ0gkToMgn6h\nWw6mDpVWeavfs/yP0XuEz90/0LwfyTRORF9C3IZpjniQB3UAXfvmw5FhdSuNDTa5\nnqm/JwvLPwKBgCB/9fvMJpbKrw+d9+Q+pSCj4C0NIszvQ/tMh8QdESEIkU3ucuZH\nOO332gMGf7Kbo5NaC5GhpAp4ARg9AfOnE9OA6s+0sFUsoP7hXtbWYpR2es+5aZch\ntOalIK2zFQibYD1V5K+wNW5070eo85w8BV/5fXpugIZPNisQYZyHh5A/AoGBAMbm\noBYw95AGX+h31mmdMacbngWklKAJ6sLkHk852uonC9ITr9r+4MCkZQwiu9O6HIIu\n9ZUHSeShzonKQaJoX2LOdG+YsC10Ldft5IhNzAUe2cc0zo+S5tr9pCSTfCYJFHlB\ne9a0GX9Y3KiQC8nfb+hyvjBx1njAlLXAJZLt9MptAoGBAIlG4ehIBWD2xxQ9Mdu4\nyEM621WHb32SHTBa3CSrOs1egUjh6QysYF3nHV8GbLBTW2CSnkVA1lrmz+pU8lYZ\n1vyr0PG8FUz68H/FMbE5MDdTLHwytZh2cr9bmZwJIzn+6KcY4d8NyJRMWCTUmGNI\nniT6f27B8msLzwYNU96EbhGY\n-----END PRIVATE KEY-----\n", "client_email": "l-project@l-project-6598.iam.gserviceaccount.com", "client_id": "112915449445549367190", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/l-project%40l-project-6598.iam.gserviceaccount.com" }
|
使用gcloud auth activate-service-account --key-file=xxx.json是可以访问的。
尝试使用gsutil创建存储分区(https://cloud.google.com/storage/docs/quickstart-gsutil),
发现创建不了,好像是需要注册结算账号,而且注册需要visa卡,我哪有这个。。
最后测试一下删除服务账号密钥,再用gcloud auth命令认证
删除后再认证的结果果然和上面的是一样的
所以应该是题目环境不存在了,最后无法获取flag。
最后截一下参考链接里大佬的图,看一下连上之后的基本操作。
总结完这道题之后,对Google Cloud Storage有了新的认识。