猿人学-Android端爬虫比赛第五关【双向认证】解题笔记

一、知识点:

单向认证:服务端向客户端发送CA证书,并用证书中的公钥对随机数加密使其成为通信秘钥

双向认证:服务端和客户端都有CA证书,并向对方发送,服务端选择加密方案让客户端进行加密密钥。

以上认证可以使用中间人抓取数据。为了防止中间人抓取又出现了:SSL-pinning

SSL-pinning有两种方式

证书锁定(Certificate Pinning):客户端代码内置仅接受指定域名的证书.
公钥锁定(Public Key Pinning):提取证书中的公钥并内置到客户端中,通过与服务器对比公钥值来验证连接的正确性.

二、实战:

打开charles抓包:

猿人学-Android端爬虫比赛第五关【双向认证】解题笔记_第1张图片

 猿人学-Android端爬虫比赛第五关【双向认证】解题笔记_第2张图片

返回信息是 SSL握手失败,那么最大的可能就是使用了SLL-pinning。

那么我们尝试把证书down下来。frida代码如下:

function hook_KeyStore_load() {
    Java.perform(function () {
        var ByteString = Java.use("com.android.okhttp.okio.ByteString");
        var myArray=new Array(1024);
        var i = 0
        for (i = 0; i < myArray.length; i++) {
            myArray[i]= 0x0;
         }
        var buffer = Java.array('byte',myArray);
        
        var StringClass = Java.use("java.lang.String");
        var KeyStore = Java.use("java.security.KeyStore");
        KeyStore.load.overload('java.security.KeyStore$LoadStoreParameter').implementation = function (arg0) {
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));

            console.log("KeyStore.load1:", arg0);
            this.load(arg0);
        };
        KeyStore.load.overload('java.io.InputStream', '[C').implementation = function (arg0, arg1) {
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));

            console.log("KeyStore.load2:", arg0, arg1 ? StringClass.$new(arg1) : null);

            if (arg0){
                var file =  Java.use("java.io.File").$new("/sdcard/Download/"+ String(arg0)+".p12");
                var out = Java.use("java.io.FileOutputStream").$new(file);
                var r;
                while( (r = arg0.read(buffer)) > 0){
                    out.write(buffer,0,r)
                }
                console.log("save success!")
                out.close()
            }
            this.load(arg0, arg1);
        };

        console.log("hook_KeyStore_load...");
    });
}

猿人学-Android端爬虫比赛第五关【双向认证】解题笔记_第3张图片

  把证书pull到电脑,使用KeyStore Explorer工具转换为.p12文件,此处保存的虽然也是.p12但真实文件可能并不是.p12。所以此处需要转换一下。

此处转换后色.p12文件导入charles一直报密码错误。但是密码真的没有错。但是就是无法导入,没有找到具体原因,所以我们转换为了PEM证书,并成功导入。

猿人学-Android端爬虫比赛第五关【双向认证】解题笔记_第4张图片

但是我们添加完证书之后还是抓取不到数据

猿人学-Android端爬虫比赛第五关【双向认证】解题笔记_第5张图片 错误是处理证书发生错误 

此处我们猜测是将服务器证书与APP预埋证书做对比,来完成强校验。

那么我们直接hook它会用到的API

function hook_ssl() {
    Java.perform(function() {
        var ClassName = "com.android.org.conscrypt.Platform";
        var Platform = Java.use(ClassName);
        var targetMethod = "checkServerTrusted";
        var len = Platform[targetMethod].overloads.length;
        console.log(len);
        for(var i = 0; i < len; ++i) {
            Platform[targetMethod].overloads[i].implementation = function () {
                console.log("class:", ClassName, "target:", targetMethod, " i:", i, arguments);
                //printStack(ClassName + "." + targetMethod);
            }
        }
    });
}

再次抓包:

猿人学-Android端爬虫比赛第五关【双向认证】解题笔记_第6张图片

成功抓取请求。

 让我们来循环出flag吧


import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)#跳过警告信息

def main():

    head = {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': '6',
        'Host': '180.76.60.244:18443',
        'Connection': 'Keep-Alive',
        'Accept-Encoding': 'gzip',
        'User-Agent': 'okhttp/3.14.9',
    }

    count = 0
    for i in range(1,101):

        payload = {
            'page': str(i),
        }
        print(i)
        r = requests.post("https://180.76.60.244:18443/api/app5", data=payload,cert="1.pem",headers=head,verify=False,allow_redirects=False )
        # print(r.status_code,r.url,i)
        data = r.json()['data']
        for v in data:
            # print("v:",v['value'])
            count += int(v['value'])

    print("count:",count)

if __name__ == '__main__':
    main()

你可能感兴趣的:(安卓,安卓逆向,爬虫,frida)