brokenpasscode Writeup

AngstromCTF2017のAndroid問題brokenpasscodeのwriteup

Writup

いつも通りJavaのコードをみる

MainActivity.java

 public void addListenerOnButton()
    {
        ((Button)findViewById(0x7f0b0055)).setOnClickListener(new android.view.View.OnClickListener() {

            public void onClick(View view)
            {
                int i = Integer.parseInt(((EditText)findViewById(0x7f0b0054)).getText().toString());
                if(i == r)
                {
                    Log.i("debug", (new StringBuilder()).append("If you think you've successfully recovered my passcode...enter actf{").append(i).append("} as the flag!").toString());
                    return;
                } else
                {
                    Log.i("debug", "lmao you messed up");
                    return;
                }
            }

            final MainActivity this$0;

            
            {
                this$0 = MainActivity.this;
                super();
            }
        }
);
    }
protected void onCreate(Bundle bundle)
    {
        super.onCreate(bundle);
        setContentView(0x7f04001a);
        try
        {
            bundle = getPackageManager().getApplicationInfo(getPackageName(), 128);
            if(((ApplicationInfo) (bundle)).metaData != null)
            {
                System.out.println(((ApplicationInfo) (bundle)).metaData.getInt("com.example.guest1.passcode_actf.key"));
                r = ((ApplicationInfo) (bundle)).metaData.getInt("com.example.guest1.passcode_actf.key");
            }
        }
        // Misplaced declaration of an exception variable
        catch(Bundle bundle)
        {
            bundle.printStackTrace();
        }
        addListenerOnButton();
    }

rがAndroidManifest.xmlにある数字だとわかる、apktoolでデコードしてみてAndroidManifest.xmlを見てみると9999999であるとわかる。だがflag送信してみると答えじゃなかった。当日はそこで諦めた。

ここからWriteupを見てみたがMETA-INFの署名情報と比較すると答えと違うことが分かる。

$ cat tmp/META-INF/MANIFEST.MF| grep Android -A 2
Created-By: Android Gradle 1.5.0

Name: res/drawable-xhdpi-v4/abc_ic_star_half_black_48dp.png
--
Name: AndroidManifest.xml
SHA1-Digest: F0T3vG9oImHgTmMPeAu0dfJ0sVk=

$ python 
>>> f = open("AndroidManifest.xml","rb")
>>> data = f.read()
>>> import hashlib
>>> import base64
>>> tmp = hashlib.sha1(data).digest()
>>> tmp
'\x07\x98R\xdaT\xd4O`g\xa5L8\xac\xa6\x0f)\x82\xa3L\x86'
>>> base64.b64encode(tmp)
'B5hS2lTUT2BnpUw4rKYPKYKjTIY='

9999999を変更していけばSHA1-Digestが一緒になるであろうことを予想する

それでbase64の感じからして9999999より小さいと思われる。後はブルートフォース

import hashlib
import base64
import struct

key = "F0T3vG9oImHgTmMPeAu0dfJ0sVk="
encode = base64.b64decode(key)

f = open("./tmp/AndroidManifest.xml","rb")
content = f.read()

for i in range(1000000,9999999):
    tmp = content.replace(struct.pack("i",9999999),struct.pack("i",i))
    if hashlib.sha1(tmp).digest() == encode:
        print(i)
$ python solve.py
8195472

flag:RCTF{8195472}となる

Dai Lai Lake Writeup

WhiteHat Contest13で解けなかったDai Lai LakeのWriteup。

正直ggr力が足りなかっただけの問題(正直知るかって感じがある)

Dai Lai Lake

問題文

Can you find my sensitive infomation?

Dai Lai has acquired a reputation for the land of graceful mountains and debonair water

Download file:

http://material.wargame.whitehat.vn/contests/13/passcode.zip

Writeup

apkが配られるので、いつものようにMainActivity.jadを見てみる

public void onClick(View view)
            {
                if(!keyPadLockedFlag)
                {
                    view = (Button)view;
                    if(userEntered.length() < 4)
                    {
                        userEntered = (new StringBuilder()).append(userEntered).append(view.getText()).toString();
                        Log.v("PinView", (new StringBuilder()).append("User entered=").append(userEntered).toString());
                        passwordInput.setText((new StringBuilder()).append(passwordInput.getText().toString()).append("*").toString());
                        if(userEntered.length() == 4)
                        {
                            view = new DataBase(MainActivity.this);
                            try
                            {
                                view.createDataBase();
                            }
                            // Misplaced declaration of an exception variable
                            catch(View view)
                            {
                                throw new Error("Unable to create database");
                            }
                            try
                            {
                                view.openDataBase();
                            }
                            // Misplaced declaration of an exception variable
                            catch(View view)
                            {
                                throw view;
                            }
                            if(view.getAllNotes().contains(userEntered))
                            {
                                statusView.setTextColor(0xff00ff00);
                                statusView.setText("Correct");
                                error = 0;
                                return;
                            }
                            MainActivity mainactivity = MainActivity.this;
                            mainactivity.error = mainactivity.error + 1;
                            if(error == 5)
                            {
                                final Dialog commentDialog = new Dialog(MainActivity.this);
                                commentDialog.setContentView(0x7f04002f);
                                ((Button)commentDialog.findViewById(0x7f0b008a)).setOnClickListener(view. new android.view.View.OnClickListener() {

                                    public void onClick(View view)
                                    {
                                        view = ((EditText)commentDialog.findViewById(0x7f0b0089)).getText().toString();
                                        String s = String.format("%04d", new Object[] {
                                            Integer.valueOf((new Random()).nextInt(9999))
                                        });
                                        db.Add(view, s);
                                        (new SendMail(_fld0, view, "PASSCODE", (new StringBuilder()).append("Your new PASSCODE is: ").append(s).toString())).execute(new Void[0]);
                                        commentDialog.dismiss();
                                    }

ここだけ見てもおそらくデータベースから照合していることを察した。で詳しく見ていくとassets/内にsqliteがあるので中を見てみる

$ sqlite3 passcode.sqlite
sqlite> .tables
user     zadminz
sqlite> select * from user;
1|xxx@gmail.com|1234
2|aaa@gmail.com|3333
sqlite> select * from zadminz;
1|admin_contest_05@spamdecoy.net|7777
sqlite> 

情報通り1234と3333でOKとかでる。zadminzの内容がflagなのかと試したけどハズレ。ここで止まってた

Writeupを見てみたらspamdecoy.netという囮のメールのものがあるらしい

そこでメールアドレスさえわかっていればメールが読める。なのでadmin_contest_05@spamdecoy.netでログインしてみると

f:id:kataware8136:20170601223138p:plain

f:id:kataware8136:20170601223159p:plain

Your new PASSCODE is: check_your_db_before_building_appがflagとなるあとはsha1にして

WhiteHat{254eb81a7b439405a5d006eb7cfdf0cd841c6d28}

CTF Android問に強くなる

はじめに

研究でAndroid系扱っているのにCTFでAndroid問が解けないので強くなりたい…. ついでにAndroid問を解くために準備しておくとよいものと私のいつものやり方(デコンパイル)を載せておきます

このページは私が見つけたAndroid問をひたすらのっけるだけ、Writeupは出来たやつからリンクをはる

Jewelはksnctfの問題なのでWriteupは載せません

問題一覧

Android CTF問を解くのに必須なもの

Android CTF問を解くのにあるとよいもの

Android CTF問でやること

apkの中身を見れるようにする

まずは配られたapkの中身を見れるようにします。

このときに使うのがapktoolunzip

apkはzipファイルなのでjavaソースコードだけでいい場合はunzipでいいです。

ただしunzipではAndroidManifestファイルが見れないのでそういうときはapktoolを使うようにしています。

$ unzip test.apk
$ apktool d test.apk

こんな感じで使います。

apkの構成は以下のようになっています。unzipを使ったときは以下の構成になっていると思います。

apktoolだとclasses.dexファイルがなくてその代わりにsmaliファイルがあります。

$ ls
AndroidManifest.xml # マニフェストファイル
META-INF/ # 署名
assets/ # アプリで必要になるデータ等がある
classes.dex # Javaのソースコード
res/ # アイコンとかのリソースが入っている
resources.asrc

dexファイルをjavaで見れるようにする

ソースコードが見れれば解けるような問題もあります。ということでdexファイルをjavaで見れるようにします

dex2jarを使うとアプリで使われているclassファイルが出てきます。あとはそれをjadを用いて見れるようにします。

基本的にはMainActivity.classが必ずあるのでそれをjadで見て、後は必要に応じてjadを使っていけばいいと思います。 MainActivity.classがどこにあるのかはfind ./ -name MainActivityとかでどうぞ

$ dex2jar classes.dex
$ jad ./***/***/MainActivity.class

apkファイルが配られたらとりあえずやることはこんな感じになると思います。