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