Pull to refresh
43.4
Rating

Масоны выбирают солнце: взлом программы для Sun Solaris & SPARC в задании NeoQUEST-2015

НеоБИТ corporate blog Information Security *Entertaining tasks CTF *
Уход от привычной x86 архитектуры — это всегда интересно, и в задании NeoQUEST-2015 «Масоны выбирают солнце» участникам было предложено взломать программу, которая разработана и написана для Sun Solaris 2.6 версии 1995-го года, да еще и для архитектуры SPARC!

Задание оказалось непростым не только для прохождения — его подготовка также заняла некоторое время. Под катом:
  • Советы по установке Solaris: как сделать это, минимизировав трудозатраты?
  • Запуск Solaris 2.6 под qemu для Windows 8.1
  • Подробный разбор двух способов прохождения задания


Изучаем исходные данные к заданию


В качестве входных данных в задании давались два бинарных файла: маленький getlaunchkey.bin и image.img, занимающий 2ГБ. Кроме того, в тексте задания фигурировали имя Ivanov и IP-адрес 79.175.2.82.

Пока качается двухгигабайтный диск, посмотрим на маленький файл getlaunchkey.bin. По сигнатуре ELF быстро становится понятно, что это за файл. Утилита readelf –a getlaunchkey.bin сообщает нам несколько полезных фактов.

Во-первых, из заголовка понятно, что программа для системы System V, а архитектура sparc x32 бита big endian:



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





Если проанализировать содержимое бинарного файла, то можно легко обнаружить в нем два IP-адреса: 192.168.1.88 и 192.168.1.22, которые присутствуют в виде строк. С учетом того, что программа явно работает с сокетами, и исполняемый файл имеет малый размер, можно сделать два предположения:

  1. Оба адреса являются адресами серверов, к которым обращается приложение;
  2. Один адрес – это адрес хостового компьютера, а второй адрес сервера.

Кроме того, оба адреса принадлежат локальной сети, значит, в исходном виде их использовать нельзя, надо заменить на какие-то другие.
Второй файл image.img в силу размера явно похож на жесткий диск. В начале файла есть сигнатура QFI, которая при быстром гуглении выдает нам информацию о том, что это формат QCOW, использующийся для динамических образов жестких дисков.

В том числе, этот формат используется в эмуляторе qemu. Если порыться в образе в hex-редакторе (или использовать утилиту наподобие strings), то можно быстро обнаружить строки вроде «Solaris_2.6», к тому же, есть строка «getlaunchkey».

Из всего вышесказанного можно сделать предварительный вывод о том, что нам достался образ установленного Solaris версии 2.6, и, судя по всему, версии sparc, и программа для этой операционной системы. С программой нам и предстоит разобраться. Теперь есть два пути: попытаться запустить образ Solaris в qemu, или попытаться написать аналог программы getlaunchkey для Windows.

Запускаем Solaris 2.6 в Windows 8.1


Для начала попробуем запустить Solaris. Если скачать и установить qemu для Windows, то в его составе будет версия, эмулирующая sparc. Пробуем запустить образ:

"c:\Program Files (x86)\qemu\qemu-system-sparc.exe" –hda .\image.img


И убеждаемся, что это не работает. Теперь пробуем гуглить и находим пару интересных статей (первая и вторая), где рассказано, как запустить Solaris 2.6 под qemu:

В результате изучения этих статей можно сформировать следующую строку запуска:

 "c:\Program Files (x86)\qemu\qemu-system-sparc.exe" -bios .\ss5-1.bin -L .\ –hda .\image.img -m 256 -M SS-5 -nographic -serial mon:telnet:127.0.0.1:4444,server,nowait


Разберем эти опции подробнее:

  • bios .\ss5-1.bin – требует от qemu использовать указанный образ BIOS. Оказывается, стандартный образ BIOS для sparc из поставки qemu не годится для Solaris 2.6 sparc. Сам образ можно скачать тут
  • hda .\image.img – указываем образ диска, с которого грузиться. Кстати, надо не забыть снять бит Read Only с файла образа, иначе qemu не сможет работать (обычно в Windows он даже об ошибке не скажет)
  • m 256 – задаем размер оперативной памяти (256 мегабайт для версии ОС 1995 вполне достаточно)
  • M SS-5 – уточняем для qemu тип эмулируемой архитектуры sparc
  • nographic – очень важная опция. В qemu, оказывается, эмулируется графический адаптер с ошибками, в результате Solaris 2.6, пытаясь использовать графику, зависает при загрузке
  • serial mon:telnet:127.0.0.1:4444,server,nowait – поскольку мы выключили графический адаптер, то отображать что-либо на экране qemu не сможет, вместо этого он сможет отображать простой COM терминал в сеть по протоколу telnet. Опция включает перенаправление эмулятора COM в заданное устройство.

Если не использовать последние две опции, то qemu запустит графическое окно:



Но после продолжительной загрузки сперва зависнет на несколько минут, а потом перезагрузится на примерно таком экране:



Итак, запускаем команду, и убеждаемся, что в командной строке все зависло – значит, виртуальная машина запустилась. Теперь, чтобы увидеть запущенную ОС, нужно подключиться к telnet:127.0.0.1:4444 с помощью putty . В результате, в консоли putty мы увидим следующий текст (на всякий случай, в консоли нужно нажать Enter, иначе не обновится экран):

Probing Memory Bank #0 32 Megabytes
Probing Memory Bank #1 32 Megabytes
Probing Memory Bank #2 32 Megabytes
Probing Memory Bank #3 32 Megabytes
Probing Memory Bank #4 32 Megabytes
Probing Memory Bank #5 32 Megabytes
Probing Memory Bank #6 32 Megabytes
Probing Memory Bank #7 32 Megabytes
Incorrect configuration checksum;
Setting NVRAM parameters to default values.
Setting diag-switch? NVRAM parameter to true
Probing CPU FMI,MB86904
Probing /iommu@0,10000000/sbus@0,10001000 at 5,0  espdma esp sd st SUNW,bpp ledma le
Probing /iommu@0,10000000/sbus@0,10001000 at 4,0  SUNW,CS4231 power-management
Probing /iommu@0,10000000/sbus@0,10001000 at 1,0  Nothing there
Probing /iommu@0,10000000/sbus@0,10001000 at 2,0  Nothing there
Probing /iommu@0,10000000/sbus@0,10001000 at 3,0  SUNW,tcx
Probing /iommu@0,10000000/sbus@0,10001000 at 0,0  Nothing there

SPARCstation 5, No Keyboard
ROM Rev. 2.15, 256 MB memory installed, Serial #1193046.
Ethernet address 52:54:0:12:34:56, Host ID: 80123456.

Boot device: /iommu/sbus/ledma@5,8400010/le@5,8c00000  File and args:
Internal loopback test -- Wrong packet length; expected 36, observed 64

Can't open boot device

Type  help  for more information
ok


И что теперь делать? Из тех же статей узнаем, что надо набрать команду для BIOS:

boot disk0:


Теперь ждем, пока загрузится Solaris 2.6. Это может занять несколько минут… Ждем и верим в ОС 1995-го года!
В результате загрузки попросят логин и пароль. Путем простого перебора выясняем, что логин: root, а пароль 123456. Не очень-то все безопасно настроено, не так ли?

zvezda console login: root
Password:
Last login: Thu Jun 19 11:30:16 on console
Sun Microsystems Inc.   SunOS 5.6       Generic August 1997
# ls
bin         devices     kernel      opt         tmp
cdrom       etc         lib         platform    usr
core        export      lost+found  proc        var
dev         home        mnt         sbin        vol
#


Из найденного в Solaris — только программа getlaunchkey


Убеждаемся, что работают привычные команды ls, ps,… Если покопаться в системе (Solaris), то можно найти много интересного, например:

GCC 3.4.6:
# /usr/local/bin/gcc -v
Reading specs from /usr/local/lib/gcc/sparc-sun-solaris2.6/3.4.6/specs
Configured with: ../configure --with-as=/usr/ccs/bin/as --with-ld=/usr/ccs/bin/ld --enable-shared --enable-languages=c,c++,f77
Thread model: posix
gcc version 3.4.6

MC:
# /usr/local/bin/mc
  Left     File     Command     Options     Right
+<-~---------------------------------v>++<-~---------------------------------v>+
|       Name      | Size  |   MTime    ||       Name      | Size  |   MTime    |
|/.mc             |    512|Jun 13  2014||/.mc             |    512|Jun 13  2014|
|~bin             |      9|Jun 13  1998||~bin             |      9|Jun 13  1998|
|/cdrom           |    512|Jun 19  2014||/cdrom           |    512|Jun 19  2014|
|/dev             |   3072|Mar 30 07:43||/dev             |   3072|Mar 30 07:43|
|/devices         |    512|Jun 13  1998||/devices         |    512|Jun 13  1998|
|/etc             |   3072|Mar 30 08:04||/etc             |   3072|Mar 30 08:04|
|/export          |    512|Jun 13  1998||/export          |    512|Jun 13  1998|
|/home            |    512|Jun 19  2014||/home            |    512|Jun 19  2014|
|/kernel          |    512|Jun 13  1998||/kernel          |    512|Jun 13  1998|
|~lib             |      9|Jun 13  1998||~lib             |      9|Jun 13  1998|
|/lost+found      |   8192|Jun 13  1998||/lost+found      |   8192|Jun 13  1998|
|/mnt             |    512|Jun 13  1998||/mnt             |    512|Jun 13  1998|
|/opt             |    512|Jun 13  1998||/opt             |    512|Jun 13  1998|
|/platform        |    512|Jun 13  1998||/platform        |    512|Jun 13  1998|
|/proc            |  65216|Mar 30 08:13||/proc            |  65216|Mar 30 08:13|
+--------------------------------------++--------------------------------------+
|/.mc                                  ||/.mc                                  |
+--------------------------------------++--------------------------------------+
Hint: If you want to see your .* files, say so in the Configuration dialog.
# WARNING: processor level 12 onboard interrupt not serviced
1Help   2Menu   3View   4Edit   5Copy   6RenMov 7Mkdir  8Del


Посмотрев различные директории, можно найти файл /home/solaris/getlaunchkey. Пробуем запустить программу. Она нас просит ввести логин и пароль. Простой перебор ничего не дает.

#  /home/solaris/getlaunchkey

Login: root

Password: 123456

Wrong password!#  /home/solaris/getlaunchkey

Login: ivanov

Password: 123456

Wrong password!# 


Предварительный реверс программы getlaunchkey


Попробуем взломать программу: займемся реверсом программы getlaunchkey. При разборе этой программы в IDA все выглядит просто. В начале программа собирает пароль и имя пользователя:



Затем считается SHA от пароля и сравнивается с захардкоденным значением. Если значение хэша SHA совпадает, то программа работает дальше, иначе завершает работу:



Затем происходит типичная настройка сокетов, в которых фигурирует адрес отправки (хост с Solaris 2.6)



и адрес получателя (некий сервер):



При этом используется порт 9930:



Далее можно заметить, что программа выполняет ряд операций и осуществляет несколько обращений к серверу и получает ответы, после чего печатает ответ на экран.
Теперь, когда известен примерный алгоритм работы программы, существует два пути решения:
  1. Написать аналогичную программу на C под Windows/Linux и попробовать ее запустить.
  2. Исправить два IP-адреса и решение о хэше введенного пароля, после чего выполнить исправленную программу в Solaris 2.6 и увидеть результат.


Способ №1. Полный реверс приложения и написание своей программы, работающей аналогично


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

Разбор алгоритма работы программы getlaunchkey

В случае успешной инициализации сети программа выполняет ряд вычислений со строкой с именем пользователя:



На схеме видно следующее:
  • сначала некая «страшная» строка попадает в локальную переменную buf (1);
  • затем выполняется цикл по значению длины имени пользователя (2) в рамках которого происходят некие вычисления (3);
  • в результате изменения buf отправляется в сеть по заданному адресу (5).


Рассмотрим блок (3) подробнее.



Суть вычислений в блоке выглядит следующим образом: в начале идет три одинаковых блока с инструкциями (1, 2, 3), которые выполняют загрузку данных из памяти в регистры (ld), и два сложения (add), осуществляющие вычисление индекса в массиве относительно char_number. В результате в регистрах o3, o4 и g1 формируются одинаковые индексы, скорее всего, равные текущему номеру элемента в массиве относительно fp (Frame Pointer – указатель текущего фрейма стека).

Номер индекса равен итерации внешнего цикла. Затем в регистры o5 и g1 записываются значения из памяти по смещениям 0x1F0 и 0x40 (4). Указанные смещения соответствуют двум локальным массивам. Эти массивы соответствуют прочитанному имени пользователя и буферу, в который была скопирована «страшная» строка. Далее в коде выполняется инструкция btog (5). После этого результат операции btog (регистр g1) записывается обратно в память массива 0x1F0 (инструкция stb) (6). Затем значение переменной char_number увеличивается на 1 (inc) (7). Последняя часть блока просто переходит на очередную итерацию цикла (8).

Осталось выяснить, что же за инструкция btog? Воспользуемся гуглом и найдем список инструкций Sparc (например, тут). В нем написано следующее:

btog reg_or_imm, rd   is XOR (rd, reg_or_imm, rd)


Суть остальных инструкций можно также прочитать в указанном источнике. Таким образом, блок кода (3) соответствует примерно следующему коду: buf[char_number] ^= user_name[char_number].
Оставшаяся часть программы ожидает ответа от сервера:



Затем для полученного ответа выполняет вновь XOR (2) с именем пользователя (1), в результате чего получается ключ (3):



Так программа повторяет несколько раз по количеству попыток. В результате завершает свою работу.



Код программы, написанный по итогам реверса getlaunchkey

В итоге проделанной работы по реверсу получится примерно такой код:

#define SRV_IP    "79.175.2.82"
#define CLIENT_IP "192.168.1.2"

int main()
{
    char login_buf[64];
    int i = 0;

    memset(login_buf, 0, sizeof(login_buf));
    printf("\nLogin: ");
    scanf("%s", login_buf);

    printf("\nTry to get Key for %s...", login_buf);

    int len = sizeof(struct sockaddr_in);
    struct sockaddr_in si_other, si_my;
    int s, i, slen = sizeof(si_other);
    
    char buf[128];
    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        printf("\nError 1");
        exit(2);
    }

    memset((char *) &si_other, 0, sizeof(si_other));
    si_other.sin_family = AF_INET;
    si_other.sin_port = htons(9930);

    if (inet_aton(SRV_IP, &si_other.sin_addr) == 0)
    {
        fprintf(stderr, "inet_aton() failed\n");
        exit(1);
    }

    memset((char *) &si_my, 0, sizeof(si_my));
    si_my.sin_family = AF_INET;
    si_my.sin_port = htons(9930);
    if (inet_aton(CLIENT_IP, &si_my.sin_addr) == 0)
    {
        fprintf(stderr, "inet_aton() failed\n");
        exit(1);
    }

    if (bind(s, &si_my, len)<0)
    {
         printf("bind failed\n");
         exit(1);
    }

    int j = 0;
    printf("\nSending request for key #%d", i);
    sprintf(buf, "yugJHyGUgtygjgftTVHftyfHgETKeY");
    for (j = 0; j < strlen(login_buf); j++)
    {
        buf[j] ^= (char)login_buf[j];
    }
      
    if (sendto(s, buf, 128, 0, &si_other, slen)==-1)
    {
        printf("\nError 2: sendto");
        exit(2);
    }
    
    slen = sizeof(si_other);
    printf("\nWaiting for answer...");
    if (recvfrom(s, buf, 128, 0, &si_other, &slen)==-1)
    {
        printf("Error 3: recvfrom");
        exit(3);
    }
    
    for (j = 0; j < strlen(login_buf); j++)
    {
        buf[j] ^= (char)login_buf[j];
    }
    
    printf("\nLaunch Key Received: %s\n\n", buf);
    close(s);
}


Указанный код можно теперь скомпилировать в Windows или Linux и запустить. После запуска вводится имя пользователя (ivanov), после обмена данными с сервером программа распечатает ответный ключ.

Такой путь требует много времени на изучение кода на относительно экзотической архитектуре sparc.

Способ №2. Исправление программы и ее запуск в Solaris 2.6.


Попробуем пройти по второму пути. Сперва нужно решить два вопроса: как закинуть исправленный файл на Solaris 2.6 и как затем обеспечить работу сети, чтобы программа сработала нормально? В результате короткого исследования узнаем, что помимо всяких программ есть на Solaris 2.6 FTP клиент ftp, с помощью которого можно обмениваться файлами Windows с Solaris. Теперь дело за малым: настроить для виртуальной машины доступ к сети.

Настройка доступа к сети для виртуальной машины

Для этого изучаем еще статью в разделе “Starting QEMU with a TAP interface” и пробуем все настроить через vpn мост. Наверное, можно как-то проще, но так, как указано дальше, сеть работает. Алгоритм действий для Windows следующий:

  1. Качаем программу openvpn. Мы тестировали на версии: openvpn-install-2.3.4-I002-x86_64.exe
  2. Переименовываем адаптер с типом “TAP-Windows Adapter V9” во что-то короткое типа tap1.
  3. Создаем мост в “Control Panel\Network and Internet\Network Connections” между сетевым адаптером, который подключен к интернету и новым виртуальным сетевым адаптером “TAP-Windows Adapter V9”.

  4. Дополняем строку запуска qemu аргументами: -net nic -net tap,ifname=tap1 и запускаем виртуальную машину qemu заново строкой:

"c:\Program Files (x86)\qemu\qemu-system-sparc.exe" -bios .\ss5-1.bin -L .\ –hda .\image.img -m 256 -M SS-5 -nographic -serial mon:telnet:127.0.0.1:4444,server,nowait -net nic -net tap,ifname=tap1


Теперь опять загружаем Solaris через putty, логинимся и настраиваем сеть. Имя сетевого интерфейса можно было заметить во время загрузки:

Copyright (c) 1983-1997, Sun Microsystems, Inc.
configuring network interfaces: le0.
Hostname: zvezda
<\source>

Проверяем текущие настройки командой ifconfig le0:

<source lang="c">
# ifconfig le0
le0: flags=863<UP,BROADCAST,NOTRAILERS,RUNNING,MULTICAST> mtu 1500
        inet 192.168.1.88 netmask ffffff00 broadcast 192.168.1.255
        ether 52:54:0:12:34:56


Обратим внимание на настройку сети: установлен статический IP-адрес 192.168.1.88, который так же присутствует и в программе, как было выяснено ранее. Следовательно, один адрес в программе соответствует локальному адресу, и его нужно заменить на новый локальный адрес, после отработки ARP. Второй адрес (192.168.1.22) соответствует адресу сервера, к которому отправляется запрос, следовательно, его нужно заменить на выданный нам в условии адрес 79.175.2.82.

Если необходимо, устанавливаем корректный IP-адрес и адрес шлюза для своей локальной сети. Например, можно настроить автоматически (тут будет полезна вот эта статья ):

ifconfig le0 auto-dhcp
route add default 192.168.1.1


Вновь проверяем настройки командой ifconfig le0:

# ifconfig le0
le0: flags=863<UP,BROADCAST,NOTRAILERS,RUNNING,MULTICAST> mtu 1500
        inet 192.168.1.12 netmask ffffff00 broadcast 192.168.1.255
        ether 52:54:0:12:34:56


Теперь проверяем ping 8.8.8.8 и ping 79.175.2.82. Если все настроено нормально, то получим такой результат:

# ping 8.8.8.8
8.8.8.8 is alive
# ping 79.175.2.82
79.175.2.82 is alive


Чтобы обеспечить связь с Windows, можно поставить на Windows FTP сервер. После чего с помощью клиента ftp на Solaris 2.6 можно обмениваться данными.

Модификация программы getlaunchkey

Вернемся к программе getlaunchkey. Если не изучать детально алгоритм программы, то для ее нормальной работы требуется выполнить всего три модификации бинарного файла программы getlaunchkey:
  1. изменить строку с адресом хоста “192.168.1.88” -> “192.168.1.12”
  2. изменить строку с адресом хоста “192.168.1.22” -> “79.175.2.82 ”
  3. изменить результат решения после проверки пароля.

Первые замены выполняются тривиально, с помощью hex-редактора. Последнюю замену нужно выполнить путем модификации кода инструкции sparc. Если обратить внимание, то переход после проверки cmp осуществляется инструкцией be (branch equal), значит, надо эту инструкцию заменить на инструкцию bne (branch not equal). Опкод требуемой инструкции можно увидеть через IDA далее по коду:



Таким образом, нужно просто изменить байт 0x02 на байт 0x12 по смещению 0x1084 (0x11084 — 0x10000):



Теперь осталось через ftp скопировать измененный getlaunchkey2.bin обратно на Solaris и выполнить его. Хост с Windows имеет IP-адрес 192.168.1.3. Для нормальной работы ftp надо не забыть включить бинарный тип передаваемых данных, в остальном все делается достаточно просто:

# ifconfig le0
le0: flags=4863<UP,BROADCAST,NOTRAILERS,RUNNING,MULTICAST,DHCP> mtu 1500
        inet 192.168.1.12 netmask ffffff00 broadcast 192.168.1.255
        ether 52:54:0:12:34:56
# ftp 192.168.1.3
Connected to 192.168.1.3.
220-FileZilla Server version 0.9.45 beta
220-written by Tim Kosse (tim.kosse@filezilla-project.org)
220 Please visit http://sourceforge.net/projects/filezilla/
Name (192.168.1.2:root): guest
331 Password required for guest
Password:
230 Logged on
ftp> binary
200 Type set to I
ftp> get getlaunchkey2.bin
200 Port command successful
150 Opening data channel for file download from server of "/getlaunchkey2.bin"
226 Successfully transferred "/getlaunchkey2.bin"
local: getlaunchkey2.bin remote: getlaunchkey2.bin
25228 bytes received in 0.0039 seconds (6389.19 Kbytes/s)
ftp> quit
221 Goodbye
# ls -l
total 100
-rwxr-xr-x   1 root     other      25228 Jun 19  2014 getkey
-rw-r--r--   1 root     other      25228 Apr  1 06:25 getlaunchkey2.bin
# chmod 777 ./getlaunchkey2.bin
# ls -l
total 100
-rwxr-xr-x   1 root     other      25228 Jun 19  2014 getkey
-rwxrwxrwx   1 root     other      25228 Apr  1 06:25 getlaunchkey2.bin
# ./getlaunchkey2.bin

Login: ivanov

Password:123

Try to get Key for ivanov...
Sending request for key #0
Waiting for answer...
Launch Key Received: a24214rf143sdfsf


Как можно видеть, программа вывела на экран ключ, который и был нужен для прохождения задания!

Советы по установке Solaris 2.6


При подготовке задания Solaris 2.6 был полностью установлен с нуля, на нем был установлен gcc (он не входит в стандартный пакет), затем была разработана и скомпилирована программа. О том, как запускать Solaris 2.6 и как настроить на нем сеть, было уже рассказано в этой статье. Для дополнения картины еще несколько советов по установке Solaris:

  1. Были перепробованы около 10 различных дистрибутивов, однако нормально удалось поставить и запустить после установки только дистрибутив, у которого файл называется так: SOL_2_6_598_SPARC_SMCC_SVR.iso.
  2. Детальную инструкцию по установке можно найти тут.
  3. При установке желательно вручную исправить таблицу разделов так, чтобы на /usr выделялось не менее 400 Mb.
  4. После установки на ОС Solaris можно дополнительно установить пакеты, которые можно скачать здесь.
  5. Для создания виртуального диска можно использовать команду: qemu-img.exe create -f qcow2 D:\qemu\sparc_36.img 36G
  6. Для установки пакета можно использовать команды:
    gzip -d package_name
    sudo pkgadd -d unzipped_package_name
    

Tags:
Hubs:
Total votes 10: ↑9 and ↓1 +8
Views 8.9K
Comments Comments 1

Information

Location
Россия
Website
neobit.ru
Employees
51–100 employees
Registered