dstruct 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/README.markdown +23 -0
- data/examples/smb_example.rb +35 -0
- data/lib/rex.rb +108 -0
- data/lib/rex/LICENSE +29 -0
- data/lib/rex/arch.rb +104 -0
- data/lib/rex/arch/sparc.rb +75 -0
- data/lib/rex/arch/x86.rb +524 -0
- data/lib/rex/assembly/nasm.rb +104 -0
- data/lib/rex/codepage.map +104 -0
- data/lib/rex/compat.rb +389 -0
- data/lib/rex/constants.rb +124 -0
- data/lib/rex/elfparsey.rb +9 -0
- data/lib/rex/elfparsey/elf.rb +121 -0
- data/lib/rex/elfparsey/elfbase.rb +256 -0
- data/lib/rex/elfparsey/exceptions.rb +25 -0
- data/lib/rex/elfscan.rb +10 -0
- data/lib/rex/elfscan/scanner.rb +226 -0
- data/lib/rex/elfscan/search.rb +44 -0
- data/lib/rex/encoder/alpha2.rb +31 -0
- data/lib/rex/encoder/alpha2/alpha_mixed.rb +68 -0
- data/lib/rex/encoder/alpha2/alpha_upper.rb +79 -0
- data/lib/rex/encoder/alpha2/generic.rb +90 -0
- data/lib/rex/encoder/alpha2/unicode_mixed.rb +116 -0
- data/lib/rex/encoder/alpha2/unicode_upper.rb +123 -0
- data/lib/rex/encoder/bloxor/bloxor.rb +327 -0
- data/lib/rex/encoder/ndr.rb +90 -0
- data/lib/rex/encoder/nonalpha.rb +61 -0
- data/lib/rex/encoder/nonupper.rb +64 -0
- data/lib/rex/encoder/xdr.rb +107 -0
- data/lib/rex/encoder/xor.rb +69 -0
- data/lib/rex/encoder/xor/dword.rb +13 -0
- data/lib/rex/encoder/xor/dword_additive.rb +13 -0
- data/lib/rex/encoders/xor_dword.rb +35 -0
- data/lib/rex/encoders/xor_dword_additive.rb +53 -0
- data/lib/rex/encoding/xor.rb +20 -0
- data/lib/rex/encoding/xor/byte.rb +15 -0
- data/lib/rex/encoding/xor/dword.rb +21 -0
- data/lib/rex/encoding/xor/dword_additive.rb +92 -0
- data/lib/rex/encoding/xor/exceptions.rb +17 -0
- data/lib/rex/encoding/xor/generic.rb +146 -0
- data/lib/rex/encoding/xor/qword.rb +15 -0
- data/lib/rex/encoding/xor/word.rb +21 -0
- data/lib/rex/exceptions.rb +275 -0
- data/lib/rex/exploitation/cmdstager.rb +10 -0
- data/lib/rex/exploitation/cmdstager/base.rb +190 -0
- data/lib/rex/exploitation/cmdstager/bourne.rb +105 -0
- data/lib/rex/exploitation/cmdstager/debug_asm.rb +140 -0
- data/lib/rex/exploitation/cmdstager/debug_write.rb +134 -0
- data/lib/rex/exploitation/cmdstager/echo.rb +164 -0
- data/lib/rex/exploitation/cmdstager/printf.rb +122 -0
- data/lib/rex/exploitation/cmdstager/tftp.rb +71 -0
- data/lib/rex/exploitation/cmdstager/vbs.rb +126 -0
- data/lib/rex/exploitation/egghunter.rb +425 -0
- data/lib/rex/exploitation/encryptjs.rb +78 -0
- data/lib/rex/exploitation/heaplib.js.b64 +331 -0
- data/lib/rex/exploitation/heaplib.rb +107 -0
- data/lib/rex/exploitation/js.rb +6 -0
- data/lib/rex/exploitation/js/detect.rb +69 -0
- data/lib/rex/exploitation/js/memory.rb +81 -0
- data/lib/rex/exploitation/js/network.rb +84 -0
- data/lib/rex/exploitation/js/utils.rb +33 -0
- data/lib/rex/exploitation/jsobfu.rb +513 -0
- data/lib/rex/exploitation/obfuscatejs.rb +336 -0
- data/lib/rex/exploitation/omelet.rb +321 -0
- data/lib/rex/exploitation/opcodedb.rb +819 -0
- data/lib/rex/exploitation/powershell.rb +62 -0
- data/lib/rex/exploitation/powershell/function.rb +63 -0
- data/lib/rex/exploitation/powershell/obfu.rb +98 -0
- data/lib/rex/exploitation/powershell/output.rb +151 -0
- data/lib/rex/exploitation/powershell/param.rb +23 -0
- data/lib/rex/exploitation/powershell/parser.rb +183 -0
- data/lib/rex/exploitation/powershell/psh_methods.rb +70 -0
- data/lib/rex/exploitation/powershell/script.rb +99 -0
- data/lib/rex/exploitation/ropdb.rb +190 -0
- data/lib/rex/exploitation/seh.rb +93 -0
- data/lib/rex/file.rb +160 -0
- data/lib/rex/image_source.rb +10 -0
- data/lib/rex/image_source/disk.rb +58 -0
- data/lib/rex/image_source/image_source.rb +44 -0
- data/lib/rex/image_source/memory.rb +35 -0
- data/lib/rex/io/bidirectional_pipe.rb +161 -0
- data/lib/rex/io/datagram_abstraction.rb +35 -0
- data/lib/rex/io/ring_buffer.rb +369 -0
- data/lib/rex/io/stream.rb +312 -0
- data/lib/rex/io/stream_abstraction.rb +209 -0
- data/lib/rex/io/stream_server.rb +221 -0
- data/lib/rex/job_container.rb +200 -0
- data/lib/rex/logging.rb +4 -0
- data/lib/rex/logging/log_dispatcher.rb +180 -0
- data/lib/rex/logging/log_sink.rb +43 -0
- data/lib/rex/logging/sinks/flatfile.rb +56 -0
- data/lib/rex/logging/sinks/stderr.rb +44 -0
- data/lib/rex/mac_oui.rb +16581 -0
- data/lib/rex/machparsey.rb +9 -0
- data/lib/rex/machparsey/exceptions.rb +34 -0
- data/lib/rex/machparsey/mach.rb +209 -0
- data/lib/rex/machparsey/machbase.rb +408 -0
- data/lib/rex/machscan.rb +9 -0
- data/lib/rex/machscan/scanner.rb +217 -0
- data/lib/rex/mime.rb +10 -0
- data/lib/rex/mime/encoding.rb +17 -0
- data/lib/rex/mime/header.rb +78 -0
- data/lib/rex/mime/message.rb +150 -0
- data/lib/rex/mime/part.rb +50 -0
- data/lib/rex/nop/opty2.rb +109 -0
- data/lib/rex/nop/opty2_tables.rb +301 -0
- data/lib/rex/ole.rb +202 -0
- data/lib/rex/ole/clsid.rb +44 -0
- data/lib/rex/ole/difat.rb +138 -0
- data/lib/rex/ole/directory.rb +228 -0
- data/lib/rex/ole/direntry.rb +237 -0
- data/lib/rex/ole/docs/dependencies.txt +8 -0
- data/lib/rex/ole/docs/references.txt +1 -0
- data/lib/rex/ole/fat.rb +96 -0
- data/lib/rex/ole/header.rb +201 -0
- data/lib/rex/ole/minifat.rb +74 -0
- data/lib/rex/ole/propset.rb +141 -0
- data/lib/rex/ole/samples/create_ole.rb +27 -0
- data/lib/rex/ole/samples/dir.rb +35 -0
- data/lib/rex/ole/samples/dump_stream.rb +34 -0
- data/lib/rex/ole/samples/ole_info.rb +23 -0
- data/lib/rex/ole/storage.rb +392 -0
- data/lib/rex/ole/stream.rb +50 -0
- data/lib/rex/ole/substorage.rb +46 -0
- data/lib/rex/ole/util.rb +154 -0
- data/lib/rex/parser/acunetix_nokogiri.rb +406 -0
- data/lib/rex/parser/apple_backup_manifestdb.rb +132 -0
- data/lib/rex/parser/appscan_nokogiri.rb +367 -0
- data/lib/rex/parser/arguments.rb +108 -0
- data/lib/rex/parser/burp_session_nokogiri.rb +291 -0
- data/lib/rex/parser/ci_nokogiri.rb +193 -0
- data/lib/rex/parser/foundstone_nokogiri.rb +342 -0
- data/lib/rex/parser/fusionvm_nokogiri.rb +109 -0
- data/lib/rex/parser/group_policy_preferences.rb +185 -0
- data/lib/rex/parser/ini.rb +186 -0
- data/lib/rex/parser/ip360_aspl_xml.rb +103 -0
- data/lib/rex/parser/ip360_xml.rb +98 -0
- data/lib/rex/parser/mbsa_nokogiri.rb +256 -0
- data/lib/rex/parser/nessus_xml.rb +121 -0
- data/lib/rex/parser/netsparker_xml.rb +109 -0
- data/lib/rex/parser/nexpose_raw_nokogiri.rb +686 -0
- data/lib/rex/parser/nexpose_simple_nokogiri.rb +330 -0
- data/lib/rex/parser/nexpose_xml.rb +172 -0
- data/lib/rex/parser/nmap_nokogiri.rb +394 -0
- data/lib/rex/parser/nmap_xml.rb +166 -0
- data/lib/rex/parser/nokogiri_doc_mixin.rb +233 -0
- data/lib/rex/parser/openvas_nokogiri.rb +172 -0
- data/lib/rex/parser/outpost24_nokogiri.rb +240 -0
- data/lib/rex/parser/retina_xml.rb +110 -0
- data/lib/rex/parser/unattend.rb +171 -0
- data/lib/rex/parser/wapiti_nokogiri.rb +105 -0
- data/lib/rex/payloads.rb +2 -0
- data/lib/rex/payloads/win32.rb +3 -0
- data/lib/rex/payloads/win32/common.rb +27 -0
- data/lib/rex/payloads/win32/kernel.rb +54 -0
- data/lib/rex/payloads/win32/kernel/common.rb +55 -0
- data/lib/rex/payloads/win32/kernel/migration.rb +13 -0
- data/lib/rex/payloads/win32/kernel/recovery.rb +51 -0
- data/lib/rex/payloads/win32/kernel/stager.rb +195 -0
- data/lib/rex/peparsey.rb +10 -0
- data/lib/rex/peparsey/exceptions.rb +30 -0
- data/lib/rex/peparsey/pe.rb +210 -0
- data/lib/rex/peparsey/pe_memdump.rb +61 -0
- data/lib/rex/peparsey/pebase.rb +1662 -0
- data/lib/rex/peparsey/section.rb +128 -0
- data/lib/rex/pescan.rb +11 -0
- data/lib/rex/pescan/analyze.rb +366 -0
- data/lib/rex/pescan/scanner.rb +230 -0
- data/lib/rex/pescan/search.rb +68 -0
- data/lib/rex/platforms.rb +2 -0
- data/lib/rex/platforms/windows.rb +52 -0
- data/lib/rex/poly.rb +134 -0
- data/lib/rex/poly/block.rb +480 -0
- data/lib/rex/poly/machine.rb +13 -0
- data/lib/rex/poly/machine/machine.rb +830 -0
- data/lib/rex/poly/machine/x86.rb +509 -0
- data/lib/rex/poly/register.rb +101 -0
- data/lib/rex/poly/register/x86.rb +41 -0
- data/lib/rex/post.rb +7 -0
- data/lib/rex/post/dir.rb +51 -0
- data/lib/rex/post/file.rb +172 -0
- data/lib/rex/post/file_stat.rb +220 -0
- data/lib/rex/post/gen.pl +13 -0
- data/lib/rex/post/io.rb +182 -0
- data/lib/rex/post/meterpreter.rb +5 -0
- data/lib/rex/post/meterpreter/channel.rb +446 -0
- data/lib/rex/post/meterpreter/channel_container.rb +54 -0
- data/lib/rex/post/meterpreter/channels/pool.rb +160 -0
- data/lib/rex/post/meterpreter/channels/pools/file.rb +62 -0
- data/lib/rex/post/meterpreter/channels/pools/stream_pool.rb +103 -0
- data/lib/rex/post/meterpreter/channels/stream.rb +87 -0
- data/lib/rex/post/meterpreter/client.rb +483 -0
- data/lib/rex/post/meterpreter/client_core.rb +352 -0
- data/lib/rex/post/meterpreter/dependencies.rb +3 -0
- data/lib/rex/post/meterpreter/extension.rb +32 -0
- data/lib/rex/post/meterpreter/extensions/android/android.rb +128 -0
- data/lib/rex/post/meterpreter/extensions/android/tlv.rb +40 -0
- data/lib/rex/post/meterpreter/extensions/espia/espia.rb +58 -0
- data/lib/rex/post/meterpreter/extensions/espia/tlv.rb +17 -0
- data/lib/rex/post/meterpreter/extensions/extapi/adsi/adsi.rb +71 -0
- data/lib/rex/post/meterpreter/extensions/extapi/clipboard/clipboard.rb +169 -0
- data/lib/rex/post/meterpreter/extensions/extapi/extapi.rb +45 -0
- data/lib/rex/post/meterpreter/extensions/extapi/service/service.rb +104 -0
- data/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +77 -0
- data/lib/rex/post/meterpreter/extensions/extapi/window/window.rb +56 -0
- data/lib/rex/post/meterpreter/extensions/extapi/wmi/wmi.rb +75 -0
- data/lib/rex/post/meterpreter/extensions/incognito/incognito.rb +94 -0
- data/lib/rex/post/meterpreter/extensions/incognito/tlv.rb +22 -0
- data/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb +361 -0
- data/lib/rex/post/meterpreter/extensions/kiwi/tlv.rb +76 -0
- data/lib/rex/post/meterpreter/extensions/lanattacks/dhcp/dhcp.rb +78 -0
- data/lib/rex/post/meterpreter/extensions/lanattacks/lanattacks.rb +43 -0
- data/lib/rex/post/meterpreter/extensions/lanattacks/tftp/tftp.rb +49 -0
- data/lib/rex/post/meterpreter/extensions/lanattacks/tlv.rb +17 -0
- data/lib/rex/post/meterpreter/extensions/mimikatz/mimikatz.rb +128 -0
- data/lib/rex/post/meterpreter/extensions/mimikatz/tlv.rb +16 -0
- data/lib/rex/post/meterpreter/extensions/networkpug/networkpug.rb +57 -0
- data/lib/rex/post/meterpreter/extensions/networkpug/tlv.rb +16 -0
- data/lib/rex/post/meterpreter/extensions/priv/fs.rb +118 -0
- data/lib/rex/post/meterpreter/extensions/priv/passwd.rb +61 -0
- data/lib/rex/post/meterpreter/extensions/priv/priv.rb +109 -0
- data/lib/rex/post/meterpreter/extensions/priv/tlv.rb +29 -0
- data/lib/rex/post/meterpreter/extensions/sniffer/sniffer.rb +117 -0
- data/lib/rex/post/meterpreter/extensions/sniffer/tlv.rb +27 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/constants.rb +396 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +284 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +399 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file_stat.rb +104 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/io.rb +48 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/arp.rb +59 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/config.rb +256 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/interface.rb +129 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/netstat.rb +97 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/resolve.rb +106 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/route.rb +67 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb +139 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb +180 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_server_channel.rb +168 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb +209 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb +38146 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/buffer_item.rb +48 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_advapi32.rb +2102 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_crypt32.rb +32 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_iphlpapi.rb +97 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_kernel32.rb +3852 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_netapi32.rb +100 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_ntdll.rb +168 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_psapi.rb +32 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_shell32.rb +32 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_user32.rb +3170 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_version.rb +41 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_wlanapi.rb +87 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_wldap32.rb +128 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_ws2_32.rb +613 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb +388 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb +111 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb +149 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_wrapper.rb +27 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/mock_magic.rb +515 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb +319 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/platform_util.rb +23 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +301 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/tlv.rb +56 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/type/pointer_util.rb +106 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +676 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb +96 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +151 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +128 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log.rb +192 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log_subsystem/event_record.rb +41 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/power.rb +60 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +408 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/image.rb +129 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/io.rb +55 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/memory.rb +336 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/thread.rb +141 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +328 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +193 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_value.rb +102 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/remote_registry_key.rb +188 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/thread.rb +180 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +236 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +259 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +201 -0
- data/lib/rex/post/meterpreter/inbound_packet_handler.rb +30 -0
- data/lib/rex/post/meterpreter/object_aliases.rb +83 -0
- data/lib/rex/post/meterpreter/packet.rb +709 -0
- data/lib/rex/post/meterpreter/packet_dispatcher.rb +543 -0
- data/lib/rex/post/meterpreter/packet_parser.rb +94 -0
- data/lib/rex/post/meterpreter/packet_response_waiter.rb +83 -0
- data/lib/rex/post/meterpreter/ui/console.rb +142 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher.rb +86 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +383 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +939 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/espia.rb +109 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi.rb +65 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb +198 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/clipboard.rb +444 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/service.rb +199 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/window.rb +118 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/wmi.rb +108 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/incognito.rb +242 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb +509 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks.rb +60 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/dhcp.rb +254 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/tftp.rb +159 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/mimikatz.rb +182 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/networkpug.rb +232 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv.rb +62 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/elevate.rb +97 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/passwd.rb +52 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/timestomp.rb +133 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/sniffer.rb +204 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi.rb +66 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +527 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +448 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +906 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +318 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb +343 -0
- data/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +99 -0
- data/lib/rex/post/permission.rb +26 -0
- data/lib/rex/post/process.rb +57 -0
- data/lib/rex/post/thread.rb +57 -0
- data/lib/rex/post/ui.rb +52 -0
- data/lib/rex/proto.rb +15 -0
- data/lib/rex/proto/addp.rb +218 -0
- data/lib/rex/proto/dcerpc.rb +7 -0
- data/lib/rex/proto/dcerpc/client.rb +362 -0
- data/lib/rex/proto/dcerpc/exceptions.rb +151 -0
- data/lib/rex/proto/dcerpc/handle.rb +48 -0
- data/lib/rex/proto/dcerpc/ndr.rb +73 -0
- data/lib/rex/proto/dcerpc/packet.rb +264 -0
- data/lib/rex/proto/dcerpc/response.rb +188 -0
- data/lib/rex/proto/dcerpc/uuid.rb +85 -0
- data/lib/rex/proto/dcerpc/wdscp.rb +3 -0
- data/lib/rex/proto/dcerpc/wdscp/constants.rb +89 -0
- data/lib/rex/proto/dcerpc/wdscp/packet.rb +94 -0
- data/lib/rex/proto/dhcp.rb +7 -0
- data/lib/rex/proto/dhcp/constants.rb +34 -0
- data/lib/rex/proto/dhcp/server.rb +334 -0
- data/lib/rex/proto/drda.rb +6 -0
- data/lib/rex/proto/drda/constants.rb +50 -0
- data/lib/rex/proto/drda/packet.rb +253 -0
- data/lib/rex/proto/drda/utils.rb +124 -0
- data/lib/rex/proto/http.rb +7 -0
- data/lib/rex/proto/http/client.rb +722 -0
- data/lib/rex/proto/http/client_request.rb +472 -0
- data/lib/rex/proto/http/handler.rb +47 -0
- data/lib/rex/proto/http/handler/erb.rb +129 -0
- data/lib/rex/proto/http/handler/proc.rb +61 -0
- data/lib/rex/proto/http/header.rb +173 -0
- data/lib/rex/proto/http/packet.rb +414 -0
- data/lib/rex/proto/http/request.rb +354 -0
- data/lib/rex/proto/http/response.rb +151 -0
- data/lib/rex/proto/http/server.rb +385 -0
- data/lib/rex/proto/iax2.rb +2 -0
- data/lib/rex/proto/iax2/call.rb +326 -0
- data/lib/rex/proto/iax2/client.rb +218 -0
- data/lib/rex/proto/iax2/codecs.rb +5 -0
- data/lib/rex/proto/iax2/codecs/alaw.rb +16 -0
- data/lib/rex/proto/iax2/codecs/g711.rb +2176 -0
- data/lib/rex/proto/iax2/codecs/mulaw.rb +17 -0
- data/lib/rex/proto/iax2/constants.rb +262 -0
- data/lib/rex/proto/ipmi.rb +57 -0
- data/lib/rex/proto/ipmi/channel_auth_reply.rb +89 -0
- data/lib/rex/proto/ipmi/open_session_reply.rb +36 -0
- data/lib/rex/proto/ipmi/rakp2.rb +36 -0
- data/lib/rex/proto/ipmi/utils.rb +125 -0
- data/lib/rex/proto/natpmp.rb +7 -0
- data/lib/rex/proto/natpmp/constants.rb +19 -0
- data/lib/rex/proto/natpmp/packet.rb +45 -0
- data/lib/rex/proto/ntlm.rb +8 -0
- data/lib/rex/proto/ntlm/base.rb +327 -0
- data/lib/rex/proto/ntlm/constants.rb +75 -0
- data/lib/rex/proto/ntlm/crypt.rb +412 -0
- data/lib/rex/proto/ntlm/exceptions.rb +17 -0
- data/lib/rex/proto/ntlm/message.rb +534 -0
- data/lib/rex/proto/ntlm/utils.rb +765 -0
- data/lib/rex/proto/ntp.rb +3 -0
- data/lib/rex/proto/ntp/constants.rb +12 -0
- data/lib/rex/proto/ntp/modes.rb +130 -0
- data/lib/rex/proto/pjl.rb +31 -0
- data/lib/rex/proto/pjl/client.rb +163 -0
- data/lib/rex/proto/proxy/socks4a.rb +441 -0
- data/lib/rex/proto/rfb.rb +13 -0
- data/lib/rex/proto/rfb/cipher.rb +82 -0
- data/lib/rex/proto/rfb/client.rb +205 -0
- data/lib/rex/proto/rfb/constants.rb +50 -0
- data/lib/rex/proto/sip.rb +4 -0
- data/lib/rex/proto/sip/response.rb +61 -0
- data/lib/rex/proto/smb.rb +8 -0
- data/lib/rex/proto/smb/client.rb +2064 -0
- data/lib/rex/proto/smb/constants.rb +1064 -0
- data/lib/rex/proto/smb/crypt.rb +37 -0
- data/lib/rex/proto/smb/evasions.rb +67 -0
- data/lib/rex/proto/smb/exceptions.rb +867 -0
- data/lib/rex/proto/smb/simpleclient.rb +173 -0
- data/lib/rex/proto/smb/simpleclient/open_file.rb +106 -0
- data/lib/rex/proto/smb/simpleclient/open_pipe.rb +57 -0
- data/lib/rex/proto/smb/utils.rb +104 -0
- data/lib/rex/proto/sunrpc.rb +2 -0
- data/lib/rex/proto/sunrpc/client.rb +196 -0
- data/lib/rex/proto/tftp.rb +13 -0
- data/lib/rex/proto/tftp/client.rb +344 -0
- data/lib/rex/proto/tftp/constants.rb +39 -0
- data/lib/rex/proto/tftp/server.rb +497 -0
- data/lib/rex/random_identifier_generator.rb +177 -0
- data/lib/rex/registry.rb +14 -0
- data/lib/rex/registry/hive.rb +132 -0
- data/lib/rex/registry/lfkey.rb +51 -0
- data/lib/rex/registry/nodekey.rb +54 -0
- data/lib/rex/registry/regf.rb +25 -0
- data/lib/rex/registry/valuekey.rb +67 -0
- data/lib/rex/registry/valuelist.rb +29 -0
- data/lib/rex/ropbuilder.rb +8 -0
- data/lib/rex/ropbuilder/rop.rb +271 -0
- data/lib/rex/script.rb +42 -0
- data/lib/rex/script/base.rb +61 -0
- data/lib/rex/script/meterpreter.rb +16 -0
- data/lib/rex/script/shell.rb +10 -0
- data/lib/rex/service.rb +49 -0
- data/lib/rex/service_manager.rb +154 -0
- data/lib/rex/services/local_relay.rb +424 -0
- data/lib/rex/socket.rb +788 -0
- data/lib/rex/socket/comm.rb +120 -0
- data/lib/rex/socket/comm/local.rb +526 -0
- data/lib/rex/socket/ip.rb +132 -0
- data/lib/rex/socket/parameters.rb +363 -0
- data/lib/rex/socket/range_walker.rb +470 -0
- data/lib/rex/socket/ssl_tcp.rb +345 -0
- data/lib/rex/socket/ssl_tcp_server.rb +188 -0
- data/lib/rex/socket/subnet_walker.rb +76 -0
- data/lib/rex/socket/switch_board.rb +289 -0
- data/lib/rex/socket/tcp.rb +79 -0
- data/lib/rex/socket/tcp_server.rb +67 -0
- data/lib/rex/socket/udp.rb +165 -0
- data/lib/rex/sslscan/result.rb +201 -0
- data/lib/rex/sslscan/scanner.rb +206 -0
- data/lib/rex/struct2.rb +5 -0
- data/lib/rex/struct2/c_struct.rb +181 -0
- data/lib/rex/struct2/c_struct_template.rb +39 -0
- data/lib/rex/struct2/constant.rb +26 -0
- data/lib/rex/struct2/element.rb +44 -0
- data/lib/rex/struct2/generic.rb +73 -0
- data/lib/rex/struct2/restraint.rb +54 -0
- data/lib/rex/struct2/s_string.rb +72 -0
- data/lib/rex/struct2/s_struct.rb +111 -0
- data/lib/rex/sync.rb +6 -0
- data/lib/rex/sync/event.rb +85 -0
- data/lib/rex/sync/read_write_lock.rb +177 -0
- data/lib/rex/sync/ref.rb +58 -0
- data/lib/rex/sync/thread_safe.rb +83 -0
- data/lib/rex/text.rb +1813 -0
- data/lib/rex/thread_factory.rb +43 -0
- data/lib/rex/time.rb +66 -0
- data/lib/rex/transformer.rb +116 -0
- data/lib/rex/ui.rb +22 -0
- data/lib/rex/ui/interactive.rb +304 -0
- data/lib/rex/ui/output.rb +85 -0
- data/lib/rex/ui/output/none.rb +19 -0
- data/lib/rex/ui/progress_tracker.rb +97 -0
- data/lib/rex/ui/subscriber.rb +160 -0
- data/lib/rex/ui/text/color.rb +98 -0
- data/lib/rex/ui/text/dispatcher_shell.rb +538 -0
- data/lib/rex/ui/text/input.rb +119 -0
- data/lib/rex/ui/text/input/buffer.rb +79 -0
- data/lib/rex/ui/text/input/readline.rb +129 -0
- data/lib/rex/ui/text/input/socket.rb +96 -0
- data/lib/rex/ui/text/input/stdio.rb +46 -0
- data/lib/rex/ui/text/irb_shell.rb +62 -0
- data/lib/rex/ui/text/output.rb +86 -0
- data/lib/rex/ui/text/output/buffer.rb +62 -0
- data/lib/rex/ui/text/output/buffer/stdout.rb +26 -0
- data/lib/rex/ui/text/output/file.rb +44 -0
- data/lib/rex/ui/text/output/socket.rb +44 -0
- data/lib/rex/ui/text/output/stdio.rb +53 -0
- data/lib/rex/ui/text/output/tee.rb +56 -0
- data/lib/rex/ui/text/progress_tracker.rb +57 -0
- data/lib/rex/ui/text/shell.rb +403 -0
- data/lib/rex/ui/text/table.rb +346 -0
- data/lib/rex/zip.rb +96 -0
- data/lib/rex/zip/archive.rb +130 -0
- data/lib/rex/zip/blocks.rb +184 -0
- data/lib/rex/zip/entry.rb +122 -0
- data/lib/rex/zip/jar.rb +283 -0
- data/lib/rex/zip/samples/comment.rb +32 -0
- data/lib/rex/zip/samples/mkwar.rb +138 -0
- data/lib/rex/zip/samples/mkzip.rb +19 -0
- data/lib/rex/zip/samples/recursive.rb +58 -0
- metadata +536 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
#
|
|
3
|
+
# RFB protocol support
|
|
4
|
+
#
|
|
5
|
+
# @author Joshua J. Drake <jduck>
|
|
6
|
+
#
|
|
7
|
+
# Based on:
|
|
8
|
+
# vnc_auth_none contributed by Matteo Cantoni <goony[at]nothink.org>
|
|
9
|
+
# vnc_auth_login contributed by carstein <carstein.sec[at]gmail.com>
|
|
10
|
+
|
|
11
|
+
require 'rex/proto/rfb/constants'
|
|
12
|
+
require 'rex/proto/rfb/cipher'
|
|
13
|
+
require 'rex/proto/rfb/client'
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
#
|
|
5
|
+
# RFB protocol support
|
|
6
|
+
#
|
|
7
|
+
# by Joshua J. Drake <jduck>
|
|
8
|
+
#
|
|
9
|
+
# Based on:
|
|
10
|
+
# vnc_auth_none contributed by Matteo Cantoni <goony[at]nothink.org>
|
|
11
|
+
# vnc_auth_login contributed by carstein <carstein.sec[at]gmail.com>
|
|
12
|
+
#
|
|
13
|
+
##
|
|
14
|
+
|
|
15
|
+
# Required for VNC authentication
|
|
16
|
+
require 'openssl'
|
|
17
|
+
|
|
18
|
+
module Rex
|
|
19
|
+
module Proto
|
|
20
|
+
module RFB
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# A bit of information about the DES algorithm was found here:
|
|
24
|
+
# http://www.vidarholen.net/contents/junk/vnc.html
|
|
25
|
+
#
|
|
26
|
+
# In addition, VNC uses two individual 8 byte block encryptions rather than
|
|
27
|
+
# using any block mode (like cbc, ecb, etc).
|
|
28
|
+
##
|
|
29
|
+
|
|
30
|
+
class Cipher
|
|
31
|
+
|
|
32
|
+
def self.mangle_password(password)
|
|
33
|
+
key = ''
|
|
34
|
+
key = password.dup if password
|
|
35
|
+
key.slice!(8,key.length) if key.length > 8
|
|
36
|
+
key << "\x00" * (8 - key.length) if key.length < 8
|
|
37
|
+
|
|
38
|
+
# We have to mangle the key so the LSB are kept vs the MSB
|
|
39
|
+
[key.unpack('B*').first.scan(/.{8}/).map! { |e| e.reverse }.join].pack('B*')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.encrypt(plain, password)
|
|
43
|
+
key = self.mangle_password(password)
|
|
44
|
+
|
|
45
|
+
# pad the plain to 16 chars
|
|
46
|
+
plain << ("\x00" * (16 - plain.length)) if plain.length < 16
|
|
47
|
+
|
|
48
|
+
# VNC auth does two 8-byte blocks individually instead supporting some block mode
|
|
49
|
+
cipher = ''
|
|
50
|
+
2.times { |x|
|
|
51
|
+
c = OpenSSL::Cipher::Cipher.new('des')
|
|
52
|
+
c.encrypt
|
|
53
|
+
c.key = key
|
|
54
|
+
cipher << c.update(plain[x*8, 8])
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
cipher
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
#
|
|
61
|
+
# NOTE: The default password is that of winvnc/etc which is used for
|
|
62
|
+
# encrypting the password(s) on disk/in registry.
|
|
63
|
+
#
|
|
64
|
+
def self.decrypt(cipher, password = "\x17\x52\x6b\x06\x23\x4e\x58\x07")
|
|
65
|
+
key = self.mangle_password(password)
|
|
66
|
+
|
|
67
|
+
# pad the cipher text to 9 bytes
|
|
68
|
+
cipher << ("\x00" * (9 - cipher.length)) if cipher.length < 9
|
|
69
|
+
|
|
70
|
+
# NOTE: This only does one 8 byte block
|
|
71
|
+
plain = ''
|
|
72
|
+
c = OpenSSL::Cipher::Cipher.new('des')
|
|
73
|
+
c.decrypt
|
|
74
|
+
c.key = key
|
|
75
|
+
c.update(cipher)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
#
|
|
5
|
+
# RFB protocol support
|
|
6
|
+
#
|
|
7
|
+
# by Joshua J. Drake <jduck>
|
|
8
|
+
#
|
|
9
|
+
# Based on:
|
|
10
|
+
# vnc_auth_none contributed by Matteo Cantoni <goony[at]nothink.org>
|
|
11
|
+
# vnc_auth_login contributed by carstein <carstein.sec[at]gmail.com>
|
|
12
|
+
#
|
|
13
|
+
# TODO: determine how to detect a view-only session.
|
|
14
|
+
##
|
|
15
|
+
|
|
16
|
+
module Rex
|
|
17
|
+
module Proto
|
|
18
|
+
module RFB
|
|
19
|
+
|
|
20
|
+
class Client
|
|
21
|
+
|
|
22
|
+
def initialize(sock, opts = {})
|
|
23
|
+
@sock = sock
|
|
24
|
+
@opts = opts
|
|
25
|
+
|
|
26
|
+
@banner = nil
|
|
27
|
+
@majver = MajorVersion
|
|
28
|
+
@minver = -1
|
|
29
|
+
@auth_types = []
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def read_error_message
|
|
33
|
+
len = @sock.get_once(4)
|
|
34
|
+
return 'Unknown error' if not len or len.length != 4
|
|
35
|
+
|
|
36
|
+
len = len.unpack("N").first
|
|
37
|
+
@sock.get_once(len)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def handshake
|
|
41
|
+
@banner = @sock.get_once(12)
|
|
42
|
+
if not @banner
|
|
43
|
+
@error = "Unable to obtain banner from server"
|
|
44
|
+
return false
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# RFB Protocol Version 3.3 (1998-01)
|
|
48
|
+
# RFB Protocol Version 3.7 (2003-08)
|
|
49
|
+
# RFB Protocol Version 3.8 (2007-06)
|
|
50
|
+
|
|
51
|
+
if @banner =~ /RFB ([0-9]{3})\.([0-9]{3})/
|
|
52
|
+
maj = $1.to_i
|
|
53
|
+
if maj != MajorVersion
|
|
54
|
+
@error = "Invalid major version number: #{maj}"
|
|
55
|
+
return false
|
|
56
|
+
end
|
|
57
|
+
else
|
|
58
|
+
@error = "Invalid RFB banner: #{@banner}"
|
|
59
|
+
return false
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
@minver = $2.to_i
|
|
63
|
+
|
|
64
|
+
our_ver = "RFB %03d.%03d\n" % [MajorVersion, @minver]
|
|
65
|
+
@sock.put(our_ver)
|
|
66
|
+
|
|
67
|
+
true
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def connect(password = nil)
|
|
71
|
+
return false if not handshake
|
|
72
|
+
return false if not authenticate(password)
|
|
73
|
+
return false if not send_client_init
|
|
74
|
+
true
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def send_client_init
|
|
78
|
+
if @opts[:exclusive]
|
|
79
|
+
@sock.put("\x00") # do share.
|
|
80
|
+
else
|
|
81
|
+
@sock.put("\x01") # do share.
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def authenticate(password = nil)
|
|
86
|
+
type = negotiate_authentication
|
|
87
|
+
return false if not type
|
|
88
|
+
|
|
89
|
+
# Authenticate.
|
|
90
|
+
case type
|
|
91
|
+
when AuthType::None
|
|
92
|
+
# Nothing here.
|
|
93
|
+
|
|
94
|
+
when AuthType::VNC
|
|
95
|
+
return false if not negotiate_vnc_auth(password)
|
|
96
|
+
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Handle reading the security result message
|
|
100
|
+
result = @sock.get_once(4)
|
|
101
|
+
if not result
|
|
102
|
+
@error = "Unable to read auth result"
|
|
103
|
+
return false
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
result = result.unpack('N').first
|
|
107
|
+
case result
|
|
108
|
+
when 0
|
|
109
|
+
return true
|
|
110
|
+
|
|
111
|
+
when 1
|
|
112
|
+
if @minver >= 8
|
|
113
|
+
msg = read_error_message
|
|
114
|
+
@error = "Authentication failed: #{msg}"
|
|
115
|
+
else
|
|
116
|
+
@error = "Authentication failed"
|
|
117
|
+
end
|
|
118
|
+
when 2
|
|
119
|
+
@error = "Too many authentication attempts"
|
|
120
|
+
else
|
|
121
|
+
@error = "Unknown authentication result: #{result}"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
false
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def negotiate_authentication
|
|
128
|
+
# Authentication type negotiation is protocol version specific.
|
|
129
|
+
if @minver < 7
|
|
130
|
+
buf = @sock.get_once(4)
|
|
131
|
+
if not buf
|
|
132
|
+
@error = "Unable to obtain requested authentication method"
|
|
133
|
+
return nil
|
|
134
|
+
end
|
|
135
|
+
@auth_types = buf.unpack('N')
|
|
136
|
+
if not @auth_types or @auth_types.first == 0
|
|
137
|
+
msg = read_error_message
|
|
138
|
+
@error = "No authentication types available: #{msg}"
|
|
139
|
+
return nil
|
|
140
|
+
end
|
|
141
|
+
else
|
|
142
|
+
buf = @sock.get_once(1)
|
|
143
|
+
if not buf
|
|
144
|
+
@error = "Unable to obtain supported authentication method count"
|
|
145
|
+
return nil
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# first byte is number of security types
|
|
149
|
+
num_types = buf.unpack("C").first
|
|
150
|
+
if (num_types == 0)
|
|
151
|
+
msg = read_error_message
|
|
152
|
+
@error = "No authentication types available: #{msg}"
|
|
153
|
+
return nil
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
buf = @sock.get_once(num_types)
|
|
157
|
+
if not buf or buf.length != num_types
|
|
158
|
+
@error = "Unable to read authentication types"
|
|
159
|
+
return nil
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
@auth_types = buf.unpack("C*")
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
if not @auth_types or @auth_types.length < 1
|
|
166
|
+
@error = "No authentication types found"
|
|
167
|
+
return nil
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Select the one we prefer
|
|
171
|
+
selected = nil
|
|
172
|
+
selected ||= AuthType::None if @opts[:allow_none] and @auth_types.include? AuthType::None
|
|
173
|
+
selected ||= AuthType::VNC if @auth_types.include? AuthType::VNC
|
|
174
|
+
|
|
175
|
+
if not selected
|
|
176
|
+
@error = "No supported authentication method found."
|
|
177
|
+
return nil
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# For 3.7 and later, clients must state which security-type to use
|
|
181
|
+
@sock.put([selected].pack('C')) if @minver >= 7
|
|
182
|
+
|
|
183
|
+
selected
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def negotiate_vnc_auth(password = nil)
|
|
187
|
+
challenge = @sock.get_once(16)
|
|
188
|
+
if not challenge or challenge.length != 16
|
|
189
|
+
@error = "Unable to obtain VNC challenge"
|
|
190
|
+
return false
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
response = Cipher.encrypt(challenge, password)
|
|
194
|
+
@sock.put(response)
|
|
195
|
+
|
|
196
|
+
true
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
attr_reader :error, :majver, :minver, :auth_types
|
|
200
|
+
attr_reader :view_only
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
#
|
|
5
|
+
# RFB protocol support
|
|
6
|
+
#
|
|
7
|
+
# by Joshua J. Drake <jduck>
|
|
8
|
+
#
|
|
9
|
+
# Based on:
|
|
10
|
+
# vnc_auth_none contributed by Matteo Cantoni <goony[at]nothink.org>
|
|
11
|
+
# vnc_auth_login contributed by carstein <carstein.sec[at]gmail.com>
|
|
12
|
+
#
|
|
13
|
+
##
|
|
14
|
+
|
|
15
|
+
module Rex
|
|
16
|
+
module Proto
|
|
17
|
+
module RFB
|
|
18
|
+
|
|
19
|
+
DefaultPort = 5900
|
|
20
|
+
|
|
21
|
+
# Version information
|
|
22
|
+
MajorVersion = 3
|
|
23
|
+
# NOTE: We will emulate whatever minor version the server reports.
|
|
24
|
+
|
|
25
|
+
# Security types
|
|
26
|
+
class AuthType
|
|
27
|
+
Invalid = 0
|
|
28
|
+
None = 1
|
|
29
|
+
VNC = 2
|
|
30
|
+
RA2 = 5
|
|
31
|
+
RA2ne = 6
|
|
32
|
+
Tight = 16
|
|
33
|
+
Ultra = 17
|
|
34
|
+
TLS = 18
|
|
35
|
+
VeNCrypt = 19
|
|
36
|
+
GtkVncSasl = 20
|
|
37
|
+
MD5Hash = 21
|
|
38
|
+
ColinDeanXVP = 22
|
|
39
|
+
|
|
40
|
+
def self.to_s(num)
|
|
41
|
+
self.constants.each { |c|
|
|
42
|
+
return c.to_s if self.const_get(c) == num
|
|
43
|
+
}
|
|
44
|
+
'Unknown'
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# encoding: binary
|
|
2
|
+
|
|
3
|
+
module Rex
|
|
4
|
+
module Proto
|
|
5
|
+
# SIP protocol support
|
|
6
|
+
module SIP
|
|
7
|
+
SIP_STATUS_REGEX = /^SIP\/(\d\.\d) (\d{3})\s*(.*)$/
|
|
8
|
+
|
|
9
|
+
# Represents a generic SIP message
|
|
10
|
+
class Message
|
|
11
|
+
attr_accessor :headers
|
|
12
|
+
|
|
13
|
+
def initialize
|
|
14
|
+
@headers = {}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Returns a list of all values from all +name+ headers, regardless of case,
|
|
18
|
+
# or nil if no matching header is found
|
|
19
|
+
def header(name)
|
|
20
|
+
matches = @headers.select { |k, _| k.downcase == name.downcase }
|
|
21
|
+
return nil if matches.empty?
|
|
22
|
+
matches.values.flatten
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Returns a hash of header name to values mapping
|
|
26
|
+
# from the provided message, or nil if no headers
|
|
27
|
+
# are found
|
|
28
|
+
def self.extract_headers(message)
|
|
29
|
+
pairs = message.scan(/^([^\s:]+):\s*(.*)$/)
|
|
30
|
+
return nil if pairs.empty?
|
|
31
|
+
headers = {}
|
|
32
|
+
pairs.each do |pair|
|
|
33
|
+
headers[pair.first] ||= []
|
|
34
|
+
headers[pair.first] << pair.last.strip
|
|
35
|
+
end
|
|
36
|
+
headers
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Represents a SIP response message
|
|
41
|
+
class Response < Message
|
|
42
|
+
attr_accessor :code, :message, :status_line, :version
|
|
43
|
+
|
|
44
|
+
# Parses +data+, constructs and returns a Response
|
|
45
|
+
def self.parse(data)
|
|
46
|
+
response = Response.new
|
|
47
|
+
# do some basic sanity checking on this response to ensure that it is SIP
|
|
48
|
+
response.status_line = data.split(/\r\n/)[0]
|
|
49
|
+
unless response.status_line && response.status_line =~ SIP_STATUS_REGEX
|
|
50
|
+
fail(ArgumentError, "Invalid SIP status line: #{response.status_line}")
|
|
51
|
+
end
|
|
52
|
+
response.version = Regexp.last_match(1)
|
|
53
|
+
response.code = Regexp.last_match(2)
|
|
54
|
+
response.message = Regexp.last_match(3)
|
|
55
|
+
response.headers = extract_headers(data)
|
|
56
|
+
response
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
require 'rex/proto/smb/constants'
|
|
3
|
+
require 'rex/proto/smb/exceptions'
|
|
4
|
+
require 'rex/proto/smb/evasions'
|
|
5
|
+
require 'rex/proto/smb/crypt'
|
|
6
|
+
require 'rex/proto/smb/utils'
|
|
7
|
+
require 'rex/proto/smb/client'
|
|
8
|
+
require 'rex/proto/smb/simpleclient'
|
|
@@ -0,0 +1,2064 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
module Rex
|
|
3
|
+
module Proto
|
|
4
|
+
module SMB
|
|
5
|
+
class Client
|
|
6
|
+
|
|
7
|
+
require 'rex/text'
|
|
8
|
+
require 'rex/struct2'
|
|
9
|
+
require 'rex/proto/smb/constants'
|
|
10
|
+
require 'rex/proto/smb/exceptions'
|
|
11
|
+
require 'rex/proto/smb/evasions'
|
|
12
|
+
require 'rex/proto/smb/utils'
|
|
13
|
+
require 'rex/proto/smb/crypt'
|
|
14
|
+
require 'rex/proto/ntlm/crypt'
|
|
15
|
+
require 'rex/proto/ntlm/constants'
|
|
16
|
+
require 'rex/proto/ntlm/utils'
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Some short-hand class aliases
|
|
20
|
+
CONST = Rex::Proto::SMB::Constants
|
|
21
|
+
CRYPT = Rex::Proto::SMB::Crypt
|
|
22
|
+
UTILS = Rex::Proto::SMB::Utils
|
|
23
|
+
XCEPT = Rex::Proto::SMB::Exceptions
|
|
24
|
+
EVADE = Rex::Proto::SMB::Evasions
|
|
25
|
+
NTLM_CRYPT = Rex::Proto::NTLM::Crypt
|
|
26
|
+
NTLM_CONST = Rex::Proto::NTLM::Constants
|
|
27
|
+
NTLM_UTILS = Rex::Proto::NTLM::Utils
|
|
28
|
+
|
|
29
|
+
def initialize(socket)
|
|
30
|
+
self.socket = socket
|
|
31
|
+
self.native_os = 'Windows 2000 2195'
|
|
32
|
+
self.native_lm = 'Windows 2000 5.0'
|
|
33
|
+
self.encrypt_passwords = true
|
|
34
|
+
self.extended_security = false
|
|
35
|
+
self.multiplex_id = rand(0xffff)
|
|
36
|
+
self.process_id = rand(0xffff)
|
|
37
|
+
self.read_timeout = 10
|
|
38
|
+
self.evasion_opts = {
|
|
39
|
+
|
|
40
|
+
# Padding is performed between packet headers and data
|
|
41
|
+
'pad_data' => EVADE::EVASION_NONE,
|
|
42
|
+
|
|
43
|
+
# File path padding is performed on all open/create calls
|
|
44
|
+
'pad_file' => EVADE::EVASION_NONE,
|
|
45
|
+
|
|
46
|
+
# Modify the \PIPE\ string in trans_named_pipe calls
|
|
47
|
+
'obscure_trans_pipe' => EVADE::EVASION_NONE,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
self.verify_signature = false
|
|
51
|
+
self.use_ntlmv2 = false
|
|
52
|
+
self.usentlm2_session = true
|
|
53
|
+
self.send_lm = true
|
|
54
|
+
self.use_lanman_key = false
|
|
55
|
+
self.send_ntlm = true
|
|
56
|
+
|
|
57
|
+
# Signing
|
|
58
|
+
self.sequence_counter = 0
|
|
59
|
+
self.signing_key = ''
|
|
60
|
+
self.require_signing = false
|
|
61
|
+
|
|
62
|
+
#Misc
|
|
63
|
+
self.spnopt = {}
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Read a SMB packet from the socket
|
|
68
|
+
def smb_recv
|
|
69
|
+
|
|
70
|
+
data = socket.timed_read(4, self.read_timeout)
|
|
71
|
+
if (data.nil? or data.length < 4)
|
|
72
|
+
raise XCEPT::NoReply
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
recv_len = data[2,2].unpack('n')[0]
|
|
76
|
+
if (recv_len == 0)
|
|
77
|
+
return data
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
recv_len += 4
|
|
81
|
+
|
|
82
|
+
while (data.length != recv_len)
|
|
83
|
+
buff = ''
|
|
84
|
+
|
|
85
|
+
begin
|
|
86
|
+
buff << self.socket.timed_read(recv_len - data.length, self.read_timeout)
|
|
87
|
+
rescue Timeout::Error
|
|
88
|
+
rescue
|
|
89
|
+
raise XCEPT::ReadPacket
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
if (buff.nil? or buff.length == 0)
|
|
93
|
+
raise XCEPT::ReadPacket
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
data << buff
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
#signing
|
|
100
|
+
if self.require_signing && self.signing_key != ''
|
|
101
|
+
if self.verify_signature
|
|
102
|
+
raise XCEPT::IncorrectSigningError if not CRYPT::is_signature_correct?(self.signing_key,self.sequence_counter,data)
|
|
103
|
+
end
|
|
104
|
+
self.sequence_counter += 1
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
return data
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Send a SMB packet down the socket
|
|
113
|
+
def smb_send(data, evasion_level=0)
|
|
114
|
+
|
|
115
|
+
# evasion_level is ignored, since real evasion happens
|
|
116
|
+
# in the actual socket layer
|
|
117
|
+
|
|
118
|
+
size = 0
|
|
119
|
+
wait = 0
|
|
120
|
+
|
|
121
|
+
#signing
|
|
122
|
+
if self.require_signing && self.signing_key != ''
|
|
123
|
+
data = CRYPT::sign_smb_packet(self.signing_key, self.sequence_counter, data)
|
|
124
|
+
self.sequence_counter += 1
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
begin
|
|
128
|
+
# Just send the packet and return
|
|
129
|
+
if (size == 0 or size >= data.length)
|
|
130
|
+
return self.socket.put(data)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Break the packet up into chunks and wait between them
|
|
134
|
+
ret = 0
|
|
135
|
+
while ( (chunk = data.slice!(0, size)).length > 0 )
|
|
136
|
+
ret = self.socket.put(chunk)
|
|
137
|
+
if (wait > 0)
|
|
138
|
+
::IO.select(nil, nil, nil, wait)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
return ret
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Set the SMB parameters to some reasonable defaults
|
|
146
|
+
def smb_defaults(packet)
|
|
147
|
+
packet.v['MultiplexID'] = self.multiplex_id.to_i
|
|
148
|
+
packet.v['TreeID'] = self.last_tree_id.to_i
|
|
149
|
+
packet.v['UserID'] = self.auth_user_id.to_i
|
|
150
|
+
packet.v['ProcessID'] = self.process_id.to_i
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Receive a full SMB reply and cache the parsed packet
|
|
154
|
+
def smb_recv_and_cache
|
|
155
|
+
@smb_recv_cache ||= []
|
|
156
|
+
|
|
157
|
+
# This will throw an exception if it fails to read the whole packet
|
|
158
|
+
data = self.smb_recv
|
|
159
|
+
|
|
160
|
+
pkt = CONST::SMB_BASE_PKT.make_struct
|
|
161
|
+
pkt.from_s(data)
|
|
162
|
+
|
|
163
|
+
# Store the received packet into the cache
|
|
164
|
+
@smb_recv_cache << [ pkt, data, Time.now ]
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Scan the packet receive cache for a matching response
|
|
168
|
+
def smb_recv_cache_find_match(expected_type)
|
|
169
|
+
|
|
170
|
+
clean = []
|
|
171
|
+
found = nil
|
|
172
|
+
|
|
173
|
+
@smb_recv_cache.each do |cent|
|
|
174
|
+
pkt, data, tstamp = cent
|
|
175
|
+
|
|
176
|
+
# Return matching packets and mark for removal
|
|
177
|
+
if pkt['Payload']['SMB'].v['Command'] == expected_type
|
|
178
|
+
found = [pkt,data]
|
|
179
|
+
clean << cent
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Purge any packets older than 5 minutes
|
|
183
|
+
if Time.now.to_i - tstamp.to_i > 300
|
|
184
|
+
clean << cent
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
break if found
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
clean.each do |cent|
|
|
191
|
+
@smb_recv_cache.delete(cent)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
found
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# The main dispatcher for all incoming SMB packets
|
|
198
|
+
def smb_recv_parse(expected_type, ignore_errors = false)
|
|
199
|
+
|
|
200
|
+
pkt = nil
|
|
201
|
+
data = nil
|
|
202
|
+
|
|
203
|
+
# This allows for some leeway when a previous response has not
|
|
204
|
+
# been processed but a new request was sent. The old response
|
|
205
|
+
# will eventually be timed out of the cache.
|
|
206
|
+
1.upto(3) do |attempt|
|
|
207
|
+
smb_recv_and_cache
|
|
208
|
+
pkt,data = smb_recv_cache_find_match(expected_type)
|
|
209
|
+
break if pkt
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
begin
|
|
213
|
+
case pkt['Payload']['SMB'].v['Command']
|
|
214
|
+
|
|
215
|
+
when CONST::SMB_COM_NEGOTIATE
|
|
216
|
+
res = smb_parse_negotiate(pkt, data)
|
|
217
|
+
|
|
218
|
+
when CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
219
|
+
res = smb_parse_session_setup(pkt, data)
|
|
220
|
+
|
|
221
|
+
when CONST::SMB_COM_TREE_CONNECT_ANDX
|
|
222
|
+
res = smb_parse_tree_connect(pkt, data)
|
|
223
|
+
|
|
224
|
+
when CONST::SMB_COM_TREE_DISCONNECT
|
|
225
|
+
res = smb_parse_tree_disconnect(pkt, data)
|
|
226
|
+
|
|
227
|
+
when CONST::SMB_COM_NT_CREATE_ANDX
|
|
228
|
+
res = smb_parse_create(pkt, data)
|
|
229
|
+
|
|
230
|
+
when CONST::SMB_COM_TRANSACTION, CONST::SMB_COM_TRANSACTION2
|
|
231
|
+
res = smb_parse_trans(pkt, data)
|
|
232
|
+
|
|
233
|
+
when CONST::SMB_COM_NT_TRANSACT
|
|
234
|
+
res = smb_parse_nttrans(pkt, data)
|
|
235
|
+
|
|
236
|
+
when CONST::SMB_COM_NT_TRANSACT_SECONDARY
|
|
237
|
+
res = smb_parse_nttrans(pkt, data)
|
|
238
|
+
|
|
239
|
+
when CONST::SMB_COM_OPEN_ANDX
|
|
240
|
+
res = smb_parse_open(pkt, data)
|
|
241
|
+
|
|
242
|
+
when CONST::SMB_COM_WRITE_ANDX
|
|
243
|
+
res = smb_parse_write(pkt, data)
|
|
244
|
+
|
|
245
|
+
when CONST::SMB_COM_READ_ANDX
|
|
246
|
+
res = smb_parse_read(pkt, data)
|
|
247
|
+
|
|
248
|
+
when CONST::SMB_COM_CLOSE
|
|
249
|
+
res = smb_parse_close(pkt, data)
|
|
250
|
+
|
|
251
|
+
when CONST::SMB_COM_DELETE
|
|
252
|
+
res = smb_parse_delete(pkt, data)
|
|
253
|
+
|
|
254
|
+
else
|
|
255
|
+
raise XCEPT::InvalidCommand
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
if (ignore_errors == false and pkt['Payload']['SMB'].v['ErrorClass'] != 0)
|
|
259
|
+
raise XCEPT::ErrorCode
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
rescue XCEPT::InvalidWordCount, XCEPT::InvalidCommand, XCEPT::ErrorCode
|
|
263
|
+
$!.word_count = pkt['Payload']['SMB'].v['WordCount']
|
|
264
|
+
$!.command = pkt['Payload']['SMB'].v['Command']
|
|
265
|
+
$!.error_code = pkt['Payload']['SMB'].v['ErrorClass']
|
|
266
|
+
raise $!
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
return res
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Process incoming SMB_COM_NEGOTIATE packets
|
|
273
|
+
def smb_parse_negotiate(pkt, data)
|
|
274
|
+
#Process NTLM negotiate responses
|
|
275
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 17)
|
|
276
|
+
res = CONST::SMB_NEG_RES_NT_PKT.make_struct
|
|
277
|
+
res.from_s(data)
|
|
278
|
+
return res
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Process LANMAN negotiate responses
|
|
282
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 13)
|
|
283
|
+
res = CONST::SMB_NEG_RES_LM_PKT.make_struct
|
|
284
|
+
res.from_s(data)
|
|
285
|
+
return res
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# Process ERROR negotiate responses
|
|
289
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 1)
|
|
290
|
+
res = CONST::SMB_NEG_RES_ERR_PKT.make_struct
|
|
291
|
+
res.from_s(data)
|
|
292
|
+
return res
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# Process SMB error responses
|
|
296
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
297
|
+
return pkt
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
raise XCEPT::InvalidWordCount
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Process incoming SMB_COM_SESSION_SETUP_ANDX packets
|
|
304
|
+
def smb_parse_session_setup(pkt, data)
|
|
305
|
+
# Process NTLMSSP negotiate responses
|
|
306
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 4)
|
|
307
|
+
res = CONST::SMB_SETUP_NTLMV2_RES_PKT.make_struct
|
|
308
|
+
res.from_s(data)
|
|
309
|
+
return res
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Process LANMAN responses
|
|
313
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 3)
|
|
314
|
+
res = CONST::SMB_SETUP_RES_PKT.make_struct
|
|
315
|
+
res.from_s(data)
|
|
316
|
+
return res
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# Process SMB error responses
|
|
320
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
321
|
+
return pkt
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
raise XCEPT::InvalidWordCount
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# Process incoming SMB_COM_TREE_CONNECT_ANDX packets
|
|
328
|
+
def smb_parse_tree_connect(pkt, data)
|
|
329
|
+
|
|
330
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 3)
|
|
331
|
+
res = CONST::SMB_TREE_CONN_RES_PKT.make_struct
|
|
332
|
+
res.from_s(data)
|
|
333
|
+
return res
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# Process SMB error responses
|
|
337
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
338
|
+
return pkt
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
raise XCEPT::InvalidWordCount
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Process incoming SMB_COM_TREE_DISCONNECT packets
|
|
345
|
+
def smb_parse_tree_disconnect(pkt, data)
|
|
346
|
+
|
|
347
|
+
# Process SMB responses
|
|
348
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
349
|
+
res = CONST::SMB_TREE_DISCONN_RES_PKT.make_struct
|
|
350
|
+
res.from_s(data)
|
|
351
|
+
return res
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
raise XCEPT::InvalidWordCount
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
# Process incoming SMB_COM_NT_CREATE_ANDX packets
|
|
358
|
+
def smb_parse_create(pkt, data)
|
|
359
|
+
|
|
360
|
+
# Windows says 42, but Samba says 34, same structure :-/
|
|
361
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 42)
|
|
362
|
+
res = CONST::SMB_CREATE_RES_PKT.make_struct
|
|
363
|
+
res.from_s(data)
|
|
364
|
+
return res
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 34)
|
|
368
|
+
res = CONST::SMB_CREATE_RES_PKT.make_struct
|
|
369
|
+
res.from_s(data)
|
|
370
|
+
return res
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
# Process SMB error responses
|
|
374
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
375
|
+
return pkt
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
raise XCEPT::InvalidWordCount
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
# Process incoming SMB_COM_TRANSACTION packets
|
|
382
|
+
def smb_parse_trans(pkt, data)
|
|
383
|
+
|
|
384
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 10)
|
|
385
|
+
res = CONST::SMB_TRANS_RES_PKT.make_struct
|
|
386
|
+
res.from_s(data)
|
|
387
|
+
return res
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
# Process SMB error responses
|
|
391
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
392
|
+
return pkt
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
raise XCEPT::InvalidWordCount
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
# Process incoming SMB_COM_NT_TRANSACT packets
|
|
399
|
+
def smb_parse_nttrans(pkt, data)
|
|
400
|
+
|
|
401
|
+
# Process SMB error responses
|
|
402
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
403
|
+
return pkt
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
if (pkt['Payload']['SMB'].v['WordCount'] >= 18)
|
|
407
|
+
res = CONST::SMB_NTTRANS_RES_PKT.make_struct
|
|
408
|
+
res.from_s(data)
|
|
409
|
+
return res
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
raise XCEPT::InvalidWordCount
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
# Process incoming SMB_COM_OPEN_ANDX packets
|
|
416
|
+
def smb_parse_open(pkt, data)
|
|
417
|
+
# Process open responses
|
|
418
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 15)
|
|
419
|
+
res = CONST::SMB_OPEN_RES_PKT.make_struct
|
|
420
|
+
res.from_s(data)
|
|
421
|
+
return res
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
# Process SMB error responses
|
|
425
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
426
|
+
return pkt
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
raise XCEPT::InvalidWordCount
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
# Process incoming SMB_COM_WRITE_ANDX packets
|
|
433
|
+
def smb_parse_write(pkt, data)
|
|
434
|
+
|
|
435
|
+
# Process write responses
|
|
436
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 6)
|
|
437
|
+
res = CONST::SMB_WRITE_RES_PKT.make_struct
|
|
438
|
+
res.from_s(data)
|
|
439
|
+
return res
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
# Process SMB error responses
|
|
443
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
444
|
+
return pkt
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
raise XCEPT::InvalidWordCount
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
# Process incoming SMB_COM_READ_ANDX packets
|
|
451
|
+
def smb_parse_read(pkt, data)
|
|
452
|
+
|
|
453
|
+
# Process read responses
|
|
454
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 12)
|
|
455
|
+
res = CONST::SMB_READ_RES_PKT.make_struct
|
|
456
|
+
res.from_s(data)
|
|
457
|
+
return res
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
# Process SMB error responses
|
|
461
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
462
|
+
return pkt
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
raise XCEPT::InvalidWordCount
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
# Process incoming SMB_COM_CLOSE packets
|
|
469
|
+
def smb_parse_close(pkt, data)
|
|
470
|
+
|
|
471
|
+
# Process SMB error responses
|
|
472
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
473
|
+
return pkt
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
raise XCEPT::InvalidWordCount
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
# Process incoming SMB_COM_DELETE packets
|
|
480
|
+
def smb_parse_delete(pkt, data)
|
|
481
|
+
|
|
482
|
+
# Process SMB error responses
|
|
483
|
+
if (pkt['Payload']['SMB'].v['WordCount'] == 0)
|
|
484
|
+
res = CONST::SMB_DELETE_RES_PKT.make_struct
|
|
485
|
+
res.from_s(data)
|
|
486
|
+
return res
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
raise XCEPT::InvalidWordCount
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
# Request a SMB session over NetBIOS
|
|
493
|
+
def session_request(name = '*SMBSERVER', do_recv = true)
|
|
494
|
+
|
|
495
|
+
name ||= '*SMBSERVER'
|
|
496
|
+
|
|
497
|
+
data = ''
|
|
498
|
+
data << "\x20" + UTILS.nbname_encode(name) + "\x00"
|
|
499
|
+
data << "\x20" + CONST::NETBIOS_REDIR + "\x00"
|
|
500
|
+
|
|
501
|
+
pkt = CONST::NBRAW_PKT.make_struct
|
|
502
|
+
pkt.v['Type'] = 0x81
|
|
503
|
+
pkt['Payload'].v['Payload'] = data
|
|
504
|
+
|
|
505
|
+
# Most SMB implementations can't handle this being fragmented
|
|
506
|
+
ret = self.smb_send(pkt.to_s, EVADE::EVASION_NONE)
|
|
507
|
+
return ret if not do_recv
|
|
508
|
+
|
|
509
|
+
res = self.smb_recv
|
|
510
|
+
|
|
511
|
+
ack = CONST::NBRAW_PKT.make_struct
|
|
512
|
+
ack.from_s(res)
|
|
513
|
+
|
|
514
|
+
if (ack.v['Type'] != 130)
|
|
515
|
+
raise XCEPT::NetbiosSessionFailed
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
return ack
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
# Negotiate a SMB dialect
|
|
522
|
+
def negotiate(smb_extended_security=true, do_recv = true)
|
|
523
|
+
|
|
524
|
+
dialects = ['LANMAN1.0', 'LM1.2X002' ]
|
|
525
|
+
|
|
526
|
+
if (self.encrypt_passwords)
|
|
527
|
+
dialects.push('NT LANMAN 1.0', 'NT LM 0.12')
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
data = dialects.collect { |dialect| "\x02" + dialect + "\x00" }.join('')
|
|
531
|
+
|
|
532
|
+
pkt = CONST::SMB_NEG_PKT.make_struct
|
|
533
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
534
|
+
|
|
535
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NEGOTIATE
|
|
536
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
537
|
+
|
|
538
|
+
if(smb_extended_security)
|
|
539
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
540
|
+
else
|
|
541
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0xc001
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
pkt['Payload'].v['Payload'] = data
|
|
545
|
+
|
|
546
|
+
ret = self.smb_send(pkt.to_s, EVADE::EVASION_NONE)
|
|
547
|
+
return ret if not do_recv
|
|
548
|
+
|
|
549
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_NEGOTIATE)
|
|
550
|
+
|
|
551
|
+
idx = ack['Payload'].v['Dialect']
|
|
552
|
+
|
|
553
|
+
# Check for failed dialect selection
|
|
554
|
+
if (idx < 0 or idx >= dialects.length)
|
|
555
|
+
return nil
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
# Set the selected dialect
|
|
559
|
+
self.dialect = dialects[idx]
|
|
560
|
+
|
|
561
|
+
# Does the server support extended security negotiation?
|
|
562
|
+
if (ack['Payload'].v['Capabilities'] & 0x80000000 != 0)
|
|
563
|
+
self.extended_security = true
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
# Set the security mode
|
|
567
|
+
self.security_mode = ack['Payload'].v['SecurityMode']
|
|
568
|
+
|
|
569
|
+
#set require_signing
|
|
570
|
+
if (ack['Payload'].v['SecurityMode'] & 0x08 != 0)
|
|
571
|
+
self.require_signing = true
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
# Set the challenge key
|
|
575
|
+
if (ack['Payload'].v['EncryptionKey'] != nil)
|
|
576
|
+
self.challenge_key = ack['Payload'].v['EncryptionKey']
|
|
577
|
+
else
|
|
578
|
+
# Handle Windows NT 4.0 responses
|
|
579
|
+
if (ack['Payload'].v['KeyLength'] > 0)
|
|
580
|
+
self.challenge_key = ack['Payload'].v['Payload'][0, ack['Payload'].v['KeyLength']]
|
|
581
|
+
end
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
# Set the session identifier
|
|
585
|
+
if (ack['Payload'].v['SessionKey'] != nil)
|
|
586
|
+
self.session_id = ack['Payload'].v['SessionKey']
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
# Extract the payload (GUID/SecurityBlob)
|
|
590
|
+
buf = ack['Payload'].v['Payload'] || ''
|
|
591
|
+
|
|
592
|
+
# Set the server GUID
|
|
593
|
+
if (self.extended_security and buf.length >= 16)
|
|
594
|
+
self.server_guid = buf[0,16]
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
# Set the server SecurityBlob
|
|
598
|
+
if (self.extended_security and buf.length > 16)
|
|
599
|
+
# buf[16, buf.length - 16]
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
# The number of 100-nanosecond intervals that have elapsed since January 1, 1601, in
|
|
603
|
+
# Coordinated Universal Time (UTC) format.
|
|
604
|
+
# We convert it to a friendly Time object here
|
|
605
|
+
self.system_time = UTILS.time_smb_to_unix(ack['Payload'].v['SystemTimeHigh'],ack['Payload'].v['SystemTimeLow'])
|
|
606
|
+
self.system_time = ::Time.at( self.system_time )
|
|
607
|
+
|
|
608
|
+
# A signed 16-bit signed integer that represents the server's time zone, in minutes,
|
|
609
|
+
# from UTC. The time zone of the server MUST be expressed in minutes, plus or minus,
|
|
610
|
+
# from UTC.
|
|
611
|
+
# NOTE: althought the spec says +/- it doesn't say that it should be inverted :-/
|
|
612
|
+
system_zone = ack['Payload'].v['ServerTimeZone']
|
|
613
|
+
# Convert the ServerTimeZone to _seconds_ and back into a signed integer :-/
|
|
614
|
+
if (system_zone & 0x8000) == 0x8000
|
|
615
|
+
system_zone = (( (~system_zone) & 0x0FFF ) + 1 )
|
|
616
|
+
else
|
|
617
|
+
system_zone *= -1
|
|
618
|
+
end
|
|
619
|
+
self.system_zone = system_zone * 60
|
|
620
|
+
|
|
621
|
+
return ack
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
# Authenticate and establish a session
|
|
626
|
+
def session_setup(*args)
|
|
627
|
+
|
|
628
|
+
if (self.dialect =~ /^(NT LANMAN 1.0|NT LM 0.12)$/)
|
|
629
|
+
|
|
630
|
+
if (self.challenge_key)
|
|
631
|
+
return self.session_setup_no_ntlmssp(*args)
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
if ( self.extended_security )
|
|
635
|
+
return self.session_setup_with_ntlmssp(*args)
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
return self.session_setup_clear(*args)
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
# Authenticate using clear-text passwords
|
|
644
|
+
def session_setup_clear(user = '', pass = '', domain = '', do_recv = true)
|
|
645
|
+
|
|
646
|
+
data = [ pass, user, domain, self.native_os, self.native_lm ].collect{ |a| a + "\x00" }.join('');
|
|
647
|
+
|
|
648
|
+
pkt = CONST::SMB_SETUP_LANMAN_PKT.make_struct
|
|
649
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
650
|
+
|
|
651
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
652
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
653
|
+
if self.require_signing
|
|
654
|
+
#ascii
|
|
655
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
656
|
+
else
|
|
657
|
+
#ascii
|
|
658
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
pkt['Payload']['SMB'].v['WordCount'] = 10
|
|
662
|
+
pkt['Payload'].v['AndX'] = 255
|
|
663
|
+
pkt['Payload'].v['MaxBuff'] = 0xffdf
|
|
664
|
+
pkt['Payload'].v['MaxMPX'] = 2
|
|
665
|
+
pkt['Payload'].v['VCNum'] = 1
|
|
666
|
+
pkt['Payload'].v['PasswordLen'] = pass.length + 1
|
|
667
|
+
pkt['Payload'].v['Capabilities'] = 64
|
|
668
|
+
pkt['Payload'].v['SessionKey'] = self.session_id
|
|
669
|
+
pkt['Payload'].v['Payload'] = data
|
|
670
|
+
|
|
671
|
+
ret = self.smb_send(pkt.to_s)
|
|
672
|
+
return ret if not do_recv
|
|
673
|
+
|
|
674
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX)
|
|
675
|
+
|
|
676
|
+
if (ack['Payload'].v['Action'] != 1 and user.length > 0)
|
|
677
|
+
self.auth_user = user
|
|
678
|
+
end
|
|
679
|
+
|
|
680
|
+
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
|
681
|
+
|
|
682
|
+
info = ack['Payload'].v['Payload'].split(/\x00/n)
|
|
683
|
+
self.peer_native_os = info[0]
|
|
684
|
+
self.peer_native_lm = info[1]
|
|
685
|
+
self.default_domain = info[2]
|
|
686
|
+
|
|
687
|
+
return ack
|
|
688
|
+
end
|
|
689
|
+
|
|
690
|
+
# Authenticate without NTLMSSP
|
|
691
|
+
def session_setup_no_ntlmssp(user = '', pass = '', domain = '', do_recv = true)
|
|
692
|
+
|
|
693
|
+
# Requires a challenge key to have been seen during negotiation
|
|
694
|
+
raise XCEPT::NTLM1MissingChallenge if not self.challenge_key
|
|
695
|
+
|
|
696
|
+
#
|
|
697
|
+
# We can not yet handle signing in this situation
|
|
698
|
+
# But instead of throwing an exception,we will disable signing, continue and hope for the best.
|
|
699
|
+
#
|
|
700
|
+
|
|
701
|
+
#raise XCEPT::SigningError if self.require_signing
|
|
702
|
+
self.require_signing = false if self.require_signing
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
if NTLM_UTILS.is_pass_ntlm_hash?(pass)
|
|
706
|
+
arglm = {
|
|
707
|
+
:lm_hash => [ pass.upcase()[0,32] ].pack('H32'),
|
|
708
|
+
:challenge => self.challenge_key
|
|
709
|
+
}
|
|
710
|
+
hash_lm = NTLM_CRYPT::lm_response(arglm)
|
|
711
|
+
|
|
712
|
+
argntlm = {
|
|
713
|
+
:ntlm_hash => [ pass.upcase()[33,65] ].pack('H32'),
|
|
714
|
+
:challenge => self.challenge_key
|
|
715
|
+
}
|
|
716
|
+
hash_nt = NTLM_CRYPT::ntlm_response(argntlm)
|
|
717
|
+
else
|
|
718
|
+
hash_lm = pass.length > 0 ? NTLM_CRYPT.lanman_des(pass, self.challenge_key) : ''
|
|
719
|
+
hash_nt = pass.length > 0 ? NTLM_CRYPT.ntlm_md4(pass, self.challenge_key) : ''
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
data = ''
|
|
723
|
+
data << hash_lm
|
|
724
|
+
data << hash_nt
|
|
725
|
+
data << user + "\x00"
|
|
726
|
+
data << domain + "\x00"
|
|
727
|
+
data << self.native_os + "\x00"
|
|
728
|
+
data << self.native_lm + "\x00"
|
|
729
|
+
|
|
730
|
+
pkt = CONST::SMB_SETUP_NTLMV1_PKT.make_struct
|
|
731
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
732
|
+
|
|
733
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
734
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
735
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2001
|
|
736
|
+
pkt['Payload']['SMB'].v['WordCount'] = 13
|
|
737
|
+
pkt['Payload'].v['AndX'] = 255
|
|
738
|
+
pkt['Payload'].v['MaxBuff'] = 0xffdf
|
|
739
|
+
pkt['Payload'].v['MaxMPX'] = 2
|
|
740
|
+
pkt['Payload'].v['VCNum'] = 1
|
|
741
|
+
pkt['Payload'].v['PasswordLenLM'] = hash_lm.length
|
|
742
|
+
pkt['Payload'].v['PasswordLenNT'] = hash_nt.length
|
|
743
|
+
pkt['Payload'].v['Capabilities'] = 64
|
|
744
|
+
pkt['Payload'].v['SessionKey'] = self.session_id
|
|
745
|
+
pkt['Payload'].v['Payload'] = data
|
|
746
|
+
|
|
747
|
+
ret = self.smb_send(pkt.to_s)
|
|
748
|
+
return ret if not do_recv
|
|
749
|
+
|
|
750
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX)
|
|
751
|
+
|
|
752
|
+
if (ack['Payload'].v['Action'] != 1 and user.length > 0)
|
|
753
|
+
self.auth_user = user
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
|
757
|
+
|
|
758
|
+
info = ack['Payload'].v['Payload'].split(/\x00/n)
|
|
759
|
+
|
|
760
|
+
self.peer_native_os = info[0]
|
|
761
|
+
self.peer_native_lm = info[1]
|
|
762
|
+
self.default_domain = info[2]
|
|
763
|
+
|
|
764
|
+
return ack
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
# Authenticate without ntlmssp with a precomputed hash pair
|
|
769
|
+
def session_setup_no_ntlmssp_prehash(user, domain, hash_lm, hash_nt, do_recv = true)
|
|
770
|
+
|
|
771
|
+
data = ''
|
|
772
|
+
data << hash_lm
|
|
773
|
+
data << hash_nt
|
|
774
|
+
data << user + "\x00"
|
|
775
|
+
data << domain + "\x00"
|
|
776
|
+
data << self.native_os + "\x00"
|
|
777
|
+
data << self.native_lm + "\x00"
|
|
778
|
+
|
|
779
|
+
pkt = CONST::SMB_SETUP_NTLMV1_PKT.make_struct
|
|
780
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
781
|
+
|
|
782
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
783
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
784
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2001
|
|
785
|
+
pkt['Payload']['SMB'].v['WordCount'] = 13
|
|
786
|
+
pkt['Payload'].v['AndX'] = 255
|
|
787
|
+
pkt['Payload'].v['MaxBuff'] = 0xffdf
|
|
788
|
+
pkt['Payload'].v['MaxMPX'] = 2
|
|
789
|
+
pkt['Payload'].v['VCNum'] = 1
|
|
790
|
+
pkt['Payload'].v['PasswordLenLM'] = hash_lm.length
|
|
791
|
+
pkt['Payload'].v['PasswordLenNT'] = hash_nt.length
|
|
792
|
+
pkt['Payload'].v['Capabilities'] = 64
|
|
793
|
+
pkt['Payload'].v['SessionKey'] = self.session_id
|
|
794
|
+
pkt['Payload'].v['Payload'] = data
|
|
795
|
+
|
|
796
|
+
ret = self.smb_send(pkt.to_s)
|
|
797
|
+
return ret if not do_recv
|
|
798
|
+
|
|
799
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX)
|
|
800
|
+
|
|
801
|
+
if (ack['Payload'].v['Action'] != 1 and user.length > 0)
|
|
802
|
+
self.auth_user = user
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
|
806
|
+
|
|
807
|
+
info = ack['Payload'].v['Payload'].split(/\x00/n)
|
|
808
|
+
|
|
809
|
+
self.peer_native_os = info[0]
|
|
810
|
+
self.peer_native_lm = info[1]
|
|
811
|
+
self.default_domain = info[2]
|
|
812
|
+
|
|
813
|
+
return ack
|
|
814
|
+
end
|
|
815
|
+
|
|
816
|
+
# Authenticate using extended security negotiation
|
|
817
|
+
def session_setup_with_ntlmssp(user = '', pass = '', domain = '', name = nil, do_recv = true)
|
|
818
|
+
|
|
819
|
+
ntlm_options = {
|
|
820
|
+
:signing => self.require_signing,
|
|
821
|
+
:usentlm2_session => self.usentlm2_session,
|
|
822
|
+
:use_ntlmv2 => self.use_ntlmv2,
|
|
823
|
+
:send_lm => self.send_lm,
|
|
824
|
+
:send_ntlm => self.send_ntlm,
|
|
825
|
+
:use_lanman_key => self.use_lanman_key
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options)
|
|
829
|
+
|
|
830
|
+
if (name == nil)
|
|
831
|
+
name = Rex::Text.rand_text_alphanumeric(16)
|
|
832
|
+
end
|
|
833
|
+
|
|
834
|
+
blob = NTLM_UTILS.make_ntlmssp_secblob_init(domain, name, ntlmssp_flags)
|
|
835
|
+
|
|
836
|
+
native_data = ''
|
|
837
|
+
native_data << self.native_os + "\x00"
|
|
838
|
+
native_data << self.native_lm + "\x00"
|
|
839
|
+
|
|
840
|
+
pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
|
|
841
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
842
|
+
|
|
843
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
844
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
845
|
+
if require_signing
|
|
846
|
+
#ascii
|
|
847
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
848
|
+
else
|
|
849
|
+
#ascii
|
|
850
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
851
|
+
end
|
|
852
|
+
pkt['Payload']['SMB'].v['WordCount'] = 12
|
|
853
|
+
pkt['Payload'].v['AndX'] = 255
|
|
854
|
+
pkt['Payload'].v['MaxBuff'] = 0xffdf
|
|
855
|
+
pkt['Payload'].v['MaxMPX'] = 2
|
|
856
|
+
pkt['Payload'].v['VCNum'] = 1
|
|
857
|
+
pkt['Payload'].v['SecurityBlobLen'] = blob.length
|
|
858
|
+
pkt['Payload'].v['Capabilities'] = 0x800000d4
|
|
859
|
+
pkt['Payload'].v['SessionKey'] = self.session_id
|
|
860
|
+
pkt['Payload'].v['Payload'] = blob + native_data
|
|
861
|
+
|
|
862
|
+
ret = self.smb_send(pkt.to_s)
|
|
863
|
+
|
|
864
|
+
return ret if not do_recv
|
|
865
|
+
|
|
866
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, true)
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
# The server doesn't know about NTLM_NEGOTIATE
|
|
870
|
+
if (ack['Payload']['SMB'].v['ErrorClass'] == 0x00020002)
|
|
871
|
+
return session_setup_no_ntlmssp(user, pass, domain)
|
|
872
|
+
end
|
|
873
|
+
|
|
874
|
+
# Make sure the error code tells us to continue processing
|
|
875
|
+
if (ack['Payload']['SMB'].v['ErrorClass'] != 0xc0000016)
|
|
876
|
+
failure = XCEPT::ErrorCode.new
|
|
877
|
+
failure.word_count = ack['Payload']['SMB'].v['WordCount']
|
|
878
|
+
failure.command = ack['Payload']['SMB'].v['Command']
|
|
879
|
+
failure.error_code = ack['Payload']['SMB'].v['ErrorClass']
|
|
880
|
+
raise failure
|
|
881
|
+
end
|
|
882
|
+
|
|
883
|
+
# Extract the SecurityBlob from the response
|
|
884
|
+
data = ack['Payload'].v['Payload']
|
|
885
|
+
blob = data.slice!(0, ack['Payload'].v['SecurityBlobLen'])
|
|
886
|
+
|
|
887
|
+
# Extract the native lanman and os strings
|
|
888
|
+
info = data.split(/\x00/n)
|
|
889
|
+
self.peer_native_os = info[0]
|
|
890
|
+
self.peer_native_lm = info[1]
|
|
891
|
+
|
|
892
|
+
# Save the temporary UserID for use in the next request
|
|
893
|
+
temp_user_id = ack['Payload']['SMB'].v['UserID']
|
|
894
|
+
|
|
895
|
+
# Get default data
|
|
896
|
+
blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(blob)
|
|
897
|
+
self.challenge_key = blob_data[:challenge_key]
|
|
898
|
+
server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
|
|
899
|
+
#netbios name
|
|
900
|
+
self.default_name = blob_data[:default_name] || ''
|
|
901
|
+
#netbios domain
|
|
902
|
+
self.default_domain = blob_data[:default_domain] || ''
|
|
903
|
+
#dns name
|
|
904
|
+
self.dns_host_name = blob_data[:dns_host_name] || ''
|
|
905
|
+
#dns domain
|
|
906
|
+
self.dns_domain_name = blob_data[:dns_domain_name] || ''
|
|
907
|
+
#Client time
|
|
908
|
+
chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || ''
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(user, pass, self.challenge_key, domain,
|
|
912
|
+
default_name, default_domain, dns_host_name,
|
|
913
|
+
dns_domain_name, chall_MsvAvTimestamp ,
|
|
914
|
+
self.spnopt, ntlm_options)
|
|
915
|
+
enc_session_key = ''
|
|
916
|
+
self.sequence_counter = 0
|
|
917
|
+
|
|
918
|
+
if self.require_signing
|
|
919
|
+
self.signing_key, enc_session_key, ntlmssp_flags = NTLM_UTILS.create_session_key(ntlmssp_flags, server_ntlmssp_flags, user, pass, domain,
|
|
920
|
+
self.challenge_key, client_challenge, ntlm_cli_challenge,
|
|
921
|
+
ntlm_options)
|
|
922
|
+
end
|
|
923
|
+
|
|
924
|
+
# Create the security blob data
|
|
925
|
+
blob = NTLM_UTILS.make_ntlmssp_secblob_auth(domain, name, user, resp_lm, resp_ntlm, enc_session_key, ntlmssp_flags)
|
|
926
|
+
|
|
927
|
+
pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
|
|
928
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
929
|
+
|
|
930
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
931
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
932
|
+
if self.require_signing
|
|
933
|
+
#ascii
|
|
934
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
935
|
+
else
|
|
936
|
+
#ascii
|
|
937
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
938
|
+
end
|
|
939
|
+
pkt['Payload']['SMB'].v['WordCount'] = 12
|
|
940
|
+
pkt['Payload']['SMB'].v['UserID'] = temp_user_id
|
|
941
|
+
pkt['Payload'].v['AndX'] = 255
|
|
942
|
+
pkt['Payload'].v['MaxBuff'] = 0xffdf
|
|
943
|
+
pkt['Payload'].v['MaxMPX'] = 2
|
|
944
|
+
pkt['Payload'].v['VCNum'] = 1
|
|
945
|
+
pkt['Payload'].v['Capabilities'] = 0x8000d05c
|
|
946
|
+
pkt['Payload'].v['SessionKey'] = self.session_id
|
|
947
|
+
pkt['Payload'].v['SecurityBlobLen'] = blob.length
|
|
948
|
+
pkt['Payload'].v['Payload'] = blob + native_data
|
|
949
|
+
|
|
950
|
+
# NOTE: if do_recv is set to false, we cant reach here...
|
|
951
|
+
self.smb_send(pkt.to_s)
|
|
952
|
+
|
|
953
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, true)
|
|
954
|
+
|
|
955
|
+
# Make sure that authentication succeeded
|
|
956
|
+
if (ack['Payload']['SMB'].v['ErrorClass'] != 0)
|
|
957
|
+
|
|
958
|
+
if (user.length == 0)
|
|
959
|
+
# Ensure that signing is disabled when we hit this corner case
|
|
960
|
+
self.require_signing = false
|
|
961
|
+
|
|
962
|
+
# Fall back to the non-ntlmssp authentication method
|
|
963
|
+
return self.session_setup_no_ntlmssp(user, pass, domain)
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
failure = XCEPT::ErrorCode.new
|
|
967
|
+
failure.word_count = ack['Payload']['SMB'].v['WordCount']
|
|
968
|
+
failure.command = ack['Payload']['SMB'].v['Command']
|
|
969
|
+
failure.error_code = ack['Payload']['SMB'].v['ErrorClass']
|
|
970
|
+
raise failure
|
|
971
|
+
end
|
|
972
|
+
|
|
973
|
+
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
|
974
|
+
|
|
975
|
+
if (ack['Payload'].v['Action'] != 1 and user.length > 0)
|
|
976
|
+
self.auth_user = user
|
|
977
|
+
end
|
|
978
|
+
|
|
979
|
+
return ack
|
|
980
|
+
end
|
|
981
|
+
|
|
982
|
+
|
|
983
|
+
# An exploit helper function for sending arbitrary SPNEGO blobs
|
|
984
|
+
def session_setup_with_ntlmssp_blob(blob = '', do_recv = true, userid = 0)
|
|
985
|
+
native_data = ''
|
|
986
|
+
native_data << self.native_os + "\x00"
|
|
987
|
+
native_data << self.native_lm + "\x00"
|
|
988
|
+
|
|
989
|
+
pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
|
|
990
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
991
|
+
|
|
992
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
993
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
994
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
995
|
+
pkt['Payload']['SMB'].v['WordCount'] = 12
|
|
996
|
+
pkt['Payload']['SMB'].v['UserID'] = userid
|
|
997
|
+
pkt['Payload'].v['AndX'] = 255
|
|
998
|
+
pkt['Payload'].v['MaxBuff'] = 0xffdf
|
|
999
|
+
pkt['Payload'].v['MaxMPX'] = 2
|
|
1000
|
+
pkt['Payload'].v['VCNum'] = 1
|
|
1001
|
+
pkt['Payload'].v['SecurityBlobLen'] = blob.length
|
|
1002
|
+
pkt['Payload'].v['Capabilities'] = 0x8000d05c
|
|
1003
|
+
pkt['Payload'].v['SessionKey'] = self.session_id
|
|
1004
|
+
pkt['Payload'].v['Payload'] = blob + native_data
|
|
1005
|
+
|
|
1006
|
+
ret = self.smb_send(pkt.to_s)
|
|
1007
|
+
return ret if not do_recv
|
|
1008
|
+
|
|
1009
|
+
self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, false)
|
|
1010
|
+
end
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
# Authenticate using extended security negotiation (NTLMSSP), but stop half-way, using the temporary ID
|
|
1014
|
+
def session_setup_with_ntlmssp_temp(domain = '', name = nil, do_recv = true)
|
|
1015
|
+
|
|
1016
|
+
if (name == nil)
|
|
1017
|
+
name = Rex::Text.rand_text_alphanumeric(16)
|
|
1018
|
+
end
|
|
1019
|
+
|
|
1020
|
+
blob = NTLM_UTILS.make_ntlmssp_secblob_init(domain, name)
|
|
1021
|
+
|
|
1022
|
+
native_data = ''
|
|
1023
|
+
native_data << self.native_os + "\x00"
|
|
1024
|
+
native_data << self.native_lm + "\x00"
|
|
1025
|
+
|
|
1026
|
+
pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
|
|
1027
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1028
|
+
|
|
1029
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
|
1030
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1031
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1032
|
+
pkt['Payload']['SMB'].v['WordCount'] = 12
|
|
1033
|
+
pkt['Payload'].v['AndX'] = 255
|
|
1034
|
+
pkt['Payload'].v['MaxBuff'] = 0xffdf
|
|
1035
|
+
pkt['Payload'].v['MaxMPX'] = 2
|
|
1036
|
+
pkt['Payload'].v['VCNum'] = 1
|
|
1037
|
+
pkt['Payload'].v['SecurityBlobLen'] = blob.length
|
|
1038
|
+
pkt['Payload'].v['Capabilities'] = 0x8000d05c
|
|
1039
|
+
pkt['Payload'].v['SessionKey'] = self.session_id
|
|
1040
|
+
pkt['Payload'].v['Payload'] = blob + native_data
|
|
1041
|
+
|
|
1042
|
+
ret = self.smb_send(pkt.to_s)
|
|
1043
|
+
return ret if not do_recv
|
|
1044
|
+
|
|
1045
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, true)
|
|
1046
|
+
|
|
1047
|
+
# The server doesn't know about NTLM_NEGOTIATE, try ntlmv1
|
|
1048
|
+
if (ack['Payload']['SMB'].v['ErrorClass'] == 0x00020002)
|
|
1049
|
+
return session_setup_no_ntlmssp(user, pass, domain)
|
|
1050
|
+
end
|
|
1051
|
+
|
|
1052
|
+
# Make sure the error code tells us to continue processing
|
|
1053
|
+
if (ack['Payload']['SMB'].v['ErrorClass'] != 0xc0000016)
|
|
1054
|
+
failure = XCEPT::ErrorCode.new
|
|
1055
|
+
failure.word_count = ack['Payload']['SMB'].v['WordCount']
|
|
1056
|
+
failure.command = ack['Payload']['SMB'].v['Command']
|
|
1057
|
+
failure.error_code = ack['Payload']['SMB'].v['ErrorClass']
|
|
1058
|
+
raise failure
|
|
1059
|
+
end
|
|
1060
|
+
|
|
1061
|
+
# Extract the SecurityBlob from the response
|
|
1062
|
+
data = ack['Payload'].v['Payload']
|
|
1063
|
+
blob = data.slice!(0, ack['Payload'].v['SecurityBlobLen'])
|
|
1064
|
+
|
|
1065
|
+
# Extract the native lanman and os strings
|
|
1066
|
+
info = data.split(/\x00/n)
|
|
1067
|
+
self.peer_native_os = info[0]
|
|
1068
|
+
self.peer_native_lm = info[1]
|
|
1069
|
+
|
|
1070
|
+
# Save the temporary UserID for use in the next request
|
|
1071
|
+
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
|
1072
|
+
|
|
1073
|
+
# Extract the NTLM challenge key the lazy way
|
|
1074
|
+
cidx = blob.index("NTLMSSP\x00\x02\x00\x00\x00")
|
|
1075
|
+
|
|
1076
|
+
if (cidx == -1)
|
|
1077
|
+
raise XCEPT::NTLM2MissingChallenge
|
|
1078
|
+
end
|
|
1079
|
+
|
|
1080
|
+
# Store the challenge key
|
|
1081
|
+
self.challenge_key = blob[cidx + 24, 8]
|
|
1082
|
+
|
|
1083
|
+
return ack
|
|
1084
|
+
end
|
|
1085
|
+
|
|
1086
|
+
# Connect to a specified share with an optional password
|
|
1087
|
+
def tree_connect(share = 'IPC$', pass = '', do_recv = true)
|
|
1088
|
+
|
|
1089
|
+
data = [ pass, share, '?????' ].collect{ |a| a + "\x00" }.join('');
|
|
1090
|
+
|
|
1091
|
+
pkt = CONST::SMB_TREE_CONN_PKT.make_struct
|
|
1092
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1093
|
+
pkt['Payload']['SMB'].v['TreeID'] = 0
|
|
1094
|
+
|
|
1095
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TREE_CONNECT_ANDX
|
|
1096
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1097
|
+
if self.require_signing
|
|
1098
|
+
#ascii
|
|
1099
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
1100
|
+
else
|
|
1101
|
+
#ascii
|
|
1102
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1103
|
+
end
|
|
1104
|
+
|
|
1105
|
+
pkt['Payload']['SMB'].v['WordCount'] = 4
|
|
1106
|
+
pkt['Payload'].v['AndX'] = 255
|
|
1107
|
+
pkt['Payload'].v['PasswordLen'] = pass.length + 1
|
|
1108
|
+
pkt['Payload'].v['Capabilities'] = 64
|
|
1109
|
+
pkt['Payload'].v['Payload'] = data
|
|
1110
|
+
|
|
1111
|
+
ret = self.smb_send(pkt.to_s)
|
|
1112
|
+
return ret if not do_recv
|
|
1113
|
+
|
|
1114
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_TREE_CONNECT_ANDX)
|
|
1115
|
+
|
|
1116
|
+
self.last_tree_id = ack['Payload']['SMB'].v['TreeID']
|
|
1117
|
+
# why bother?
|
|
1118
|
+
# info = ack['Payload'].v['Payload'].split(/\x00/)
|
|
1119
|
+
|
|
1120
|
+
return ack
|
|
1121
|
+
end
|
|
1122
|
+
|
|
1123
|
+
# Disconnect from the current tree
|
|
1124
|
+
def tree_disconnect(tree_id = self.last_tree_id, do_recv = true)
|
|
1125
|
+
|
|
1126
|
+
pkt = CONST::SMB_TREE_DISCONN_PKT.make_struct
|
|
1127
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1128
|
+
|
|
1129
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TREE_DISCONNECT
|
|
1130
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1131
|
+
if self.require_signing
|
|
1132
|
+
#ascii
|
|
1133
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
1134
|
+
else
|
|
1135
|
+
#ascii
|
|
1136
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1137
|
+
end
|
|
1138
|
+
|
|
1139
|
+
pkt['Payload']['SMB'].v['WordCount'] = 0
|
|
1140
|
+
pkt['Payload']['SMB'].v['TreeID'] = tree_id
|
|
1141
|
+
|
|
1142
|
+
ret = self.smb_send(pkt.to_s)
|
|
1143
|
+
return ret if not do_recv
|
|
1144
|
+
|
|
1145
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_TREE_DISCONNECT)
|
|
1146
|
+
|
|
1147
|
+
if (tree_id == self.last_tree_id)
|
|
1148
|
+
self.last_tree_id = 0
|
|
1149
|
+
end
|
|
1150
|
+
|
|
1151
|
+
return ack
|
|
1152
|
+
end
|
|
1153
|
+
|
|
1154
|
+
# Returns a SMB_CREATE_RES response for a given named pipe
|
|
1155
|
+
def create_pipe(filename, disposition = 1, impersonation = 2)
|
|
1156
|
+
self.create(filename)
|
|
1157
|
+
end
|
|
1158
|
+
|
|
1159
|
+
# Creates a file or opens an existing pipe
|
|
1160
|
+
def create(filename, disposition = 1, impersonation = 2, do_recv = true)
|
|
1161
|
+
|
|
1162
|
+
pkt = CONST::SMB_CREATE_PKT.make_struct
|
|
1163
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1164
|
+
|
|
1165
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_CREATE_ANDX
|
|
1166
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1167
|
+
if self.require_signing
|
|
1168
|
+
#ascii
|
|
1169
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
1170
|
+
else
|
|
1171
|
+
#ascii
|
|
1172
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1173
|
+
end
|
|
1174
|
+
|
|
1175
|
+
pkt['Payload']['SMB'].v['WordCount'] = 24
|
|
1176
|
+
|
|
1177
|
+
pkt['Payload'].v['AndX'] = 255
|
|
1178
|
+
pkt['Payload'].v['FileNameLen'] = filename.length
|
|
1179
|
+
pkt['Payload'].v['CreateFlags'] = 0x16
|
|
1180
|
+
pkt['Payload'].v['AccessMask'] = 0x02000000 # Maximum Allowed
|
|
1181
|
+
pkt['Payload'].v['ShareAccess'] = 7
|
|
1182
|
+
pkt['Payload'].v['CreateOptions'] = 0
|
|
1183
|
+
pkt['Payload'].v['Impersonation'] = impersonation
|
|
1184
|
+
pkt['Payload'].v['Disposition'] = disposition
|
|
1185
|
+
pkt['Payload'].v['Payload'] = filename + "\x00"
|
|
1186
|
+
|
|
1187
|
+
ret = self.smb_send(pkt.to_s)
|
|
1188
|
+
return ret if not do_recv
|
|
1189
|
+
|
|
1190
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_NT_CREATE_ANDX)
|
|
1191
|
+
|
|
1192
|
+
# Save off the FileID
|
|
1193
|
+
if (ack['Payload'].v['FileID'] > 0)
|
|
1194
|
+
self.last_file_id = ack['Payload'].v['FileID']
|
|
1195
|
+
end
|
|
1196
|
+
|
|
1197
|
+
return ack
|
|
1198
|
+
end
|
|
1199
|
+
|
|
1200
|
+
# Deletes a file from a share
|
|
1201
|
+
def delete(filename, tree_id = self.last_tree_id, do_recv = true)
|
|
1202
|
+
|
|
1203
|
+
pkt = CONST::SMB_DELETE_PKT.make_struct
|
|
1204
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1205
|
+
|
|
1206
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_DELETE
|
|
1207
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1208
|
+
if self.require_signing
|
|
1209
|
+
#ascii
|
|
1210
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
1211
|
+
else
|
|
1212
|
+
#ascii
|
|
1213
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1214
|
+
end
|
|
1215
|
+
|
|
1216
|
+
pkt['Payload']['SMB'].v['TreeID'] = tree_id
|
|
1217
|
+
pkt['Payload']['SMB'].v['WordCount'] = 1
|
|
1218
|
+
|
|
1219
|
+
pkt['Payload'].v['SearchAttributes'] = 0x06
|
|
1220
|
+
pkt['Payload'].v['BufferFormat'] = 4
|
|
1221
|
+
pkt['Payload'].v['Payload'] = filename + "\x00"
|
|
1222
|
+
|
|
1223
|
+
ret = self.smb_send(pkt.to_s)
|
|
1224
|
+
return ret if not do_recv
|
|
1225
|
+
|
|
1226
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_DELETE)
|
|
1227
|
+
|
|
1228
|
+
return ack
|
|
1229
|
+
end
|
|
1230
|
+
|
|
1231
|
+
# Opens an existing file or creates a new one
|
|
1232
|
+
def open(filename, mode = 0x12, access = 0x42, do_recv = true)
|
|
1233
|
+
|
|
1234
|
+
pkt = CONST::SMB_OPEN_PKT.make_struct
|
|
1235
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1236
|
+
|
|
1237
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_OPEN_ANDX
|
|
1238
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1239
|
+
if self.require_signing
|
|
1240
|
+
#ascii
|
|
1241
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
1242
|
+
else
|
|
1243
|
+
#ascii
|
|
1244
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1245
|
+
end
|
|
1246
|
+
|
|
1247
|
+
pkt['Payload']['SMB'].v['WordCount'] = 15
|
|
1248
|
+
|
|
1249
|
+
pkt['Payload'].v['AndX'] = 255
|
|
1250
|
+
pkt['Payload'].v['Access'] = access
|
|
1251
|
+
pkt['Payload'].v['SearchAttributes'] = 0x06
|
|
1252
|
+
pkt['Payload'].v['OpenFunction'] = mode
|
|
1253
|
+
pkt['Payload'].v['Payload'] = filename + "\x00"
|
|
1254
|
+
|
|
1255
|
+
ret = self.smb_send(pkt.to_s)
|
|
1256
|
+
return ret if not do_recv
|
|
1257
|
+
|
|
1258
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_OPEN_ANDX)
|
|
1259
|
+
|
|
1260
|
+
# Save off the FileID
|
|
1261
|
+
if (ack['Payload'].v['FileID'] > 0)
|
|
1262
|
+
self.last_file_id = ack['Payload'].v['FileID']
|
|
1263
|
+
end
|
|
1264
|
+
|
|
1265
|
+
return ack
|
|
1266
|
+
end
|
|
1267
|
+
|
|
1268
|
+
# Closes an open file handle
|
|
1269
|
+
def close(file_id = self.last_file_id, tree_id = self.last_tree_id, do_recv = true)
|
|
1270
|
+
|
|
1271
|
+
pkt = CONST::SMB_CLOSE_PKT.make_struct
|
|
1272
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1273
|
+
|
|
1274
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_CLOSE
|
|
1275
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1276
|
+
if self.require_signing
|
|
1277
|
+
#ascii
|
|
1278
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
1279
|
+
else
|
|
1280
|
+
#ascii
|
|
1281
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1282
|
+
end
|
|
1283
|
+
|
|
1284
|
+
pkt['Payload']['SMB'].v['TreeID'] = tree_id
|
|
1285
|
+
pkt['Payload']['SMB'].v['WordCount'] = 3
|
|
1286
|
+
|
|
1287
|
+
pkt['Payload'].v['FileID'] = file_id
|
|
1288
|
+
pkt['Payload'].v['LastWrite'] = -1
|
|
1289
|
+
|
|
1290
|
+
ret = self.smb_send(pkt.to_s)
|
|
1291
|
+
return ret if not do_recv
|
|
1292
|
+
|
|
1293
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_CLOSE)
|
|
1294
|
+
|
|
1295
|
+
return ack
|
|
1296
|
+
end
|
|
1297
|
+
|
|
1298
|
+
# Writes data to an open file handle
|
|
1299
|
+
def write(file_id = self.last_file_id, offset = 0, data = '', do_recv = true)
|
|
1300
|
+
pkt = CONST::SMB_WRITE_PKT.make_struct
|
|
1301
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1302
|
+
|
|
1303
|
+
data_offset = pkt.to_s.length - 4
|
|
1304
|
+
|
|
1305
|
+
filler = EVADE.make_offset_filler(evasion_opts['pad_data'], 4096 - data.length - data_offset)
|
|
1306
|
+
|
|
1307
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_WRITE_ANDX
|
|
1308
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1309
|
+
if self.require_signing
|
|
1310
|
+
#ascii
|
|
1311
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2805
|
|
1312
|
+
else
|
|
1313
|
+
#ascii
|
|
1314
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1315
|
+
end
|
|
1316
|
+
|
|
1317
|
+
pkt['Payload']['SMB'].v['WordCount'] = 14
|
|
1318
|
+
|
|
1319
|
+
pkt['Payload'].v['AndX'] = 255
|
|
1320
|
+
pkt['Payload'].v['FileID'] = file_id
|
|
1321
|
+
pkt['Payload'].v['Offset'] = offset
|
|
1322
|
+
pkt['Payload'].v['Reserved2'] = -1
|
|
1323
|
+
pkt['Payload'].v['WriteMode'] = 8
|
|
1324
|
+
pkt['Payload'].v['Remaining'] = data.length
|
|
1325
|
+
# pkt['Payload'].v['DataLenHigh'] = (data.length / 65536).to_i
|
|
1326
|
+
pkt['Payload'].v['DataLenLow'] = (data.length % 65536).to_i
|
|
1327
|
+
pkt['Payload'].v['DataOffset'] = data_offset + filler.length
|
|
1328
|
+
pkt['Payload'].v['Payload'] = filler + data
|
|
1329
|
+
|
|
1330
|
+
ret = self.smb_send(pkt.to_s)
|
|
1331
|
+
return ret if not do_recv
|
|
1332
|
+
|
|
1333
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_WRITE_ANDX)
|
|
1334
|
+
|
|
1335
|
+
return ack
|
|
1336
|
+
end
|
|
1337
|
+
|
|
1338
|
+
|
|
1339
|
+
# Reads data from an open file handle
|
|
1340
|
+
def read(file_id = self.last_file_id, offset = 0, data_length = 64000, do_recv = true)
|
|
1341
|
+
|
|
1342
|
+
pkt = CONST::SMB_READ_PKT.make_struct
|
|
1343
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1344
|
+
|
|
1345
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_READ_ANDX
|
|
1346
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1347
|
+
if self.require_signing
|
|
1348
|
+
#ascii
|
|
1349
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
1350
|
+
else
|
|
1351
|
+
#ascii
|
|
1352
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1353
|
+
end
|
|
1354
|
+
|
|
1355
|
+
pkt['Payload']['SMB'].v['WordCount'] = 10
|
|
1356
|
+
|
|
1357
|
+
pkt['Payload'].v['AndX'] = 255
|
|
1358
|
+
pkt['Payload'].v['FileID'] = file_id
|
|
1359
|
+
pkt['Payload'].v['Offset'] = offset
|
|
1360
|
+
# pkt['Payload'].v['MaxCountHigh'] = (data_length / 65536).to_i
|
|
1361
|
+
pkt['Payload'].v['MaxCountLow'] = (data_length % 65536).to_i
|
|
1362
|
+
pkt['Payload'].v['MinCount'] = data_length
|
|
1363
|
+
pkt['Payload'].v['Reserved2'] = -1
|
|
1364
|
+
|
|
1365
|
+
ret = self.smb_send(pkt.to_s)
|
|
1366
|
+
return ret if not do_recv
|
|
1367
|
+
|
|
1368
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_READ_ANDX, true)
|
|
1369
|
+
|
|
1370
|
+
err = ack['Payload']['SMB'].v['ErrorClass']
|
|
1371
|
+
|
|
1372
|
+
# Catch some non-fatal error codes
|
|
1373
|
+
if (err != 0 && err != CONST::SMB_ERROR_BUFFER_OVERFLOW)
|
|
1374
|
+
failure = XCEPT::ErrorCode.new
|
|
1375
|
+
failure.word_count = ack['Payload']['SMB'].v['WordCount']
|
|
1376
|
+
failure.command = ack['Payload']['SMB'].v['Command']
|
|
1377
|
+
failure.error_code = ack['Payload']['SMB'].v['ErrorClass']
|
|
1378
|
+
raise failure
|
|
1379
|
+
end
|
|
1380
|
+
|
|
1381
|
+
return ack
|
|
1382
|
+
end
|
|
1383
|
+
|
|
1384
|
+
|
|
1385
|
+
# Perform a transaction against a named pipe
|
|
1386
|
+
def trans_named_pipe(file_id, data = '', no_response = nil)
|
|
1387
|
+
pipe = EVADE.make_trans_named_pipe_name(evasion_opts['pad_file'])
|
|
1388
|
+
self.trans(pipe, '', data, 2, [0x26, file_id].pack('vv'), no_response)
|
|
1389
|
+
end
|
|
1390
|
+
|
|
1391
|
+
# Perform a mailslot write over SMB
|
|
1392
|
+
# Warning: This can kill srv.sys unless MS06-035 is applied
|
|
1393
|
+
def trans_mailslot (name, data = '')
|
|
1394
|
+
# Setup data must be:
|
|
1395
|
+
# Operation: 1 (write)
|
|
1396
|
+
# Priority: 0
|
|
1397
|
+
# Class: Reliable
|
|
1398
|
+
self.trans_maxzero(name, '', data, 3, [1, 0, 1].pack('vvv'), true )
|
|
1399
|
+
end
|
|
1400
|
+
|
|
1401
|
+
# Perform a transaction against a given pipe name
|
|
1402
|
+
def trans(pipe, param = '', body = '', setup_count = 0, setup_data = '', no_response = false, do_recv = true)
|
|
1403
|
+
|
|
1404
|
+
# Null-terminate the pipe parameter if needed
|
|
1405
|
+
if (pipe[-1,1] != "\x00")
|
|
1406
|
+
pipe << "\x00"
|
|
1407
|
+
end
|
|
1408
|
+
|
|
1409
|
+
pkt = CONST::SMB_TRANS_PKT.make_struct
|
|
1410
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1411
|
+
|
|
1412
|
+
# Packets larger than mlen will cause XP SP2 to disconnect us ;-(
|
|
1413
|
+
mlen = 4200
|
|
1414
|
+
|
|
1415
|
+
# Figure out how much space is taken up by our current arguments
|
|
1416
|
+
xlen = pipe.length + param.length + body.length
|
|
1417
|
+
|
|
1418
|
+
filler1 = ''
|
|
1419
|
+
filler2 = ''
|
|
1420
|
+
|
|
1421
|
+
# Fill any available space depending on the evasion settings
|
|
1422
|
+
if (xlen < mlen)
|
|
1423
|
+
filler1 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
|
|
1424
|
+
filler2 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
|
|
1425
|
+
end
|
|
1426
|
+
|
|
1427
|
+
# Squish the whole thing together
|
|
1428
|
+
data = pipe + filler1 + param + filler2 + body
|
|
1429
|
+
|
|
1430
|
+
# Throw some form of a warning out?
|
|
1431
|
+
if (data.length > mlen)
|
|
1432
|
+
# XXX This call will more than likely fail :-(
|
|
1433
|
+
end
|
|
1434
|
+
|
|
1435
|
+
# Calculate all of the offsets
|
|
1436
|
+
base_offset = pkt.to_s.length + (setup_count * 2) - 4
|
|
1437
|
+
param_offset = base_offset + pipe.length + filler1.length
|
|
1438
|
+
data_offset = param_offset + filler2.length + param.length
|
|
1439
|
+
|
|
1440
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION
|
|
1441
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1442
|
+
if self.require_signing
|
|
1443
|
+
#ascii
|
|
1444
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
1445
|
+
else
|
|
1446
|
+
#ascii
|
|
1447
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1448
|
+
end
|
|
1449
|
+
|
|
1450
|
+
pkt['Payload']['SMB'].v['WordCount'] = 14 + setup_count
|
|
1451
|
+
|
|
1452
|
+
pkt['Payload'].v['ParamCountTotal'] = param.length
|
|
1453
|
+
pkt['Payload'].v['DataCountTotal'] = body.length
|
|
1454
|
+
pkt['Payload'].v['ParamCountMax'] = 1024
|
|
1455
|
+
pkt['Payload'].v['DataCountMax'] = 65000
|
|
1456
|
+
pkt['Payload'].v['ParamCount'] = param.length
|
|
1457
|
+
pkt['Payload'].v['ParamOffset'] = param_offset
|
|
1458
|
+
pkt['Payload'].v['DataCount'] = body.length
|
|
1459
|
+
pkt['Payload'].v['DataOffset'] = data_offset
|
|
1460
|
+
pkt['Payload'].v['SetupCount'] = setup_count
|
|
1461
|
+
pkt['Payload'].v['SetupData'] = setup_data
|
|
1462
|
+
|
|
1463
|
+
pkt['Payload'].v['Payload'] = data
|
|
1464
|
+
|
|
1465
|
+
if no_response
|
|
1466
|
+
pkt['Payload'].v['Flags'] = 2
|
|
1467
|
+
end
|
|
1468
|
+
|
|
1469
|
+
ret = self.smb_send(pkt.to_s)
|
|
1470
|
+
return ret if no_response or not do_recv
|
|
1471
|
+
|
|
1472
|
+
self.smb_recv_parse(CONST::SMB_COM_TRANSACTION)
|
|
1473
|
+
end
|
|
1474
|
+
|
|
1475
|
+
|
|
1476
|
+
|
|
1477
|
+
# Perform a transaction against a given pipe name
|
|
1478
|
+
# Difference from trans: sets MaxParam/MaxData to zero
|
|
1479
|
+
# This is required to trigger mailslot bug :-(
|
|
1480
|
+
def trans_maxzero(pipe, param = '', body = '', setup_count = 0, setup_data = '', no_response = false, do_recv = true)
|
|
1481
|
+
|
|
1482
|
+
# Null-terminate the pipe parameter if needed
|
|
1483
|
+
if (pipe[-1] != 0)
|
|
1484
|
+
pipe << "\x00"
|
|
1485
|
+
end
|
|
1486
|
+
|
|
1487
|
+
pkt = CONST::SMB_TRANS_PKT.make_struct
|
|
1488
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1489
|
+
|
|
1490
|
+
# Packets larger than mlen will cause XP SP2 to disconnect us ;-(
|
|
1491
|
+
mlen = 4200
|
|
1492
|
+
|
|
1493
|
+
# Figure out how much space is taken up by our current arguments
|
|
1494
|
+
xlen = pipe.length + param.length + body.length
|
|
1495
|
+
|
|
1496
|
+
filler1 = ''
|
|
1497
|
+
filler2 = ''
|
|
1498
|
+
|
|
1499
|
+
# Fill any available space depending on the evasion settings
|
|
1500
|
+
if (xlen < mlen)
|
|
1501
|
+
filler1 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
|
|
1502
|
+
filler2 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
|
|
1503
|
+
end
|
|
1504
|
+
|
|
1505
|
+
# Squish the whole thing together
|
|
1506
|
+
data = pipe + filler1 + param + filler2 + body
|
|
1507
|
+
|
|
1508
|
+
# Throw some form of a warning out?
|
|
1509
|
+
if (data.length > mlen)
|
|
1510
|
+
# XXX This call will more than likely fail :-(
|
|
1511
|
+
end
|
|
1512
|
+
|
|
1513
|
+
# Calculate all of the offsets
|
|
1514
|
+
base_offset = pkt.to_s.length + (setup_count * 2) - 4
|
|
1515
|
+
param_offset = base_offset + pipe.length + filler1.length
|
|
1516
|
+
data_offset = param_offset + filler2.length + param.length
|
|
1517
|
+
|
|
1518
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION
|
|
1519
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1520
|
+
if self.require_signing
|
|
1521
|
+
#ascii
|
|
1522
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
1523
|
+
else
|
|
1524
|
+
#ascii
|
|
1525
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1526
|
+
end
|
|
1527
|
+
|
|
1528
|
+
pkt['Payload']['SMB'].v['WordCount'] = 14 + setup_count
|
|
1529
|
+
|
|
1530
|
+
pkt['Payload'].v['ParamCountTotal'] = param.length
|
|
1531
|
+
pkt['Payload'].v['DataCountTotal'] = body.length
|
|
1532
|
+
pkt['Payload'].v['ParamCountMax'] = 0
|
|
1533
|
+
pkt['Payload'].v['DataCountMax'] = 0
|
|
1534
|
+
pkt['Payload'].v['ParamCount'] = param.length
|
|
1535
|
+
pkt['Payload'].v['ParamOffset'] = param_offset
|
|
1536
|
+
pkt['Payload'].v['DataCount'] = body.length
|
|
1537
|
+
pkt['Payload'].v['DataOffset'] = data_offset
|
|
1538
|
+
pkt['Payload'].v['SetupCount'] = setup_count
|
|
1539
|
+
pkt['Payload'].v['SetupData'] = setup_data
|
|
1540
|
+
|
|
1541
|
+
pkt['Payload'].v['Payload'] = data
|
|
1542
|
+
|
|
1543
|
+
if no_response
|
|
1544
|
+
pkt['Payload'].v['Flags'] = 2
|
|
1545
|
+
end
|
|
1546
|
+
|
|
1547
|
+
ret = self.smb_send(pkt.to_s)
|
|
1548
|
+
return ret if no_response or not do_recv
|
|
1549
|
+
|
|
1550
|
+
self.smb_recv_parse(CONST::SMB_COM_TRANSACTION)
|
|
1551
|
+
end
|
|
1552
|
+
|
|
1553
|
+
|
|
1554
|
+
# Perform a transaction against a given pipe name (no null terminator)
|
|
1555
|
+
def trans_nonull(pipe, param = '', body = '', setup_count = 0, setup_data = '', no_response = false, do_recv = true)
|
|
1556
|
+
|
|
1557
|
+
pkt = CONST::SMB_TRANS_PKT.make_struct
|
|
1558
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1559
|
+
|
|
1560
|
+
# Packets larger than mlen will cause XP SP2 to disconnect us ;-(
|
|
1561
|
+
mlen = 4200
|
|
1562
|
+
|
|
1563
|
+
# Figure out how much space is taken up by our current arguments
|
|
1564
|
+
xlen = pipe.length + param.length + body.length
|
|
1565
|
+
|
|
1566
|
+
filler1 = ''
|
|
1567
|
+
filler2 = ''
|
|
1568
|
+
|
|
1569
|
+
# Fill any available space depending on the evasion settings
|
|
1570
|
+
if (xlen < mlen)
|
|
1571
|
+
filler1 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
|
|
1572
|
+
filler2 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
|
|
1573
|
+
end
|
|
1574
|
+
|
|
1575
|
+
# Squish the whole thing together
|
|
1576
|
+
data = pipe + filler1 + param + filler2 + body
|
|
1577
|
+
|
|
1578
|
+
# Throw some form of a warning out?
|
|
1579
|
+
if (data.length > mlen)
|
|
1580
|
+
# XXX This call will more than likely fail :-(
|
|
1581
|
+
end
|
|
1582
|
+
|
|
1583
|
+
# Calculate all of the offsets
|
|
1584
|
+
base_offset = pkt.to_s.length + (setup_count * 2) - 4
|
|
1585
|
+
param_offset = base_offset + pipe.length + filler1.length
|
|
1586
|
+
data_offset = param_offset + filler2.length + param.length
|
|
1587
|
+
|
|
1588
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION
|
|
1589
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1590
|
+
if self.require_signing
|
|
1591
|
+
#ascii
|
|
1592
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
1593
|
+
else
|
|
1594
|
+
#ascii
|
|
1595
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1596
|
+
end
|
|
1597
|
+
|
|
1598
|
+
pkt['Payload']['SMB'].v['WordCount'] = 14 + setup_count
|
|
1599
|
+
|
|
1600
|
+
pkt['Payload'].v['ParamCountTotal'] = param.length
|
|
1601
|
+
pkt['Payload'].v['DataCountTotal'] = body.length
|
|
1602
|
+
pkt['Payload'].v['ParamCountMax'] = 0
|
|
1603
|
+
pkt['Payload'].v['DataCountMax'] = 0
|
|
1604
|
+
pkt['Payload'].v['ParamCount'] = param.length
|
|
1605
|
+
pkt['Payload'].v['ParamOffset'] = param_offset
|
|
1606
|
+
pkt['Payload'].v['DataCount'] = body.length
|
|
1607
|
+
pkt['Payload'].v['DataOffset'] = data_offset
|
|
1608
|
+
pkt['Payload'].v['SetupCount'] = setup_count
|
|
1609
|
+
pkt['Payload'].v['SetupData'] = setup_data
|
|
1610
|
+
|
|
1611
|
+
pkt['Payload'].v['Payload'] = data
|
|
1612
|
+
|
|
1613
|
+
if no_response
|
|
1614
|
+
pkt['Payload'].v['Flags'] = 2
|
|
1615
|
+
end
|
|
1616
|
+
|
|
1617
|
+
ret = self.smb_send(pkt.to_s)
|
|
1618
|
+
return ret if no_response or not do_recv
|
|
1619
|
+
|
|
1620
|
+
self.smb_recv_parse(CONST::SMB_COM_TRANSACTION)
|
|
1621
|
+
end
|
|
1622
|
+
|
|
1623
|
+
# Perform a transaction2 request using the specified subcommand, parameters, and data
|
|
1624
|
+
def trans2(subcommand, param = '', body = '', do_recv = true)
|
|
1625
|
+
|
|
1626
|
+
setup_count = 1
|
|
1627
|
+
setup_data = [subcommand].pack('v')
|
|
1628
|
+
|
|
1629
|
+
data = param + body
|
|
1630
|
+
|
|
1631
|
+
pkt = CONST::SMB_TRANS2_PKT.make_struct
|
|
1632
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1633
|
+
|
|
1634
|
+
base_offset = pkt.to_s.length + (setup_count * 2) - 4
|
|
1635
|
+
param_offset = base_offset
|
|
1636
|
+
data_offset = param_offset + param.length
|
|
1637
|
+
|
|
1638
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION2
|
|
1639
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1640
|
+
if self.require_signing
|
|
1641
|
+
#ascii
|
|
1642
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
1643
|
+
else
|
|
1644
|
+
#ascii
|
|
1645
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1646
|
+
end
|
|
1647
|
+
|
|
1648
|
+
pkt['Payload']['SMB'].v['WordCount'] = 14 + setup_count
|
|
1649
|
+
|
|
1650
|
+
pkt['Payload'].v['ParamCountTotal'] = param.length
|
|
1651
|
+
pkt['Payload'].v['DataCountTotal'] = body.length
|
|
1652
|
+
pkt['Payload'].v['ParamCountMax'] = 1024
|
|
1653
|
+
pkt['Payload'].v['DataCountMax'] = 65000
|
|
1654
|
+
pkt['Payload'].v['ParamCount'] = param.length
|
|
1655
|
+
pkt['Payload'].v['ParamOffset'] = param_offset
|
|
1656
|
+
pkt['Payload'].v['DataCount'] = body.length
|
|
1657
|
+
pkt['Payload'].v['DataOffset'] = data_offset
|
|
1658
|
+
pkt['Payload'].v['SetupCount'] = setup_count
|
|
1659
|
+
pkt['Payload'].v['SetupData'] = setup_data
|
|
1660
|
+
|
|
1661
|
+
pkt['Payload'].v['Payload'] = data
|
|
1662
|
+
|
|
1663
|
+
ret = self.smb_send(pkt.to_s)
|
|
1664
|
+
return ret if not do_recv
|
|
1665
|
+
|
|
1666
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_TRANSACTION2)
|
|
1667
|
+
|
|
1668
|
+
return ack
|
|
1669
|
+
end
|
|
1670
|
+
|
|
1671
|
+
|
|
1672
|
+
# Perform a nttransaction request using the specified subcommand, parameters, and data
|
|
1673
|
+
def nttrans(subcommand, param = '', body = '', setup_count = 0, setup_data = '', do_recv = true)
|
|
1674
|
+
|
|
1675
|
+
data = param + body
|
|
1676
|
+
|
|
1677
|
+
pkt = CONST::SMB_NTTRANS_PKT.make_struct
|
|
1678
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1679
|
+
|
|
1680
|
+
base_offset = pkt.to_s.length + (setup_count * 2) - 4
|
|
1681
|
+
param_offset = base_offset
|
|
1682
|
+
data_offset = param_offset + param.length
|
|
1683
|
+
|
|
1684
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_TRANSACT
|
|
1685
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1686
|
+
if self.require_signing
|
|
1687
|
+
#ascii
|
|
1688
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
1689
|
+
else
|
|
1690
|
+
#ascii
|
|
1691
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1692
|
+
end
|
|
1693
|
+
|
|
1694
|
+
pkt['Payload']['SMB'].v['WordCount'] = 19 + setup_count
|
|
1695
|
+
|
|
1696
|
+
pkt['Payload'].v['ParamCountTotal'] = param.length
|
|
1697
|
+
pkt['Payload'].v['DataCountTotal'] = body.length
|
|
1698
|
+
pkt['Payload'].v['ParamCountMax'] = 1024
|
|
1699
|
+
pkt['Payload'].v['DataCountMax'] = 65000
|
|
1700
|
+
pkt['Payload'].v['ParamCount'] = param.length
|
|
1701
|
+
pkt['Payload'].v['ParamOffset'] = param_offset
|
|
1702
|
+
pkt['Payload'].v['DataCount'] = body.length
|
|
1703
|
+
pkt['Payload'].v['DataOffset'] = data_offset
|
|
1704
|
+
pkt['Payload'].v['SetupCount'] = setup_count
|
|
1705
|
+
pkt['Payload'].v['SetupData'] = setup_data
|
|
1706
|
+
pkt['Payload'].v['Subcommand'] = subcommand
|
|
1707
|
+
|
|
1708
|
+
pkt['Payload'].v['Payload'] = data
|
|
1709
|
+
|
|
1710
|
+
ret = self.smb_send(pkt.to_s)
|
|
1711
|
+
return ret if not do_recv
|
|
1712
|
+
|
|
1713
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_NT_TRANSACT)
|
|
1714
|
+
return ack
|
|
1715
|
+
end
|
|
1716
|
+
|
|
1717
|
+
# Perform a nttransaction request using the specified subcommand, parameters, and data
|
|
1718
|
+
def nttrans_secondary(param = '', body = '', do_recv = true)
|
|
1719
|
+
|
|
1720
|
+
data = param + body
|
|
1721
|
+
|
|
1722
|
+
pkt = CONST::SMB_NTTRANS_SECONDARY_PKT.make_struct
|
|
1723
|
+
self.smb_defaults(pkt['Payload']['SMB'])
|
|
1724
|
+
|
|
1725
|
+
base_offset = pkt.to_s.length - 4
|
|
1726
|
+
param_offset = base_offset
|
|
1727
|
+
data_offset = param_offset + param.length
|
|
1728
|
+
|
|
1729
|
+
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_TRANSACT_SECONDARY
|
|
1730
|
+
pkt['Payload']['SMB'].v['Flags1'] = 0x18
|
|
1731
|
+
if self.require_signing
|
|
1732
|
+
#ascii
|
|
1733
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2807
|
|
1734
|
+
else
|
|
1735
|
+
#ascii
|
|
1736
|
+
pkt['Payload']['SMB'].v['Flags2'] = 0x2801
|
|
1737
|
+
end
|
|
1738
|
+
|
|
1739
|
+
pkt['Payload']['SMB'].v['WordCount'] = 18
|
|
1740
|
+
|
|
1741
|
+
pkt['Payload'].v['ParamCountTotal'] = param.length
|
|
1742
|
+
pkt['Payload'].v['DataCountTotal'] = body.length
|
|
1743
|
+
pkt['Payload'].v['ParamCount'] = param.length
|
|
1744
|
+
pkt['Payload'].v['ParamOffset'] = param_offset
|
|
1745
|
+
pkt['Payload'].v['DataCount'] = body.length
|
|
1746
|
+
pkt['Payload'].v['DataOffset'] = data_offset
|
|
1747
|
+
|
|
1748
|
+
pkt['Payload'].v['Payload'] = data
|
|
1749
|
+
|
|
1750
|
+
ret = self.smb_send(pkt.to_s)
|
|
1751
|
+
return ret if not do_recv
|
|
1752
|
+
|
|
1753
|
+
ack = self.smb_recv_parse(CONST::SMB_COM_NT_TRANSACT_SECONDARY)
|
|
1754
|
+
return ack
|
|
1755
|
+
end
|
|
1756
|
+
|
|
1757
|
+
def queryfs(level)
|
|
1758
|
+
parm = [level].pack('v')
|
|
1759
|
+
|
|
1760
|
+
begin
|
|
1761
|
+
resp = trans2(CONST::TRANS2_QUERY_FS_INFO, parm, '')
|
|
1762
|
+
|
|
1763
|
+
pcnt = resp['Payload'].v['ParamCount']
|
|
1764
|
+
dcnt = resp['Payload'].v['DataCount']
|
|
1765
|
+
poff = resp['Payload'].v['ParamOffset']
|
|
1766
|
+
doff = resp['Payload'].v['DataOffset']
|
|
1767
|
+
|
|
1768
|
+
# Get the raw packet bytes
|
|
1769
|
+
resp_rpkt = resp.to_s
|
|
1770
|
+
|
|
1771
|
+
# Remove the NetBIOS header
|
|
1772
|
+
resp_rpkt.slice!(0, 4)
|
|
1773
|
+
|
|
1774
|
+
resp_parm = resp_rpkt[poff, pcnt]
|
|
1775
|
+
resp_data = resp_rpkt[doff, dcnt]
|
|
1776
|
+
return resp_data
|
|
1777
|
+
|
|
1778
|
+
rescue ::Exception
|
|
1779
|
+
raise $!
|
|
1780
|
+
end
|
|
1781
|
+
end
|
|
1782
|
+
|
|
1783
|
+
def symlink(src,dst)
|
|
1784
|
+
parm = [513, 0x00000000].pack('vV') + src + "\x00"
|
|
1785
|
+
|
|
1786
|
+
begin
|
|
1787
|
+
resp = trans2(CONST::TRANS2_SET_PATH_INFO, parm, dst + "\x00")
|
|
1788
|
+
|
|
1789
|
+
pcnt = resp['Payload'].v['ParamCount']
|
|
1790
|
+
dcnt = resp['Payload'].v['DataCount']
|
|
1791
|
+
poff = resp['Payload'].v['ParamOffset']
|
|
1792
|
+
doff = resp['Payload'].v['DataOffset']
|
|
1793
|
+
|
|
1794
|
+
# Get the raw packet bytes
|
|
1795
|
+
resp_rpkt = resp.to_s
|
|
1796
|
+
|
|
1797
|
+
# Remove the NetBIOS header
|
|
1798
|
+
resp_rpkt.slice!(0, 4)
|
|
1799
|
+
|
|
1800
|
+
resp_parm = resp_rpkt[poff, pcnt]
|
|
1801
|
+
resp_data = resp_rpkt[doff, dcnt]
|
|
1802
|
+
return resp_data
|
|
1803
|
+
|
|
1804
|
+
rescue ::Exception
|
|
1805
|
+
raise $!
|
|
1806
|
+
end
|
|
1807
|
+
end
|
|
1808
|
+
|
|
1809
|
+
# Obtains allocation information on the mounted tree
|
|
1810
|
+
def queryfs_info_allocation
|
|
1811
|
+
data = queryfs(CONST::SMB_INFO_ALLOCATION)
|
|
1812
|
+
head = %w{fs_id sectors_per_unit unit_total units_available bytes_per_sector}
|
|
1813
|
+
vals = data.unpack('VVVVv')
|
|
1814
|
+
info = { }
|
|
1815
|
+
head.each_index {|i| info[head[i]]=vals[i]}
|
|
1816
|
+
return info
|
|
1817
|
+
end
|
|
1818
|
+
|
|
1819
|
+
# Obtains volume information on the mounted tree
|
|
1820
|
+
def queryfs_info_volume
|
|
1821
|
+
data = queryfs(CONST::SMB_INFO_VOLUME)
|
|
1822
|
+
vals = data.unpack('VCA*')
|
|
1823
|
+
return {
|
|
1824
|
+
'serial' => vals[0],
|
|
1825
|
+
'label' => vals[2][0,vals[1]].gsub("\x00", '')
|
|
1826
|
+
}
|
|
1827
|
+
end
|
|
1828
|
+
|
|
1829
|
+
# Obtains file system volume information on the mounted tree
|
|
1830
|
+
def queryfs_fs_volume
|
|
1831
|
+
data = queryfs(CONST::SMB_QUERY_FS_VOLUME_INFO)
|
|
1832
|
+
vals = data.unpack('VVVVCCA*')
|
|
1833
|
+
return {
|
|
1834
|
+
'create_time' => (vals[1] << 32) + vals[0],
|
|
1835
|
+
'serial' => vals[2],
|
|
1836
|
+
'label' => vals[6][0,vals[3]].gsub("\x00", '')
|
|
1837
|
+
}
|
|
1838
|
+
end
|
|
1839
|
+
|
|
1840
|
+
# Obtains file system size information on the mounted tree
|
|
1841
|
+
def queryfs_fs_size
|
|
1842
|
+
data = queryfs(CONST::SMB_QUERY_FS_SIZE_INFO)
|
|
1843
|
+
vals = data.unpack('VVVVVV')
|
|
1844
|
+
return {
|
|
1845
|
+
'total_alloc_units' => (vals[1] << 32) + vals[0],
|
|
1846
|
+
'total_free_units' => (vals[3] << 32) + vals[2],
|
|
1847
|
+
'sectors_per_unit' => vals[4],
|
|
1848
|
+
'bytes_per_sector' => vals[5]
|
|
1849
|
+
}
|
|
1850
|
+
end
|
|
1851
|
+
|
|
1852
|
+
# Obtains file system device information on the mounted tree
|
|
1853
|
+
def queryfs_fs_device
|
|
1854
|
+
data = queryfs(CONST::SMB_QUERY_FS_DEVICE_INFO)
|
|
1855
|
+
vals = data.unpack('VV')
|
|
1856
|
+
return {
|
|
1857
|
+
'device_type' => vals[0],
|
|
1858
|
+
'device_chars' => vals[1],
|
|
1859
|
+
}
|
|
1860
|
+
end
|
|
1861
|
+
|
|
1862
|
+
# Obtains file system attribute information on the mounted tree
|
|
1863
|
+
def queryfs_fs_attribute
|
|
1864
|
+
data = queryfs(CONST::SMB_QUERY_FS_ATTRIBUTE_INFO)
|
|
1865
|
+
vals = data.unpack('VVVA*')
|
|
1866
|
+
return {
|
|
1867
|
+
'fs_attributes' => vals[0],
|
|
1868
|
+
'max_file_name' => vals[1],
|
|
1869
|
+
'fs_name' => vals[3][0, vals[2]].gsub("\x00", '')
|
|
1870
|
+
}
|
|
1871
|
+
end
|
|
1872
|
+
|
|
1873
|
+
# Enumerates a specific path on the mounted tree
|
|
1874
|
+
def find_first(path)
|
|
1875
|
+
files = { }
|
|
1876
|
+
parm = [
|
|
1877
|
+
26, # Search for ALL files
|
|
1878
|
+
20, # Maximum search count
|
|
1879
|
+
6, # Resume and Close on End of Search
|
|
1880
|
+
260, # Level of interest
|
|
1881
|
+
0, # Storage type is zero
|
|
1882
|
+
].pack('vvvvV') + path + "\x00"
|
|
1883
|
+
|
|
1884
|
+
resp = trans2(CONST::TRANS2_FIND_FIRST2, parm, '')
|
|
1885
|
+
search_next = 0
|
|
1886
|
+
|
|
1887
|
+
# Loop until we run out of results
|
|
1888
|
+
loop do
|
|
1889
|
+
pcnt = resp['Payload'].v['ParamCount']
|
|
1890
|
+
dcnt = resp['Payload'].v['DataCount']
|
|
1891
|
+
poff = resp['Payload'].v['ParamOffset']
|
|
1892
|
+
doff = resp['Payload'].v['DataOffset']
|
|
1893
|
+
|
|
1894
|
+
# Get the raw packet bytes
|
|
1895
|
+
resp_rpkt = resp.to_s
|
|
1896
|
+
|
|
1897
|
+
# Remove the NetBIOS header
|
|
1898
|
+
resp_rpkt.slice!(0, 4)
|
|
1899
|
+
|
|
1900
|
+
resp_parm = resp_rpkt[poff, pcnt]
|
|
1901
|
+
resp_data = resp_rpkt[doff, dcnt]
|
|
1902
|
+
|
|
1903
|
+
if search_next == 0
|
|
1904
|
+
# search id, search count, end of search, error offset, last name offset
|
|
1905
|
+
sid, scnt, eos, eoff, loff = resp_parm.unpack('v5')
|
|
1906
|
+
else
|
|
1907
|
+
# FIND_NEXT doesn't return a SID
|
|
1908
|
+
scnt, eos, eoff, loff = resp_parm.unpack('v4')
|
|
1909
|
+
end
|
|
1910
|
+
|
|
1911
|
+
didx = 0
|
|
1912
|
+
while (didx < resp_data.length)
|
|
1913
|
+
info_buff = resp_data[didx, 70]
|
|
1914
|
+
break if info_buff.length != 70
|
|
1915
|
+
|
|
1916
|
+
info = info_buff.unpack(
|
|
1917
|
+
'V'+ # Next Entry Offset
|
|
1918
|
+
'V'+ # File Index
|
|
1919
|
+
'VV'+ # Time Create
|
|
1920
|
+
'VV'+ # Time Last Access
|
|
1921
|
+
'VV'+ # Time Last Write
|
|
1922
|
+
'VV'+ # Time Change
|
|
1923
|
+
'VV'+ # End of File
|
|
1924
|
+
'VV'+ # Allocation Size
|
|
1925
|
+
'V'+ # File Attributes
|
|
1926
|
+
'V'+ # File Name Length
|
|
1927
|
+
'V'+ # Extended Attr List Length
|
|
1928
|
+
'C'+ # Short File Name Length
|
|
1929
|
+
'C' # Reserved
|
|
1930
|
+
)
|
|
1931
|
+
|
|
1932
|
+
name = resp_data[didx + 70 + 24, info[15]]
|
|
1933
|
+
|
|
1934
|
+
# Verify that the filename was actually present
|
|
1935
|
+
break unless name
|
|
1936
|
+
|
|
1937
|
+
# Key the file list minus any trailing nulls
|
|
1938
|
+
files[name.sub(/\x00+$/n, '')] =
|
|
1939
|
+
{
|
|
1940
|
+
'type' => ( info[14] & CONST::SMB_EXT_FILE_ATTR_DIRECTORY == 0 ) ? 'F' : 'D',
|
|
1941
|
+
'attr' => info[14],
|
|
1942
|
+
'info' => info
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
break if info[0] == 0
|
|
1946
|
+
didx += info[0]
|
|
1947
|
+
end
|
|
1948
|
+
|
|
1949
|
+
last_search_id = sid
|
|
1950
|
+
last_offset = loff
|
|
1951
|
+
last_filename = name
|
|
1952
|
+
|
|
1953
|
+
# Exit the search if we reached the end of our results
|
|
1954
|
+
break if (eos != 0 or last_search_id.nil? or last_offset.to_i == 0)
|
|
1955
|
+
|
|
1956
|
+
# If we aren't at the end of the search, run find_next
|
|
1957
|
+
resp = find_next(last_search_id, last_offset, last_filename)
|
|
1958
|
+
|
|
1959
|
+
# Flip bit so response params will parse correctly
|
|
1960
|
+
search_next = 1
|
|
1961
|
+
end
|
|
1962
|
+
|
|
1963
|
+
files
|
|
1964
|
+
end
|
|
1965
|
+
|
|
1966
|
+
# Supplements find_first if file/dir count exceeds max search count
|
|
1967
|
+
def find_next(sid, resume_key, last_filename)
|
|
1968
|
+
|
|
1969
|
+
parm = [
|
|
1970
|
+
sid, # Search ID
|
|
1971
|
+
20, # Maximum search count (Size of 20 keeps response to 1 packet)
|
|
1972
|
+
260, # Level of interest
|
|
1973
|
+
resume_key, # Resume key from previous (Last name offset)
|
|
1974
|
+
6, # Close search if end of search
|
|
1975
|
+
].pack('vvvVv') +
|
|
1976
|
+
last_filename.to_s + # Last filename returned from find_first or find_next
|
|
1977
|
+
"\x00" # Terminate the file name
|
|
1978
|
+
|
|
1979
|
+
# Returns the FIND_NEXT2 response packet for parsing by the find_first function
|
|
1980
|
+
trans2(CONST::TRANS2_FIND_NEXT2, parm, '')
|
|
1981
|
+
end
|
|
1982
|
+
|
|
1983
|
+
# Recursively search for files matching a regular expression
|
|
1984
|
+
def file_search(current_path, regex, depth)
|
|
1985
|
+
depth -= 1
|
|
1986
|
+
return [] if depth < 0
|
|
1987
|
+
|
|
1988
|
+
results = find_first(current_path + "*")
|
|
1989
|
+
files = []
|
|
1990
|
+
|
|
1991
|
+
results.each_pair do |fname, finfo|
|
|
1992
|
+
|
|
1993
|
+
# Skip current and parent directory results
|
|
1994
|
+
next if %W{. ..}.include?(fname)
|
|
1995
|
+
|
|
1996
|
+
# Verify the results contain an attribute
|
|
1997
|
+
next unless finfo and finfo['attr']
|
|
1998
|
+
|
|
1999
|
+
if finfo['attr'] & CONST::SMB_EXT_FILE_ATTR_DIRECTORY == 0
|
|
2000
|
+
# Add any matching files to our result set
|
|
2001
|
+
files << "#{current_path}#{fname}" if fname =~ regex
|
|
2002
|
+
else
|
|
2003
|
+
# Recurse into the discovery subdirectory for more files
|
|
2004
|
+
begin
|
|
2005
|
+
search_path = "#{current_path}#{fname}\\"
|
|
2006
|
+
file_search(search_path, regex, depth).each {|fn| files << fn }
|
|
2007
|
+
rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
|
|
2008
|
+
|
|
2009
|
+
# Ignore common errors related to permissions and non-files
|
|
2010
|
+
if %W{
|
|
2011
|
+
STATUS_ACCESS_DENIED
|
|
2012
|
+
STATUS_NO_SUCH_FILE
|
|
2013
|
+
STATUS_OBJECT_NAME_NOT_FOUND
|
|
2014
|
+
STATUS_OBJECT_PATH_NOT_FOUND
|
|
2015
|
+
}.include? e.get_error(e.error_code)
|
|
2016
|
+
next
|
|
2017
|
+
end
|
|
2018
|
+
|
|
2019
|
+
$stderr.puts [e, e.get_error(e.error_code), search_path]
|
|
2020
|
+
|
|
2021
|
+
raise e
|
|
2022
|
+
end
|
|
2023
|
+
end
|
|
2024
|
+
|
|
2025
|
+
end
|
|
2026
|
+
|
|
2027
|
+
files.uniq
|
|
2028
|
+
end
|
|
2029
|
+
|
|
2030
|
+
# Creates a new directory on the mounted tree
|
|
2031
|
+
def create_directory(name)
|
|
2032
|
+
files = { }
|
|
2033
|
+
parm = [0].pack('V') + name + "\x00"
|
|
2034
|
+
resp = trans2(CONST::TRANS2_CREATE_DIRECTORY, parm, '')
|
|
2035
|
+
end
|
|
2036
|
+
|
|
2037
|
+
# public read/write methods
|
|
2038
|
+
attr_accessor :native_os, :native_lm, :encrypt_passwords, :extended_security, :read_timeout, :evasion_opts
|
|
2039
|
+
attr_accessor :verify_signature, :use_ntlmv2, :usentlm2_session, :send_lm, :use_lanman_key, :send_ntlm
|
|
2040
|
+
attr_accessor :system_time, :system_zone
|
|
2041
|
+
attr_accessor :spnopt
|
|
2042
|
+
|
|
2043
|
+
# public read methods
|
|
2044
|
+
attr_reader :dialect, :session_id, :challenge_key, :peer_native_lm, :peer_native_os
|
|
2045
|
+
attr_reader :default_domain, :default_name, :auth_user, :auth_user_id
|
|
2046
|
+
attr_reader :multiplex_id, :last_tree_id, :last_file_id, :process_id, :last_search_id
|
|
2047
|
+
attr_reader :dns_host_name, :dns_domain_name
|
|
2048
|
+
attr_reader :security_mode, :server_guid
|
|
2049
|
+
attr_reader :sequence_counter,:signing_key, :require_signing
|
|
2050
|
+
|
|
2051
|
+
# private write methods
|
|
2052
|
+
attr_writer :dialect, :session_id, :challenge_key, :peer_native_lm, :peer_native_os
|
|
2053
|
+
attr_writer :default_domain, :default_name, :auth_user, :auth_user_id
|
|
2054
|
+
attr_writer :dns_host_name, :dns_domain_name
|
|
2055
|
+
attr_writer :multiplex_id, :last_tree_id, :last_file_id, :process_id, :last_search_id
|
|
2056
|
+
attr_writer :security_mode, :server_guid
|
|
2057
|
+
attr_writer :sequence_counter,:signing_key, :require_signing
|
|
2058
|
+
|
|
2059
|
+
attr_accessor :socket
|
|
2060
|
+
|
|
2061
|
+
end
|
|
2062
|
+
end
|
|
2063
|
+
end
|
|
2064
|
+
end
|