Sharif University Quals CTF 2014 Commercial Application Writeup

Github Link

Markdown哪兒都好就是插圖太麻煩,盡量用語(yǔ)言描述

Overview

題目給的是一個(gè)Demo小程序,安裝在手機(jī)或者虛擬機(jī)之后看是一個(gè)看圖程序,一共三張圖圖,預(yù)覽版只可以看一張,輸入key之后可以看另外兩張,提供了一個(gè)輸入key的窗口,輸入錯(cuò)誤之后會(huì)提示錯(cuò)誤(廢話),想必正確的key就是題目的flag.

Analyse

首先例行的對(duì)給的apk進(jìn)行基礎(chǔ)操作,我的習(xí)慣是同時(shí)恢復(fù)Java代碼和Smali代碼.分析的時(shí)候Java代碼比較方便,出錯(cuò)或者是需要重新打包dex的時(shí)候使用Smali.逆向之后發(fā)現(xiàn)程序沒(méi)有l(wèi)ib目錄,且Java代碼只經(jīng)過(guò)簡(jiǎn)單混淆,沒(méi)有報(bào)錯(cuò),說(shuō)明單純分析Java代碼邏輯即可.

從輸入錯(cuò)誤key時(shí)候給出的報(bào)錯(cuò)語(yǔ)句入手,Your licence key is incorrect...! Please try again with another.這句在源程序中出現(xiàn)兩次,都在/edu/sharif/ctf/activities/MainActivity.java之中,查看代碼關(guān)鍵位置.

public void onClick(DialogInterface paramDialogInterface, int paramInt)
      {
        if (KeyVerifier.isValidLicenceKey(this.val$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(this.val$context, "Thank you, Your application has full licence. Enjoy it...!");
          return;
        }
        MainActivity.this.showAlertDialog(this.val$context, "Your licence key is incorrect...! Please try again with another.");
      }

發(fā)現(xiàn)關(guān)鍵邏輯位于KeyVerifier.isValidLicenceKey函數(shù)中,對(duì)所在文件進(jìn)行分析,會(huì)發(fā)現(xiàn)實(shí)質(zhì)性調(diào)用的是encrypt函數(shù),該函數(shù)需要三個(gè)參數(shù).

public static boolean isValidLicenceKey(String paramString1, String paramString2, String paramString3)
  {
    return encrypt(paramString1, paramString2, paramString3).equals("29a002d9340fc4bd54492f327269f3e051619b889dc8da723e135ce486965d84");
  }
  
public static String encrypt(String paramString1, String paramString2, String paramString3)
  {
    try
    {
      SecretKeySpec localSecretKeySpec = new SecretKeySpec(hexStringToBytes(paramString2), "AES");
      Cipher localCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
      localCipher.init(1, localSecretKeySpec, new IvParameterSpec(paramString3.getBytes()));
      String str = bytesToHexString(localCipher.doFinal(paramString1.getBytes()));
      return str;
    }
    catch (Exception localException)
    {
      localException.printStackTrace();
    }
    return "";
  }

由代碼可以發(fā)現(xiàn),加密使用AES算法,對(duì)稱加密就可逆,現(xiàn)在需要找出使用的三個(gè)參數(shù)paramString1,paramString2,paramString3,即可逆推出輸入的值.回到MainActivity中考察傳遞三個(gè)參數(shù)的位置作分析,
KeyVerifier.isValidLicenceKey(this.val$userInput.getText().toString(), MainActivity.this.app.getDataHelper().getConfig().getSecurityKey(), MainActivity.this.app.getDataHelper().getConfig().getSecurityIv())
第一個(gè)參數(shù)是從UI中讀入的用戶輸入,即用戶輸入的key,第二個(gè)是SecurityKey,第三個(gè)是SecurityIv,通過(guò)調(diào)用進(jìn)一步分析源碼包括程序帶的SQLite數(shù)據(jù)庫(kù)可以找到后兩者的值,而AES加密之后的值應(yīng)該是
29a002d9340fc4bd54492f327269f3e051619b889dc8da723e135ce486965d84
這里使用一個(gè)奇技淫巧不去進(jìn)一步考察代碼,而是修改Smali代碼,在使用三個(gè)值之前將它們從Log中打印出來(lái),條用位置位于class Ledu/sharif/ctf/activities/MainActivity$4之中

.line 211
    .local v0, "iv":Ljava/lang/String;

    invoke-static {v3, v3}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I
    invoke-static {v3, v2}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I
    invoke-static {v3, v0}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I

    invoke-static {v3, v2, v0}, Ledu/sharif/ctf/security/KeyVerifier;->isValidLicenceKey(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z

    move-result v1

重新打包dex,插入apk中,簽名,運(yùn)行之后隨便輸入點(diǎn)東西,通過(guò)Logcat可以截取三條Log,tag都是隨便輸入的內(nèi)容,后兩條即SecurityKey,SecurityIv

SecurityKey = 37eaae0141f1a3adf8a1dee655853714
SecurityIv = a5efdbd57b84ca36
encrypted = 29a002d9340fc4bd54492f327269f3e051619b889dc8da723e135ce486965d84

Solve

經(jīng)過(guò)以上分析,已經(jīng)可以基本確定解決問(wèn)題方法,即利用KeyVerifier中的代碼,更改Cipher工作模式為解密,接觸答案并ASCII化為字符串,即為key(flag).完整代碼如下所示

package com.company;

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));
        }
    }

}

運(yùn)行得到結(jié)果
Flag:fl-ag-IS-se-ri-al-NU-MB-ER

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末熏版,一起剝皮案震驚了整個(gè)濱河市甜奄,隨后出現(xiàn)的幾起案子关串,更是在濱河造成了極大的恐慌,老刑警劉巖踩寇,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件啄清,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡俺孙,警方通過(guò)查閱死者的電腦和手機(jī)辣卒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)睛榄,“玉大人荣茫,你說(shuō)我怎么就攤上這事〕⊙ィ” “怎么了啡莉?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)旨剥。 經(jīng)常有香客問(wèn)我咧欣,道長(zhǎng),這世上最難降的妖魔是什么轨帜? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任魄咕,我火速辦了婚禮,結(jié)果婚禮上蚌父,老公的妹妹穿的比我還像新娘哮兰。我一直安慰自己,他們只是感情好苟弛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布奠蹬。 她就那樣靜靜地躺著,像睡著了一般嗡午。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冀痕,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天荔睹,我揣著相機(jī)與錄音,去河邊找鬼言蛇。 笑死僻他,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的腊尚。 我是一名探鬼主播吨拗,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了劝篷?” 一聲冷哼從身側(cè)響起哨鸭,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎娇妓,沒(méi)想到半個(gè)月后像鸡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡哈恰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年只估,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片着绷。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蛔钙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荠医,到底是詐尸還是另有隱情吁脱,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布子漩,位于F島的核電站豫喧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏幢泼。R本人自食惡果不足惜紧显,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缕棵。 院中可真熱鬧孵班,春花似錦、人聲如沸招驴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)别厘。三九已至虱饿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間触趴,已是汗流浹背氮发。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留冗懦,地道東北人爽冕。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像披蕉,于是被迫代替她去往敵國(guó)和親颈畸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子乌奇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容