Всеми забытый: writeup
Ссылка на задачу http://f8tasks.ru/challenges#%D0%92%D1%81%D0%B5%D0%BC%D0%B8%20%D0%B7%D0%B0%D0%B1%D1%8B%D1%82%D1%8B%D0%B9...-18
Всеми забытый
| Category | Crypto |
| Difficulty | Easy |
| Encoding | Base58 |
| Flag | flag{forg3t_br0th3r} |
Recon
«Всеми забытый… Думай, что с этим можно сделать… Он был такой же как все его братья»
Единственный артефакт задачи — строка:
2RmC5owouixWFsJsWW5jKTgBSBS4
Первичный анализ:
- длина 28 символов
- только буквы и цифры — нет
+,/,=,-,_ - нет символов
0,O,I,l
Формулировка «братья» прямо указывает на семейство base-кодировок. Отсутствие 0/O/I/l — характерный признак: именно эти символы исключены в Base58 как визуально неоднозначные.
Base58 Identification: анализ алфавита
Сравнение популярных base-кодировок по структурным признакам:
| Кодировка | Алфавит | Паддинг | Спецсимволы |
|---|---|---|---|
| Base64 | A–Z, a–z, 0–9, +, / | = | +, / |
| Base32 | A–Z, 2–7 | = | нет |
| Base62 | 0–9, A–Z, a–z | нет | нет |
| Base58 | 1–9, A–Z без O, a–z без 0/I/l | нет | нет |
Отличие Base58 от Base62: оба используют только буквы и цифры, но Base58 исключает 0, O, I, l. Наша строка содержит J (есть в Base58) и не содержит 0, O, I, l — полное совпадение.
Алгоритм декодирования — накапливаемая сумма по основанию 58:
num = 0
для каждого символа: num = num × 58 + index(символ в алфавите)
Ручной расчёт первых четырёх символов строки 2RmC...:
| # | Символ | Индекс | num после шага |
|---|---|---|---|
| 0 | 2 | 1 | 1 |
| 1 | R | 24 | 1 × 58 + 24 = 82 |
| 2 | m | 44 | 82 × 58 + 44 = 4800 |
| 3 | C | 11 | 4800 × 58 + 11 = 278411 |
После прохода всех 28 символов получаем большое целое число, которое конвертируется в байты: num.to_bytes((num.bit_length() + 7) // 8, "big").
Decryption
| Шаг | Действие | Детали |
|---|---|---|
| 1 | Проверить алфавит | все символы строки входят в Base58 |
| 2 | Построить число | num = 0; for ch: num = num*58 + idx(ch) |
| 3 | Конвертировать в байты | num.to_bytes((num.bit_length()+7)//8, "big") |
| 4 | Декодировать UTF-8 | decoded.decode("utf-8") |
Результат:
flag{forg3t_br0th3r}
Automation
#!/usr/bin/env python3
ALPHABET58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
ENCODED = "2RmC5owouixWFsJsWW5jKTgBSBS4"
def b58decode(value: str) -> bytes:
number = 0
for char in value:
if char not in ALPHABET58:
raise ValueError(f"invalid Base58 character: {char!r}")
number = number * 58 + ALPHABET58.index(char)
decoded = number.to_bytes((number.bit_length() + 7) // 8, "big")
leading_zeros = len(value) - len(value.lstrip("1"))
return b"\x00" * leading_zeros + decoded
def main() -> None:
decoded = b58decode(ENCODED)
print(decoded.decode("utf-8"))
if __name__ == "__main__":
main()
python3 solve.py
# flag{forg3t_br0th3r}
Key Takeaways
Кодирование ≠ шифрование. Base58 полностью обратимо без ключа: это смена представления, а не защита. Флаг не спрятан — он просто записан другим алфавитом.
Алфавит — главная улика. Отсутствие
0,O,I,lоднозначно выделяет Base58 среди похожих кодировок. Анализ набора символов сужает гипотезы быстрее любого инструмента.Исключённые символы — не случайность. Base58 придумали для Bitcoin-адресов, чтобы люди не путали похожие символы при ручном вводе. Понимание контекста происхождения формата помогает быстрее его опознать.
