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

Відхід від звичної 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-256 m-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

Пароль: 123456

Wrong password!# /home/solaris/getlaunchkey

Login: ivanov

Пароль: 123456

Wrong password!# 


Попередній реверс програми getlaunchkey

Спробуємо зламати програму: займемося реверсом програми getlaunchkey. При розборі цієї програми в IDA все виглядає просто. На початку програма збирає пароль та ім'я користувача:



Потім вважається SHA від пароля і порівнюється з захардкоденным значенням. Якщо хеш-значення SHA збігається, то програма працює далі, інакше завершує роботу:



Потім відбувається типова налаштування ssl, в яких фігурує адреса надсилання (хост з 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 answer for...");
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-256 m-M SS-5-nographic-serial mon:telnet:127.0.0.1:4444,server,nowait-net nic-net tap,ifname=tap1


Тепер знову завантажуємо Solaris через putty, логинимся і налаштовуємо мережу. Ім'я мережного інтерфейсу можна було помітити під час завантаження:

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

Перевіряємо поточні налаштування командою ifconfig le0:

<source lang="с">
# 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 Мб.
  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
    


Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.