shellcode执行

前言

今天看到一个比较好玩的东西,虽然原理很简单,但是使用golang来做还是挺新鲜,所以还是分享给大家。

第一节

PoC、Exp、Payload与Shellcode

首先说一下PoC、Exp、Payload与Shellcode这几个概念,这在渗透测试中非常常见。

PoC,全称”Proof of Concept”,中文“概念验证”,常指一段漏洞证明的代码。

Exp,全称”Exploit”,中文“利用”,指利用系统漏洞进行攻击的动作。

Payload,中文“有效载荷”,指成功exploit之后,真正在目标系统执行的代码或指令。

Shellcode,简单翻译“shell代码”,是Payload的一种,由于其建立正向/反向shell而得名。其实就是一段可以运行的二进制代码。

PoC是用来证明漏洞存在的,Exp是用来利用漏洞的,两者通常不是一类,或者说,PoC通常是无害的,Exp通常是有害的,有了PoC,才有Exp。

Payload有很多种,它可以是Shellcode,也可以直接是一段系统命令。同一个Payload可以用于多个漏洞,但每个漏洞都有其自己的Exp,也就是说不存在通用的Exp。

Shellcode也有很多种,包括正向的,反向的,甚至meterpreter。

今天要讲的就是使用golang 加载并执行shellcode,玩一些极客的感觉。

第二节

windows版shellcode加载器

shellcode既然是一段二进制代码,那加载器的功能则是将二进制写到内存中,并将这段内存设置为可执行,最后从头到尾执行这段代码即可。来看代码:

代码中主要是用了windows里kernel32.dll的VirtualProtect函数。在MSDN中的定义如下:

  • lpAddress:内存起始地址
  • dwsize:内存区域大小
  • flNewProtect:内存属性,PAGE_EXECUTE_READWRITE(0x40)
  • lpflOldProtect:内存原始属性保存地址

在代码中,我们声明一个函数,将函数指向读入的shellcode字节数据那片内存,并将内存设置为可读可写可执行,最后调用函数就将shellcode运行起来了。

第三节

linux版shellcode加载器

对于linux版shellcode加载器也是同样的原理,只是实现的方式不一样。使用C.call的方式进行调用,最本质的实现其实是在C语言中的call函数。

在call函数中,首先使用mmap生成一片可读可写可执行的匿名映射内存,然后将shellcode使用memcpy复制到这段内存中,并将这段内存的首地址强转为函数指针,直接当作函数运行即可。

mmap函数如下:

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

  • 参数addr: 指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。
  • 参数length: 代表将文件中多大的部分映射到内存。
  • 参数prot: 映射区域的保护方式。可以为以下几种方式的组合: PROT_EXEC 映射区域可被执行 PROT_READ 映射区域可被读取 PROT_WRITE 映射区域可被写入 PROT_NONE 映射区域不能存取
  • 参数flags: 影响映射区域的各种特性。在调用mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。 MAP_FIXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此。 MAP_SHARED对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。 MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。 MAP_ANONYMOUS建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。 MAP_DENYWRITE只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。 MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。
  • 参数fd: 要映射到内存中的文件描述符。如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。
  • 参数offset: 文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。

Tips: mmap详解

https://blog.csdn.net/notbaron/article/details/80019134

第四节

编译与load shellcode

golang支持多平台编译,假如你使用win32编译的golang程序,那你的shellcode也需要是32位的,不然无法执行。那我们怎么生成shellcode呢?这就需要kali系统下的一个神器:msfvenom。咱们使用它生成一个弹出计算器的shellcode,执行如下命令:

将红框圈住的字符串当作参数:go_shellcode.exe 参数,运行后会弹出计算器。