一题三解花式拷打Android CTF:攻防世界#ill-intentions

admin 2024年5月9日03:42:36评论4 views字数 7332阅读24分26秒阅读模式
投某社区被毙了,说题目太老,让我记录一下今年会被毙几篇。
昨天发的那篇标题有点小问题,又懒得重新推,就这样吧。

. . . * . * ☄️. * . * . 🦉 .* . * . 🌟 .* . * . . .

读题-确定方向

这道题笔者个人认为比较有代表性,代表性在有那么一些些android知识,有点迷惑性,而破题的思路又非常多,适合花样拷打~

一题三解花式拷打Android CTF:攻防世界#ill-intentions

首先GDA一把梭,无加壳无混淆。直接看向主Activity,发现其注册了一个广播(Receiver),对象为Send_to_Activity:

一题三解花式拷打Android CTF:攻防世界#ill-intentions

跟过来,这里去读了传递Intent里的String msg,然后根据它的值跳转到对应的Activity。

一题三解花式拷打Android CTF:攻防世界#ill-intentions

跟到ThisIsTheRealOne,发现这里使用的是native函数

一题三解花式拷打Android CTF:攻防世界#ill-intentions

而且这个native函数要在点击Button之后才能调用,调用后发送一个广播:

一题三解花式拷打Android CTF:攻防世界#ill-intentions

但是从前文来看,这个广播根本没有落脚点(广播了,但是没有后续了,因为唯一一个Receiver只会进入else然后不展示msg),并且一开始的MainActivity也不会导向任何一个Activity。也就是说出题人构造了一个不可能实现的调用,那么破题思路就在于主动调用Activity或者更直接的调用对应的算flag函数


方法一 ActivityManager+Frida Hook

Hook是最常见的思路,毕竟flag已经在运行中算出来了,但没展示而已。

先用am直接拉起ThisIsTheRealOne,然后点击BROADCAST INTENT:

拉起语句为:

am start-activity -n com.example.hellojni/com.example.application.IsThisTheRealOne

一题三解花式拷打Android CTF:攻防世界#ill-intentions

点击之后并没有输出flag,因为onClick算出flag之后将其作为Intent返回了Send_to_Activity。

这也简单,我们只需要Hook到sendBroadcast或者putExtra即可(不要怀疑,通常Hook越底层越方便,Hook Android自带函数最好^ ^)。

var intent=Java.use('android.content.Intent');intent.putExtra.overload('java.lang.String', 'java.lang.String').implementation=function(name,stri){  console.log("进入Hook");  console.log(name);  console.log(stri);}

Hook成功之后使用am依次拉起三个Activity,即可获得flag:

一题三解花式拷打Android CTF:攻防世界#ill-intentions

一题三解花式拷打Android CTF:攻防世界#ill-intentions

flag为CTF{IDontHaveABadjokeSorry}。


方法二 Java+Unidbg还原调用环境

根据前面对源码的分析,我们知道,三个Activity分别都会调用一个native方法算flag,而native方法传的参又经过了一个自建方法的加密(Utilities.doBoth):

一题三解花式拷打Android CTF:攻防世界#ill-intentions

而Unidbg实际上也是在Java环境运行的(不过一般的JDK环境和Android SDK环境肯定是有些不同的,更不要说不同JDK之间都会打架)。也就是说我们可以直接复制这个类到Unidbg的环境中进行调用~这也多亏了GDA反编译的Java代码一般都十分甚至九分可读,照搬之后需要改的地方并不多。

这是改好的工具类代码,扔进随便一个Java工程里导个包就行:

import java.lang.Object;import java.lang.String;import java.security.MessageDigest;import java.lang.StringBuilder;import java.lang.Byte;import org.apache.commons.codec.binary.Base64;

import java.util.HashMap;import java.lang.Integer;import java.lang.Character;import java.util.Map;

public class Utilities  // class@000019 from classes.dex{    public static String customEncodeValue(String input){        MessageDigest md = null;        String output = "";        byte[] input_bytes = input.getBytes();        try{            md = MessageDigest.getInstance("SHA-224");        }catch(java.security.NoSuchAlgorithmException e5){        }        md.update(input_bytes, 0, input_bytes.length);        byte[] hash_bytes = md.digest();        for (int i = 0; i < hash_bytes.length; i++) {            Object[] objArray = new Object[]{Byte.valueOf(hash_bytes[i])};            StringBuilder sb= new StringBuilder("");            output = sb.append(output).append(String.format("%02x", objArray)).toString();        }        return new Base64().encodeToString(output.getBytes());    }    public static String doBoth(String input){        return Utilities.translate(Utilities.customEncodeValue(input));    }    public static String translate(String input){        input = input.replace('=', '?');        char[] inputchars = input.toCharArray();        Map table = new HashMap();        int[] ointArray = {1,2,3,4,5,6,7,8,9,0};        char[] uocharArray = {'W','h','a','t','i','s','d','o','n','e'};        for (int i = 0; i < 10; i++) {            table.put(Integer.valueOf(ointArray[i]), Character.valueOf(uocharArray[i]));        }        int i = 0;        while (i < inputchars.length) {            int charcode = inputchars[i];            if (charcode > '/' && charcode < ':') {                charcode = charcode - 48;                inputchars[i] = ((Character)table.get(charcode)).charValue();            }            i++;        }        return new String(inputchars);    }}

在解决工具类的问题之后,我们需要找到这几个依托Android R类(把它当成Android一种取资源的方法就行,如果读者开发过类似Android和Unity的工程就会明白)获取的参数。

我们以IsThisTheRealOne为例(做一道题三遍已经很烦了,不要让我做一个思路三遍):

一题三解花式拷打Android CTF:攻防世界#ill-intentions

a为R.string.(0x7f...)+一个固定字符串。0x7f...是这个string ID对应的十六进制ID。要讲这些ID怎么映射到代码里的str再映射到实际的Object比较困难,但是想找它们很容易:全局搜索就行。

一题三解花式拷打Android CTF:攻防世界#ill-intentions

搜到的对应名为str3,然后我们折回resources.asrc,找到values/strings.xml(所有的R.strings都存在这个文件里):

一题三解花式拷打Android CTF:攻防世界#ill-intentions

str3为TRytfrgooq|F{i-JovFBungFk,则a为TRytfrgooq|F{i-JovFBungFk\VlphgQbwvj~HuDgaeTzuSt.@Lex^~。

b为Utilities.doBoth(SendAnIntentApplication)

c这里有点说道,因为是匿名类,前面this.getClass().getName()应该是com.example.application.IsThisTheRealOne$1,后面去掉两位是com.example.application.IsThisTheRealOne,则c为Utilities.doBoth(com.example.application.IsThisTheRealOne)。

然后打开IDA直接看这个native函数的偏移量,为0x07ac:

一题三解花式拷打Android CTF:攻防世界#ill-intentions

unidbg梭哈一把,代码如下:

AndroidEmulator emulator = AndroidEmulatorBuilder.for64Bit()        .setProcessName("com.augusttheodor.ctf")        .addBackendFactory(new Unicorn2Factory(true))        .build(); // 创建模拟器实例,要模拟32位或者64位,在这里区分final Memory memory = emulator.getMemory(); // 模拟器的内存操作接口memory.setLibraryResolver(new AndroidResolver(23)); // 设置系统类库解析VM vm = emulator.createDalvikVM(); // 创建Android虚拟机new AndroidModule(emulator,vm).register(memory);DalvikModule dm = vm.loadLibrary(new File("\lib\arm64-v8a\libhello-jni.so"), false); dm.callJNI_OnLoad(emulator); // 手动执行JNI_OnLoad函数 Module module = dm.getModule(); DvmClass dvc = vm.resolveClass("com/example/application/ThisIsTheRealOne");//System.out.print(Utilities.customEncodeValue("123"));List<Object> argss = new ArrayList<>(10);argss.add(vm.getJNIEnv());argss.add(vm.addLocalObject(new StringObject(vm,"")));argss.add(vm.addLocalObject(new StringObject(vm,"TRytfrgooq|F{i-JovFBungFk\VlphgQbwvj~HuDgaeTzuSt.@Lex^~")));argss.add(vm.addLocalObject(new StringObject(vm, Utilities.doBoth("SendAnIntentApplication"))));argss.add(vm.addLocalObject(new StringObject(vm, Utilities.doBoth("com.example.application.IsThisTheRealOne"))));Number result=module.callFunction(emulator,0x07ac,argss.toArray()); String resText=vm.getObject(result.intValue()).getValue().toString();System.out.println("result is "+resText);

运行,成功得到flag:

一题三解花式拷打Android CTF:攻防世界#ill-intentions


方法三 修改APP内容直接显示flag

这个其实最简单,不过看上去没什么人会用,也许是因为这个方法要求做题人要对Android有一定了解。俗话说,治不了反汇编还治不了smali嘛,smali可比读反汇编舒服多了,真的。

使用apktool反编译APP:

java -jar .apktool_2.7.0.jar d 2bb0718ee4324207b2d2d1ffdd42f4e7.apk

一题三解花式拷打Android CTF:攻防世界#ill-intentions

在修改Smali代码的过程中可以使用jeb打开APP在旁辅助,比如这样:

一题三解花式拷打Android CTF:攻防世界#ill-intentions

要达到我们的目标,需要做两步。我们可以先用Java来写出要修改的步骤,然后再改成smali。

首先我们需要吊起IsThisTheRealOne这个Activity,这一步不需要Java来做,可以直接修改AndroidManifest.xml达成。

其次,我们需要使得调用perhapsThis获得的返回显示出来。Android环境不同于Java,System.Out.println是无效的。但我们可以通过调用其他组件的setText方法来展示输出。不过目前所在的onClick处于匿名类中,调用外部组件不太方便(实际上,我也不太了解怎么在smali中使用this),所以我会使用Toast发送一个弹框。

思路完整之后就直接开始修改代码。

先修改AndroidManifest.xml,移除MainActivity的intent-filter然后加到IsThisTheRealOne下:

<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.hellojni" platformBuildVersionCode="22" platformBuildVersionName="5.1.1-1819727">    <permission android:description="@string/android.permission._msg" android:name="ctf.permission._MSG" android:protectionLevel="signature"/>    <permission android:description="@string/android.permission._msg" android:name="ctf.permission._SEND"/>    <application android:icon="@mipmap/ic_launcher" android:label="CTF Application">        <activity android:label="Main Activity" android:name="com.example.application.MainActivity">                    </activity>        <activity android:label="Activity: Is This The Real One" android:name="com.example.application.IsThisTheRealOne">            <intent-filter>                <action android:name="android.intent.action.MAIN"/>                <category android:name="android.intent.category.LAUNCHER"/>            </intent-filter>        </activity>        <activity android:label="This Is The Real One" android:name="com.example.application.ThisIsTheRealOne"/>        <activity android:label="Definitely Not This One" android:name="com.example.application.DefinitelyNotThisOne"/>        <receiver android:exported="true" android:name="com.example.application.Send_to_Activity"/>    </application></manifest>

然后修改IsThisTheRealOne的smali代码,这是我加上的部分,加在perhapsThis返回之后:

 invoke-virtual {p1}, Landroid/view/View;->getContext()Landroid/content/Context;    move-result-object v9    const/4 v3, 0x1  invoke-static {p1, v6, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;  move-result-object v3  invoke-virtual {v3}, Landroid/widget/Toast;->show()V

然后移除原本的加入Intent->发送broadcast步骤,也就是我这里红框的部分(因为我上面的代码使用了寄存器v3,删除是防止下面因为v3报错,如果希望留着就自己改一改寄存器):

一题三解花式拷打Android CTF:攻防世界#ill-intentions

修改后使用apktool重新打包:

java -jar .apktool_2.7.0.jar b .2bb0718ee4324207b2d2d1ffdd42f4e7

一题三解花式拷打Android CTF:攻防世界#ill-intentions

使用NP管理器签名重新安装,进入后点击按钮即返回flag:

一题三解花式拷打Android CTF:攻防世界#ill-intentions

. . . * . * 🌟 * . * . . .

原文始发于微信公众号(重生之成为赛博女保安):一题三解花式拷打Android CTF:攻防世界#ill-intentions

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年5月9日03:42:36
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   一题三解花式拷打Android CTF:攻防世界#ill-intentionshttps://cn-sec.com/archives/2722268.html

发表评论

匿名网友 填写信息