首页
社区
课程
招聘
攻防世界Mobile通关记录_app1app2app3_wp
发表于: 2022-10-13 11:49 6269

攻防世界Mobile通关记录_app1app2app3_wp

2022-10-13 11:49
6269

app1

题目信息

 

首先改app的后缀为 zip。然后解压缩:

 

 

我们通过安卓逆向工具 Android逆向助手 v2.2

 

将 classes.dex转成 jar

 

 

然后 就 自动到这个页面了。

 

即反编译后的页面。

 

分析

MainActivty是我们开始要分析的入口。

 

然后我们去分析 找到 解题的关键函数

 

 

 

所以

 

str1 是我们输入的字符串

 

str2 是 "X<cP[?PHNB<P?aj"

 

i=15

 

我们看关键函数。

 

 

如果 str1[j] 等于 str2[j]^15 的话 就能 成功开启大闯关门了

解题

写python 脚本:

1
2
3
4
5
6
7
8
i=15
str1=""
str2="X<cP[?PHNB<P?aj"
 
for j in range(len(str2)):
    str1+=chr(ord(str2[j])^i)
 
print str1 #W3l_T0_GAM3_0ne

运行脚本拿到正确答案即W3l_T0_GAM3_0ne

app2

题目信息

下载附件将其运行

 

 

点击登陆跳转到下面的界面

 

分析

将apk拖入jeb中分析,首先看MainActivity

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package com.tencent.testvuln;
 
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences$Editor;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View$OnClickListener;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.tencent.testvuln.c.SignatureTool;
 
@SuppressLint(value={"ShowToast"}) public class MainActivity extends Activity implements View$OnClickListener {
    private Button lojin;
    private Handler b;
    private EditText mEd_Username;
    private EditText Ed_Password;
 
    public MainActivity() {
        super();
        this.b = null;
    }
    public void onClick(View arg6) {
        switch(arg6.getId()) {
            case 2131165187: {
                if(this.mEd_Username.getText().length() != 0 && this.Ed_Password.getText().length() != 0) {
                    String username = this.mEd_Username.getText().toString();
                    String password = this.Ed_Password.getText().toString();
                    Log.e("test", username + " test2 = " + password);
                    Intent v2 = new Intent(((Context)this), SecondActivity.class);  // 将输入的username和password传递给了SecondActivity界面
                    v2.putExtra("ili", username);
                    v2.putExtra("lil", password);
                    this.startActivity(v2);
                    return;
                }
                Toast.makeText(((Context)this), "不能为空", 1).show();
                break;
            }
        }
    }
    protected void onCreate(Bundle arg5) {
        super.onCreate(arg5);
        this.setContentView(0x7F030000);
        this.lojin = this.findViewById(0x7F070003);
        this.lojin.setOnClickListener(((View$OnClickListener)this));
        this.mEd_Username = this.findViewById(0x7F070001);
        this.Ed_Password = this.findViewById(0x7F070002);
        SharedPreferences$Editor v0 = this.getSharedPreferences("test", 0).edit();
        v0.putLong("ili", System.currentTimeMillis());
        v0.commit();
        Log.d("hashcode", SignatureTool.getSignature(((Context)this)) + "");
    }
    public boolean onCreateOptionsMenu(Menu arg3) {
        this.getMenuInflater().inflate(0x7F060000, arg3);
        return 1;
    }
    public boolean onOptionsItemSelected(MenuItem arg3) {
        boolean v0 = arg3.getItemId() == 0x7F070004 ? true : super.onOptionsItemSelected(arg3);
        return v0;
    }
}

首先判断用户和密码的两个编辑框是否为空,如果都不为空则跳转到SecondActivity,并将用户及密码给传递过去。

 

然后去看下SecondActivity

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.tencent.testvuln;
 
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences$Editor;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import com.tencent.testvuln.c.Encryto;
 
public class SecondActivity extends a {
    class com.tencent.testvuln.SecondActivity$1 extends BroadcastReceiver {
        com.tencent.testvuln.SecondActivity$1(SecondActivity arg1) {
            this.a = arg1;
            super();
        }
        public void onReceive(Context arg3, Intent arg4) {
            Toast.makeText(arg3, "myReceiver receive", 0).show();
            arg3.getPackageName().equals(arg4.getAction());
        }
    }
    private BroadcastReceiver c;
    public SecondActivity() {
        super();
        this.c = new com.tencent.testvuln.SecondActivity$1(this);
    }
    protected void onCreate(Bundle arg6) {
        super.onCreate(arg6);
        this.setContentView(0x7F030001);
        Intent v0 = this.getIntent();  // 获取到传入的intent
        String username = v0.getStringExtra("ili");
        String password = v0.getStringExtra("lil");
        if(Encryto.doRawData(this, username + password).equals("VEIzd/V2UPYNdn/bxH3Xig==")) { 
            // 调用类Encryto中的doRawData方法,参数为usename+password,如果返回值和VEIzd/V2UPYNdn/bxH3Xig== 相等则进入if
            v0.setAction("android.test.action.MoniterInstallService");
            v0.setClass(((Context)this), MoniterInstallService.class);
            v0.putExtra("company", "tencent");
            v0.putExtra("name", "hacker");
            v0.putExtra("age", 18);
            this.startActivity(v0);
            this.startService(v0);
        }
 
        SharedPreferences$Editor v0_1 = this.getSharedPreferences("test", 0).edit();
        v0_1.putString("ilil", username);
        v0_1.putString("lili", password);
        v0_1.commit();
    }
    public boolean onCreateOptionsMenu(Menu arg3) {
        this.getMenuInflater().inflate(0x7F060000, arg3);
        return 1;
    }
    public boolean onOptionsItemSelected(MenuItem arg3) {
        boolean v0 = arg3.getItemId() == 0x7F070004 ? true : super.onOptionsItemSelected(arg3);
        return v0;
    }
}

首先它接收了传递过来的用户和密码。调用类Encryto中的doRawData方法,参数为usename+password,如果返回值和VEIzd/V2UPYNdn/bxH3Xig== 相等则进入if中。待会再看if中的代码。我们首先定位到类Encryto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.tencent.testvuln.c;
 
public class Encryto {
    static {
        System.loadLibrary("JNIEncrypt");//加载so库
    }
    public Encryto() {
        super();
    }
    public native String HelloLoad() {
    }
    public static native int checkSignature(Object arg0) {
    }
    public static native String decode(Object arg0, String arg1) {
    }
    public static native String doRawData(Object arg0, String arg1) {//doRawData方法
    }
    public static native String encode(Object arg0, String arg1) {
    }
}

所以我们将so拖入ida,发现它将user+pass的字符串给进行了AES加密,其中key为"thisisatestkey==",AES加密方式为ECB,数据块为128位,加密后的结果作为返回值。

 

 

所以要输入的用户名和密码就是将"VEIzd/V2UPYNdn/bxH3Xig=="给进行对应的aes解密后的值,

 

在线解密即可

 

在线AES加密解密、AES在线加密解密、AES encryption and decryption--查错网 (chacuo.net)

 

AES加密、AES解密 - 在线工具 - OKTools

 

 

所以username+password就是"aimagetencent"

 

这里其实比较奇怪。在逻辑上只要用户名和密码连在一起是aimagetencent就是正确的,然后进入if中。

1
2
3
4
5
6
7
8
9
10
if(Encryto.doRawData(this, username + password).equals("VEIzd/V2UPYNdn/bxH3Xig==")) { 
// 调用类Encryto中的doRawData方法,参数为usename+password,如果返回值和VEIzd/V2UPYNdn/bxH3Xig== 相等则进入if
    v0.setAction("android.test.action.MoniterInstallService");
    v0.setClass(((Context)this), MoniterInstallService.class);
    v0.putExtra("company", "tencent");
    v0.putExtra("name", "hacker");
    v0.putExtra("age", 18);
    this.startActivity(v0);
    this.startService(v0);
}

但感觉逻辑上怎么都和类FileDataActivity连串不起来。但看别人的分析这题的flag就是在类FileDataActivity中。

解题

这题中还有一个类FileDataActivity,在创建这个Activity时,将TextView c给设置为Encryto.decode(this, "9YuQ2dk8CSaCe7DTAmaqAA==")返回值

 

 

然后在ida中看下decode方法,即将9YuQ2dk8CSaCe7DTAmaqAA==给进行aes解密,key同样为 thisisatestkey==。

 

 

在线解密得到

 

 

这里就是答案

1
Cas3_0f_A_CAK3

这里其实可以对aes加解密的代码实现。

 

这里有2个动态分析的文章后续再看看。

 

首页-程序员文章分享 (361shipin.com)

 

(32条消息) Mobile App2 攻防世界 实战_zapata_ok的博客-CSDN博客

app3

题目信息

 

下载附件发现是个app3.ab

 

.ab后缀文件为android应用的备份文件,需要用安卓备份解析abe.jar工具将数据给提取出来。

1
2
abe.ja项目地址
https://github.com/nelenkov/android-backup-extractor/releases

备份文件有两种,一种是未加密的,一种是加密的

 

未加密的ab文件有着0x18字节的文件头,并包含有none

 

加密的ab文件的文件头比较复杂了,暂时知道有这个东西就可以了。

分析

将这个app3.ab放入16进制中,发现它没有进行加密。

 

所以使用安卓备份解析abe.jar工具对它进行数据提取

1
2
3
>java -jar abe.jar unpack app3.ab app3.tar
0% 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% 41% 42% 43% 44% 45% 46% 47% 48% 49% 50% 51% 52% 53% 54% 55% 56% 57% 58% 59% 60% 61% 62% 63% 64% 65% 66% 67% 68% 69% 70% 71% 72% 73% 74% 75% 76% 77% 78% 79% 80% 81% 82% 83% 84% 85% 86% 87% 88% 89% 90% 91% 92% 93% 94% 95% 96% 97% 98% 99% 100%
9097216 bytes written to app3.tar.

然后将得到的app3.tar压缩包进行解压

1
2
3
4
5
6
7
└─app3
    └─apps
        └─com.example.yaphetshan.tencentwelcome
            ├─a-base.apk
            └─db-Demo.db
            -_manifest
            -Encryto.db

发现base.apk

 

将其放入到jeb中查看MainActivity入口

 

首先看下onCreate方法

 

创建个SharedPreferences$Editor对象,并向里面存入了3个值

1
2
3
v0.putString("Is_Encroty", "1");
 v0.putString("Encryto", "SqlCipher");
 v0.putString("ver_sion", "3_4_0");

 

然后调用了this.a()方法

 

 

首先分析下MainActivity入口类中的a函数实现了什么

 

首先加载Demo.db数据库

 

创建数据结构ContentValues

 

将name赋值为"Stranger" 将password赋值为"123456"。得到数据库有这两个字段名

 

然后v1是com.example.yaphetshan.tencentwelcome.a类的(构造方法)实例化对象。

 

看下com.example.yaphetshan.tencentwelcome.a类吧

 

 

然后v2被赋值为了v1对象中的a(arg4,arg5)方法的返回值。

 

即"Stranger" 的前4个字符加上"123456"前四个字符。

 

即v2此时为"Stra1234"

 

然后v1.b(v2, v0.getAsString("password"))就是

 

v1.b("Stra1234", "123456"))对应于com.example.yaphetshan.tencentwelcome.a类中的String b(String arg2, String arg3)方法。

1
2
3
4
public String b(String arg2, String arg3) {
    new b();
    return b.a(arg2);
}

它将类b进行实例化,并调用了类b中的a方法,参数为"Stra1234"。

 

去看下b类是怎么实现,将参数进行md5加密后又将其进行base16加密

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
public class b {
    public b() {
        super();
    }
 
    public static final String a(String arg9) {
        String v0_2;
        int i = 0;
        char[] v2 = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] arg = arg9.getBytes();
            MessageDigest v3 = MessageDigest.getInstance("MD5");
            v3.update(arg);
            byte[] md5_out = v3.digest();
            int len = md5_out.length;
            char[] v5 = new char[len * 2];
            int j = 0;
            while(i < len) {
                int v6 = md5_out[i];
                int v7 = j + 1;
                v5[j] = v2[v6 >>> 4 & 15];
                j = v7 + 1;
                v5[v7] = v2[v6 & 15];
                ++i;
            }
 
            v0_2 = new String(v5);
        }
        catch(Exception v0_1) {
            v0_2 = null;
        }

 

然后返回的结果前面拼接上v2,作为参数,调用v1对象的a(含一个参数的)方法

1
this.b.getWritableDatabase(v1.a(v2 + ret_str).substring(0, 7));

而v1对象的a(含一个参数的)方法又进行调用了b类中的b方法,参数为前面返回的结果前面拼接上v2,然后面在拼接上"yaphetshan"

1
2
3
4
public String a(String arg3) {
    new b();
    return b.b(arg3 + this.a);
}

所以现在去看下b类中的b方法是怎么实现的。

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
public static final String b(String arg9) {
        String v0_2;
        int i = 0;
        char[] v2 = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] arg = arg9.getBytes();
            MessageDigest v3 = MessageDigest.getInstance("SHA-1");
            v3.update(arg);
            byte[] sha1_out = v3.digest();
            int v4 = sha1_out.length;
            char[] v5 = new char[v4 * 2];
            int j = 0;
            while(i < v4) {
                int v6 = sha1_out[i];
                int v7 = j + 1;
                v5[j] = v2[v6 >>> 4 & 15];
                j = v7 + 1;
                v5[v7] = v2[v6 & 15];
                ++i;
            }
 
            v0_2 = new String(v5);
        }
        catch(Exception v0_1) {
            v0_2 = null;
        }
 
        return v0_2;
    }

 

发现是将参数先用sha1进行加密然后再用base16加密的。然后将其返回

1
2
this.a = this.b.getWritableDatabase(ret_str.substring(0, 7));
 this.a.insert("TencentMicrMsg", null, v0);

并取前7个字符,作为数据库存储的密码。

解题

程序顺序执行中会会到这步的,如果通关动调打断点的方式是可以成功查出这个值的。

 

如果不动调的话,就可以写脚本对这些函数进行模拟运行将它给输出出来。想了下,直接写java吧。因为可以直接复制jeb反编译的代码。得到pass为ae56f99。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.example.app3_20221012;
 
public class Main {
    public static void main(String[] args) {
 
        String arg  = "Stra1234";
        String step1=b.a(arg);
        System.out.println(step1);
 
        String step2=arg+step1+"yaphetshan";
        System.out.println(step2);
 
        String step3=b.b(step2);
        System.out.println(step3);
        String pass= step3.substring(0,7);
        System.out.println(pass);
    }
}

 

这里其实也可用python实现,暂时不管。另外关于动调的方式回头再写一篇,这里就不写了。哦对,使用在smali代码中插log也是可以将其输出的。

 

拿到密码后继续向下看

1
2
this.a = this.b.getWritableDatabase(v1.a(v2 + v1.b(v2, v0.getAsString("password"))).substring(0, 7));
this.a.insert("TencentMicrMsg", null, v0);//向数据表TencentMicrMsg表插入username和password

我们看下a类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.example.yaphetshan.tencentwelcome;
 
import android.content.Context;
import net.sqlcipher.database.SQLiteDatabase$CursorFactory;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteOpenHelper;
 
public class a extends SQLiteOpenHelper {
    private int a;
 
    public a(Context arg2, String arg3, CursorFactory arg4, int arg5) {
        super(arg2, arg3, arg4, arg5);
        this.a = 0;
    }
 
    public void onCreate(SQLiteDatabase arg2) {
        arg2.execSQL("create table TencentMicrMsg(name text,password integer,F_l_a_g text)");
    }
 
    public void onUpgrade(SQLiteDatabase arg1, int arg2, int arg3) {
    }
}

所以flag应该在TencentMicrMsg表中,为第三个字段。

 

这里我们解压app3.tar后得到两个db文件,分别去查看下即可获得flag。

 

看网上都是使用DB Browser for SQLCipher打开然后输入密码就可以的。

 

我也用这个吧

 

下载地址

 

Downloads - DB Browser for SQLite (sqlitebrowser.org)

 

 

 

成功看到flag

 

VGN0ZntIM2xsMF9Eb19ZMHVfTG92M19UZW5jM250IX0=

 

对其进行base64解密即可。

 

Tctf{H3ll0_Do_Y0u_Lov3_Tenc3nt!}


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2022-10-13 12:41 被陌上恋静编辑 ,原因: 忘记加入原创话题了
收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 310
活跃值: (960)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
本人菜鸡一个,欢迎大佬们陆续加入到QQ群 801022487 一起交流学习.
2022-10-13 12:39
0
游客
登录 | 注册 方可回帖
返回
//