Всем привет!
Подошёл к концу Backdoor CTF и я хочу поделиться решениями некоторых тасков.
Сейчас разберу пока 2 таска: на реверс и форензику.
1. Reverse: Open Sesame
Нам дается apk файл.
Запускаем, смотрим что есть. Есть поле для ввода имени и ключа(далее пароль).
Запускаем APKlab в VScode и смотрим MainActivity.java.
Сразу были найдены переменные valid_user, а также valid_password, который равен
Отбрасываем valid_user, работаем только с паролем.
Далее у нас идет XOR строки "U|]rURuoU^PoR_FDMo@X]uBUg" с тем самым паролем и проверки на валидность введенного пароля(нам ни к чему).
Обращаем внимание на то, что в valid_password не все значения числовые. Строка "AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR" тоже является числом, так как
Пишем солвер:
Получаем флаг:
2. Forensics: Forenscript
Нам даётся какой-то файл a.bin. Смотрим в hex редакторе:
Очень похоже на "магические" байты png картинки, да только в странном порядке.
Чтобы восстановить картинку нам надо сделать реверс каждых 4 байт, например "47 4e 50 89" должны превратиться в "89 50 4e 47"
Пишем программу для декодирования:
Открываем и видим сие:
Раз флаг не на экране - значит он в картинке.
Открываем
Скачиваем, распаковываем, переименовываем нужный файл в "flag.png" и получаем флаг:
Спасибо за прочтение!
Подошёл к концу Backdoor CTF и я хочу поделиться решениями некоторых тасков.
Сейчас разберу пока 2 таска: на реверс и форензику.
1. Reverse: Open Sesame
Нам дается apk файл.
Запускаем, смотрим что есть. Есть поле для ввода имени и ключа(далее пароль).
Запускаем APKlab в VScode и смотрим MainActivity.java.
Java:
package com.example.open_sesame;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
/* loaded from: classes.dex */
public class MainActivity extends AppCompatActivity {
private static final int[] valid_password = {52, AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR, 49, 98, 97, 98, 97};
private static final String valid_user = "Jack Ma";
private Button buttonLogin;
private EditText editTextPassword;
private EditText editTextUsername;
/* JADX INFO: Access modifiers changed from: protected */
@Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(C0567R.layout.activity_main);
this.editTextUsername = (EditText) findViewById(C0567R.C0570id.editTextUsername);
this.editTextPassword = (EditText) findViewById(C0567R.C0570id.editTextPassword);
Button button = (Button) findViewById(C0567R.C0570id.buttonLogin);
this.buttonLogin = button;
button.setOnClickListener(new View.OnClickListener() { // from class: com.example.open_sesame.MainActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View view) {
MainActivity.this.validateCredentials();
}
});
}
/* JADX INFO: Access modifiers changed from: private */
public void validateCredentials() {
String trim = this.editTextUsername.getText().toString().trim();
String trim2 = this.editTextPassword.getText().toString().trim();
if (trim.equals(valid_user) && n4ut1lus(trim2)) {
String str = "flag{" + flag(Integer.toString(sl4y3r(sh4dy(trim2))), "U|]rURuoU^PoR_FDMo@X]uBUg") + "}";
return;
}
showToast("Invalid credentials. Please try again.");
}
private boolean n4ut1lus(String str) {
int[] it4chi = it4chi(str);
if (it4chi.length != valid_password.length) {
return false;
}
for (int i = 0; i < it4chi.length; i++) {
if (it4chi[i] != valid_password[i]) {
return false;
}
}
return true;
}
private int[] it4chi(String str) {
int[] iArr = new int[str.length()];
for (int i = 0; i < str.length(); i++) {
iArr[i] = str.charAt(i);
}
return iArr;
}
private String sh4dy(String str) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
char charAt = str.charAt(i);
if (Character.isDigit(charAt)) {
sb.append(charAt);
}
}
return sb.toString();
}
private int sl4y3r(String str) {
return Integer.parseInt(str) - 1;
}
private String flag(String str, String str2) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str2.length(); i++) {
sb.append((char) (str2.charAt(i) ^ str.charAt(i % str.length())));
}
return sb.toString();
}
private void showToast(String str) {
Toast.makeText(this, str, 0).show();
}
}
Сразу были найдены переменные valid_user, а также valid_password, который равен
{52, AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR, 49, 98, 97, 98, 97};
.Отбрасываем valid_user, работаем только с паролем.
Далее у нас идет XOR строки "U|]rURuoU^PoR_FDMo@X]uBUg" с тем самым паролем и проверки на валидность введенного пароля(нам ни к чему).
Обращаем внимание на то, что в valid_password не все значения числовые. Строка "AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR" тоже является числом, так как
Ссылка скрыта от гостей
"108".Пишем солвер:
Python:
import re
valid_password = [52, 108, 49, 98, 97, 98, 97]
TextPassword = ''.join(chr(num) for num in valid_password)
def sh4dy(str_value):
digits_only = re.sub(r"\D", "", str_value)
return digits_only
def sl4y3r(str_value):
return int(str_value) - 1
def flag(str1, str2):
sb = []
for i in range(len(str2)):
sb.append(chr(ord(str2[i]) ^ ord(str1[i % len(str1)])))
return "".join(sb)
print(flag(str(sl4y3r(sh4dy(TextPassword))), "U|]rURuoU^PoR_FDMo@X]uBUg"))
Получаем флаг:
flag{aLiBabA_and_forty_thiEveS}
2. Forensics: Forenscript
Нам даётся какой-то файл a.bin. Смотрим в hex редакторе:
Очень похоже на "магические" байты png картинки, да только в странном порядке.
Чтобы восстановить картинку нам надо сделать реверс каждых 4 байт, например "47 4e 50 89" должны превратиться в "89 50 4e 47"
Пишем программу для декодирования:
Python:
with open('C:/users/hidden/Desktop/a.bin', 'rb') as file:
data = file.read()
output = b''
for i in range(0, len(data), 4):
segment = data[i:i+4]
reversed_segment = segment[::-1]
output += reversed_segment
with open('C:/users/hidden/Desktop/out.png', 'wb') as file:
file.write(output)
Открываем и видим сие:
Раз флаг не на экране - значит он в картинке.
Открываем
Ссылка скрыта от гостей
, видим что там есть ещё одна картинка:Скачиваем, распаковываем, переименовываем нужный файл в "flag.png" и получаем флаг:
flag{scr1pt1ng_r34lly_t0ugh_a4n't_1t??}
Спасибо за прочтение!
Последнее редактирование: