Задание: Даниил Фукалов, SPbCTF Прохождение: Влад Росков, SPbCTF
К вам подходит старушка с кибернетической ногой и протягивает терминал: «Помоги бабушке! Купила вот умную избушку на курьих ножках, а она глупая! Говоришь ей вперед — она стоит как вкопанная. Ключ какой-то клянчит. Посмотри, что там в ней сломано?».
Провод терминала ведет к избушке: iZba.apk
Помогите бабушке переместить избушку на юго-восток леса.
Запустим приложение на эмуляторе Андроида — можно выбрать официальный от гугла или, например, Bluestacks.
Перед нами экран, требующий ввести валидный графический ключ. Никакие функции не работают, ключ неизвестен.
Всё, что остаётся — декомпилировать приложение и посмотреть его внутри. Хороший декомпилятор приложений под Андроид — JADX.
/* com.epriori.witch.control */
public class MainActivity extends AppCompatActivity {
ImageButton down;
ImageButton left;
private LockView lockView;
private PasswordChecker passwordChecker = new PasswordChecker();
ImageButton right;
private Animation shakeAnimation;
private TextView textInputPassword;
}
/* com.epriori.witch.control.password */
public class PasswordChecker implements LockView.PasswordChecker {
private double hashPassword = 0.4881882901949958d;
private double eps = 1.0E-12d;
@Override // com.epriori.witch.control.p004ui.lock.LockView.PasswordChecker
public boolean isPasswordAccept(ArrayList<Integer> arrayList) {
return !arrayList.isEmpty() && Math.abs(hashPassword(toNumber(arrayList)) - this.hashPassword) < this.eps;
}
private double hashPassword(double d) {
double d2 = 0.0d;
int i = 1;
double d3 = 1.0d;
double d4 = d;
double d5 = 2.0d;
while (d4 / d3 > this.eps) {
d2 += (i * d4) / d3;
i *= -1;
d4 *= d * d;
d3 *= (d5 * d5) + d5;
d5 += 2.0d;
}
return d2;
}
private double toNumber(ArrayList<Integer> arrayList) {
Iterator<Integer> it = arrayList.iterator();
double d = 0.0d;
double d2 = 1.0d;
while (it.hasNext()) {
d += it.next().intValue() * d2;
d2 /= 10.0d;
}
return d;
}
}
Итак, судя по коду, проверка ключа заключается в следующем:
A.BCDEFGH
hashPassword
, и результат сравнивается с 0.4881882901949958
с точностью до 12-го знака после запятойСпособов определить, что делает функция hashPassword
, несколько — увидеть глазами и вспомнить, поэкспериментировать с входными и выходными значениями, подобрать нужное входное значение бинарным поиском. Я спросил ChatGPT.
ChatGPT говорит про отличия от настоящего разложения, но это галлюцинации
Получается, нам нужно дать проверке пароля на вход такое число, синус от которого будет равен 0.4881882901949958. Посчитаем арксинус:
In [1]: import math
In [2]: math.asin(0.4881882901949958)
Out[2]: 0.5100126535899954
Не похоже, чтобы мы могли ввести 0.510012… графическим ключом — много повторяющихся цифр. Вспомним, что синус — периодическая функция: сначал нарастает до 𝜋/2, потом убывает, и имеет период 2𝜋.
Нам подходят красные точки