2017-08-07 10:23:56
阅读:362次
点赞(0)
收藏
来源: 安全客
作者:for_while
作者:for_while
预估稿费:200RMB
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
插件介绍
在测试一些应用的时候(以移动端为例),会经常发现客户端和服务端的通讯数据是加密过的,在这种情况下,我们如果想继续测试下去,就得去逆向程序中使用的加密算法,然后写程序实现它,然后在后续测试中使用它。这种方式需要耗费大量的时间和精力。而Brida这款插件的出现简直天降神器。Frida是一款多平台的hook框架, 其具体功能请看官网:https://www.frida.re/。
Brida使用了frida的功能,并且和 BurpSuite结合,可以在BurpSuite中直接调用目标应用程序中的加/解密函数,而不用去逆向它,节省精力。
插件安装
安装 python 2.7 和Pyro4 模块(可以使用 pip安装:pip install pyro4)
下载Brida_01.jar, 并在 BurpSuite 中手动安装该 jar 包
Tips:插件安装,使用过程中出现了问题请查看插件的错误日志
插件测试
为了测试该插件,写了个安卓的apk, 使用 Java实现了一个Encryption类用于对数据进行AES加密和解密。该类的代码如下:
importjava.security.SecureRandom; importjavax.crypto.Cipher; importjavax.crypto.KeyGenerator; importjavax.crypto.SecretKey; importjavax.crypto.spec.IvParameterSpec; importjavax.crypto.spec.SecretKeySpec; /** *CreatedbyAdministratoron2017/7/30. */ publicclassEncryption{ privatefinalstaticStringHEX="0123456789ABCDEF"; privatestaticfinalStringCBC_PKCS5_PADDING="AES/CBC/PKCS5Padding";//AES是加密方式CBC是工作模式PKCS5Padding是填充模式 privatestaticfinalStringAES="AES";//AES加密 privatestaticfinalStringSHA1PRNG="SHA1PRNG";////SHA1PRNG强随机种子算法,要区别4.2以上版本的调用方法 /* *加密 */ publicstaticStringencrypt(Stringkey,Stringcleartext){ if(cleartext.isEmpty()){ returncleartext; } try{ byte[]result=encrypt(key,cleartext.getBytes()); returnbytesToHexString(result); }catch(Exceptione){ e.printStackTrace(); } returnnull; } /* *加密 */ privatestaticbyte[]encrypt(Stringkey,byte[]clear)throwsException{ byte[]raw=getRawKey(key.getBytes()); SecretKeySpecskeySpec=newSecretKeySpec(raw,AES); Ciphercipher=Cipher.getInstance(CBC_PKCS5_PADDING); cipher.init(Cipher.ENCRYPT_MODE,skeySpec,newIvParameterSpec(newbyte[cipher.getBlockSize()])); byte[]encrypted=cipher.doFinal(clear); returnencrypted; } /* *解密 */ publicstaticStringdecrypt(Stringkey,Stringencrypted){ if(encrypted.isEmpty()){ returnencrypted; } try{ byte[]enc=hexStringToBytes(encrypted); byte[]result=decrypt(key,enc); returnnewString(result); }catch(Exceptione){ e.printStackTrace(); } returnnull; } /* *解密 */ privatestaticbyte[]decrypt(Stringkey,byte[]encrypted)throwsException{ byte[]raw=getRawKey(key.getBytes()); SecretKeySpecskeySpec=newSecretKeySpec(raw,AES); Ciphercipher=Cipher.getInstance(CBC_PKCS5_PADDING); cipher.init(Cipher.DECRYPT_MODE,skeySpec,newIvParameterSpec(newbyte[cipher.getBlockSize()])); byte[]decrypted=cipher.doFinal(encrypted); returndecrypted; } /** *Convertbyte[]tohexstring.这里我们可以将byte转换成int,然后利用Integer.toHexString(int)来转换成16进制字符串。 *@paramsrcbyte[]data *@returnhexstring */ publicstaticStringbytesToHexString(byte[]src){ StringBuilderstringBuilder=newStringBuilder(""); if(src==null||src.length<=0){ returnnull; } for(inti=0;i<src.length;i++){ intv=src[i]&0xFF; Stringhv=Integer.toHexString(v); if(hv.length()<2){ stringBuilder.append(0); } stringBuilder.append(hv); } returnstringBuilder.toString(); } /** *Converthexstringtobyte[] *@paramhexStringthehexstring *@returnbyte[] */ publicstaticbyte[]hexStringToBytes(StringhexString){ if(hexString==null||hexString.equals("")){ returnnull; } hexString=hexString.toUpperCase(); intlength=hexString.length()/2; char[]hexChars=hexString.toCharArray(); byte[]d=newbyte[length]; for(inti=0;i<length;i++){ intpos=i*2; d[i]=(byte)(charToByte(hexChars[pos])<<4|charToByte(hexChars[pos+1])); } returnd; } /** *Convertchartobyte *@paramcchar *@returnbyte */ privatestaticbytecharToByte(charc){ return(byte)"0123456789ABCDEF".indexOf(c); } //对密钥进行处理 privatestaticbyte[]getRawKey(byte[]seed)throwsException{ KeyGeneratorkgen=KeyGenerator.getInstance(AES); //forandroid SecureRandomsr=null; //在4.2以上版本中,SecureRandom获取方式发生了改变 if(android.os.Build.VERSION.SDK_INT>=17){ sr=SecureRandom.getInstance(SHA1PRNG,"Crypto"); }else{ sr=SecureRandom.getInstance(SHA1PRNG); } //forJava //secureRandom=SecureRandom.getInstance(SHA1PRNG); sr.setSeed(seed); kgen.init(128,sr);//256bitsor128bits,192bits //AES中128位密钥版本有10个加密循环,192比特密钥版本有12个加密循环,256比特密钥版本则有14个加密循环。 SecretKeyskey=kgen.generateKey(); byte[]raw=skey.getEncoded(); returnraw; } }Encryption.encrypt(key, str)用于对str, 使用key进行 aes加密,Encryption.decrypt(key, str)则用于解密。他们均返回处理后的字符串。为了模拟在安全测试中的场景,我会在burp中使用 Brida插件 调用Encryption.encrypt进行加密, 调用Encryption.decrypt进行解密。
正常情况下,进入插件的界面如下:
其实最重要的就是 Frida js文件的内容了。下面给一个官方的例子
'usestrict'; //1-FRIDAEXPORTS rpc.exports={ //BECAREFUL:Donotuseuppercasecharactersinexportedfunctionname(automaticallyconvertedlowercasebyPyro) exportedfunction:function(){ //Dostuff... //ThisfunctionscanbecalledfromcustompluginsorfromBrida"Executemethod"dedicatedtab }, //FunctionexecutedwhenexecutedBridacontextualmenuoption1. //InputispassedfromBridaencodedinASCIIHEXandmustbereturnedinASCIIHEX(becauseBridawilldecodetheoutput //fromASCIIHEX).Useauxiliaryfunctionsfortheconversions. contextcustom1:function(message){ return"6566"; }, //FunctionexecutedwhenexecutedBridacontextualmenuoption2. //InputispassedfromBridaencodedinASCIIHEXandmustbereturnedinASCIIHEX(becauseBridawilldecodetheoutput //fromASCIIHEX).Useauxiliaryfunctionsfortheconversions. contextcustom2:function(message){ return"6768"; }, //FunctionexecutedwhenexecutedBridacontextualmenuoption3. //InputispassedfromBridaencodedinASCIIHEXandmustbereturnedinASCIIHEX(becauseBridawilldecodetheoutput //fromASCIIHEX).Useauxiliaryfunctionsfortheconversions. contextcustom3:function(message){ return"6768"; }, //FunctionexecutedwhenexecutedBridacontextualmenuoption4. //InputispassedfromBridaencodedinASCIIHEXandmustbereturnedinASCIIHEX(becauseBridawilldecodetheoutput //fromASCIIHEX).Useauxiliaryfunctionsfortheconversions. contextcustom4:function(message){ return"6768"; } } //2-AUXILIARYFUNCTIONS //Convertahexstringtoabytearray functionhexToBytes(hex){ for(varbytes=[],c=0;c<hex.length;c+=2) bytes.push(parseInt(hex.substr(c,2),16)); returnbytes; } //ConvertaASCIIstringtoahexstring functionstringToHex(str){ returnstr.split("").map(function(c){ return("0"+c.charCodeAt(0).toString(16)).slice(-2); }).join(""); } //ConvertahexstringtoaASCIIstring functionhexToString(hexStr){ varhex=hexStr.toString();//forceconversion varstr=''; for(vari=0;i<hex.length;i+=2) str+=String.fromCharCode(parseInt(hex.substr(i,2),16)); returnstr; } //Convertabytearraytoahexstring functionbytesToHex(bytes){ for(varhex=[],i=0;i<bytes.length;i++){ hex.push((bytes[i]>>>4).toString(16)); hex.push((bytes[i]&0xF).toString(16)); } returnhex.join(""); } //3-FRIDAHOOKS(ifneeded) if(ObjC.available){ //InserthereFridainterceptionmethods,ifneeded //(es.BypassPinning,savevalues,etc.) }
代码中的注释写的非常清楚,我说一下我认为的重点。
rpc.exports的每一项是一个函数,:前面的为函数名(全部为小写),比如contextcustom1, 后面为函数的具体内容,rpc.exports中的函数都可以被 Brida调用。
contextcustom1和contextcustom2可以在 burp中使用右键调用,不能改他们的名字
函数接收的参数,和返回的数据都是以16进制编码的,所以我们使用时要先对他们进行16进制解码,然后返回的时候在进行16进制编码。在上述脚本中包含了这些转换所需的函数,方便我们进行处理。该脚本会被Frida注入到我们在Brida中指定的进程中所以我们可以直接使用Frida的api。
我们可以先试试,Brida能否正常运行,类似上图设置好参数,使用官方的那个js文件,以安卓为例,使用Frida Remote.
首先我们要在 android设备上安装 Frida,安装过程可以参考这里:http://www.jianshu.com/p/ca8381d3e094
当你使用frida-ps -R能出现类似下面结果的会继续
λfrida-ps-R PIDName -------------------------------------------- 272adbd 5262android.process.acore 841android.process.media 181bridgemgrd 8430com.android.calendar 8450com.android.deskclock 1867com.android.gallery3d 873com.android.inputmethod.latin 920com.android.launcher 8327com.android.mms 908com.android.nfc 858com.android.phasebeam 897com.android.phone 1020com.android.smspush 718com.android.systemui 1049com.illuminate.texaspoker 1132com.illuminate.texaspoker:xg_service_v2 2174daemonsu:0 13649daemonsu:0:13646然后 分别点击start server和spawn application.然后我们在Execute methonTab中测试下contextcustom2函数
他会在 Output中输出6768 ,这是16进制编码的字符串(方便调试),解码后为gh
如果在burp中选中数据右键调用的话就会直接输出 解码后的字符串。
这样Brida_test就会被替换为gh.
上面就是官方脚本的测试。下面我们来调用Encryption.encrypt和Encryption.decrypt。这其实就是frida的使用了,可以参考官方文档。一个Tips:使用全局变量来获取函数的返回值。
varencrypt_data=""; vardecrypt_data=""; rpc.exports={ contextcustom1:function(message){ Java.perform(function(){ varEncryption=Java.use('learn.hacklh.me.MobileSafe.tools.Encryption'); encrypt_data=stringToHex(Encryption.encrypt("just_test",hexToString(message))); }); returnencrypt_data }, contextcustom2:function(message){ Java.perform(function(){ varEncryption=Java.use('learn.hacklh.me.MobileSafe.tools.Encryption'); decrypt_data=stringToHex(Encryption.decrypt("just_test",hexToString(message))); }); returndecrypt_data }, }完整代码如下:
'usestrict'; //1-FRIDAEXPORTS varencrypt_data=""; vardecrypt_data=""; rpc.exports={ //BECAREFUL:Donotuseuperpcasecharactersinexportedfunctionname(automaticallyconvertedlowercasebyPyro) exportedfunction:function(){ //Dostuff... //ThisfunctionscanbecalledfromcustompluginsorfromBrida"Executemethod"dedicatedtab }, //FunctionexecutedwhenexecutedBridacontextualmenuoption1. //InputispassedfromBridaencodedinASCIIHEXandmustbereturnedinASCIIHEX(becauseBridawilldecodetheoutput //fromASCIIHEX).Useauxiliaryfunctionsfortheconversions. contextcustom1:function(message){ Java.perform(function(){ varEncryption=Java.use('learn.hacklh.me.MobileSafe.tools.Encryption'); encrypt_data=stringToHex(Encryption.encrypt("just_test",hexToString(message))); }); returnencrypt_data }, //FunctionexecutedwhenexecutedBridacontextualmenuoption2. //InputispassedfromBridaencodedinASCIIHEXandmustbereturnedinASCIIHEX(becauseBridawilldecodetheoutput //fromASCIIHEX).Useauxiliaryfunctionsfortheconversions. contextcustom2:function(message){ Java.perform(function(){ varEncryption=Java.use('learn.hacklh.me.MobileSafe.tools.Encryption'); decrypt_data=stringToHex(Encryption.decrypt("just_test",hexToString(message))); }); returndecrypt_data }, //FunctionexecutedwhenexecutedBridacontextualmenuoption3. //InputispassedfromBridaencodedinASCIIHEXandmustbereturnedinASCIIHEX(becauseBridawilldecodetheoutput //fromASCIIHEX).Useauxiliaryfunctionsfortheconversions. contextcustom3:function(message){ return"6768"; }, //FunctionexecutedwhenexecutedBridacontextualmenuoption4. //InputispassedfromBridaencodedinASCIIHEXandmustbereturnedinASCIIHEX(becauseBridawilldecodetheoutput //fromASCIIHEX).Useauxiliaryfunctionsfortheconversions. contextcustom4:function(message){ return"6768"; } } //2-AUXILIARYFUNCTIONS //Convertahexstringtoabytearray functionhexToBytes(hex){ for(varbytes=[],c=0;c<hex.length;c+=2) bytes.push(parseInt(hex.substr(c,2),16)); returnbytes; } //ConvertaASCIIstringtoahexstring functionstringToHex(str){ returnstr.split("").map(function(c){ return("0"+c.charCodeAt(0).toString(16)).slice(-2); }).join(""); } //ConvertahexstringtoaASCIIstring functionhexToString(hexStr){ varhex=hexStr.toString();//forceconversion varstr=''; for(vari=0;i<hex.length;i+=2) str+=String.fromCharCode(parseInt(hex.substr(i,2),16)); returnstr; } //Convertabytearraytoahexstring functionbytesToHex(bytes){ for(varhex=[],i=0;i<bytes.length;i++){ hex.push((bytes[i]>>>4).toString(16)); hex.push((bytes[i]&0xF).toString(16)); } returnhex.join(""); } //3-FRIDAHOOKS(ifneeded) //InserthereFridainterceptionmethods,ifneeded //(es.BypassPinning,savevalues,etc.)测试
首先 选中文本 ,右键调用contextcustom1对文本 使用 key为just_test,进行AES加密。
得到结果:f5f91a52df876b902054e4dfd94d3341
然后解密
成功解密
总结
使用该插件,我们在测试一些加密应用时提供另外一种节省精力的方法,我们可以直接调用应用中的方法,来对数据进行加/解密 ,而不用去逆向对应的方法。这节省了测试人员的精力。
本文由 安全客 翻译,转载请注明“转自安全客”,并附上链接。
原文链接:https://techblog.mediaservice.net/2017/07/brida-advanced-mobile-application-penetration-testing-with-frida/