티스토리 뷰
하나밖에 없는 모바일 리버싱 관련 문제였습니다. CTF 참여 당시에는 분류가 Reversing 이라고 되어 있긴 했지만 저는 Reversing 보단 모바일 문제라고 생각되었습니다.
jadx 툴로 apk 를 먼저 분석해보았습니다. 들어가자마자 보이는 건 APK 서명이 없었습니다.
그래서 apktools 도구로 서명부터 해주었습니다.
그런 다음에 AndroidManifest.xml 파일을 확인해보았습니다. 다음과 같았습니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" android:compileSdkVersion="30" android:compileSdkVersionCodename="11" package="com.example.leap" platformBuildVersionCode="30" platformBuildVersionName="11">
<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="30"/>
<application android:theme="@style/AppTheme" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:debuggable="true" android:testOnly="true" android:allowBackup="true" android:supportsRtl="true" android:roundIcon="@mipmap/ic_launcher_round" android:appComponentFactory="androidx.core.app.CoreComponentFactory">
<activity android:name="com.example.leap.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
중요한 건 MainActivity 가 하나 있고, 패키지명은 com.example.leap 이며 android:testOnly="true" 를 보면 test 용 앱임을 알 수 있었습니다.
test 용 앱을 설치하기 위해서는 adb install -t 옵션을 주면 설치가 가능하다고 합니다.
https://developer.android.com/studio/command-line/adb#-t-option
그리고 우선 소스코드를 분석해보았습니다. 액티비티가 하나밖에 없어서 MainActivity 만 분석해보았습니다.
package com.example.leap;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
int cross = 1;
int index = 0;
Random random = new Random();
public native String stringFromJNI();
static {
System.loadLibrary("native-lib");
}
/* access modifiers changed from: protected */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView((int) R.layout.activity_main);
((Button) findViewById(R.id.button)).setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
MainActivity.this.func();
MainActivity.this.cross();
}
});
}
public void func() {
ImageView stone2 = (ImageView) findViewById(R.id.stone2);
ImageView stone3 = (ImageView) findViewById(R.id.stone3);
ImageView stone4 = (ImageView) findViewById(R.id.stone4);
ImageView stone5 = (ImageView) findViewById(R.id.stone5);
int nextInt = this.random.nextInt(4);
this.index = nextInt;
if (nextInt == 0) {
stone2.setVisibility(0);
stone3.setVisibility(4);
stone4.setVisibility(4);
stone5.setVisibility(4);
Log.d("tttt", String.valueOf(this.index));
} else if (nextInt == 1) {
stone2.setVisibility(4);
stone3.setVisibility(0);
stone4.setVisibility(4);
stone5.setVisibility(4);
Log.d("tttt", String.valueOf(this.index));
} else if (nextInt == 2) {
stone2.setVisibility(4);
stone3.setVisibility(4);
stone4.setVisibility(0);
stone5.setVisibility(4);
Log.d("tttt", String.valueOf(this.index));
} else if (nextInt == 3) {
stone2.setVisibility(4);
stone3.setVisibility(4);
stone4.setVisibility(4);
stone5.setVisibility(0);
Log.d("tttt", String.valueOf(this.index));
}
}
public void cross() {
ImageView stone2 = (ImageView) findViewById(R.id.stone2);
ImageView stone3 = (ImageView) findViewById(R.id.stone3);
ImageView stone4 = (ImageView) findViewById(R.id.stone4);
ImageView stone5 = (ImageView) findViewById(R.id.stone5);
ImageView people1 = (ImageView) findViewById(R.id.people1);
ImageView people2 = (ImageView) findViewById(R.id.people2);
ImageView people3 = (ImageView) findViewById(R.id.people3);
ImageView people4 = (ImageView) findViewById(R.id.people4);
ImageView people5 = (ImageView) findViewById(R.id.people5);
ImageView help2 = (ImageView) findViewById(R.id.help2);
ImageView help3 = (ImageView) findViewById(R.id.help3);
ImageView help4 = (ImageView) findViewById(R.id.help4);
ImageView help5 = (ImageView) findViewById(R.id.help5);
ImageView imageView = (ImageView) findViewById(R.id.stone1);
TextView textView = (TextView) findViewById(R.id.sample_text);
int i = this.cross;
ImageView people6 = (ImageView) findViewById(R.id.people6);
if (i == 0) {
people1.setVisibility(0);
people2.setVisibility(4);
people3.setVisibility(4);
people4.setVisibility(4);
people5.setVisibility(4);
help2.setVisibility(4);
help3.setVisibility(4);
help4.setVisibility(4);
help5.setVisibility(4);
stone2.setVisibility(0);
stone3.setVisibility(0);
stone4.setVisibility(0);
stone5.setVisibility(0);
this.cross++;
} else if (i == 1) {
if (stone2.getVisibility() == 0) {
people1.setVisibility(4);
people2.setVisibility(0);
people3.setVisibility(4);
people4.setVisibility(4);
people5.setVisibility(4);
this.cross++;
} else if (stone2.getVisibility() == 4) {
people1.setVisibility(4);
people2.setVisibility(4);
people3.setVisibility(4);
people4.setVisibility(4);
people5.setVisibility(4);
help2.setVisibility(0);
this.cross = 0;
} else {
TextView textView2 = textView;
ImageView imageView2 = people6;
}
} else if (i == 2) {
if (stone3.getVisibility() == 0) {
people1.setVisibility(4);
people2.setVisibility(4);
people3.setVisibility(0);
people4.setVisibility(4);
people5.setVisibility(4);
this.cross++;
} else if (stone3.getVisibility() == 4) {
people1.setVisibility(4);
people2.setVisibility(4);
people3.setVisibility(4);
people4.setVisibility(4);
people5.setVisibility(4);
help3.setVisibility(0);
this.cross = 0;
} else {
TextView textView3 = textView;
ImageView imageView3 = people6;
}
} else if (i == 3) {
if (stone4.getVisibility() == 0) {
people1.setVisibility(4);
people2.setVisibility(4);
people3.setVisibility(4);
people4.setVisibility(0);
people5.setVisibility(4);
this.cross++;
} else if (stone4.getVisibility() == 4) {
people1.setVisibility(4);
people2.setVisibility(4);
people3.setVisibility(4);
people4.setVisibility(4);
people5.setVisibility(4);
help4.setVisibility(0);
this.cross = 0;
} else {
TextView textView4 = textView;
ImageView imageView4 = people6;
}
} else if (i == 4) {
if (stone5.getVisibility() == 0) {
people1.setVisibility(4);
people2.setVisibility(4);
people3.setVisibility(4);
people4.setVisibility(0);
people5.setVisibility(4);
} else if (stone5.getVisibility() == 4) {
people1.setVisibility(4);
people2.setVisibility(4);
people3.setVisibility(4);
people4.setVisibility(4);
people5.setVisibility(4);
help5.setVisibility(0);
this.cross = 0;
} else {
TextView textView5 = textView;
ImageView imageView5 = people6;
}
} else if (i == 5) {
people1.setVisibility(4);
people2.setVisibility(4);
people3.setVisibility(4);
people4.setVisibility(4);
people6.setVisibility(0);
textView.setText(stringFromJNI());
} else {
ImageView imageView6 = people6;
}
}
}
코드는 위 내용이 다였습니다. JNI 로 native-lib 모듈이 import 되어 있었습니다. 보니깐 cross 값이 초기엔 1로 설정되어 있고 5일 때 stringFromJNI 함수를 호출하게 되어 있었습니다.
별로 볼 것도 없이 그냥 stringFromJNI 함수가 호출되게 하면 되겠구나 싶었습니다. 지금 생각한 건 그냥 cross 값을 5로 바꾸었으면 훨씬 쉬웠을 것 같긴하지만 그 당시에는 그냥 stringFromJNI 함수를 Log.d 함수의 인자값으로 넣어서 logcat 으로부터 stringFromJNI 함수의 반환 값을 확인하고자 하였습니다.
그래서 아래는 MainActivity.smali 코드를 변경한 코드입니다.
iget v4, p0, Lcom/example/leap/MainActivity;->index:I
invoke-static {v4}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object v4
invoke-virtual/range {p0 .. p0}, Lcom/example/leap/MainActivity;->stringFromJNI()Ljava/lang/String;
move-result-object v6
invoke-static {v6, v4}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
smali 코드 문법이나 문서를 따로 참고하지 않고 풀었어서 저게 정확히는 무슨 뜻인진 모르겠지만, 그냥 눈 대중으로 봤을 때 stringFromJNI 함수의 반환 값을 v6 에 넣고 Log.d 의 인자값으로 넘겨주는 코드인 것 같아서 위와 같이 짜집기 후 패키지를 리패키징해서 새로운 apk 파일로 만들었습니다.
그리고 nox 에서 실행 후 logcat을 확인해보았습니다.
08-30 04:57:59.826 3885 3885 D 6c30304b202062334630723320593055206c335e70: 3
확인해보니 hex 값이 나왔습니다. 무슨 값인지 확인을 위하여 ascii 값으로 우선 변환해보았습니다.
확인 해보니 Flag 값처럼 보여서 INCO{l00K b3F0r3 Y0U l3^p} 라고 입력해보았더니 문제가 풀렸습니다.
이번 문제는 요약하자면 apk 파일 분석 → smali 코드 분석 및 수정 → 앱 리패키징 → 모바일 서명키 생성 → adb install -t 과정으로 풀 수 있었던 것 같습니다.
'보안 > CTF' 카테고리의 다른 글
[Misc] Deconstructionism - 2021 INCOGNITO CTF Writeup (0) | 2021.08.31 |
---|---|
[Forensics] 코로나바이러스 대응 긴급조회 - 2021 INCOGNITO CTF Writeup (0) | 2021.08.31 |
[Forensics] data_collector - 2021 INCOGNITO CTF Writeup (0) | 2021.08.31 |
[Web] Rotton Onion - 2021 INCOGNITO CTF Writeup (0) | 2021.08.31 |
[Web] Do you know Hashes - 2021 INCOGNITO CTF Writeup (0) | 2021.08.31 |