吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3342|回复: 1
收起左侧

[Android CTF] 攻防世界mobile新手区app3详细writeup

[复制链接]
不朽的终将不朽 发表于 2020-2-14 15:19
本帖最后由 不朽的终将不朽 于 2020-2-14 20:17 编辑

0x00下载附件
下载下来是一个.ab文件,百度了一下ab文件,一些分析文章说该格式是一个安卓备份文件,分为有加密与无加密两种。

若是已加密的备份文件,则文件头会显示加密方式。.ab这种东西第一次接触,有点蒙蔽.......

0x01解压.ab文件
java -jar abe.jar unpack app3.ab app3.rar

解压之后发现里面有一个base.apk以及一个Encrypt.db以及一个demo.db

0x02分析
估计这个加密的.db文件里面有我们想要的。base.apk拖进模拟器之后效果如下:
image.png
打开这个demo.db看下:尝试用SQLiteSpy打开,发现需要输入密码:
image.png
找不到密码,那就先把apk上dex2jar看看代码逻辑:
[Java] 纯文本查看 复制代码
package com.example.yaphetshan.tencentwelcome;
 
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import com.example.yaphetshan.tencentwelcome.a.a;
import net.sqlcipher.database.SQLiteDatabase;
 
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  private SQLiteDatabase a;
  
  private a b;
  
  private Button c;
  
  private void a() {
    SQLiteDatabase.loadLibs((Context)this);
    this.b = new a((Context)this, "Demo.db", null, 1);
    ContentValues contentValues = new ContentValues();
    contentValues.put("name", "Stranger");
    contentValues.put("password", Integer.valueOf(123456));
    a a1 = new a();
    String str2 = a1.a(contentValues.getAsString("name"), contentValues.getAsString("password"));
    String str3 = a1.b(str2, contentValues.getAsString("password"));
    String str1 = a1.a(str2 + str3);
    this.a = this.b.getWritableDatabase(str1.substring(0, 7));
    this.a.insert("TencentMicrMsg", null, contentValues);
  }
  
  public void onClick(View paramView) {
    if (paramView == this.c) {
      Intent intent = new Intent();
      intent.putExtra("name", "name");
      intent.putExtra("password", "pass");
      intent.setClass((Context)this, AnotherActivity.class);
      startActivity(intent);
    } 
  }
  
  protected void onCreate(Bundle paramBundle) {
    super.onCreate(paramBundle);
    setContentView(2130968603);
    this.c = (Button)findViewById(2131427417);
    this.c.setOnClickListener(this);
    SharedPreferences.Editor editor = getSharedPreferences("test", 0).edit();
    editor.putString("Is_Encroty", "1");
    editor.putString("Encryto", "SqlCipher");
    editor.putString("ver_sion", "3_4_0");
    editor.apply();
    a();
  }
}
看看onCreate方法:
[Java] 纯文本查看 复制代码
 
  protected void onCreate(Bundle paramBundle) {
    super.onCreate(paramBundle);
    setContentView(2130968603);
    this.c = (Button)findViewById(2131427417);
    this.c.setOnClickListener(this);
    SharedPreferences.Editor editor = getSharedPreferences("test", 0).edit();
    editor.putString("Is_Encroty", "1");       //设置加密标志位为1
    editor.putString("Encryto", "SqlCipher");  //????
    editor.putString("ver_sion", "3_4_0");     //版本为3.4.0
    editor.apply();
    a();                                      //上述操作执行完毕,执行本地a()方法
  }
现在来看a()方法:
[Java] 纯文本查看 复制代码
 private void a() {[/size][/font][/color]    SQLiteDatabase.loadLibs((Context)this);            //加载数据库lib
    this.b = new a((Context)this, "Demo.db", null, 1); //创建Demo.db的数据库文件
//其中,this.b主要是创建如下语句:
//create table TencentMicrMsg(name text,password integer,F_l_a_g text)
    ContentValues contentValues = new ContentValues();   //ContentValues用于存储基本数据类型
    contentValues.put("name", "Stranger");
    contentValues.put("password", Integer.valueOf(123456));
    a a1 = new a();       //实例化一个a对象
    String str2 = a1.a(contentValues.getAsString("name"), contentValues.getAsString("password"));
    String str3 = a1.b(str2, contentValues.getAsString("password"));
    String str1 = a1.a(str2 + str3);
    this.a = this.b.getWritableDatabase(str1.substring(0, 7));
    this.a.insert("TencentMicrMsg", null, contentValues);
  }

实例化这个a a1 = new a()的时候,a的代码如下:
[Java] 纯文本查看 复制代码
package com.example.yaphetshan.tencentwelcome.a;[/size][/font][/color] 
public class a {
  private String a = "yaphetshan";
  
  public String a(String paramString) {
    new b();
    return b.b(paramString + this.a);
  }
  
  public String a(String paramString1, String paramString2) {
    paramString1 = paramString1.substring(0, 4);
    paramString2 = paramString2.substring(0, 4);
    return paramString1 + paramString2;
  }
  
  public String b(String paramString1, String paramString2) {
    new b();
    return b.a(paramString1);
  }
}

这里我的dex2jar好像出了点问题,执行到
    new b();
    return b.a(paramString1);
这两句的时候,点击进去b的代码是一堆类似汇编的注释,我估计是dex2jar的缺陷导致代码反编译有问题。于是上jadx:
[Java] 纯文本查看 复制代码
 
package com.example.yaphetshan.tencentwelcome.a;
 
import java.security.MessageDigest;
 
/* compiled from: SHA1Manager */
public class b {
    public static final String a(String str) {
        char[] cArr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] bytes = str.getBytes();
            MessageDigest instance = MessageDigest.getInstance("MD5");
            instance.update(bytes);
            char[] cArr2 = new char[(r4 * 2)];
            int i = 0;
            for (byte b : instance.digest()) {
                int i2 = i + 1;
                cArr2[i] = cArr[(b >>> 4) & 15];
                i = i2 + 1;
                cArr2[i2] = cArr[b & 15];
            }
            return new String(cArr2);
        } catch (Exception e) {
            return null;
        }
    }
 
    public static final String b(String str) {
        char[] cArr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] bytes = str.getBytes();
            MessageDigest instance = MessageDigest.getInstance("SHA-1");
            instance.update(bytes);
            char[] cArr2 = new char[(r4 * 2)];
            int i = 0;
            for (byte b : instance.digest()) {
                int i2 = i + 1;
                cArr2[i] = cArr[(b >>> 4) & 15];
                i = i2 + 1;
                cArr2[i2] = cArr[b & 15];
            }
            return new String(cArr2);
        } catch (Exception e) {
            return null;
        }
    }
}
然而还是有问题:变量r4仿佛是凭空变出来的,作为一种强类型语言,Java不允许像python那样不声明直接使用一个变量。因此,jadx还是不行,于是上JEB2: image.png
点击MainActivity:
image.png
出来的是smali代码,这里我们右键MainActivity,点击Decompile,就出来java代码了。然后上述两个函数实际如下:
[Asm] 纯文本查看 复制代码
public static final String a(String arg9) {
        String v0_2;
        int v0 = 0;
        char[] v2 = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] v1 = arg9.getBytes();
            MessageDigest v3 = MessageDigest.getInstance("MD5");
            v3.update(v1);
            byte[] v3_1 = v3.digest();
            int v4 = v3_1.length;
            char[] v5 = new char[v4 * 2];
            int v1_1 = 0;
            while(v0 < v4) {
                int v6 = v3_1[v0];
                int v7 = v1_1 + 1;
                v5[v1_1] = v2[v6 >>> 4 & 15];
                v1_1 = v7 + 1;
                v5[v7] = v2[v6 & 15];
                ++v0;
            }
 
            v0_2 = new String(v5);
        }
        catch(Exception v0_1) {
            v0_2 = null;
        }
 
        return v0_2;
    }
 
    public static final String b(String arg9) {
        String v0_2;
        int v0 = 0;
        char[] v2 = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] v1 = arg9.getBytes();
            MessageDigest v3 = MessageDigest.getInstance("SHA-1");
            v3.update(v1);
            byte[] v3_1 = v3.digest();
            int v4 = v3_1.length;
            char[] v5 = new char[v4 * 2];
            int v1_1 = 0;
            while(v0 < v4) {
                int v6 = v3_1[v0];
                int v7 = v1_1 + 1;
                v5[v1_1] = v2[v6 >>> 4 & 15];
                v1_1 = v7 + 1;
                v5[v7] = v2[v6 & 15];
                ++v0;
            }
 
            v0_2 = new String(v5);
        }
        catch(Exception v0_1) {
            v0_2 = null;
        }
 
        return v0_2;
    }

这次就没有无中生有的变量出现了。根据这次的代码我们就可以根据"Strange"、"123456"、"yaphetshan"计算数据库的密码。此处给出计算数据库密码的Java代码:
[Asm] 纯文本查看 复制代码
package Test;[/size][/font][/color] 
import java.security.MessageDigest;
 
 
public class Test {
        public static void main(String[] args) throws Exception {
                String name = "Stranger",password="123456";
                 String v2 = v1a(name, password);
                System.out.println(v1a(v2+v1b(v2,password)).substring(0,7));
        }
        public static String v1b(String arg2, String arg3) {
        return MD5(arg2);
    }
        public static String v1a(String arg4, String arg5) {
        return arg4.substring(0, 4) + arg5.substring(0, 4);
    }
        public static String v1a(String arg3) {
                String a = "yaphetshan";
           return SHA1(arg3+a);
          }
        public static final String MD5(String arg9) {
                String v0_2;
        int v0 = 0;
        char[] v2 = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] v1 = arg9.getBytes();
            MessageDigest v3 = MessageDigest.getInstance("MD5");
            v3.update(v1);
            byte[] v3_1 = v3.digest();
            int v4 = v3_1.length;
            char[] v5 = new char[v4 * 2];
            int v1_1 = 0;
            while(v0 < v4) {
                int v6 = v3_1[v0];
                int v7 = v1_1 + 1;
                v5[v1_1] = v2[v6 >>> 4 & 15];
                v1_1 = v7 + 1;
                v5[v7] = v2[v6 & 15];
                ++v0;
            }
 
            v0_2 = new String(v5);
        }
        catch(Exception v0_1) {
            v0_2 = null;
        }
 
        return v0_2;
    }
        public static final String SHA1(String arg9) {
                String v0_2;
        int v0 = 0;
        char[] v2 = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] v1 = arg9.getBytes();
            MessageDigest v3 = MessageDigest.getInstance("SHA-1");
            v3.update(v1);
            byte[] v3_1 = v3.digest();
            int v4 = v3_1.length;
            char[] v5 = new char[v4 * 2];
            int v1_1 = 0;
            while(v0 < v4) {
                int v6 = v3_1[v0];
                int v7 = v1_1 + 1;
                v5[v1_1] = v2[v6 >>> 4 & 15];
                v1_1 = v7 + 1;
                v5[v7] = v2[v6 & 15];
                ++v0;
            }
 
            v0_2 = new String(v5);
        }
        catch(Exception v0_1) {
            v0_2 = null;
        }
 
        return v0_2;
    }
}

这里说拿到密码之后怎么操作。

其他大神的wp我不知道是因为他们太吊所以省略步骤,还是题目有所变动,他们的wp在拿到数据库密码之后直接就用DB Browser for SQLite或者SQLiteStudio直接就能打开,太(芬芳)了。

我研究了半天,发现需要先用sqlcipher对.db文件操作一波,将里面的内容复制到一个新的无密码的.db文件里面:
1.命令行在sqlcipher的安装目录中输入:sqlcipher-shell64.exe encryted.db
2.进入sqlLite>
3.sqlite> PRAGMA key = '这里是数据库的密码';
4.sqlite> ATTACH DATABASE '这里是要复制到的新数据库名' AS plaintext KEY '';
5.sqlite> SELECT sqlcipher_export('plaintext');
6.sqlite> DETACH DATABASE plaintext;
上面步骤操作完,就可以拿到一个无加密的数据库.db文件。然后用SQLiteSpy打开它:
image.png
拿去base64一波就能得到flag。
---------end.我感觉我简直菜得真实------------

免费评分

参与人数 1威望 +1 吾爱币 +9 热心值 +1 收起 理由
qtfreet00 + 1 + 9 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

木毅 发表于 2020-7-15 17:02
学习了,大佬牛逼
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 19:57

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表