Analysis
Code
onCreate
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView((int) R.layout.activity_flag_seven_sqlite);
C((Toolbar) findViewById(R.id.toolbar));
j.g.a(this);
H();
((FloatingActionButton) findViewById(R.id.fab)).setOnClickListener(new a(this));
SQLiteDatabase writableDatabase = this.u.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("title", Base64.decode("VGhlIGZsYWcgaGFzaCE=", 0));
contentValues.put("subtitle", Base64.decode("MmFiOTYzOTBjN2RiZTM0MzlkZTc0ZDBjOWIwYjE3Njc=", 0));
writableDatabase.insert("Thisisatest", (String) null, contentValues);
contentValues.put("title", Base64.decode("VGhlIGZsYWcgaXMgYWxzbyBhIHBhc3N3b3JkIQ==", 0));
contentValues.put("subtitle", h.c());
writableDatabase.insert("Thisisatest", (String) null, contentValues);
}
onCreate함수를 보면 다음과 같은 역할을 한다.
- SQLiteDatabase 클래스를 사용하여 데이터 베이스를 생성한다
- Thisisatest 데이터 베이스의 title과 subtitle에 base64로 인코딩 된 값을 디코딩하여 넣어준다.
- 마지막 subtitle은 h 클래스의 c 함수 리턴값을 넣어준다.
submitFlag
public final void submitFlag(View view) {
EditText editText = (EditText) findViewById(R.id.editText8);
d.m.b.d.b(editText, "editText8");
String obj = editText.getText().toString();
EditText editText2 = (EditText) findViewById(R.id.editText7);
d.m.b.d.b(editText2, "editText7");
String obj2 = editText2.getText().toString();
j jVar = new j();
String c2 = jVar.c("flagSevenEncrypted", "");
String c3 = jVar.c("flagSevenPasswordEncrypted", "");
if (!d.m.b.d.a(obj, c2) || !d.m.b.d.a(obj2, c3)) {
Toast.makeText(this, "Try again! :D", 0).show();
return;
}
FlagsOverview.E = true;
j jVar2 = new j();
Context applicationContext = getApplicationContext();
d.m.b.d.b(applicationContext, "applicationContext");
jVar2.b(applicationContext, "flagSevenButtonColor", true);
F();
}
public final class j extends Application {
private final SharedPreferences e;
public final String c(String str, String str2) {
d.f(str, "s"); // f 함수는 첫번쨰 인자 값이 null인지 확인한다.
d.f(str2, "s1");
return this.e.getString(str, str2);
}
}
public class d {
public static boolean a(Object obj, Object obj2) {
return obj == null ? obj2 == null : obj.equals(obj2);
}
}
submitFlag함수를 보면 다음과 같은 역할을 한다.
- 사용자에게 입력받은 값을 각각 obj, obj2에 string 형태로 저장한다.
- SharedPreference를 사용하여 각각 c2, c3에 저장된 값을 가져온다.
- d클래스 a 함수에 각각 (obj, c2), (obj2, c3)값을 비교하여 만약 둘 다 값이 같다면 넘어가고 그렇지 않다면 리턴으로 제외시킨다.
여기서 문제는 base64로 인코딩 된 민감한 정보를 코드상에 노출한 다는 점과 사용자가 확인할 수 있는 데이터 베이스에 저장한다는 점이다.
Exploit
데이터 베이스는 /data/data/b3nac.injuredandroid/databases 에서 확인할 수 있다.
파일을 내보내기 위해 tar 명령어를 사용하여 db.tar로 만든 후 /storage/emulator/0/Download로 파일을 옮겨준다. (파일을 옮겨주는 이유는 adb pull로 파일을 가져올 때 기존 경로는 권한 문제로 가져올 수 없기 때문에 옮겨주는 것이다)
옮긴 후 adb pull을 사용하여 파일을 꺼내 준다.
이후 압축을 풀어주면 다음과 같이 데이터 베이스 파일을 가져올 수 있다.
추출한 데이터 베이스 파일을 열어준 후 Thisistest 테이블을 확인하면 다음과 같이 값을 확인할 수 있다.
이후 각각의 값을 MD5와 ROT47로 해독하면 flag와 password를 알아낼 수 있다.
2ab96390c7dbe3439de74d0c9b0b1767 - MD5 Decrpytion ⇒ hunter2
9EEADi^^:?;FC652?5C@:5]7:C632D6:@]4@>^DB=:E6];D@? - ROT47 Decoding ⇒ https://injuredandroid.firebaseio.com/sqlite.json
마지막으로 알아낸 값을 입력해주면 문제를 해결할 수 있다.
Reference
- Resources, string
https://developer.android.com/guide/topics/resources/string-resource?hl=ko - base64 decoder
https://www.base64decode.org/ - md5 decryption
https://www.md5online.org/md5-decrypt.html - rot 47 decoder
https://www.dcode.fr/rot-47-cipher
'Android > InjuredAndroid' 카테고리의 다른 글
FLAG SIX - Login 3 (0) | 2021.09.21 |
---|---|
FLAG FOUR - Login 2 (0) | 2021.09.21 |
FLAG THREE - RESOURCES (0) | 2021.09.21 |
FLAG TWO - EXPORTED ACTIVITY (0) | 2021.09.21 |
FLAG ONE - Login (0) | 2021.09.21 |