APP渗透—Android 7.0 抓包

 

本文首发于公众号:白帽子左一

用到的工具

Proxifier(可在内网渗透上课件中找到)或:https://www.jb51.net/softs/527902.html
burpsuite(其他抓包工具亦可)
雷电模拟器4 (Android 7)https://www.ldmnq.com/?n=6000&bd_vid=7476744816742092625

 

抓包前的准备

打开burp,选择Proxy,Options,确保Proxy Listens下的监听端口与待会要设置的一致,并且处于勾选状态

安装Proxifier后打开,点击配置文件,选择代理服务器,点击添加

3.确保设置的地址和端口与burpsuite的监听端口一致

4.点击检查,确保可以正常连接,(注:如果没开burp或者burp监听的地址不是127.0.0.1:8080或者改选项没有勾选,那么会连接不超过)
配置不正确的话那么就会不成功

配置成功就是如下图所示

(注:在进行这一步之前你要确保你的电脑已经安装了burpsuite的证书并且可以正常抓取https的包)

在Proxifier中添加代理规则

配置文件 -> 代理规则 -> 添加

应用程序选择 dnplayer.exe;LdVBoxHeadless.exe;
dnplayer雷电模拟器启动程序和模拟器主程序
LdVBoxHeadless雷电模拟器对外网络协议走的都是这个程序
动作选择刚才添加的代理服务器。
PS:LdVBoxHeadless.exe不同的版本,名称可能不一样,如果不知道在哪,可以直接在任务管理器,找到名为VirtualBox Headless Frontend的进程,右键打开文件所在的位置,即可找到

到这一步我们进入模拟器,打开浏览器以后,就可以从Proxifier看到模拟器的流量,但是我们现在还抓不了https

 

解决抓取https问题:

不能抓取https的包肯定是没多大意义的。所以我们要来解决这个问题,经过查询资料了解到安卓7.0以上后默认不在信任用户自行安装的证书文件、如果需要抓包我们就要把自己的证书放到系统目录下、或者对app进行修改从而进行抓包。在这里我选择安装系统证书的方式进行更加通用的方式进行处理。
从浏览器导出burp证书

选择Base64 编码X.509(.CER)(S)

找个地方取个名字,保存

切换到模拟器,点击更多,选择共享文件,然后选择打开电脑文件夹,把刚才导入的证书拖进去,这个证书就会出现在模拟器相应的Pictures文件夹里

然后进入模拟器,设置,安全,从SD卡安装证书,把刚才拖进来的证书导入

第一次添加证书会要求设置密码,随便设置一下就行了

然后回到桌面,打开文件管理器(记得开启Root权限,模拟器的右边,设置,其他设置,Root权限,点击开启)

点击左上角的三条杠,选择根目录(确保有超级用户(Root)权限)

进入:/data/misc/user/0/cacerts-added 这个文件夹下(该目录存储的是用户自己安装的证书文件)

给该.0文件左边打上勾(文件名可能是不一样的)

切换目录到/etc/security/cacerts 下,点击右上角三个点,点击粘贴选择项,就把证书复制到系统证书目录了

现在可以开心地抓取模拟器的https的包了

 

雷电模拟器安装Xposed

什么是Xposed

Xposed框架(Xposed Framework)是一套开源的、在Android高权限模式下运行的框架服务,可以在不修改APK文件的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作。

安装Xposed流程

首先打开雷电游戏中心

搜索Xposed,下载安装

打开Xposed,查看系统信息

可以看到,系统是Android 7.1.2,x86(32位)
下载相应的Xposed包:https://dl-xda.xposed.info/framework/

选择想用的版本,我比较喜欢用最新的,所以我选择sdk27
选择与自己系统对应的,我的是x86

最后下载.zip为后缀的文件

然后打开模拟器与电脑的共享文件夹,把压缩包解压,并把文件夹重命名为system
再新建一个文件夹,重命名为xposed,把刚才的system移动到xposed文件夹中

再在xposed文件夹下新建一个flash-script.sh 文件,用记事本打开,把如下内容复制进去保存

#################################################################
#
# Xposed framework installer zip.
## This script installs the Xposed framework files to the system partition.
# The Xposed Installer app is needed as well to manage the installed modules.
#

#################################################################
grep_prop() {
REGEX=”s/^$1=//p”
shift
FILES=$@
if [ -z “$FILES” ]; then
FILES=’/system/build.prop’
fi
cat $FILES 2>/dev/null | sed -n $REGEX | head -n 1
}
android_version() {
case $1 in
15) echo ‘4.0 / SDK’$1;;
16) echo ‘4.1 / SDK’$1;;
17) echo ‘4.2 / SDK’$1;;
18) echo ‘4.3 / SDK’$1;;
19) echo ‘4.4 / SDK’$1;;
21) echo ‘5.0 / SDK’$1;;
22) echo ‘5.1 / SDK’$1;;
23) echo ‘6.0 / SDK’$1;;
24) echo ‘7.0 / SDK’$1;;
25) echo ‘7.1 / SDK’$1;;
26) echo ‘8.0 / SDK’$1;;
27) echo ‘8.1 / SDK’$1;;
*) echo ‘SDK’$1;;
esac
}
cp_perm() {
cp -f $1 $2 || exit 1
set_perm $2 $3 $4 $5 $6
}
set_perm() {
chown $2:$3 $1 || exit 1
chmod $4 $1 || exit 1
if [ “$5” ]; then
chcon $5 $1 2>/dev/null
else
chcon ‘u:object_r:system_file:s0’ $1 2>/dev/null
fi
}
install_nobackup() {
cp_perm ./$1 $1 $2 $3 $4 $5
}
install_and_link() {
TARGET=$1
XPOSED=”${1}_xposed”
BACKUP=”${1}_original”
if [ ! -f ./$XPOSED ]; then
return
fi
cp_perm ./$XPOSED $XPOSED $2 $3 $4 $5
if [ ! -f $BACKUP ]; then
mv $TARGET $BACKUP || exit 1
ln -s $XPOSED $TARGET || exit 1
chcon -h ‘u:object_r:system_file:s0’ $TARGET 2>/dev/null
fi
}
install_overwrite() {
TARGET=$1
if [ ! -f ./$TARGET ]; then
return
fi
BACKUP=”${1}.orig”
NO_ORIG=”${1}.no_orig”
if [ ! -f $TARGET ]; then
touch $NO_ORIG || exit 1
set_perm $NO_ORIG 0 0 600
elif [ -f $BACKUP ]; then
rm -f $TARGET
gzip $BACKUP || exit 1
set_perm “${BACKUP}.gz” 0 0 600
elif [ ! -f “${BACKUP}.gz” -a ! -f $NO_ORIG ]; then
mv $TARGET $BACKUP || exit 1
gzip $BACKUP || exit 1
set_perm “${BACKUP}.gz” 0 0 600
fi
cp_perm ./$TARGET $TARGET $2 $3 $4 $5
}

echo “**“
echo “Xposed framework installer zip”
echo “**“
if [ ! -f “system/xposed.prop” ]; then
echo “! Failed: Extracted file system/xposed.prop not found!”
exit 1
fi
echo “- Mounting /system and /vendor read-write”
mount /system >/dev/null 2>&1
mount /vendor >/dev/null 2>&1
mount -o remount,rw /system
mount -o remount,rw /vendor >/dev/null 2>&1
if [ ! -f ‘/system/build.prop’ ]; then
echo “! Failed: /system could not be mounted!”
exit 1
fi
echo “- Checking environment”
API=$(grep_prop ro.build.version.sdk)
APINAME=$(android_version $API)
ABI=$(grep_prop ro.product.cpu.abi | cut -c-3)
ABI2=$(grep_prop ro.product.cpu.abi2 | cut -c-3)
ABILONG=$(grep_prop ro.product.cpu.abi)
XVERSION=$(grep_prop version system/xposed.prop)
XARCH=$(grep_prop arch system/xposed.prop)
XMINSDK=$(grep_prop minsdk system/xposed.prop)
XMAXSDK=$(grep_prop maxsdk system/xposed.prop)
XEXPECTEDSDK=$(android_version $XMINSDK)
if [ “$XMINSDK” != “$XMAXSDK” ]; then
XEXPECTEDSDK=$XEXPECTEDSDK’ - ‘$(android_version $XMAXSDK)
fi
ARCH=arm
IS64BIT=
if [ “$ABI” = “x86” ]; then ARCH=x86; fi;
if [ “$ABI2” = “x86” ]; then ARCH=x86; fi;
if [ “$API” -ge “21” ]; then
if [ “$ABILONG” = “arm64-v8a” ]; then ARCH=arm64; IS64BIT=1; fi;
if [ “$ABILONG” = “x86_64” ]; then ARCH=x64; IS64BIT=1; fi;
fi
echo “DBG [$API] [$ABI] [$ABI2] [$ABILONG] [$ARCH] [$XARCH] [$XMINSDK] [$XMAXSDK] [$XVERSION]”
echo “ Xposed version: $XVERSION”
XVALID=
if [ “$ARCH” = “$XARCH” ]; then
if [ “$API” -ge “$XMINSDK” ]; then
if [ “$API” -le “$XMAXSDK” ]; then
XVALID=1
else
echo “! Wrong Android version: $APINAME”
echo “! This file is for: $XEXPECTEDSDK”
fi
else
echo “! Wrong Android version: $APINAME”
echo “! This file is for: $XEXPECTEDSDK”
fi
else
echo “! Wrong platform: $ARCH”
echo “! This file is for: $XARCH”
fi
if [ -z $XVALID ]; then
echo “! Please download the correct package”
echo “! for your platform/ROM!”
exit 1
fi
echo “- Placing files”
install_nobackup /system/xposed.prop 0 0 0644
install_nobackup /system/framework/XposedBridge.jar 0 0 0644
install_and_link /system/bin/app_process32 0 2000 0755 u:object_r:zygote_exec:s0
install_overwrite /system/bin/dex2oat 0 2000 0755 u:object_r:dex2oat_exec:s0
install_overwrite /system/bin/oatdump 0 2000 0755
install_overwrite /system/bin/patchoat 0 2000 0755 u:object_r:dex2oat_exec:s0
install_overwrite /system/lib/libart.so 0 0 0644
install_overwrite /system/lib/libart-compiler.so 0 0 0644
install_overwrite /system/lib/libart-disassembler.so 0 0 0644
install_overwrite /system/lib/libsigchain.so 0 0 0644
install_nobackup /system/lib/libxposed_art.so 0 0 0644
if [ $IS64BIT ]; then
install_and_link /system/bin/app_process64 0 2000 0755 u:object_r:zygote_exec:s0
install_overwrite /system/lib64/libart.so 0 0 0644
install_overwrite /system/lib64/libart-compiler.so 0 0 0644
install_overwrite /system/lib64/libart-disassembler.so 0 0 0644
install_overwrite /system/lib64/libsigchain.so 0 0 0644
install_nobackup /system/lib64/libxposed_art.so 0 0 0644
fi
if [ “$API” -ge “25” ]; then
find /system /vendor -type f -name ‘*.odex.gz’ 2>/dev/null | while read f; do mv “$f” “$f.xposed”; done
fi
echo “- Done”
exit 0

把xposed文件夹复制到根目录的system文件夹下(需要有root权限)

安装一个终端模拟器(这个百度一堆,我就随便下了一个,能执行命令就行)

输入su,回车,获取root权限

cd /system/xposed 切换到xposed文件夹,输入sh flash-script.sh
然后就安装成功啦!

重启模拟器,打开Xposed Installer,发现安装成功

然后就可以去安装JustTrustMe、SSLUnpinning等插件了

 

双向认证

什么是双向认证

双向认证,服务端会校验客户端(也就是我们的app)的证书;客户端也会校验服务端的证书,先来看看这篇文章的资料。SSL/TLS 双向认证(一) — SSL/TLS工作原理https://blog.csdn.net/ustccw/article/details/76691248
,看完这篇文章就可以了解到,对于双向证书校验要破解有:

证书密码

cer或者p12证书

双向认证抓包有两种解决方法:

一是:按照搞定证书的思路去想的话,就是要想办法拿到真正的证书。

二是:Hook SSL 对数据解密数据的地方。

方法一:

因为 APP 能正常跟服务端通信,所以真正的证书肯定是在 APP 里面。所以就是要想办法从 APP 里抠出证书。

抠证书有开源的 Frida Hook 脚本。如下地址是开源作者写的 Frida Hook 脚本 https://gist.github.com/ceres- c/cb3b69e53713d5ad9cf6aac9b8e895d2gfgg
可以把证书从内存里读出来保存到本地,并且证书密码也能读出来,非常的方便。

该脚本的原理是: 因为 APP 在向服务端发请求时, APP 肯定会操作证书,所以如果能找到 APP 操作证书的代码地方, Hook 这部分代码,对参数做些输出打印,证书和证书密码就都有了。

大部分情况下,我们不用非常熟悉安卓原理,比如安卓在代码层面是如何操作证书的(当然熟悉更好)。因为资讯发达,一般灵活借助搜索引擎,灵活查阅资料,可以大体知道这些,就可以尝试去写 Hook 脚本去尝试看看。

查阅资料可以知道,安卓操作证书通常是 java.security.KeyStore 这个类,然后再了解下这个类的用法,参数形式。

就可以尝试去 Hook 了。

上述脚本就是 Hook java.security.KeyStore 这个类的 load 方法,load 方法的形参就是我们需要的证书和密码。 抠出的证书和密码,配置进 fiddler 或 charles 里面,就可以抓到双向认证的包。
PS: 还要注意证书的格式,抠出的证书可能是 jks 或 bks 格式的,fiddler 可能需要 p12 格式的, 所以要找工具先转换一下格式。

方法二:

如果只是想抓包,还有另一种方法,不需要抠证书的方法。

虽然 https 在传输过程中是加密的,但在终端显示的时候,必然会解密,不然 APP 上都没法显示了。所以如果能知道安卓解密 SSL 加解密是哪个类, Hook 这个类, 类里相关方法的输入输出肯定就是传输的明文数据。

所以可以查阅资料,看看相关类的用法,就可以尝试去 Hook 打印输出看看情况。

也有开源作者开源了该 Hook 脚本, 比如 5alt 老板在google开源的脚本基础上做了修改了的 ssl_logger 。 https://github.com/5alt/ssl_logger

能够 Hook SSL 加解密的地方,它会把传输的数据保存为 pcap 格式。再使用 wireshark 打开该 pcap文件, 在 wireshark 上就可以看到明文的数据了。

如果要模拟向服务器发送请求的话,还是只能使用第一种方法,因为客服端必须要提交正确的证书,服务端才会正确响应。必须得抠出证书,模拟请求时必须带上证书,才能请求到数据。安卓上的证书好多是 jks/bks格式的, 如果使用 Python requests 库的话, 不支持这个格式, 所以要想办法把证书转成 cert 格式的。

上面两种方法都是使用 Frida 进行 Hook ,所以要有 Root 过的手机和明白Frida 怎么使用就能搞定。 对于爬虫来说,搞定抓包和请求参数加密的问题,大部分 Hook ,都可以通过 Hook 安卓系统 API 来找到 APP 代码位置,或直接搞定。

其实很少人能很熟悉安卓系统的各种原理,大部分时候能灵活通过各种关键字能查到相关原理的讲解文献,文献里讲的 API 灵活点拿去 Hook 康康线索,就能搞定很多拉。 其实使用双向认证的 APP 还是少数, 对服务器性能多少有影响。

 

某APP双向认证突破

因为app没有进行加固,可以直接用jadx反编译出来,然后全局搜索”.cer”、”.crt”、”.pfx”、”PKCS12”、”keyStore”等等关键字。

jadx下载地址:https://github.com/skylot/jadx/releases/tag/v1.2.0

转到代码位置查看详情(证书安装密码、其他密码等等信息),可以看到,pfx证书没有设置密码(本地测试安装了下,看到有需要输入密码

第一次尝试过输入密码,结果提示密码错误

第二次尝试不输入密码却安装成功了,于是开启了全局搜索之旅,看到没有设置证书安装密码):

使用akptool将APP拆开,apktool下载地址:https://bitbucket.org/iBotPeaches/apktool/downloads/

进入apktool生成的目录,可以搜索一些证书的后缀文件,例如cer/p12/pfx等,一般安卓下的为bks,也可以先去assets或者res目录下去找找。我碰到的apk就在assets目录下存放:

本来以为还得在文件夹里面继续找key,找了一圈无果,后来知道这里可以直接把key导出来
openssl pkcs12 –in client.pfx –nocerts –nodes –out client.key

这里需要注意的是,导出key的时候需要输入密码,也就是这个地方(如下图)

因为我这里是没有设置密码的,所以不用输入,直接回车导出;如果设置了证书密码,这里需要输入证书密码才能把key导出来。

有了key剩下的就好办了,将crt证书和key文件合并成“.p12”证书文件,合并的时候记得对证书进行加密(也就是加个证书密码),不加密码burpsuite是无法导入的。

合并证书命令:openssl pkcs12 -export -inkey client.key -in client.crt -out client.p12

将证书导入到burpsuite:

然后就可以成功导入证书,并且启用

最后就可以开始抓包了,抓包前最好是把模拟器关闭再重新打开

(完)