librex 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +4 -0
- data/lib/rex.rb +101 -0
- data/lib/rex.rb.ts.rb +70 -0
- data/lib/rex/LICENSE +29 -0
- data/lib/rex/arch.rb +103 -0
- data/lib/rex/arch/sparc.rb +75 -0
- data/lib/rex/arch/sparc.rb.ut.rb +18 -0
- data/lib/rex/arch/x86.rb +513 -0
- data/lib/rex/arch/x86.rb.ut.rb +93 -0
- data/lib/rex/assembly/nasm.rb +100 -0
- data/lib/rex/assembly/nasm.rb.ut.rb +22 -0
- data/lib/rex/codepage.map +104 -0
- data/lib/rex/compat.rb +281 -0
- data/lib/rex/constants.rb +113 -0
- data/lib/rex/elfparsey.rb +11 -0
- data/lib/rex/elfparsey/elf.rb +123 -0
- data/lib/rex/elfparsey/elfbase.rb +260 -0
- data/lib/rex/elfparsey/exceptions.rb +27 -0
- data/lib/rex/elfscan.rb +12 -0
- data/lib/rex/elfscan/scanner.rb +207 -0
- data/lib/rex/elfscan/search.rb +46 -0
- data/lib/rex/encoder/alpha2.rb +31 -0
- data/lib/rex/encoder/alpha2/alpha_mixed.rb +68 -0
- data/lib/rex/encoder/alpha2/alpha_upper.rb +79 -0
- data/lib/rex/encoder/alpha2/generic.rb +113 -0
- data/lib/rex/encoder/alpha2/unicode_mixed.rb +117 -0
- data/lib/rex/encoder/alpha2/unicode_upper.rb +129 -0
- data/lib/rex/encoder/ndr.rb +89 -0
- data/lib/rex/encoder/ndr.rb.ut.rb +44 -0
- data/lib/rex/encoder/nonalpha.rb +61 -0
- data/lib/rex/encoder/nonupper.rb +64 -0
- data/lib/rex/encoder/xdr.rb +106 -0
- data/lib/rex/encoder/xdr.rb.ut.rb +29 -0
- data/lib/rex/encoder/xor.rb +69 -0
- data/lib/rex/encoder/xor/dword.rb +13 -0
- data/lib/rex/encoder/xor/dword_additive.rb +13 -0
- data/lib/rex/encoders/xor_dword.rb +35 -0
- data/lib/rex/encoders/xor_dword_additive.rb +53 -0
- data/lib/rex/encoders/xor_dword_additive.rb.ut.rb +12 -0
- data/lib/rex/encoding/xor.rb +20 -0
- data/lib/rex/encoding/xor.rb.ts.rb +14 -0
- data/lib/rex/encoding/xor/byte.rb +15 -0
- data/lib/rex/encoding/xor/byte.rb.ut.rb +21 -0
- data/lib/rex/encoding/xor/dword.rb +21 -0
- data/lib/rex/encoding/xor/dword.rb.ut.rb +15 -0
- data/lib/rex/encoding/xor/dword_additive.rb +92 -0
- data/lib/rex/encoding/xor/dword_additive.rb.ut.rb +15 -0
- data/lib/rex/encoding/xor/exceptions.rb +17 -0
- data/lib/rex/encoding/xor/generic.rb +146 -0
- data/lib/rex/encoding/xor/generic.rb.ut.rb +120 -0
- data/lib/rex/encoding/xor/qword.rb +15 -0
- data/lib/rex/encoding/xor/word.rb +21 -0
- data/lib/rex/encoding/xor/word.rb.ut.rb +13 -0
- data/lib/rex/exceptions.rb +275 -0
- data/lib/rex/exceptions.rb.ut.rb +44 -0
- data/lib/rex/exploitation/cmdstager.rb +133 -0
- data/lib/rex/exploitation/egghunter.rb +143 -0
- data/lib/rex/exploitation/egghunter.rb.ut.rb +25 -0
- data/lib/rex/exploitation/encryptjs.rb +77 -0
- data/lib/rex/exploitation/heaplib.js.b64 +331 -0
- data/lib/rex/exploitation/heaplib.rb +94 -0
- data/lib/rex/exploitation/javascriptosdetect.rb +735 -0
- data/lib/rex/exploitation/obfuscatejs.rb +335 -0
- data/lib/rex/exploitation/opcodedb.rb +818 -0
- data/lib/rex/exploitation/opcodedb.rb.ut.rb +279 -0
- data/lib/rex/exploitation/seh.rb +92 -0
- data/lib/rex/exploitation/seh.rb.ut.rb +19 -0
- data/lib/rex/file.rb +84 -0
- data/lib/rex/file.rb.ut.rb +16 -0
- data/lib/rex/image_source.rb +12 -0
- data/lib/rex/image_source/disk.rb +60 -0
- data/lib/rex/image_source/image_source.rb +46 -0
- data/lib/rex/image_source/memory.rb +37 -0
- data/lib/rex/io/bidirectional_pipe.rb +157 -0
- data/lib/rex/io/datagram_abstraction.rb +35 -0
- data/lib/rex/io/stream.rb +313 -0
- data/lib/rex/io/stream_abstraction.rb +186 -0
- data/lib/rex/io/stream_server.rb +211 -0
- data/lib/rex/job_container.rb +202 -0
- data/lib/rex/logging.rb +4 -0
- data/lib/rex/logging/log_dispatcher.rb +179 -0
- data/lib/rex/logging/log_sink.rb +42 -0
- data/lib/rex/logging/sinks/flatfile.rb +55 -0
- data/lib/rex/logging/sinks/stderr.rb +43 -0
- data/lib/rex/machparsey.rb +9 -0
- data/lib/rex/machparsey/exceptions.rb +34 -0
- data/lib/rex/machparsey/mach.rb +209 -0
- data/lib/rex/machparsey/machbase.rb +408 -0
- data/lib/rex/machscan.rb +9 -0
- data/lib/rex/machscan/scanner.rb +217 -0
- data/lib/rex/mime.rb +9 -0
- data/lib/rex/mime/header.rb +75 -0
- data/lib/rex/mime/message.rb +112 -0
- data/lib/rex/mime/part.rb +20 -0
- data/lib/rex/nop/opty2.rb +108 -0
- data/lib/rex/nop/opty2.rb.ut.rb +23 -0
- data/lib/rex/nop/opty2_tables.rb +300 -0
- data/lib/rex/ole.rb +128 -0
- data/lib/rex/ole/clsid.rb +47 -0
- data/lib/rex/ole/difat.rb +141 -0
- data/lib/rex/ole/directory.rb +230 -0
- data/lib/rex/ole/direntry.rb +240 -0
- data/lib/rex/ole/fat.rb +99 -0
- data/lib/rex/ole/header.rb +204 -0
- data/lib/rex/ole/minifat.rb +77 -0
- data/lib/rex/ole/samples/create_ole.rb +27 -0
- data/lib/rex/ole/samples/dir.rb +35 -0
- data/lib/rex/ole/samples/dump_stream.rb +34 -0
- data/lib/rex/ole/samples/ole_info.rb +23 -0
- data/lib/rex/ole/storage.rb +395 -0
- data/lib/rex/ole/stream.rb +53 -0
- data/lib/rex/ole/substorage.rb +49 -0
- data/lib/rex/ole/util.rb +157 -0
- data/lib/rex/parser/arguments.rb +97 -0
- data/lib/rex/parser/arguments.rb.ut.rb +67 -0
- data/lib/rex/parser/ini.rb +185 -0
- data/lib/rex/parser/ini.rb.ut.rb +29 -0
- data/lib/rex/parser/nmap_xml.rb +111 -0
- data/lib/rex/payloads.rb +1 -0
- data/lib/rex/payloads/win32.rb +2 -0
- data/lib/rex/payloads/win32/common.rb +26 -0
- data/lib/rex/payloads/win32/kernel.rb +53 -0
- data/lib/rex/payloads/win32/kernel/common.rb +54 -0
- data/lib/rex/payloads/win32/kernel/migration.rb +12 -0
- data/lib/rex/payloads/win32/kernel/recovery.rb +50 -0
- data/lib/rex/payloads/win32/kernel/stager.rb +171 -0
- data/lib/rex/peparsey.rb +12 -0
- data/lib/rex/peparsey/exceptions.rb +32 -0
- data/lib/rex/peparsey/pe.rb +188 -0
- data/lib/rex/peparsey/pe_memdump.rb +63 -0
- data/lib/rex/peparsey/pebase.rb +1655 -0
- data/lib/rex/peparsey/section.rb +136 -0
- data/lib/rex/pescan.rb +13 -0
- data/lib/rex/pescan/analyze.rb +309 -0
- data/lib/rex/pescan/scanner.rb +206 -0
- data/lib/rex/pescan/search.rb +56 -0
- data/lib/rex/platforms.rb +1 -0
- data/lib/rex/platforms/windows.rb +51 -0
- data/lib/rex/poly.rb +132 -0
- data/lib/rex/poly/block.rb +468 -0
- data/lib/rex/poly/register.rb +100 -0
- data/lib/rex/poly/register/x86.rb +40 -0
- data/lib/rex/post.rb +8 -0
- data/lib/rex/post/dir.rb +51 -0
- data/lib/rex/post/file.rb +172 -0
- data/lib/rex/post/file_stat.rb +220 -0
- data/lib/rex/post/gen.pl +13 -0
- data/lib/rex/post/io.rb +182 -0
- data/lib/rex/post/meterpreter.rb +4 -0
- data/lib/rex/post/meterpreter/channel.rb +438 -0
- data/lib/rex/post/meterpreter/channel_container.rb +54 -0
- data/lib/rex/post/meterpreter/channels/pool.rb +160 -0
- data/lib/rex/post/meterpreter/channels/pools/file.rb +62 -0
- data/lib/rex/post/meterpreter/channels/pools/stream_pool.rb +103 -0
- data/lib/rex/post/meterpreter/channels/stream.rb +87 -0
- data/lib/rex/post/meterpreter/client.rb +335 -0
- data/lib/rex/post/meterpreter/client_core.rb +274 -0
- data/lib/rex/post/meterpreter/dependencies.rb +3 -0
- data/lib/rex/post/meterpreter/extension.rb +32 -0
- data/lib/rex/post/meterpreter/extensions/espia/espia.rb +58 -0
- data/lib/rex/post/meterpreter/extensions/espia/tlv.rb +16 -0
- data/lib/rex/post/meterpreter/extensions/incognito/incognito.rb +94 -0
- data/lib/rex/post/meterpreter/extensions/incognito/tlv.rb +21 -0
- data/lib/rex/post/meterpreter/extensions/priv/fs.rb +118 -0
- data/lib/rex/post/meterpreter/extensions/priv/passwd.rb +61 -0
- data/lib/rex/post/meterpreter/extensions/priv/priv.rb +104 -0
- data/lib/rex/post/meterpreter/extensions/priv/tlv.rb +28 -0
- data/lib/rex/post/meterpreter/extensions/sniffer/sniffer.rb +100 -0
- data/lib/rex/post/meterpreter/extensions/sniffer/tlv.rb +24 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/constants.rb +333 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +273 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +235 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file_stat.rb +103 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/io.rb +48 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/config.rb +144 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/interface.rb +73 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/route.rb +56 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb +137 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb +167 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_server_channel.rb +167 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb +192 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +139 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +97 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log.rb +184 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log_subsystem/event_record.rb +41 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/power.rb +61 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +361 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/image.rb +129 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/io.rb +55 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/memory.rb +336 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/thread.rb +141 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +279 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +182 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_value.rb +102 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/thread.rb +174 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +185 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +227 -0
- data/lib/rex/post/meterpreter/inbound_packet_handler.rb +30 -0
- data/lib/rex/post/meterpreter/object_aliases.rb +83 -0
- data/lib/rex/post/meterpreter/packet.rb +596 -0
- data/lib/rex/post/meterpreter/packet_dispatcher.rb +409 -0
- data/lib/rex/post/meterpreter/packet_parser.rb +94 -0
- data/lib/rex/post/meterpreter/packet_response_waiter.rb +83 -0
- data/lib/rex/post/meterpreter/ui/console.rb +135 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher.rb +62 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +595 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/espia.rb +108 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/incognito.rb +241 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv.rb +61 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/elevate.rb +98 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/passwd.rb +51 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/timestomp.rb +132 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/sniffer.rb +187 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi.rb +63 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +376 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +270 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +484 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +315 -0
- data/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +95 -0
- data/lib/rex/post/permission.rb +26 -0
- data/lib/rex/post/process.rb +57 -0
- data/lib/rex/post/thread.rb +57 -0
- data/lib/rex/post/ui.rb +52 -0
- data/lib/rex/proto.rb +12 -0
- data/lib/rex/proto.rb.ts.rb +8 -0
- data/lib/rex/proto/dcerpc.rb +6 -0
- data/lib/rex/proto/dcerpc.rb.ts.rb +9 -0
- data/lib/rex/proto/dcerpc/client.rb +358 -0
- data/lib/rex/proto/dcerpc/client.rb.ut.rb +491 -0
- data/lib/rex/proto/dcerpc/exceptions.rb +150 -0
- data/lib/rex/proto/dcerpc/handle.rb +47 -0
- data/lib/rex/proto/dcerpc/handle.rb.ut.rb +85 -0
- data/lib/rex/proto/dcerpc/ndr.rb +72 -0
- data/lib/rex/proto/dcerpc/ndr.rb.ut.rb +41 -0
- data/lib/rex/proto/dcerpc/packet.rb +253 -0
- data/lib/rex/proto/dcerpc/packet.rb.ut.rb +56 -0
- data/lib/rex/proto/dcerpc/response.rb +186 -0
- data/lib/rex/proto/dcerpc/response.rb.ut.rb +15 -0
- data/lib/rex/proto/dcerpc/uuid.rb +84 -0
- data/lib/rex/proto/dcerpc/uuid.rb.ut.rb +46 -0
- data/lib/rex/proto/drda.rb +5 -0
- data/lib/rex/proto/drda.rb.ts.rb +17 -0
- data/lib/rex/proto/drda/constants.rb +49 -0
- data/lib/rex/proto/drda/constants.rb.ut.rb +23 -0
- data/lib/rex/proto/drda/packet.rb +252 -0
- data/lib/rex/proto/drda/packet.rb.ut.rb +109 -0
- data/lib/rex/proto/drda/utils.rb +123 -0
- data/lib/rex/proto/drda/utils.rb.ut.rb +84 -0
- data/lib/rex/proto/http.rb +5 -0
- data/lib/rex/proto/http.rb.ts.rb +12 -0
- data/lib/rex/proto/http/client.rb +817 -0
- data/lib/rex/proto/http/client.rb.ut.rb +93 -0
- data/lib/rex/proto/http/handler.rb +46 -0
- data/lib/rex/proto/http/handler/erb.rb +128 -0
- data/lib/rex/proto/http/handler/erb.rb.ut.rb +21 -0
- data/lib/rex/proto/http/handler/erb.rb.ut.rb.rhtml +1 -0
- data/lib/rex/proto/http/handler/proc.rb +54 -0
- data/lib/rex/proto/http/handler/proc.rb.ut.rb +24 -0
- data/lib/rex/proto/http/header.rb +161 -0
- data/lib/rex/proto/http/header.rb.ut.rb +46 -0
- data/lib/rex/proto/http/packet.rb +394 -0
- data/lib/rex/proto/http/packet.rb.ut.rb +165 -0
- data/lib/rex/proto/http/request.rb +356 -0
- data/lib/rex/proto/http/request.rb.ut.rb +214 -0
- data/lib/rex/proto/http/response.rb +85 -0
- data/lib/rex/proto/http/response.rb.ut.rb +149 -0
- data/lib/rex/proto/http/server.rb +367 -0
- data/lib/rex/proto/http/server.rb.ut.rb +79 -0
- data/lib/rex/proto/smb.rb +7 -0
- data/lib/rex/proto/smb.rb.ts.rb +8 -0
- data/lib/rex/proto/smb/client.rb +1733 -0
- data/lib/rex/proto/smb/client.rb.ut.rb +223 -0
- data/lib/rex/proto/smb/constants.rb +1062 -0
- data/lib/rex/proto/smb/constants.rb.ut.rb +18 -0
- data/lib/rex/proto/smb/crypt.rb +95 -0
- data/lib/rex/proto/smb/crypt.rb.ut.rb +20 -0
- data/lib/rex/proto/smb/evasions.rb +65 -0
- data/lib/rex/proto/smb/exceptions.rb +846 -0
- data/lib/rex/proto/smb/simpleclient.rb +292 -0
- data/lib/rex/proto/smb/simpleclient.rb.ut.rb +128 -0
- data/lib/rex/proto/smb/utils.rb +514 -0
- data/lib/rex/proto/smb/utils.rb.ut.rb +20 -0
- data/lib/rex/proto/sunrpc.rb +1 -0
- data/lib/rex/proto/sunrpc/client.rb +195 -0
- data/lib/rex/script.rb +42 -0
- data/lib/rex/script/base.rb +59 -0
- data/lib/rex/script/meterpreter.rb +9 -0
- data/lib/rex/script/shell.rb +9 -0
- data/lib/rex/service.rb +48 -0
- data/lib/rex/service_manager.rb +141 -0
- data/lib/rex/service_manager.rb.ut.rb +32 -0
- data/lib/rex/services/local_relay.rb +423 -0
- data/lib/rex/socket.rb +586 -0
- data/lib/rex/socket.rb.ut.rb +86 -0
- data/lib/rex/socket/comm.rb +119 -0
- data/lib/rex/socket/comm/local.rb +409 -0
- data/lib/rex/socket/comm/local.rb.ut.rb +75 -0
- data/lib/rex/socket/ip.rb +129 -0
- data/lib/rex/socket/parameters.rb +345 -0
- data/lib/rex/socket/parameters.rb.ut.rb +51 -0
- data/lib/rex/socket/range_walker.rb +295 -0
- data/lib/rex/socket/range_walker.rb.ut.rb +55 -0
- data/lib/rex/socket/ssl_tcp.rb +184 -0
- data/lib/rex/socket/ssl_tcp.rb.ut.rb +39 -0
- data/lib/rex/socket/ssl_tcp_server.rb +122 -0
- data/lib/rex/socket/ssl_tcp_server.rb.ut.rb +51 -0
- data/lib/rex/socket/subnet_walker.rb +75 -0
- data/lib/rex/socket/subnet_walker.rb.ut.rb +28 -0
- data/lib/rex/socket/switch_board.rb +272 -0
- data/lib/rex/socket/switch_board.rb.ut.rb +52 -0
- data/lib/rex/socket/tcp.rb +76 -0
- data/lib/rex/socket/tcp.rb.ut.rb +64 -0
- data/lib/rex/socket/tcp_server.rb +67 -0
- data/lib/rex/socket/tcp_server.rb.ut.rb +44 -0
- data/lib/rex/socket/udp.rb +157 -0
- data/lib/rex/socket/udp.rb.ut.rb +44 -0
- data/lib/rex/struct2.rb +5 -0
- data/lib/rex/struct2/c_struct.rb +181 -0
- data/lib/rex/struct2/c_struct_template.rb +39 -0
- data/lib/rex/struct2/constant.rb +26 -0
- data/lib/rex/struct2/element.rb +44 -0
- data/lib/rex/struct2/generic.rb +73 -0
- data/lib/rex/struct2/restraint.rb +54 -0
- data/lib/rex/struct2/s_string.rb +72 -0
- data/lib/rex/struct2/s_struct.rb +111 -0
- data/lib/rex/sync.rb +6 -0
- data/lib/rex/sync/event.rb +94 -0
- data/lib/rex/sync/read_write_lock.rb +176 -0
- data/lib/rex/sync/ref.rb +57 -0
- data/lib/rex/sync/thread_safe.rb +82 -0
- data/lib/rex/test.rb +35 -0
- data/lib/rex/text.rb +1029 -0
- data/lib/rex/text.rb.ut.rb +168 -0
- data/lib/rex/time.rb +65 -0
- data/lib/rex/transformer.rb +115 -0
- data/lib/rex/transformer.rb.ut.rb +38 -0
- data/lib/rex/ui.rb +21 -0
- data/lib/rex/ui/interactive.rb +252 -0
- data/lib/rex/ui/output.rb +80 -0
- data/lib/rex/ui/output/none.rb +18 -0
- data/lib/rex/ui/progress_tracker.rb +96 -0
- data/lib/rex/ui/subscriber.rb +149 -0
- data/lib/rex/ui/text/color.rb +97 -0
- data/lib/rex/ui/text/color.rb.ut.rb +18 -0
- data/lib/rex/ui/text/dispatcher_shell.rb +382 -0
- data/lib/rex/ui/text/input.rb +117 -0
- data/lib/rex/ui/text/input/buffer.rb +75 -0
- data/lib/rex/ui/text/input/readline.rb +129 -0
- data/lib/rex/ui/text/input/socket.rb +95 -0
- data/lib/rex/ui/text/input/stdio.rb +45 -0
- data/lib/rex/ui/text/irb_shell.rb +55 -0
- data/lib/rex/ui/text/output.rb +80 -0
- data/lib/rex/ui/text/output/buffer.rb +65 -0
- data/lib/rex/ui/text/output/file.rb +37 -0
- data/lib/rex/ui/text/output/socket.rb +43 -0
- data/lib/rex/ui/text/output/stdio.rb +40 -0
- data/lib/rex/ui/text/progress_tracker.rb +56 -0
- data/lib/rex/ui/text/progress_tracker.rb.ut.rb +34 -0
- data/lib/rex/ui/text/shell.rb +321 -0
- data/lib/rex/ui/text/table.rb +254 -0
- data/lib/rex/ui/text/table.rb.ut.rb +55 -0
- data/lib/rex/zip.rb +93 -0
- data/lib/rex/zip/archive.rb +91 -0
- data/lib/rex/zip/blocks.rb +182 -0
- data/lib/rex/zip/entry.rb +95 -0
- data/lib/rex/zip/samples/comment.rb +32 -0
- data/lib/rex/zip/samples/mkwar.rb +138 -0
- data/lib/rex/zip/samples/mkzip.rb +19 -0
- data/lib/rex/zip/samples/recursive.rb +58 -0
- metadata +435 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
require 'rex/text'
|
|
2
|
+
module Rex
|
|
3
|
+
module Exploitation
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
# Obfuscates javascript in various ways
|
|
7
|
+
#
|
|
8
|
+
class ObfuscateJS
|
|
9
|
+
attr_reader :opts
|
|
10
|
+
|
|
11
|
+
#
|
|
12
|
+
# Obfuscates a javascript string.
|
|
13
|
+
#
|
|
14
|
+
# Options are 'Symbols', described below, and 'Strings', a boolean
|
|
15
|
+
# which specifies whether strings within the javascript should be
|
|
16
|
+
# mucked with (defaults to false).
|
|
17
|
+
#
|
|
18
|
+
# The 'Symbols' argument should have the following format:
|
|
19
|
+
#
|
|
20
|
+
# {
|
|
21
|
+
# 'Variables' => [ 'var1', ... ],
|
|
22
|
+
# 'Methods' => [ 'method1', ... ],
|
|
23
|
+
# 'Namespaces' => [ 'n', ... ],
|
|
24
|
+
# 'Classes' => [ { 'Namespace' => 'n', 'Class' => 'y'}, ... ]
|
|
25
|
+
# }
|
|
26
|
+
#
|
|
27
|
+
# Make sure you order your methods, classes, and namespaces by most
|
|
28
|
+
# specific to least specific to prevent partial substitution. For
|
|
29
|
+
# instance, if you have two methods (joe and joeBob), you should place
|
|
30
|
+
# joeBob before joe because it is more specific and will be globally
|
|
31
|
+
# replaced before joe is replaced.
|
|
32
|
+
#
|
|
33
|
+
# A simple example follows:
|
|
34
|
+
#
|
|
35
|
+
# <code>
|
|
36
|
+
# js = ObfuscateJS.new <<ENDJS
|
|
37
|
+
# function say_hi() {
|
|
38
|
+
# var foo = "Hello, world";
|
|
39
|
+
# document.writeln(foo);
|
|
40
|
+
# }
|
|
41
|
+
# ENDJS
|
|
42
|
+
# js.obfuscate(
|
|
43
|
+
# 'Symbols' => {
|
|
44
|
+
# 'Variables' => [ 'foo' ],
|
|
45
|
+
# 'Methods' => [ 'say_hi' ]
|
|
46
|
+
# }
|
|
47
|
+
# 'Strings' => true
|
|
48
|
+
# )
|
|
49
|
+
# </code>
|
|
50
|
+
#
|
|
51
|
+
# which should generate something like the following:
|
|
52
|
+
#
|
|
53
|
+
# <code>
|
|
54
|
+
# function oJaDYRzFOyJVQCOHk() { var cLprVG = "\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64"; document.writeln(cLprVG); }
|
|
55
|
+
# </code>
|
|
56
|
+
#
|
|
57
|
+
# String obfuscation tries to deal with escaped quotes within strings but
|
|
58
|
+
# won't catch things like
|
|
59
|
+
# "\\"
|
|
60
|
+
# so be careful.
|
|
61
|
+
#
|
|
62
|
+
def self.obfuscate(js, opts = {})
|
|
63
|
+
ObfuscateJS.new(js).obfuscate(opts)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
#
|
|
67
|
+
# Initialize an instance of the obfuscator
|
|
68
|
+
#
|
|
69
|
+
def initialize(js = "", opts = {})
|
|
70
|
+
@js = js
|
|
71
|
+
@dynsym = {}
|
|
72
|
+
@opts = {
|
|
73
|
+
'Symbols' => {
|
|
74
|
+
'Variables'=>[],
|
|
75
|
+
'Methods'=>[],
|
|
76
|
+
'Namespaces'=>[],
|
|
77
|
+
'Classes'=>[]
|
|
78
|
+
},
|
|
79
|
+
'Strings'=>false
|
|
80
|
+
}
|
|
81
|
+
@done = false
|
|
82
|
+
update_opts(opts) if (opts.length > 0)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def update_opts(opts)
|
|
86
|
+
if (opts.nil? or opts.length < 1)
|
|
87
|
+
return
|
|
88
|
+
end
|
|
89
|
+
if (@opts['Symbols'] && opts['Symbols'])
|
|
90
|
+
['Variables', 'Methods', 'Namespaces', 'Classes'].each { |k|
|
|
91
|
+
if (@opts['Symbols'][k] && opts['Symbols'][k])
|
|
92
|
+
opts['Symbols'][k].each { |s|
|
|
93
|
+
if (not @opts['Symbols'][k].include? s)
|
|
94
|
+
@opts['Symbols'][k].push(s)
|
|
95
|
+
end
|
|
96
|
+
}
|
|
97
|
+
elsif (opts['Symbols'][k])
|
|
98
|
+
@opts['Symbols'][k] = opts['Symbols'][k]
|
|
99
|
+
end
|
|
100
|
+
}
|
|
101
|
+
elsif opts['Symbols']
|
|
102
|
+
@opts['Symbols'] = opts['Symbols']
|
|
103
|
+
end
|
|
104
|
+
@opts['Strings'] ||= opts['Strings']
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
#
|
|
108
|
+
# Returns the dynamic symbol associated with the supplied symbol name
|
|
109
|
+
#
|
|
110
|
+
# If obfuscation has not yet been performed (i.e. obfuscate() has not been
|
|
111
|
+
# called), then this method simply returns its argument
|
|
112
|
+
#
|
|
113
|
+
def sym(name)
|
|
114
|
+
@dynsym[name] || name
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
#
|
|
118
|
+
# Obfuscates the javascript string passed to the constructor
|
|
119
|
+
#
|
|
120
|
+
def obfuscate(opts = {})
|
|
121
|
+
#return @js if (@done)
|
|
122
|
+
@done = true
|
|
123
|
+
|
|
124
|
+
update_opts(opts)
|
|
125
|
+
|
|
126
|
+
if (@opts['Strings'])
|
|
127
|
+
obfuscate_strings()
|
|
128
|
+
|
|
129
|
+
# Full space randomization does not work for javascript -- despite
|
|
130
|
+
# claims that space is irrelavent, newlines break things. Instead,
|
|
131
|
+
# use only space (0x20) and tab (0x09).
|
|
132
|
+
|
|
133
|
+
#@js.gsub!(/[\x09\x20]+/) { |s|
|
|
134
|
+
# len = rand(50)+2
|
|
135
|
+
# set = "\x09\x20"
|
|
136
|
+
# buf = ''
|
|
137
|
+
# while (buf.length < len)
|
|
138
|
+
# buf << set[rand(set.length)].chr
|
|
139
|
+
# end
|
|
140
|
+
#
|
|
141
|
+
# buf
|
|
142
|
+
#}
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Remove our comments
|
|
146
|
+
remove_comments
|
|
147
|
+
|
|
148
|
+
# Globally replace symbols
|
|
149
|
+
replace_symbols(@opts['Symbols']) if @opts['Symbols']
|
|
150
|
+
|
|
151
|
+
return @js
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
#
|
|
155
|
+
# Returns the replaced javascript string
|
|
156
|
+
#
|
|
157
|
+
def to_s
|
|
158
|
+
@js
|
|
159
|
+
end
|
|
160
|
+
alias :to_str :to_s
|
|
161
|
+
|
|
162
|
+
def <<(str)
|
|
163
|
+
@js << str
|
|
164
|
+
end
|
|
165
|
+
def +(str)
|
|
166
|
+
@js + str
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
protected
|
|
170
|
+
attr_accessor :done
|
|
171
|
+
|
|
172
|
+
#
|
|
173
|
+
# Get rid of both single-line C++ style comments and multiline C style comments.
|
|
174
|
+
#
|
|
175
|
+
# Note: embedded comments (e.g.: "/*/**/*/") will break this,
|
|
176
|
+
# but they also break real javascript engines so I don't care.
|
|
177
|
+
#
|
|
178
|
+
def remove_comments
|
|
179
|
+
@js.gsub!(%r{\s+//.*$}, '')
|
|
180
|
+
@js.gsub!(%r{/\*.*?\*/}m, '')
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Replace method, class, and namespace symbols found in the javascript
|
|
184
|
+
# string
|
|
185
|
+
def replace_symbols(symbols)
|
|
186
|
+
taken = { }
|
|
187
|
+
|
|
188
|
+
# Generate random symbol names
|
|
189
|
+
[ 'Variables', 'Methods', 'Classes', 'Namespaces' ].each { |symtype|
|
|
190
|
+
next if symbols[symtype].nil?
|
|
191
|
+
symbols[symtype].each { |sym|
|
|
192
|
+
dyn = Rex::Text.rand_text_alpha(rand(32)+1) until dyn and not taken.key?(dyn)
|
|
193
|
+
|
|
194
|
+
taken[dyn] = true
|
|
195
|
+
|
|
196
|
+
if symtype == 'Classes'
|
|
197
|
+
full_sym = sym['Namespace'] + "." + sym['Class']
|
|
198
|
+
@dynsym[full_sym] = dyn
|
|
199
|
+
|
|
200
|
+
@js.gsub!(/#{full_sym}/) { |m|
|
|
201
|
+
sym['Namespace'] + "." + dyn
|
|
202
|
+
}
|
|
203
|
+
else
|
|
204
|
+
@dynsym[sym] = dyn
|
|
205
|
+
|
|
206
|
+
@js.gsub!(/#{sym}/, dyn)
|
|
207
|
+
end
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
#
|
|
213
|
+
# Change each string into some javascript that will generate that string
|
|
214
|
+
#
|
|
215
|
+
# There are a couple of caveats to using string obfuscation:
|
|
216
|
+
# * it tries to deal with escaped quotes within strings but won't catch
|
|
217
|
+
# things like: "\\"
|
|
218
|
+
# * depending on the random choices, this can easily balloon a short
|
|
219
|
+
# string up to hundreds of kilobytes if called multiple times.
|
|
220
|
+
# so be careful.
|
|
221
|
+
#
|
|
222
|
+
def obfuscate_strings()
|
|
223
|
+
@js.gsub!(/".*?[^\\]"|'.*?[^\\]'/) { |str|
|
|
224
|
+
buf = ''
|
|
225
|
+
quote = str[0,1]
|
|
226
|
+
# Pull the quotes off either end
|
|
227
|
+
str = str[1, str.length-2]
|
|
228
|
+
case (rand(2))
|
|
229
|
+
# Disable hex encoding for now. It's just too big a hassle.
|
|
230
|
+
#when 0
|
|
231
|
+
# # This is where we can run into trouble with generating
|
|
232
|
+
# # incorrect code. If we hex encode a string twice, the second
|
|
233
|
+
# # encoding will generate the first instead of the original
|
|
234
|
+
# # string.
|
|
235
|
+
# if str =~ /\\x/
|
|
236
|
+
# # Always have to remove spaces from strings so the space
|
|
237
|
+
# # randomization doesn't mess with them.
|
|
238
|
+
# buf = quote + str.gsub(/ /, '\x20') + quote
|
|
239
|
+
# else
|
|
240
|
+
# buf = '"' + Rex::Text.to_hex(str) + '"'
|
|
241
|
+
# end
|
|
242
|
+
when 0
|
|
243
|
+
#
|
|
244
|
+
# Escape sequences when naively encoded for unescape become a
|
|
245
|
+
# literal backslash instead of the intended meaning. To avoid
|
|
246
|
+
# that problem, we scan the string for escapes and leave them
|
|
247
|
+
# unmolested.
|
|
248
|
+
#
|
|
249
|
+
buf << 'unescape("'
|
|
250
|
+
bytes = str.unpack("C*")
|
|
251
|
+
c = 0
|
|
252
|
+
while bytes[c]
|
|
253
|
+
if bytes[c].chr == "\\"
|
|
254
|
+
# XXX This is pretty slow.
|
|
255
|
+
esc_len = parse_escape(bytes, c)
|
|
256
|
+
buf << bytes[c, esc_len].map{|a| a.chr}.join
|
|
257
|
+
c += esc_len
|
|
258
|
+
next
|
|
259
|
+
end
|
|
260
|
+
buf << "%%%0.2x"%(bytes[c])
|
|
261
|
+
# Break the string into smaller strings
|
|
262
|
+
if bytes[c+1] and rand(10) == 0
|
|
263
|
+
buf << '" + "'
|
|
264
|
+
end
|
|
265
|
+
c += 1
|
|
266
|
+
end
|
|
267
|
+
buf << '")'
|
|
268
|
+
when 1
|
|
269
|
+
buf = "String.fromCharCode( "
|
|
270
|
+
bytes = str.unpack("C*")
|
|
271
|
+
c = 0
|
|
272
|
+
while bytes[c]
|
|
273
|
+
if bytes[c].chr == "\\"
|
|
274
|
+
case bytes[c+1].chr
|
|
275
|
+
# For chars that contain their non-escaped selves, step
|
|
276
|
+
# past the backslash and let the rand() below decide
|
|
277
|
+
# how to represent the character.
|
|
278
|
+
when '"'; c += 1
|
|
279
|
+
when "'"; c += 1
|
|
280
|
+
when "\\"; c += 1
|
|
281
|
+
# For others, just take the hex representation out of
|
|
282
|
+
# laziness.
|
|
283
|
+
when "n"; buf << "0x0a"; c += 2; next
|
|
284
|
+
when "t"; buf << "0x09"; c += 2; next
|
|
285
|
+
# Lastly, if it's a hex, unicode, or octal escape,
|
|
286
|
+
# leave it, and anything after it, alone. At some
|
|
287
|
+
# point we may want to parse up to the end of the
|
|
288
|
+
# escapes and encode subsequent non-escape characters.
|
|
289
|
+
# Since this is the lazy way to do it, spaces after an
|
|
290
|
+
# escape sequence will get away unmodified. To prevent
|
|
291
|
+
# the space randomizer from hosing the string, convert
|
|
292
|
+
# spaces specifically.
|
|
293
|
+
else
|
|
294
|
+
buf = buf[0,buf.length-1] + " )"
|
|
295
|
+
buf << ' + ("' + bytes[c, bytes.length].map{|a| a==0x20 ? '\x20' : a.chr}.join + '" '
|
|
296
|
+
break
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
case (rand(3))
|
|
300
|
+
when 0
|
|
301
|
+
buf << " %i,"%(bytes[c])
|
|
302
|
+
when 1
|
|
303
|
+
buf << " 0%o,"%(bytes[c])
|
|
304
|
+
when 2
|
|
305
|
+
buf << " 0x%0.2x,"%(bytes[c])
|
|
306
|
+
end
|
|
307
|
+
c += 1
|
|
308
|
+
end
|
|
309
|
+
# Strip off the last comma
|
|
310
|
+
buf = buf[0,buf.length-1] + " )"
|
|
311
|
+
end
|
|
312
|
+
buf
|
|
313
|
+
}
|
|
314
|
+
@js
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def parse_escape(bytes, offset)
|
|
318
|
+
esc_len = 0
|
|
319
|
+
if bytes[offset].chr == "\\"
|
|
320
|
+
case bytes[offset+1].chr
|
|
321
|
+
when "u"; esc_len = 6 # unicode \u1234
|
|
322
|
+
when "x"; esc_len = 4 # hex, \x41
|
|
323
|
+
when /[0-9]/ # octal, \123, \0
|
|
324
|
+
oct = bytes[offset+1, 4].map{|a|a.chr}.join
|
|
325
|
+
oct =~ /([0-9]+)/
|
|
326
|
+
esc_len = 1 + $1.length
|
|
327
|
+
else; esc_len = 2 # \" \n, etc.
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
esc_len
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
end
|
|
335
|
+
end
|
|
@@ -0,0 +1,818 @@
|
|
|
1
|
+
require 'rexml/rexml'
|
|
2
|
+
require 'rexml/source'
|
|
3
|
+
require 'rexml/document'
|
|
4
|
+
require 'rexml/parsers/treeparser'
|
|
5
|
+
require 'rex/proto/http'
|
|
6
|
+
require 'uri'
|
|
7
|
+
|
|
8
|
+
module Rex
|
|
9
|
+
module Exploitation
|
|
10
|
+
module OpcodeDb
|
|
11
|
+
|
|
12
|
+
module OpcodeResult # :nodoc:
|
|
13
|
+
def initialize(hash)
|
|
14
|
+
@hash = hash
|
|
15
|
+
end
|
|
16
|
+
attr_reader :hash
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
###
|
|
20
|
+
#
|
|
21
|
+
# A cachable entry.
|
|
22
|
+
#
|
|
23
|
+
###
|
|
24
|
+
module Cachable
|
|
25
|
+
|
|
26
|
+
def create(hash) # :nodoc:
|
|
27
|
+
@Cache = {} unless (@Cache)
|
|
28
|
+
if (hash_key(hash) and @Cache[hash_key(hash)])
|
|
29
|
+
@Cache[hash_key(hash)]
|
|
30
|
+
else
|
|
31
|
+
@Cache[hash_key(hash)] = self.new(hash)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def hash_key(hash) # :nodoc:
|
|
36
|
+
hash['id'] || nil
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def flush_cache # :nodoc:
|
|
40
|
+
@Cache.clear
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
###
|
|
46
|
+
#
|
|
47
|
+
# This class provides a general interface to items that come from that opcode
|
|
48
|
+
# database that have a symbolic entry identifier and name.
|
|
49
|
+
#
|
|
50
|
+
###
|
|
51
|
+
module DbEntry
|
|
52
|
+
include OpcodeResult
|
|
53
|
+
|
|
54
|
+
def initialize(hash)
|
|
55
|
+
super
|
|
56
|
+
|
|
57
|
+
@id = hash['id'].to_i
|
|
58
|
+
@name = hash['name']
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
#
|
|
62
|
+
# Fields that could possibly be filtered on for this database entry.
|
|
63
|
+
#
|
|
64
|
+
def filter_hash
|
|
65
|
+
{
|
|
66
|
+
"id" => id,
|
|
67
|
+
"name" => name
|
|
68
|
+
}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
#
|
|
72
|
+
# The unique server identifier.
|
|
73
|
+
#
|
|
74
|
+
attr_reader :id
|
|
75
|
+
#
|
|
76
|
+
# The unique name for this entry.
|
|
77
|
+
#
|
|
78
|
+
attr_reader :name
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
###
|
|
82
|
+
#
|
|
83
|
+
# This class represents a particular image module including its name,
|
|
84
|
+
# segments, imports, exports, base address, and so on.
|
|
85
|
+
#
|
|
86
|
+
###
|
|
87
|
+
class ImageModule
|
|
88
|
+
include DbEntry
|
|
89
|
+
|
|
90
|
+
###
|
|
91
|
+
#
|
|
92
|
+
# This class contains information about a module-associated segment.
|
|
93
|
+
#
|
|
94
|
+
###
|
|
95
|
+
class Segment
|
|
96
|
+
def initialize(hash)
|
|
97
|
+
@type = hash['type']
|
|
98
|
+
@base_address = hash['base_address'].to_i
|
|
99
|
+
@size = hash['segment_size'].to_i
|
|
100
|
+
@writable = hash['writable'] == "true" ? true : false
|
|
101
|
+
@readable = hash['readable'] == "true" ? true : false
|
|
102
|
+
@executable = hash['executable'] == "true" ? true : false
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
#
|
|
106
|
+
# The type of the segment, such as ".text".
|
|
107
|
+
#
|
|
108
|
+
attr_reader :type
|
|
109
|
+
#
|
|
110
|
+
# The base address of the segment.
|
|
111
|
+
#
|
|
112
|
+
attr_reader :base_address
|
|
113
|
+
#
|
|
114
|
+
# The size of the segment in bytes.
|
|
115
|
+
#
|
|
116
|
+
attr_reader :size
|
|
117
|
+
#
|
|
118
|
+
# Boolean that indicates whether or not the segment is writable.
|
|
119
|
+
#
|
|
120
|
+
attr_reader :writable
|
|
121
|
+
#
|
|
122
|
+
# Boolean that indicates whether or not the segment is readable.
|
|
123
|
+
#
|
|
124
|
+
attr_reader :readable
|
|
125
|
+
#
|
|
126
|
+
# Boolean that indicates whether or not the segment is executable.
|
|
127
|
+
#
|
|
128
|
+
attr_reader :executable
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
###
|
|
132
|
+
#
|
|
133
|
+
# This class contains information about a module-associated import.
|
|
134
|
+
#
|
|
135
|
+
###
|
|
136
|
+
class Import
|
|
137
|
+
def initialize(hash)
|
|
138
|
+
@name = hash['name']
|
|
139
|
+
@address = hash['address'].to_i
|
|
140
|
+
@ordinal = hash['ordinal'].to_i
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
#
|
|
144
|
+
# The name of the imported function.
|
|
145
|
+
#
|
|
146
|
+
attr_reader :name
|
|
147
|
+
#
|
|
148
|
+
# The address of the function pointer in the IAT.
|
|
149
|
+
#
|
|
150
|
+
attr_reader :address
|
|
151
|
+
#
|
|
152
|
+
# The ordinal of the imported symbol.
|
|
153
|
+
#
|
|
154
|
+
attr_reader :ordinal
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
###
|
|
158
|
+
#
|
|
159
|
+
# This class contains information about a module-associated export.
|
|
160
|
+
#
|
|
161
|
+
###
|
|
162
|
+
class Export
|
|
163
|
+
def initialize(hash)
|
|
164
|
+
@name = hash['name']
|
|
165
|
+
@address = hash['address'].to_i
|
|
166
|
+
@ordinal = hash['ordinal'].to_i
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
#
|
|
170
|
+
# The name of the exported function.
|
|
171
|
+
#
|
|
172
|
+
attr_reader :name
|
|
173
|
+
#
|
|
174
|
+
# The address of the exported function.
|
|
175
|
+
#
|
|
176
|
+
attr_reader :address
|
|
177
|
+
#
|
|
178
|
+
# The ordinal of the exported symbol.
|
|
179
|
+
#
|
|
180
|
+
attr_reader :ordinal
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
class <<self
|
|
184
|
+
include Cachable
|
|
185
|
+
def hash_key(hash) # :nodoc:
|
|
186
|
+
(hash['id'] || '') +
|
|
187
|
+
(hash['segments'] || '').to_s +
|
|
188
|
+
(hash['exports'] || '').to_s +
|
|
189
|
+
(hash['imports'] || '').to_s
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def initialize(hash)
|
|
194
|
+
super
|
|
195
|
+
|
|
196
|
+
@locale = Locale.create(hash['locale'])
|
|
197
|
+
@maj_maj_ver = hash['maj_maj_ver'].to_i
|
|
198
|
+
@maj_min_ver = hash['maj_min_ver'].to_i
|
|
199
|
+
@min_maj_ver = hash['min_maj_ver'].to_i
|
|
200
|
+
@min_min_ver = hash['min_min_ver'].to_i
|
|
201
|
+
@timestamp = Time.at(hash['timestamp'].to_i)
|
|
202
|
+
@vendor = hash['vendor']
|
|
203
|
+
@base_address = hash['base_address'].to_i
|
|
204
|
+
@image_size = hash['image_size'].to_i
|
|
205
|
+
|
|
206
|
+
@segments = hash['segments'].map { |ent|
|
|
207
|
+
Segment.new(ent)
|
|
208
|
+
} if (hash['segments'])
|
|
209
|
+
@imports = hash['imports'].map { |ent|
|
|
210
|
+
Import.new(ent)
|
|
211
|
+
} if (hash['imports'])
|
|
212
|
+
@exports = hash['exports'].map { |ent|
|
|
213
|
+
Export.new(ent)
|
|
214
|
+
} if (hash['exports'])
|
|
215
|
+
@platforms = hash['platforms'].map { |ent|
|
|
216
|
+
OsVersion.create(ent)
|
|
217
|
+
} if (hash['platforms'])
|
|
218
|
+
|
|
219
|
+
@segments = [] unless(@segments)
|
|
220
|
+
@imports = [] unless(@imports)
|
|
221
|
+
@exports = [] unless(@exports)
|
|
222
|
+
@platforms = [] unless(@platforms)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
#
|
|
226
|
+
# An instance of a Locale class that is associated with this module.
|
|
227
|
+
#
|
|
228
|
+
attr_reader :locale
|
|
229
|
+
#
|
|
230
|
+
# The module's major major version number (X.x.x.x).
|
|
231
|
+
#
|
|
232
|
+
attr_reader :maj_maj_ver
|
|
233
|
+
#
|
|
234
|
+
# The module's major minor version number (x.X.x.x).
|
|
235
|
+
#
|
|
236
|
+
attr_reader :maj_min_ver
|
|
237
|
+
#
|
|
238
|
+
# The module's minor major version number (x.x.X.x).
|
|
239
|
+
#
|
|
240
|
+
attr_reader :min_maj_ver
|
|
241
|
+
#
|
|
242
|
+
# The module's minor minor version number (x.x.x.X).
|
|
243
|
+
#
|
|
244
|
+
attr_reader :min_min_ver
|
|
245
|
+
#
|
|
246
|
+
# The timestamp that the image was compiled (as a Time instance).
|
|
247
|
+
#
|
|
248
|
+
attr_reader :timestamp
|
|
249
|
+
#
|
|
250
|
+
# The vendor that created the module.
|
|
251
|
+
#
|
|
252
|
+
attr_reader :vendor
|
|
253
|
+
#
|
|
254
|
+
# The preferred base address at which the module will load.
|
|
255
|
+
#
|
|
256
|
+
attr_reader :base_address
|
|
257
|
+
#
|
|
258
|
+
# The size of the image mapping associated with the module in bytes.
|
|
259
|
+
#
|
|
260
|
+
attr_reader :image_size
|
|
261
|
+
#
|
|
262
|
+
# An array of Segment instances.
|
|
263
|
+
#
|
|
264
|
+
attr_reader :segments
|
|
265
|
+
#
|
|
266
|
+
# An array of Import instances.
|
|
267
|
+
#
|
|
268
|
+
attr_reader :imports
|
|
269
|
+
#
|
|
270
|
+
# An array of Export instances.
|
|
271
|
+
#
|
|
272
|
+
attr_reader :exports
|
|
273
|
+
#
|
|
274
|
+
# An array of OsVersion instances.
|
|
275
|
+
#
|
|
276
|
+
attr_reader :platforms
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
###
|
|
280
|
+
#
|
|
281
|
+
# This class contains information about a specific locale, such as English.
|
|
282
|
+
#
|
|
283
|
+
###
|
|
284
|
+
class Locale
|
|
285
|
+
include DbEntry
|
|
286
|
+
class <<self
|
|
287
|
+
include Cachable
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
###
|
|
292
|
+
#
|
|
293
|
+
# This class contains information about a platform (operating system) version.
|
|
294
|
+
#
|
|
295
|
+
###
|
|
296
|
+
class OsVersion
|
|
297
|
+
include DbEntry
|
|
298
|
+
|
|
299
|
+
class <<self
|
|
300
|
+
include Cachable
|
|
301
|
+
def hash_key(hash)
|
|
302
|
+
hash['id'] + (hash['modules'] || '')
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def initialize(hash)
|
|
307
|
+
super
|
|
308
|
+
|
|
309
|
+
@modules = (hash['modules']) ? hash['modules'].to_i : 0
|
|
310
|
+
@desc = hash['desc']
|
|
311
|
+
@arch = hash['arch']
|
|
312
|
+
@maj_ver = hash['maj_ver'].to_i
|
|
313
|
+
@min_ver = hash['min_ver'].to_i
|
|
314
|
+
@maj_patch_level = hash['maj_patch_level'].to_i
|
|
315
|
+
@min_patch_level = hash['min_patch_level'].to_i
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
#
|
|
319
|
+
# The number of modules that exist in this operating system version.
|
|
320
|
+
#
|
|
321
|
+
attr_reader :modules
|
|
322
|
+
#
|
|
323
|
+
# The operating system version description, such as Windows XP 5.2.0.0
|
|
324
|
+
# (IA32).
|
|
325
|
+
#
|
|
326
|
+
attr_reader :desc
|
|
327
|
+
#
|
|
328
|
+
# The architecture that the operating system version runs on, such as IA32.
|
|
329
|
+
#
|
|
330
|
+
attr_reader :arch
|
|
331
|
+
#
|
|
332
|
+
# The major version of the operating system version.
|
|
333
|
+
#
|
|
334
|
+
attr_reader :maj_ver
|
|
335
|
+
#
|
|
336
|
+
# The minor version of the operating system version.
|
|
337
|
+
#
|
|
338
|
+
attr_reader :min_ver
|
|
339
|
+
#
|
|
340
|
+
# The major patch level of the operating system version, such as a service
|
|
341
|
+
# pack.
|
|
342
|
+
#
|
|
343
|
+
attr_reader :maj_patch_level
|
|
344
|
+
#
|
|
345
|
+
# The minor patch level of the operating system version.
|
|
346
|
+
#
|
|
347
|
+
attr_reader :min_patch_level
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
###
|
|
351
|
+
#
|
|
352
|
+
# An opcode group (esp => eip).
|
|
353
|
+
#
|
|
354
|
+
###
|
|
355
|
+
class Group
|
|
356
|
+
include DbEntry
|
|
357
|
+
class <<self
|
|
358
|
+
include Cachable
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
###
|
|
363
|
+
#
|
|
364
|
+
# An opcode type (jmp esp).
|
|
365
|
+
#
|
|
366
|
+
###
|
|
367
|
+
class Type
|
|
368
|
+
include DbEntry
|
|
369
|
+
|
|
370
|
+
class <<self
|
|
371
|
+
include Cachable
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
def initialize(hash)
|
|
375
|
+
super
|
|
376
|
+
|
|
377
|
+
@opcodes = (hash['opcodes']) ? hash['opcodes'].to_i : 0
|
|
378
|
+
@meta_type = MetaType.create(hash['meta_type']) if (hash['meta_type'])
|
|
379
|
+
@group = Group.create(hash['group']) if (hash['group'])
|
|
380
|
+
@arch = hash['arch']
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
#
|
|
384
|
+
# The number of opcodes associated with this type, or 0 if this information
|
|
385
|
+
# is not available.
|
|
386
|
+
#
|
|
387
|
+
attr_reader :opcodes
|
|
388
|
+
#
|
|
389
|
+
# An instance of the MetaType to which this opcode type belongs, or nil.
|
|
390
|
+
#
|
|
391
|
+
attr_reader :meta_type
|
|
392
|
+
#
|
|
393
|
+
# An instance of the Group to which this opcode type belongs, or nil.
|
|
394
|
+
#
|
|
395
|
+
attr_reader :group
|
|
396
|
+
#
|
|
397
|
+
# The architecture that this opcode type is associated with.
|
|
398
|
+
#
|
|
399
|
+
attr_reader :arch
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
###
|
|
403
|
+
#
|
|
404
|
+
# An opcode meta type (jmp reg).
|
|
405
|
+
#
|
|
406
|
+
###
|
|
407
|
+
class MetaType
|
|
408
|
+
include DbEntry
|
|
409
|
+
class <<self
|
|
410
|
+
include Cachable
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
###
|
|
415
|
+
#
|
|
416
|
+
# An opcode that has a specific address and is associated with one or more
|
|
417
|
+
# modules.
|
|
418
|
+
#
|
|
419
|
+
###
|
|
420
|
+
class Opcode
|
|
421
|
+
include DbEntry
|
|
422
|
+
|
|
423
|
+
def initialize(hash)
|
|
424
|
+
super
|
|
425
|
+
|
|
426
|
+
@address = hash['address'].to_i
|
|
427
|
+
@type = Type.create(hash['type'])
|
|
428
|
+
@group = @type.group
|
|
429
|
+
@modules = hash['modules'].map { |ent|
|
|
430
|
+
ImageModule.create(ent)
|
|
431
|
+
} if (hash['modules'])
|
|
432
|
+
|
|
433
|
+
@modules = [] unless(@modules)
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
#
|
|
437
|
+
# The address of the opcode.
|
|
438
|
+
#
|
|
439
|
+
attr_reader :address
|
|
440
|
+
#
|
|
441
|
+
# The type of the opcode indicating which instruction is found at the
|
|
442
|
+
# address. This is an instance of the Type class.
|
|
443
|
+
#
|
|
444
|
+
attr_reader :type
|
|
445
|
+
#
|
|
446
|
+
# A Group instance that reflects the group to which the opcode type found
|
|
447
|
+
# at the instance's address belongs.
|
|
448
|
+
#
|
|
449
|
+
attr_reader :group
|
|
450
|
+
#
|
|
451
|
+
# An array of ImageModule instances that show the modules that contain this
|
|
452
|
+
# address.
|
|
453
|
+
#
|
|
454
|
+
attr_reader :modules
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
###
|
|
458
|
+
#
|
|
459
|
+
# Current statistics of the opcode database.
|
|
460
|
+
#
|
|
461
|
+
###
|
|
462
|
+
class Statistics
|
|
463
|
+
def initialize(hash)
|
|
464
|
+
@modules = hash['modules'].to_i
|
|
465
|
+
@opcodes = hash['opcodes'].to_i
|
|
466
|
+
@opcode_types = hash['opcode_types'].to_i
|
|
467
|
+
@platforms = hash['platforms'].to_i
|
|
468
|
+
@architectures = hash['architectures'].to_i
|
|
469
|
+
@module_segments = hash['module_segments'].to_i
|
|
470
|
+
@module_imports = hash['module_imports'].to_i
|
|
471
|
+
@module_exports = hash['module_exports'].to_i
|
|
472
|
+
@last_update = Time.at(hash['last_update'].to_i)
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
#
|
|
476
|
+
# The number of modules found within the opcode database.
|
|
477
|
+
#
|
|
478
|
+
attr_reader :modules
|
|
479
|
+
#
|
|
480
|
+
# The number of opcodes supported by the opcode database.
|
|
481
|
+
#
|
|
482
|
+
attr_reader :opcodes
|
|
483
|
+
#
|
|
484
|
+
# The number of opcode types supported by the database.
|
|
485
|
+
#
|
|
486
|
+
attr_reader :opcode_types
|
|
487
|
+
#
|
|
488
|
+
# The number of platforms supported by the database.
|
|
489
|
+
#
|
|
490
|
+
attr_reader :platforms
|
|
491
|
+
#
|
|
492
|
+
# The number of architectures supported by the database.
|
|
493
|
+
#
|
|
494
|
+
attr_reader :architectures
|
|
495
|
+
#
|
|
496
|
+
# The number of module segments supported by the database.
|
|
497
|
+
#
|
|
498
|
+
attr_reader :module_segments
|
|
499
|
+
#
|
|
500
|
+
# The number of module imports supported by the database.
|
|
501
|
+
#
|
|
502
|
+
attr_reader :module_imports
|
|
503
|
+
#
|
|
504
|
+
# The number of module exports supported by the database.
|
|
505
|
+
#
|
|
506
|
+
attr_reader :module_exports
|
|
507
|
+
#
|
|
508
|
+
# The time at which the last database update occurred.
|
|
509
|
+
#
|
|
510
|
+
attr_reader :last_update
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
###
|
|
514
|
+
#
|
|
515
|
+
# This class implements a client interface to the Metasploit Opcode Database.
|
|
516
|
+
# It is intended to be used as a method of locating reliable return addresses
|
|
517
|
+
# given a set of executable files and a set of usable opcodes.
|
|
518
|
+
#
|
|
519
|
+
###
|
|
520
|
+
class Client
|
|
521
|
+
|
|
522
|
+
DefaultServerHost = "www.metasploit.com"
|
|
523
|
+
DefaultServerPort = 80
|
|
524
|
+
DefaultServerUri = "/users/opcode/msfopcode_server.cgi"
|
|
525
|
+
|
|
526
|
+
#
|
|
527
|
+
# Returns an instance of an initialized client that will use the supplied
|
|
528
|
+
# server values.
|
|
529
|
+
#
|
|
530
|
+
def initialize(host = DefaultServerHost, port = DefaultServerPort, uri = DefaultServerUri)
|
|
531
|
+
self.server_host = host
|
|
532
|
+
self.server_port = port
|
|
533
|
+
self.server_uri = uri
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
#
|
|
537
|
+
# Disables response parsing.
|
|
538
|
+
#
|
|
539
|
+
def disable_parse
|
|
540
|
+
@disable_parse = true
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
#
|
|
544
|
+
# Enables response parsing.
|
|
545
|
+
#
|
|
546
|
+
def enable_parse
|
|
547
|
+
@disable_parse = false
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
#
|
|
551
|
+
# Returns an array of MetaType instances.
|
|
552
|
+
#
|
|
553
|
+
def meta_types
|
|
554
|
+
request('meta_types').map { |ent| MetaType.create(ent) }
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
#
|
|
558
|
+
# Returns an array of Group instances.
|
|
559
|
+
#
|
|
560
|
+
def groups
|
|
561
|
+
request('groups').map { |ent| Group.create(ent) }
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
#
|
|
565
|
+
# Returns an array of Type instances. Opcode types are specific opcodes,
|
|
566
|
+
# such as a jmp esp. Optionally, a filter hash can be passed to include
|
|
567
|
+
# extra information in the results.
|
|
568
|
+
#
|
|
569
|
+
# Statistics (Bool)
|
|
570
|
+
#
|
|
571
|
+
# If this hash element is set to true, the number of opcodes currently in
|
|
572
|
+
# the database of this type will be returned.
|
|
573
|
+
#
|
|
574
|
+
def types(filter = {})
|
|
575
|
+
request('types', filter).map { |ent| Type.create(ent) }
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
#
|
|
579
|
+
# Returns an array of OsVersion instances. OS versions are associated with
|
|
580
|
+
# a particular operating system release (including service packs).
|
|
581
|
+
# Optionally, a filter hash can be passed to limit the number of results
|
|
582
|
+
# returned. If no filter hash is supplied, all results are returned.
|
|
583
|
+
#
|
|
584
|
+
# Names (Array)
|
|
585
|
+
#
|
|
586
|
+
# If this hash element is specified, only the operating systems that
|
|
587
|
+
# contain one or more of the names specified will be returned.
|
|
588
|
+
#
|
|
589
|
+
# Statistics (Bool)
|
|
590
|
+
#
|
|
591
|
+
# If this hash element is set to true, the number of modules associated
|
|
592
|
+
# with this matched operating system versions will be returned.
|
|
593
|
+
#
|
|
594
|
+
def platforms(filter = {})
|
|
595
|
+
request('platforms', filter).map { |ent| OsVersion.create(ent) }
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
#
|
|
599
|
+
# Returns an array of ImageModule instances. Image modules are
|
|
600
|
+
# version-specific, locale-specific, and operating system version specific
|
|
601
|
+
# image files. Modules have opcodes, segments, imports and exports
|
|
602
|
+
# associated with them. Optionally, a filter hash can be specified to
|
|
603
|
+
# limit the number of results returned from the database. If no filter
|
|
604
|
+
# hash is supplied, all modules will be returned.
|
|
605
|
+
#
|
|
606
|
+
# LocaleNames (Array)
|
|
607
|
+
#
|
|
608
|
+
# This hash element limits results to one or more specific locale by name.
|
|
609
|
+
#
|
|
610
|
+
# PlatformNames (Array)
|
|
611
|
+
#
|
|
612
|
+
# This hash element limits results to one or more specific platform by
|
|
613
|
+
# name.
|
|
614
|
+
#
|
|
615
|
+
# ModuleNames (Array)
|
|
616
|
+
#
|
|
617
|
+
# This hash element limits results to one or more specific module by name.
|
|
618
|
+
#
|
|
619
|
+
# Segments (Bool)
|
|
620
|
+
#
|
|
621
|
+
# If this hash element is set to true, the segments associated with each
|
|
622
|
+
# resulting module will be returned by the server.
|
|
623
|
+
#
|
|
624
|
+
# Imports (Bool)
|
|
625
|
+
#
|
|
626
|
+
# If this hash element is set to true, the imports associated with each
|
|
627
|
+
# resulting module will be returned by the server.
|
|
628
|
+
#
|
|
629
|
+
# Exports (Bool)
|
|
630
|
+
#
|
|
631
|
+
# If this hash element is set to true, the exports associated with each
|
|
632
|
+
# resulting module will be returned by the server.
|
|
633
|
+
#
|
|
634
|
+
def modules(filter = {})
|
|
635
|
+
request('modules', filter).map { |ent| ImageModule.create(ent) }
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
#
|
|
639
|
+
# Returns an array of Locale instances that are supported by the server.
|
|
640
|
+
#
|
|
641
|
+
def locales
|
|
642
|
+
request('locales').map { |ent| Locale.create(ent) }
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
#
|
|
646
|
+
# Returns an array of Opcode instances that match the filter limitations
|
|
647
|
+
# specified in the supplied filter hash. If no filter hash is specified,
|
|
648
|
+
# all opcodes will be returned (but are most likely going to be limited by
|
|
649
|
+
# the server). The filter hash limiters that can be specified are:
|
|
650
|
+
#
|
|
651
|
+
# ModuleNames (Array)
|
|
652
|
+
#
|
|
653
|
+
# This hash element limits results to one or more specific modules by
|
|
654
|
+
# name.
|
|
655
|
+
#
|
|
656
|
+
# GroupNames (Array)
|
|
657
|
+
#
|
|
658
|
+
# This hash element limits results to one or more specific opcode group by
|
|
659
|
+
# name.
|
|
660
|
+
#
|
|
661
|
+
# TypeNames (Array)
|
|
662
|
+
#
|
|
663
|
+
# This hash element limits results to one or more specific opcode type by
|
|
664
|
+
# name.
|
|
665
|
+
#
|
|
666
|
+
# MetaTypeNames (Array)
|
|
667
|
+
#
|
|
668
|
+
# This hash element limits results to one or more specific opcode meta
|
|
669
|
+
# type by name.
|
|
670
|
+
#
|
|
671
|
+
# LocaleNames (Array)
|
|
672
|
+
#
|
|
673
|
+
# Limits results to one or more specific locale by name.
|
|
674
|
+
#
|
|
675
|
+
# PlatformNames (Array)
|
|
676
|
+
#
|
|
677
|
+
# Limits reslts to one or more specific operating system version by name.
|
|
678
|
+
#
|
|
679
|
+
# Addresses (Array)
|
|
680
|
+
#
|
|
681
|
+
# Limits results to a specific set of addresses.
|
|
682
|
+
#
|
|
683
|
+
# Portable (Bool)
|
|
684
|
+
#
|
|
685
|
+
# If this hash element is true, opcode results will be limited to ones
|
|
686
|
+
# that span more than one operating system version.
|
|
687
|
+
#
|
|
688
|
+
def search(filter = {})
|
|
689
|
+
request('search', filter).map { |ent| Opcode.new(ent) }
|
|
690
|
+
end
|
|
691
|
+
|
|
692
|
+
#
|
|
693
|
+
# Returns an instance of the Statistics class that holds information about
|
|
694
|
+
# the server's database stats.
|
|
695
|
+
#
|
|
696
|
+
def statistics
|
|
697
|
+
Statistics.new(request('statistics'))
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
#
|
|
701
|
+
# These attributes convey information about the remote server and can be
|
|
702
|
+
# changed in order to point it to a locate copy as necessary.
|
|
703
|
+
#
|
|
704
|
+
attr_accessor :server_host, :server_port, :server_uri
|
|
705
|
+
|
|
706
|
+
#
|
|
707
|
+
# Retrieves the last raw XML response to be processed.
|
|
708
|
+
#
|
|
709
|
+
attr_reader :last_xml
|
|
710
|
+
|
|
711
|
+
protected
|
|
712
|
+
|
|
713
|
+
#
|
|
714
|
+
# Transmits a request to the Opcode database server and translates the
|
|
715
|
+
# response into a native general ruby datatype.
|
|
716
|
+
#
|
|
717
|
+
def request(method, opts = {})
|
|
718
|
+
client = Rex::Proto::Http::Client.new(server_host, server_port)
|
|
719
|
+
|
|
720
|
+
begin
|
|
721
|
+
|
|
722
|
+
# Create the CGI parameter list
|
|
723
|
+
vars = { 'method' => method }
|
|
724
|
+
|
|
725
|
+
opts.each_pair do |k, v|
|
|
726
|
+
vars[k] = xlate_param(v)
|
|
727
|
+
end
|
|
728
|
+
|
|
729
|
+
client.set_config('uri_encode_mode' => 'none')
|
|
730
|
+
|
|
731
|
+
# Initialize the request with the POST body.
|
|
732
|
+
request = client.request_cgi(
|
|
733
|
+
'method' => 'POST',
|
|
734
|
+
'uri' => server_uri,
|
|
735
|
+
'vars_post' => vars
|
|
736
|
+
)
|
|
737
|
+
|
|
738
|
+
# Send the request and grab the response.
|
|
739
|
+
response = client.send_recv(request, 300)
|
|
740
|
+
|
|
741
|
+
# Non-200 return code?
|
|
742
|
+
if (response.code != 200)
|
|
743
|
+
raise RuntimeError, "Invalid response received from server."
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
# Convert the return value to the native type.
|
|
747
|
+
parse_response(response.body)
|
|
748
|
+
rescue ::SocketError
|
|
749
|
+
raise RuntimeError, "Could not communicate with the opcode service: #{$!.class} #{$!}"
|
|
750
|
+
ensure
|
|
751
|
+
client.close
|
|
752
|
+
end
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
#
|
|
756
|
+
# Translates a parameter into a flat CGI parameter string.
|
|
757
|
+
#
|
|
758
|
+
def xlate_param(v)
|
|
759
|
+
if (v.kind_of?(Array))
|
|
760
|
+
v.map { |ent|
|
|
761
|
+
xlate_param(ent)
|
|
762
|
+
}.join(',,')
|
|
763
|
+
elsif (v.kind_of?(Hash))
|
|
764
|
+
v.map { |k,v|
|
|
765
|
+
"#{URI.escape(k)}:#{xlate_param(v)}" if (v)
|
|
766
|
+
}.join(',,')
|
|
767
|
+
else
|
|
768
|
+
URI.escape(v.to_s)
|
|
769
|
+
end
|
|
770
|
+
end
|
|
771
|
+
|
|
772
|
+
#
|
|
773
|
+
# Translate the data type from a flat string to a ruby native type.
|
|
774
|
+
#
|
|
775
|
+
def parse_response(xml)
|
|
776
|
+
@last_xml = xml
|
|
777
|
+
|
|
778
|
+
if (!@disable_parse)
|
|
779
|
+
source = REXML::Source.new(xml)
|
|
780
|
+
doc = REXML::Document.new
|
|
781
|
+
|
|
782
|
+
REXML::Parsers::TreeParser.new(source, doc).parse
|
|
783
|
+
|
|
784
|
+
translate_element(doc.root)
|
|
785
|
+
end
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
#
|
|
789
|
+
# Translate elements conveyed as data types.
|
|
790
|
+
#
|
|
791
|
+
def translate_element(element)
|
|
792
|
+
case element.name
|
|
793
|
+
when "Array"
|
|
794
|
+
return element.elements.map { |child| translate_element(child) }
|
|
795
|
+
when "Hash"
|
|
796
|
+
hsh = {}
|
|
797
|
+
|
|
798
|
+
element.each_element { |child|
|
|
799
|
+
if (e = child.elements[1])
|
|
800
|
+
v = translate_element(e)
|
|
801
|
+
else
|
|
802
|
+
v = child.text
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
hsh[child.attributes['name']] = v
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
return hsh
|
|
809
|
+
else
|
|
810
|
+
return element.text
|
|
811
|
+
end
|
|
812
|
+
end
|
|
813
|
+
|
|
814
|
+
end
|
|
815
|
+
|
|
816
|
+
end
|
|
817
|
+
end
|
|
818
|
+
end
|