Skip to content
This repository has been archived by the owner on Mar 30, 2020. It is now read-only.

Write-up of task "SCADA Server" from Kaspersky Industrial CTF

Notifications You must be signed in to change notification settings

orsinium-archive/kaspersky-ctf-scada-write-up

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

##Task

Figure out the logic of Super Secured SCADA Python Server and get the flags! ip: 119.81.178.102:1337

#300 SCADA Server 1 [network]

  1. Подключаемся к серверу и пытаемся ввести некоторые стандартные команды. Мне удалось найти только help (который не выводил ничего полезного) и exit. На Всё остальное получаем следующий ответ: Unknown command: ИМЯ_КОМАНДЫ

  2. Автоматически переберем команды. Код команды смотри в brute_commands.py.

  3. Находим команду get. Пробуем. Получаем ответ: No such file or directory Очевидно, после команды должен указываться файл или директория для открытия. Пробуем get ., получаем ответ Is a directory.

  4. Вспоминаем, что сервер на питоне. Перебираем стандартные имена, типа __init__.py, main.py и... И находим server.py!

Первое задание решено.

#100 SCADA Server 2 [network]

Смотрим код server.py. После беглого просмотра видим открытие файла private/flag_ki_ctf_2016_telnet.txt. Очевидно, там флаг. Мы помним, что команда get не дает нам открывать директории. Однако если попробовать get flag_ki_ctf_2016_telnet.txt, то выяснится, что в текущей директории тоже есть файл с таким названием. Задание решено.

#700 SCADA Server 3 [network]

  1. Находим в коде server.py обработку команды login. Работает это следующим образом: 0. Пользователь посылает команду login вместе с логином и паролем, разделенными пробелом. 0. Сервер объединяет логин и пароль символом : и подает на вход функции calc_hash. 0. Если результат calc_hash равен 0xC84E20E52E25E5E8, сервер возвращает флаг.
  2. Функция calc_hash содержится в модуле custom_crypt. Получаем его с помощью команды get custom_crypt.py.

Посмотрим содержимое функции:

def calc_hash(crc, s):
    for byte in s:
        crc = crc64_tab[(crc ^ ord(byte))&0xFF] ^ ((crc << 8)&0xFFFFFFFFFFFFFFFF)
    return crc

Для простоты восприятия разобьем содержимое цикла на несколько строк:

def calc_hash(crc, s):
    for byte in s:
		tmp1 = (crc ^ ord(byte)) & 0xFF
        tmp2 = crc64_tab[tmp1]
        crc = tmp2 ^ ((crc << 8) & 0xFFFFFFFFFFFFFFFF)
    return crc

Замечаем следующие вещи:

  1. Из-за сдвига crc на 8 бит влево (<< 8) и последующего логического умножения (&) на каждой итерации мы теряем 1 байт из старшей части.
  2. crc умножается на 8 байт, поэтому при обратном прохождении мы можем предсказать только 8 итераций функции.
  3. Т.к. crc сдвигается на байт влево, то 1 байт из младшей части заполнен нулям. Затем он складывается по модулю 2 (XOR) с tmp2, а это значит, что последние 8 баит tmp2 не изменяются, поэтому у итогового crc и tmp2 будет совпадать старший байт.

Исходя из сказанного выше, можно задать следующие требования к обратной функции: 0. Мы можем предсказать только последние 8 байт текста. Соответственно, после 8 итераций алгоритм должен завершать свою работу. 0. Мы можем отыскать требуемый tmp2 по младшему байту. tmp2 берется из crc64_tab, у некоторых значений которого последний байт совпадает. Исходя из этого необходимо рассматривать несколько вариантов, в зависимости от значения tmp2, выбранного на каждой итерации. 0. Также, очевидно, логин и пароль должны состоять только из печатных символов.

С учётом перечисленных требований напишем обратную функцию: crypt_hack.py.

В итоге получаем строку VOplmH2n. Однако это только последние 8 символов. Переберём остальные через основную функцию: crypt_brute.py

Получаем ответ: login b hVOplmH2n

Отправляем полученную команду серверу. Задание решено.

About

Write-up of task "SCADA Server" from Kaspersky Industrial CTF

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages