sakのノート

興味のあることについて色々と

高専セキュリティコンテスト 2019 Writeup

10/26に開催された高専セキュリティコンテストに参加しました。
残念ながらあまり問題を解くことができませんでしたが、復習も兼ねてWriteupを書きます。

03 [Crypto100] 20回もやれば、暗号と認めてやっても良いだろう

問題文でかなり長い暗号化(?)された文字列が渡されます。
問題名と暗号文からBase64と推測できるので、以下のサイトで20回デコードしてみたらフラグが得られました。
www.base64decode.org

CTFKIT{20_times_base64!}

06 [Binary 100] 無言のELF

ELFのバイナリが渡されます。
stringsで見てみると、"kosensecuritycontest2019"の文字列が見えたので実行時にこれを入力してみたらフラグが得られました。

CTFKIT{hpb5iphbr_et3phet5o} 

09 [Misc 50] プログラミン言語を当てよう

何の言語かなぁと問題を見てみると今話題のBlawnでした。
(問題を忘れたので情報量ゼロですみません。。)

CTFKIT{BLAWN}

12 [NetWork 50] 大人たちの無意味な慣習

pcapファイルが渡されたのでWiresharkで見てみると、zipファイルがあったので取り出してみましたが鍵がかかっていました。
もう一度パケットを見直すと、"zlap7b0p"というパスワードくさい文字列があったので打ち込んでみたら無事解除できてフラグが得られました。

CTFKIT{majide_muimina_shuukan_dayonee}

14 [Forensics 100] お茶をさぐれ

apkファイルが渡されます。
とりあえず展開して、classes.dexをdex2jarでjarファイルに変換しjdで見てみると、LoginActivity.classが怪しいです。

package com.example.ureshino.ctfmondai_android;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Loader;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build.VERSION;
import android.os.Bundle;
import android.provider.ContactsContract.Profile;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewPropertyAnimator;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import java.util.ArrayList;
import java.util.List;

public class LoginActivity
  extends AppCompatActivity
  implements LoaderManager.LoaderCallbacks<Cursor>
{
  private static final String[] DUMMY_CREDENTIALS = { "herfuvab@sr2b3.wc:tenaoyhr" };
  private static final int REQUEST_READ_CONTACTS = 0;
  private UserLoginTask mAuthTask = null;
  private AutoCompleteTextView mEmailView;
  private View mLoginFormView;
  private EditText mPasswordView;
  private View mProgressView;
  
  private boolean LoginTask(String paramString1, String paramString2)
  {
    String[] arrayOfString1 = DUMMY_CREDENTIALS;
    int j = arrayOfString1.length;
    boolean bool = false;
    int i = 0;
    while (i < j)
    {
      String[] arrayOfString2 = nyaho(arrayOfString1[i]).split(":");
      if (arrayOfString2[0].equals(paramString1)) {
        bool = arrayOfString2[1].equals(paramString2);
      }
      i += 1;
    }
    return bool;
  }
  
  private void addEmailsToAutoComplete(List<String> paramList)
  {
    paramList = new ArrayAdapter(this, 17367050, paramList);
    this.mEmailView.setAdapter(paramList);
  }
  
  private void attemptLogin()
  {
    if (this.mAuthTask != null) {
      return;
    }
    this.mEmailView.setError(null);
    this.mPasswordView.setError(null);
    Object localObject3 = this.mEmailView.getText().toString();
    String str = this.mPasswordView.getText().toString();
    int j = 0;
    Object localObject2 = null;
    int i = j;
    Object localObject1 = localObject2;
    if (!TextUtils.isEmpty(str))
    {
      i = j;
      localObject1 = localObject2;
      if (!isPasswordValid(str))
      {
        this.mPasswordView.setError(getString(2131558449));
        localObject1 = this.mPasswordView;
        i = 1;
      }
    }
    if (TextUtils.isEmpty((CharSequence)localObject3))
    {
      this.mEmailView.setError(getString(2131558446));
      localObject1 = this.mEmailView;
      i = 1;
    }
    else if (!isEmailValid((String)localObject3))
    {
      this.mEmailView.setError(getString(2131558448));
      localObject1 = this.mEmailView;
      i = 1;
    }
    if (i != 0)
    {
      ((View)localObject1).requestFocus();
      return;
    }
    if (LoginTask((String)localObject3, str))
    {
      localObject1 = (TextView)findViewById(2131230792);
      ((TextView)localObject1).setVisibility(0);
      localObject2 = new StringBuilder();
      ((StringBuilder)localObject2).append(f());
      ((StringBuilder)localObject2).append(l());
      ((StringBuilder)localObject2).append(o());
      ((StringBuilder)localObject2).append(g());
      ((StringBuilder)localObject2).append(g2());
      ((StringBuilder)localObject2).append(e());
      ((StringBuilder)localObject2).append(h());
      ((StringBuilder)localObject2).append(i());
      ((StringBuilder)localObject2).append(j());
      ((StringBuilder)localObject2).append(k());
      ((StringBuilder)localObject2).append(l2());
      ((StringBuilder)localObject2).append(n());
      ((StringBuilder)localObject2).append(o2());
      localObject2 = ((StringBuilder)localObject2).toString();
      localObject3 = new StringBuilder();
      ((StringBuilder)localObject3).append("CTFKIT{");
      ((StringBuilder)localObject3).append(nyaho((String)localObject2));
      ((StringBuilder)localObject3).append("}");
      ((TextView)localObject1).setText(((StringBuilder)localObject3).toString());
      return;
    }
    this.mEmailView.setError("Login Failed.... ((((((((((������)�� ");
    ((TextView)findViewById(2131230792)).setVisibility(4);
    this.mEmailView.requestFocus();
  }
  
  private boolean isEmailValid(String paramString)
  {
    return paramString.contains("@");
  }
  
  private boolean isPasswordValid(String paramString)
  {
    return paramString.length() > 4;
  }
  
  private boolean mayRequestContacts()
  {
    if (Build.VERSION.SDK_INT < 23) {
      return true;
    }
    if (checkSelfPermission("android.permission.READ_CONTACTS") == 0) {
      return true;
    }
    if (shouldShowRequestPermissionRationale("android.permission.READ_CONTACTS"))
    {
      Snackbar.make(this.mEmailView, 2131558459, -2).setAction(17039370, new View.OnClickListener()
      {
        @TargetApi(23)
        public void onClick(View paramAnonymousView)
        {
          LoginActivity.this.requestPermissions(new String[] { "android.permission.READ_CONTACTS" }, 0);
        }
      });
      return false;
    }
    requestPermissions(new String[] { "android.permission.READ_CONTACTS" }, 0);
    return false;
  }
  
  private void populateAutoComplete()
  {
    if (!mayRequestContacts()) {
      return;
    }
    getLoaderManager().initLoader(0, null, this);
  }
  
  @TargetApi(13)
  private void showProgress(final boolean paramBoolean)
  {
    int i = Build.VERSION.SDK_INT;
    int k = 0;
    int j = 0;
    if (i >= 13)
    {
      k = getResources().getInteger(17694720);
      localObject = this.mLoginFormView;
      if (paramBoolean) {
        i = 8;
      } else {
        i = 0;
      }
      ((View)localObject).setVisibility(i);
      localObject = this.mLoginFormView.animate().setDuration(k);
      float f2 = 1.0F;
      float f1;
      if (paramBoolean) {
        f1 = 0.0F;
      } else {
        f1 = 1.0F;
      }
      ((ViewPropertyAnimator)localObject).alpha(f1).setListener(new AnimatorListenerAdapter()
      {
        public void onAnimationEnd(Animator paramAnonymousAnimator)
        {
          paramAnonymousAnimator = LoginActivity.this.mLoginFormView;
          int i;
          if (paramBoolean) {
            i = 8;
          } else {
            i = 0;
          }
          paramAnonymousAnimator.setVisibility(i);
        }
      });
      localObject = this.mProgressView;
      if (paramBoolean) {
        i = j;
      } else {
        i = 8;
      }
      ((View)localObject).setVisibility(i);
      localObject = this.mProgressView.animate().setDuration(k);
      if (paramBoolean) {
        f1 = f2;
      } else {
        f1 = 0.0F;
      }
      ((ViewPropertyAnimator)localObject).alpha(f1).setListener(new AnimatorListenerAdapter()
      {
        public void onAnimationEnd(Animator paramAnonymousAnimator)
        {
          paramAnonymousAnimator = LoginActivity.this.mProgressView;
          int i;
          if (paramBoolean) {
            i = 0;
          } else {
            i = 8;
          }
          paramAnonymousAnimator.setVisibility(i);
        }
      });
      return;
    }
    Object localObject = this.mProgressView;
    if (paramBoolean) {
      i = 0;
    } else {
      i = 8;
    }
    ((View)localObject).setVisibility(i);
    localObject = this.mLoginFormView;
    i = k;
    if (paramBoolean) {
      i = 8;
    }
    ((View)localObject).setVisibility(i);
  }
  
  public String e()
  {
    return "v";
  }
  
  public String f()
  {
    return "h";
  }
  
  public String g()
  {
    return "f";
  }
  
  public String g2()
  {
    return "u";
  }
  
  public String h()
  {
    return "a";
  }
  
  public String i()
  {
    return "b";
  }
  
  public String j()
  {
    return "_";
  }
  
  public String k()
  {
    return "g";
  }
  
  public String l()
  {
    return "e";
  }
  
  public String l2()
  {
    return "r";
  }
  
  public String n()
  {
    return "n";
  }
  
  public String nyaho(String paramString)
  {
    char[] arrayOfChar = new char[paramString.length()];
    int k = 0;
    while (k < paramString.length())
    {
      int j = paramString.charAt(k);
      int i;
      if ((j >= 97) && (j <= 109))
      {
        i = (char)(j + 13);
      }
      else if ((j >= 65) && (j <= 77))
      {
        i = (char)(j + 13);
      }
      else if ((j >= 110) && (j <= 122))
      {
        i = (char)(j - 13);
      }
      else
      {
        i = j;
        if (j >= 78)
        {
          i = j;
          if (j <= 90) {
            i = (char)(j - 13);
          }
        }
      }
      arrayOfChar[k] = i;
      k += 1;
    }
    return String.valueOf(arrayOfChar);
  }
  
  public String o()
  {
    return "r";
  }
  
  public String o2()
  {
    return "_";
  }
  
  protected void onCreate(Bundle paramBundle)
  {
    super.onCreate(paramBundle);
    setContentView(2131427356);
    this.mEmailView = ((AutoCompleteTextView)findViewById(2131230778));
    populateAutoComplete();
    this.mPasswordView = ((EditText)findViewById(2131230832));
    this.mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener()
    {
      public boolean onEditorAction(TextView paramAnonymousTextView, int paramAnonymousInt, KeyEvent paramAnonymousKeyEvent)
      {
        if ((paramAnonymousInt != 6) && (paramAnonymousInt != 0)) {
          return false;
        }
        LoginActivity.this.attemptLogin();
        return true;
      }
    });
    ((Button)findViewById(2131230780)).setOnClickListener(new View.OnClickListener()
    {
      public void onClick(View paramAnonymousView)
      {
        LoginActivity.this.attemptLogin();
      }
    });
    this.mLoginFormView = findViewById(2131230812);
    this.mProgressView = findViewById(2131230813);
  }
  
  public Loader<Cursor> onCreateLoader(int paramInt, Bundle paramBundle)
  {
    return new CursorLoader(this, Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI, "data"), ProfileQuery.PROJECTION, "mimetype = ?", new String[] { "vnd.android.cursor.item/email_v2" }, "is_primary DESC");
  }
  
  public void onLoadFinished(Loader<Cursor> paramLoader, Cursor paramCursor)
  {
    paramLoader = new ArrayList();
    paramCursor.moveToFirst();
    while (!paramCursor.isAfterLast())
    {
      paramLoader.add(paramCursor.getString(0));
      paramCursor.moveToNext();
    }
    addEmailsToAutoComplete(paramLoader);
  }
  
  public void onLoaderReset(Loader<Cursor> paramLoader) {}
  
  public void onRequestPermissionsResult(int paramInt, @NonNull String[] paramArrayOfString, @NonNull int[] paramArrayOfInt)
  {
    if ((paramInt == 0) && (paramArrayOfInt.length == 1) && (paramArrayOfInt[0] == 0)) {
      populateAutoComplete();
    }
  }
  
  private static abstract interface ProfileQuery
  {
    public static final int ADDRESS = 0;
    public static final int IS_PRIMARY = 1;
    public static final String[] PROJECTION = { "data1", "is_primary" };
  }
  
  public class UserLoginTask
    extends AsyncTask<Void, Void, Boolean>
  {
    private final String mEmail;
    private final String mPassword;
    
    UserLoginTask(String paramString1, String paramString2)
    {
      this.mEmail = paramString1;
      this.mPassword = paramString2;
    }
    
    protected Boolean doInBackground(Void... paramVarArgs)
    {
      try
      {
        Thread.sleep(100L);
        paramVarArgs = LoginActivity.DUMMY_CREDENTIALS;
        int j = paramVarArgs.length;
        int i = 0;
        while (i < j)
        {
          String[] arrayOfString = paramVarArgs[i].split(":");
          if (arrayOfString[0].equals(this.mEmail)) {
            arrayOfString[1].equals(this.mPassword);
          }
          i += 1;
        }
        return Boolean.valueOf(true);
      }
      catch (InterruptedException paramVarArgs) {}
      return Boolean.valueOf(false);
    }
    
    protected void onCancelled()
    {
      LoginActivity.access$402(LoginActivity.this, null);
      LoginActivity.this.showProgress(false);
    }
    
    protected void onPostExecute(Boolean paramBoolean)
    {
      LoginActivity.access$402(LoginActivity.this, null);
      LoginActivity.this.showProgress(false);
      if (paramBoolean.booleanValue())
      {
        LoginActivity.this.finish();
        return;
      }
      LoginActivity.this.mPasswordView.setError(LoginActivity.this.getString(2131558447));
      LoginActivity.this.mPasswordView.requestFocus();
    }
  }
}

読んでみると、
e() -> "v"
f() -> "h"
g() -> "f"
g2() -> "u"
h() -> "a"
i() -> "b"
j() -> "_"
k() -> "g"
l() -> "e"
l2() -> "r"
n() -> "n"
o() -> "r"
o2() -> "_"
このような感じで定義されていて、
フラグはlocalObject2にこれらの値を順々に追加した後、nyaho(localObject2)で返ってきた値なので、あとは人力で何とかしてフラグを手に入れました(笑)

CTFKIT{ureshino_tea_}

感想

右も左もわからなかった去年と比べたらかなり解けるようになったとは思いますが、やはり自分の力不足を痛感しました。
今回は色々なジャンルの問題を広く浅くやってしまい高得点問題で詰んでしまったので、来年はチームメンバーとジャンルの役割分担をして高難易度問題まで解けるようにしたいなと思います。