2014 Sharif University Quals CTF Commercial Application

CTF,java層靜態分析java

題目地址:github.com/ctf-wiki/ct…android

1. 運行

點擊右上按鈕,出現輸入Key的界面。 git

隨便輸入幾個字符,發現報錯。 github

2. 定位關鍵代碼

根據報錯信息 Your licence key is incorrect...! Please try again with another,定位關鍵代碼。算法

private void checkLicenceKey(final Context context) {
        //檢測是否已綁定證書
        if (this.app.getDataHelper().getConfig().hasLicence()) {
            showAlertDialog(context, OK_LICENCE_MSG);
            return;
        }
        View promptsView = LayoutInflater.from(context).inflate(R.layout.propmt, null);
        Builder alertDialogBuilder = new Builder(context);
        alertDialogBuilder.setView(promptsView);
        final EditText userInput = (EditText) promptsView.findViewById(R.id.editTextDialogUserInput);
        alertDialogBuilder.setCancelable(false).setPositiveButton("Continue", new OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                if (KeyVerifier.isValidLicenceKey(userInput.getText().toString(), MainActivity.this.app.getDataHelper().getConfig().getSecurityKey(), MainActivity.this.app.getDataHelper().getConfig().getSecurityIv())) {
                    MainActivity.this.app.getDataHelper().updateLicence(2014);
                    MainActivity.isRegisterd = true;
                    MainActivity.this.showAlertDialog(context, MainActivity.OK_LICENCE_MSG);
                    return;
                }
                MainActivity.this.showAlertDialog(context, MainActivity.NOK_LICENCE_MSG);
            }
        }).setNegativeButton("Cancel", new OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                dialog.cancel();
            }
        });
        alertDialogBuilder.create().show();
    }
複製代碼

3.詳細分析

3.1 分析參數

觀察得出,關鍵代碼爲sql

KeyVerifier.isValidLicenceKey(
userInput.getText().toString(), MainActivity.this.app.getDataHelper().getConfig().getSecurityKey(), MainActivity.this.app.getDataHelper().getConfig().getSecurityIv()
)
複製代碼

共有三個參數數據庫

  1. 用戶輸入的字符串
  2. 函數getSecurityKey()getSecurityIv()
public AppConfig getConfig() {
        boolean z = true;
        AppConfig agency = new AppConfig();
        Cursor cursor = this.myDataBase.rawQuery(SELECT_QUERY, null);
        if (cursor.moveToFirst()) {
            agency.setId(cursor.getInt(0));
            agency.setName(cursor.getString(1));
            agency.setInstallDate(cursor.getString(2));
            if (cursor.getInt(3) <= 0) {
                z = false;
            }
            agency.setValidLicence(z);
            agency.setSecurityIv(cursor.getString(4));
            agency.setSecurityKey(cursor.getString(5));
            agency.setDesc(cursor.getString(7));
        }
        return agency;
    }
複製代碼

數據庫相關信息:bash

private static String DB_NAME = "db.db";
    private static String DB_PATH = "/data/data/edu.sharif.ctf/databases/";
    public static final String SELECT_QUERY = ("SELECT * FROM " + TABLE_NAME + " WHERE a=1");
    private static String TABLE_NAME = "config";
複製代碼

邏輯:app

  1. Cursor cursor = this.myDataBase.rawQuery(SELECT_QUERY, null); 獲取表config的首行
  2. agency.setSecurityIv(cursor.getString(4)); 表中第四行賦值給Iv
  3. agency.setSecurityKey(cursor.getString(5)); 表中第五行賦值給Key

用jeb打開apk,導出db.db ,用 DB browser 打開。函數

SecurityIv:a5efdbd57b84ca36
SecurityKey: 37eaae0141f1a3adf8a1dee655853714

3.2 分析加密算法

package edu.sharif.ctf.security;

import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class KeyVerifier {
    public static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
    public static final String VALID_LICENCE = "29a002d9340fc4bd54492f327269f3e051619b889dc8da723e135ce486965d84";

    public KeyVerifier() {
        super();
    }

    public static String bytesToHexString(byte[] arg8) {
        StringBuilder v1 = new StringBuilder();
        int v4 = arg8.length;
        int v2;
        for(v2 = 0; v2 < v4; ++v2) {
            v1.append(String.format("%02x", Integer.valueOf(arg8[v2] & 0xFF)));
        }

        return v1.toString();
    }

    public static String encrypt(String arg8, String arg9, String arg10) {
        String v3;
        try {
            SecretKeySpec v5 = new SecretKeySpec(KeyVerifier.hexStringToBytes(arg9), "AES");
            Cipher v0 = Cipher.getInstance("AES/CBC/PKCS5Padding");
            v0.init(1, ((Key)v5), new IvParameterSpec(arg10.getBytes()));
            v3 = KeyVerifier.bytesToHexString(v0.doFinal(arg8.getBytes()));
        }
        catch(Exception v1) {
            v1.printStackTrace();
        }

        return v3;
    }

    public static byte[] hexStringToBytes(String arg7) {
        int v6 = 16;
        int v2 = arg7.length();
        byte[] v0 = new byte[v2 / 2];
        int v1;
        for(v1 = 0; v1 < v2; v1 += 2) {
            v0[v1 / 2] = ((byte)((Character.digit(arg7.charAt(v1), v6) << 4) + Character.digit(arg7.charAt(v1 + 1), v6)));
        }

        return v0;
    }
    
    // 調用加密算法
    public static boolean isValidLicenceKey(String arg2, String arg3, String arg4) {
        boolean v1 = KeyVerifier.encrypt(arg2, arg3, arg4).equals("29a002d9340fc4bd54492f327269f3e051619b889dc8da723e135ce486965d84") ? true : false;
        return v1;
    }
}
複製代碼

加密算法爲AES/CBC/PKCS5Padding,寫出對應的解密算法

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Main {

    public static void main(String[] args) {
        // write your code here
        String encrypted = "29a002d9340fc4bd54492f327269f3e051619b889dc8da723e135ce486965d84";
        String securityKey = "37eaae0141f1a3adf8a1dee655853714";
        String securityIv = "a5efdbd57b84ca36";
        String result = decrypt(encrypted, securityKey, securityIv);
        System.out.println(result);
    }

    public static String bytesToHexString(byte[] paramArrayOfByte) {
        StringBuilder localStringBuilder = new StringBuilder();
        int i = paramArrayOfByte.length;
        for (int j = 0; ; j++) {
            if (j >= i)
                return localStringBuilder.toString();
            int k = paramArrayOfByte[j];
            Object[] arrayOfObject = new Object[1];
            arrayOfObject[0] = Integer.valueOf(k & 0xFF);
            localStringBuilder.append(String.format("%02x", arrayOfObject));
        }
    }

    public static String decrypt(String paramString1, String paramString2, String paramString3) {
        try {
            SecretKeySpec localSecretKeySpec = new SecretKeySpec(hexStringToBytes(paramString2), "AES");
            Cipher localCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            localCipher.init(Cipher.DECRYPT_MODE, localSecretKeySpec, new IvParameterSpec(paramString3.getBytes()));
            byte[] bytes = localCipher.doFinal(hexStringToBytes(paramString1));
            String flag = "";
            for (byte b : bytes) {
                flag += (char) b;
            }
            return flag;
        } catch (Exception localException) {
            localException.printStackTrace();
        }
        return "";
    }

    public static byte[] hexStringToBytes(String paramString) {
        int i = paramString.length();
        byte[] arrayOfByte = new byte[i / 2];
        for (int j = 0; ; j += 2) {
            if (j >= i)
                return arrayOfByte;
            arrayOfByte[(j / 2)] = (byte) ((Character.digit(paramString.charAt(j), 16) << 4) + Character.digit(paramString.charAt(j + 1), 16));
        }
    }
}
複製代碼

運行獲得結果:

fl-ag-IS-se-ri-al-NU-MB-ER
複製代碼

4. 備註

4.1 工具

  1. jadx
  2. jeb
  3. DB Browser for SQLite sqlitebrowser.org/

4.2 參考文章

  1. Sharif University Quals CTF 2014 Commercial Application Writeup
  2. CTF-wiki 2014 Sharif University Quals CTF Commercial Application
相關文章
相關標籤/搜索