watobo 0.9.21 → 0.9.23
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 +7 -0
- data/CHANGELOG.md +46 -1
- data/bin/nfq_server.rb +0 -9
- data/bin/watobo_gui.rb +3 -13
- data/custom-views/prettify-json.rb +9 -18
- data/icons/watobo.ico +0 -0
- data/icons/watobo.ico.old +0 -0
- data/lib/watobo.rb +10 -19
- data/lib/watobo/adapters.rb +5 -14
- data/lib/watobo/adapters/data_store.rb +50 -59
- data/lib/watobo/adapters/file/file_store.rb +287 -296
- data/lib/watobo/adapters/file/marshal_store.rb +293 -296
- data/lib/watobo/adapters/session_store.rb +5 -14
- data/lib/watobo/ca.rb +1 -10
- data/lib/watobo/config.rb +197 -206
- data/lib/watobo/constants.rb +0 -9
- data/lib/watobo/core.rb +3 -12
- data/lib/watobo/core/active_check.rb +72 -135
- data/lib/watobo/core/active_checks.rb +49 -58
- data/lib/watobo/core/ca.rb +369 -389
- data/lib/watobo/core/cert_store.rb +34 -43
- data/lib/watobo/core/chat.rb +92 -101
- data/lib/watobo/core/chats.rb +271 -280
- data/lib/watobo/core/client_cert_store.rb +106 -35
- data/lib/watobo/core/conversation.rb +48 -57
- data/lib/watobo/core/cookie.rb +23 -32
- data/lib/watobo/core/egress_handlers.rb +98 -0
- data/lib/watobo/core/finding.rb +66 -75
- data/lib/watobo/core/findings.rb +107 -114
- data/lib/watobo/core/forwarding_proxy.rb +13 -22
- data/lib/watobo/core/fuzz_gen.rb +0 -9
- data/lib/watobo/core/intercept_carver.rb +166 -177
- data/lib/watobo/core/intercept_filter.rb +235 -244
- data/lib/watobo/core/interceptor.rb +98 -107
- data/lib/watobo/core/min_class.rb +4 -13
- data/lib/watobo/core/netfilter_queue.rb +170 -179
- data/lib/watobo/core/ott_cache.rb +132 -141
- data/lib/watobo/core/parameter.rb +43 -52
- data/lib/watobo/core/passive_check.rb +103 -102
- data/lib/watobo/core/passive_checks.rb +48 -57
- data/lib/watobo/core/passive_scanner.rb +54 -55
- data/lib/watobo/core/plugin.rb +11 -20
- data/lib/watobo/core/project.rb +3 -9
- data/lib/watobo/core/proxy.rb +43 -52
- data/lib/watobo/core/request.rb +125 -123
- data/lib/watobo/core/response.rb +44 -53
- data/lib/watobo/core/scanner.rb +0 -9
- data/lib/watobo/core/scanner3.rb +405 -414
- data/lib/watobo/core/scope.rb +83 -92
- data/lib/watobo/core/session.rb +1043 -1026
- data/lib/watobo/core/sid_cache.rb +98 -107
- data/lib/watobo/core/subscriber.rb +25 -34
- data/lib/watobo/defaults.rb +21 -30
- data/lib/watobo/external/diff/lcs.rb +0 -9
- data/lib/watobo/external/diff/lcs/array.rb +0 -9
- data/lib/watobo/external/diff/lcs/block.rb +0 -9
- data/lib/watobo/external/diff/lcs/callbacks.rb +0 -9
- data/lib/watobo/external/diff/lcs/change.rb +0 -9
- data/lib/watobo/external/diff/lcs/hunk.rb +0 -9
- data/lib/watobo/external/diff/lcs/ldiff.rb +0 -9
- data/lib/watobo/external/diff/lcs/string.rb +0 -9
- data/lib/watobo/externals.rb +6 -15
- data/lib/watobo/framework.rb +4 -13
- data/lib/watobo/framework/create_project.rb +60 -69
- data/lib/watobo/framework/init.rb +0 -9
- data/lib/watobo/framework/init_modules.rb +0 -9
- data/lib/watobo/framework/license_text.rb +28 -37
- data/lib/watobo/framework/load_chat.rb +13 -22
- data/lib/watobo/gui.rb +132 -123
- data/lib/watobo/gui/about_watobo.rb +0 -9
- data/lib/watobo/gui/browser_preview.rb +0 -9
- data/lib/watobo/gui/certificate_dialog.rb +0 -9
- data/lib/watobo/gui/chat_diff.rb +0 -9
- data/lib/watobo/gui/chatviewer_frame.rb +73 -72
- data/lib/watobo/gui/checkboxtree.rb +0 -9
- data/lib/watobo/gui/checks_policy_frame.rb +0 -9
- data/lib/watobo/gui/client_cert_dialog.rb +96 -87
- data/lib/watobo/gui/confirm_scan_dialog.rb +0 -9
- data/lib/watobo/gui/conversation_table.rb +158 -164
- data/lib/watobo/gui/conversation_table_ctrl.rb +207 -216
- data/lib/watobo/gui/conversation_table_ctrl2.rb +373 -382
- data/lib/watobo/gui/csrf_token_dialog.rb +0 -9
- data/lib/watobo/gui/custom_viewer.rb +374 -383
- data/lib/watobo/gui/dashboard.rb +296 -303
- data/lib/watobo/gui/define_scope_frame.rb +0 -9
- data/lib/watobo/gui/differ_frame.rb +215 -224
- data/lib/watobo/gui/edit_comment.rb +0 -9
- data/lib/watobo/gui/edit_scope_dialog.rb +0 -9
- data/lib/watobo/gui/export_dialog.rb +104 -113
- data/lib/watobo/gui/finding_info.rb +0 -9
- data/lib/watobo/gui/findings_tree.rb +210 -217
- data/lib/watobo/gui/full_scan_dialog.rb +0 -9
- data/lib/watobo/gui/fuzzer_gui.rb +1295 -1313
- data/lib/watobo/gui/fxsave_thread.rb +14 -0
- data/lib/watobo/gui/goto_url_dialog.rb +70 -79
- data/lib/watobo/gui/hex_viewer.rb +0 -9
- data/lib/watobo/gui/html_viewer.rb +287 -296
- data/lib/watobo/gui/intercept_filter_dialog.rb +188 -197
- data/lib/watobo/gui/interceptor_gui.rb +1041 -1051
- data/lib/watobo/gui/interceptor_settings_dialog.rb +0 -9
- data/lib/watobo/gui/json_viewer.rb +287 -0
- data/lib/watobo/gui/list_box.rb +101 -110
- data/lib/watobo/gui/log_file_viewer.rb +32 -41
- data/lib/watobo/gui/log_viewer.rb +83 -88
- data/lib/watobo/gui/login_wizzard.rb +0 -9
- data/lib/watobo/gui/main_window.rb +587 -618
- data/lib/watobo/gui/manual_request_editor.rb +620 -565
- data/lib/watobo/gui/master_pw_dialog.rb +0 -9
- data/lib/watobo/gui/mixins/gui_settings.rb +29 -38
- data/lib/watobo/gui/page_tree.rb +217 -226
- data/lib/watobo/gui/password_policy_dialog.rb +0 -9
- data/lib/watobo/gui/plugin_board.rb +0 -9
- data/lib/watobo/gui/preferences_dialog.rb +0 -9
- data/lib/watobo/gui/progress_window.rb +17 -27
- data/lib/watobo/gui/project_wizzard.rb +0 -9
- data/lib/watobo/gui/proxy_dialog.rb +1 -10
- data/lib/watobo/gui/quick_scan_dialog.rb +0 -9
- data/lib/watobo/gui/request_builder_frame.rb +102 -111
- data/lib/watobo/gui/request_editor.rb +181 -137
- data/lib/watobo/gui/rewrite_filters_dialog.rb +394 -403
- data/lib/watobo/gui/rewrite_rules_dialog.rb +372 -381
- data/lib/watobo/gui/save_chat_dialog.rb +140 -149
- data/lib/watobo/gui/scanner_settings_dialog.rb +0 -9
- data/lib/watobo/gui/select_chat_dialog.rb +0 -9
- data/lib/watobo/gui/session_management_dialog.rb +0 -9
- data/lib/watobo/gui/sites_tree.rb +0 -9
- data/lib/watobo/gui/status_bar.rb +0 -9
- data/lib/watobo/gui/table_editor.rb +0 -9
- data/lib/watobo/gui/tagless_viewer.rb +0 -9
- data/lib/watobo/gui/templates/plugin.rb +0 -9
- data/lib/watobo/gui/templates/plugin2.rb +92 -100
- data/lib/watobo/gui/templates/plugin_base.rb +144 -153
- data/lib/watobo/gui/text_viewer.rb +0 -9
- data/lib/watobo/gui/transcoder_window.rb +0 -9
- data/lib/watobo/gui/utils/gui_utils.rb +0 -9
- data/lib/watobo/gui/utils/init_icons.rb +86 -95
- data/lib/watobo/gui/utils/load_icons.rb +33 -42
- data/lib/watobo/gui/utils/load_plugins.rb +116 -119
- data/lib/watobo/gui/utils/master_password.rb +68 -77
- data/lib/watobo/gui/utils/save_default_settings.rb +113 -122
- data/lib/watobo/gui/utils/save_project_settings.rb +0 -9
- data/lib/watobo/gui/utils/save_proxy_settings.rb +41 -50
- data/lib/watobo/gui/utils/save_scanner_settings.rb +18 -27
- data/lib/watobo/gui/utils/session_history.rb +112 -121
- data/lib/watobo/gui/workspace_dialog.rb +0 -9
- data/lib/watobo/gui/www_auth_dialog.rb +0 -9
- data/lib/watobo/gui/xml_viewer_frame.rb +0 -9
- data/lib/watobo/http.rb +4 -13
- data/lib/watobo/http/cookies/cookies.rb +26 -35
- data/lib/watobo/http/data/data.rb +45 -54
- data/lib/watobo/http/data/json.rb +47 -55
- data/lib/watobo/http/url/url.rb +38 -47
- data/lib/watobo/http/xml/xml.rb +124 -130
- data/lib/watobo/interceptor.rb +3 -12
- data/lib/watobo/interceptor/proxy.rb +742 -739
- data/lib/watobo/interceptor/transparent.rb +22 -24
- data/lib/watobo/mixins.rb +10 -19
- data/lib/watobo/mixins/check_info.rb +27 -36
- data/lib/watobo/mixins/httpparser.rb +613 -637
- data/lib/watobo/mixins/request_parser.rb +88 -97
- data/lib/watobo/mixins/shapers.rb +515 -529
- data/lib/watobo/mixins/transcoders.rb +3 -11
- data/lib/watobo/parser.rb +1 -10
- data/lib/watobo/parser/html.rb +83 -92
- data/lib/watobo/patch_fxruby_setfocus.rb +26 -0
- data/lib/watobo/sockets.rb +3 -12
- data/lib/watobo/sockets/agent.rb +828 -837
- data/lib/watobo/sockets/client_socket.rb +308 -312
- data/lib/watobo/sockets/connection.rb +401 -410
- data/lib/watobo/sockets/http_socket.rb +11 -13
- data/lib/watobo/sockets/ntlm_auth.rb +129 -138
- data/lib/watobo/utils.rb +10 -19
- data/lib/watobo/utils/check_regex.rb +0 -9
- data/lib/watobo/utils/copy_object.rb +0 -9
- data/lib/watobo/utils/crypto.rb +0 -9
- data/lib/watobo/utils/expand_range.rb +23 -32
- data/lib/watobo/utils/export_xml.rb +97 -106
- data/lib/watobo/utils/file_management.rb +9 -11
- data/lib/watobo/utils/hexprint.rb +9 -18
- data/lib/watobo/utils/load_chat.rb +0 -9
- data/lib/watobo/utils/load_icon.rb +0 -9
- data/lib/watobo/utils/ntlm.rb +866 -875
- data/lib/watobo/utils/print_debug.rb +12 -21
- data/lib/watobo/utils/response_builder.rb +90 -99
- data/lib/watobo/utils/response_hash.rb +0 -9
- data/lib/watobo/utils/secure_eval.rb +0 -9
- data/lib/watobo/utils/strings.rb +10 -19
- data/lib/watobo/utils/text2request.rb +0 -9
- data/lib/watobo/utils/url.rb +23 -32
- data/lib/watobo/utils/utf16.rb +11 -20
- data/modules/active/Apache/mod_status.rb +0 -9
- data/modules/active/Apache/multiview.rb +151 -160
- data/modules/active/Flash/crossdomain.rb +0 -9
- data/modules/active/JWT/jwt_oauth2_none.rb +111 -0
- data/modules/active/cq5/cq5_default_selectors.rb +106 -115
- data/modules/active/cq5/cqp_user_enumeration.rb +125 -134
- data/modules/active/directories/dirwalker.rb +0 -9
- data/modules/active/discovery/fileextensions.rb +0 -9
- data/modules/active/discovery/http_methods.rb +0 -9
- data/modules/active/discovery/jsmapfiles.rb +79 -0
- data/modules/active/domino/domino_db.rb +68 -76
- data/modules/active/dotNET/custom_errors.rb +102 -111
- data/modules/active/dotNET/dotnet_files.rb +90 -99
- data/modules/active/fileinclusion/lfi_simple.rb +0 -9
- data/modules/active/jboss/jboss_basic.rb +0 -9
- data/modules/active/sap/business_objects.rb +51 -60
- data/modules/active/sap/its_commands.rb +0 -9
- data/modules/active/sap/its_service_parameter.rb +0 -9
- data/modules/active/sap/its_services.rb +0 -9
- data/modules/active/sap/its_xss.rb +0 -9
- data/modules/active/shell_shock/shell_shock.rb +139 -148
- data/modules/active/siebel/siebel_apps.rb +160 -169
- data/modules/active/sqlinjection/sql_boolean.rb +0 -9
- data/modules/active/sqlinjection/sql_numerical.rb +198 -0
- data/modules/active/sqlinjection/sqli_error.rb +0 -9
- data/modules/active/sqlinjection/sqli_timing.rb +220 -229
- data/modules/active/struts2/default_handler_ognl.rb +106 -115
- data/modules/active/struts2/include_params_ognl.rb +105 -114
- data/modules/active/xml/xml_xxe.rb +112 -123
- data/modules/active/xss/xss_ng.rb +214 -223
- data/modules/active/xss/xss_simple.rb +0 -9
- data/modules/passive/ajax.rb +68 -77
- data/modules/passive/autocomplete.rb +56 -65
- data/modules/passive/cookie_options.rb +0 -9
- data/modules/passive/cookie_xss.rb +0 -9
- data/modules/passive/detect_code.rb +0 -9
- data/modules/passive/detect_fileupload.rb +0 -9
- data/modules/passive/detect_infrastructure.rb +0 -9
- data/modules/passive/detect_one_time_tokens.rb +0 -9
- data/modules/passive/dirindexing.rb +0 -9
- data/modules/passive/disclosure_domino.rb +55 -64
- data/modules/passive/disclosure_emails.rb +0 -9
- data/modules/passive/disclosure_ipaddr.rb +55 -53
- data/modules/passive/filename_as_parameter.rb +0 -9
- data/modules/passive/form_spotter.rb +0 -9
- data/modules/passive/hidden_fields.rb +50 -59
- data/modules/passive/hotspots.rb +0 -9
- data/modules/passive/in_script_parameter.rb +0 -9
- data/modules/passive/json_web_token.rb +93 -0
- data/modules/passive/multiple_server_headers.rb +0 -9
- data/modules/passive/possible_login.rb +0 -9
- data/modules/passive/redirect_url.rb +0 -9
- data/modules/passive/redirectionz.rb +0 -9
- data/modules/passive/sap-headers.rb +56 -65
- data/modules/passive/xss_dom.rb +0 -9
- data/plugins/aem/aem.rb +11 -20
- data/plugins/aem/gui/main.rb +118 -127
- data/plugins/aem/gui/tree_view.rb +171 -180
- data/plugins/aem/lib/agent.rb +130 -138
- data/plugins/aem/lib/dispatcher.rb +45 -51
- data/plugins/aem/lib/engine.rb +177 -186
- data/plugins/catalog/catalog.rb +345 -355
- data/plugins/crawler/crawler.rb +4 -13
- data/plugins/crawler/gui.rb +5 -14
- data/plugins/crawler/gui/auth_frame.rb +270 -279
- data/plugins/crawler/gui/crawler_gui.rb +271 -276
- data/plugins/crawler/gui/general_settings_frame.rb +96 -105
- data/plugins/crawler/gui/hooks_frame.rb +80 -89
- data/plugins/crawler/gui/scope_frame.rb +50 -59
- data/plugins/crawler/gui/settings_tabbook.rb +38 -47
- data/plugins/crawler/gui/status_frame.rb +59 -68
- data/plugins/crawler/lib/bags.rb +18 -27
- data/plugins/crawler/lib/constants.rb +11 -20
- data/plugins/crawler/lib/engine.rb +488 -497
- data/plugins/crawler/lib/grabber.rb +68 -77
- data/plugins/crawler/lib/status.rb +71 -80
- data/plugins/crawler/lib/uri_mp.rb +12 -21
- data/plugins/filefinder/filefinder.rb +326 -333
- data/plugins/sqlmap/bin/test.rb +78 -87
- data/plugins/sqlmap/gui.rb +4 -13
- data/plugins/sqlmap/gui/main.rb +218 -227
- data/plugins/sqlmap/gui/options_frame.rb +97 -106
- data/plugins/sqlmap/lib/sqlmap_ctrl.rb +90 -100
- data/plugins/sqlmap/sqlmap.rb +2 -11
- data/plugins/sslchecker/cli/sslchecker_cli.rb +0 -9
- data/plugins/sslchecker/gui/cipher_table.rb +246 -254
- data/plugins/sslchecker/gui/gui.rb +258 -264
- data/plugins/sslchecker/gui/sslchecker.rb +4 -13
- data/plugins/sslchecker/lib/check.rb +127 -133
- data/plugins/wshell/gui/main.rb +119 -117
- data/plugins/wshell/lib/core.rb +38 -88
- data/plugins/wshell/wshell.rb +11 -20
- metadata +170 -164
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
#.
|
|
2
|
-
# transcoders.rb
|
|
3
|
-
#.
|
|
4
|
-
# Copyright 2014 by siberas, http://www.siberas.de
|
|
5
|
-
# This file is part of WATOBO (Web Application Tool Box) http://watobo.sourceforge.com
|
|
6
|
-
# WATOBO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License.
|
|
7
|
-
# WATOBO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
8
|
-
# You should have received a copy of the GNU General Public License along with WATOBO; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
9
|
-
|
|
10
1
|
# @private
|
|
11
2
|
module Watobo#:nodoc: all
|
|
12
3
|
module Mixin
|
|
@@ -23,8 +14,9 @@ module Watobo#:nodoc: all
|
|
|
23
14
|
err_count = 0
|
|
24
15
|
begin
|
|
25
16
|
b64string = self.force_encoding('ASCII-8BIT')
|
|
26
|
-
rs = Base64.strict_decode64(b64string)
|
|
27
|
-
#
|
|
17
|
+
#rs = Base64.strict_decode64(b64string)
|
|
18
|
+
# using regular decode64 because of JWT (JSON Web Tokens) decoding
|
|
19
|
+
rs = Base64.decode64(b64string)
|
|
28
20
|
return rs
|
|
29
21
|
rescue
|
|
30
22
|
#b64string.gsub!(/.$/,'')
|
data/lib/watobo/parser.rb
CHANGED
|
@@ -1,10 +1 @@
|
|
|
1
|
-
|
|
2
|
-
# parser.rb
|
|
3
|
-
#.
|
|
4
|
-
# Copyright 2014 by siberas, http://www.siberas.de
|
|
5
|
-
# This file is part of WATOBO (Web Application Tool Box) http://watobo.sourceforge.com
|
|
6
|
-
# WATOBO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License.
|
|
7
|
-
# WATOBO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
8
|
-
# You should have received a copy of the GNU General Public License along with WATOBO; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
9
|
-
|
|
10
|
-
require 'watobo/parser/html'
|
|
1
|
+
require 'watobo/parser/html'
|
data/lib/watobo/parser/html.rb
CHANGED
|
@@ -1,94 +1,85 @@
|
|
|
1
|
-
#.
|
|
2
|
-
# html.rb
|
|
3
|
-
#.
|
|
4
|
-
# Copyright 2014 by siberas, http://www.siberas.de
|
|
5
|
-
# This file is part of WATOBO (Web Application Tool Box) http://watobo.sourceforge.com
|
|
6
|
-
# WATOBO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License.
|
|
7
|
-
# WATOBO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
8
|
-
# You should have received a copy of the GNU General Public License along with WATOBO; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
9
|
-
|
|
10
1
|
# @private
|
|
11
|
-
module Watobo#:nodoc: all
|
|
12
|
-
module Parser
|
|
13
|
-
module HTML
|
|
14
|
-
class Form
|
|
15
|
-
def input_fields(&block)
|
|
16
|
-
if block_given?
|
|
17
|
-
@input_fields.each do |field|
|
|
18
|
-
yield field
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
@input_fields
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def initialize(form_css)
|
|
25
|
-
@form = form_css
|
|
26
|
-
@input_fields = []
|
|
27
|
-
@form.css('input').each do |i|
|
|
28
|
-
@input_fields << InputField.new(i)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
class InputField
|
|
35
|
-
attr :id
|
|
36
|
-
attr :value
|
|
37
|
-
attr :name
|
|
38
|
-
# attr :autocomplete
|
|
39
|
-
|
|
40
|
-
def to_www_form_parm()
|
|
41
|
-
Watobo::WWWFormParameter.new(:name => @name, :value => @value)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def to_url_parm()
|
|
45
|
-
Watobo::UrlParameter.new(:name => @name, :value => @value)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def initialize(input_css)
|
|
49
|
-
@css = input_css
|
|
50
|
-
@id = input_css["id"].nil? ? "" : input_css["id"]
|
|
51
|
-
@value = input_css["value"].nil? ? "" : input_css["value"]
|
|
52
|
-
@name = input_css["name"].nil? ? "" : input_css["name"]
|
|
53
|
-
#@autocomplete = input_css["autocomplete"]
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def method_missing(name, *args, &block)
|
|
57
|
-
@css[name.to_s].nil? ? "" : input_css[name.to_s]
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
class Links
|
|
63
|
-
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def links(&block)
|
|
67
|
-
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def input_fields(&block)
|
|
71
|
-
fields = []
|
|
72
|
-
forms do |form|
|
|
73
|
-
form.input_fields do |field|
|
|
74
|
-
yield field if block_given?
|
|
75
|
-
fields << field
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
fields
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def forms(&block)
|
|
83
|
-
fs = []
|
|
84
|
-
doc = Nokogiri::HTML(self.body)
|
|
85
|
-
doc.css('form').each do |f|
|
|
86
|
-
fo = Form.new(f)
|
|
87
|
-
yield fo if block_given?
|
|
88
|
-
end
|
|
89
|
-
fs
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
end
|
|
93
|
-
end
|
|
2
|
+
module Watobo#:nodoc: all
|
|
3
|
+
module Parser
|
|
4
|
+
module HTML
|
|
5
|
+
class Form
|
|
6
|
+
def input_fields(&block)
|
|
7
|
+
if block_given?
|
|
8
|
+
@input_fields.each do |field|
|
|
9
|
+
yield field
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
@input_fields
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def initialize(form_css)
|
|
16
|
+
@form = form_css
|
|
17
|
+
@input_fields = []
|
|
18
|
+
@form.css('input').each do |i|
|
|
19
|
+
@input_fields << InputField.new(i)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class InputField
|
|
26
|
+
attr :id
|
|
27
|
+
attr :value
|
|
28
|
+
attr :name
|
|
29
|
+
# attr :autocomplete
|
|
30
|
+
|
|
31
|
+
def to_www_form_parm()
|
|
32
|
+
Watobo::WWWFormParameter.new(:name => @name, :value => @value)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_url_parm()
|
|
36
|
+
Watobo::UrlParameter.new(:name => @name, :value => @value)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def initialize(input_css)
|
|
40
|
+
@css = input_css
|
|
41
|
+
@id = input_css["id"].nil? ? "" : input_css["id"]
|
|
42
|
+
@value = input_css["value"].nil? ? "" : input_css["value"]
|
|
43
|
+
@name = input_css["name"].nil? ? "" : input_css["name"]
|
|
44
|
+
#@autocomplete = input_css["autocomplete"]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def method_missing(name, *args, &block)
|
|
48
|
+
@css[name.to_s].nil? ? "" : input_css[name.to_s]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class Links
|
|
54
|
+
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def links(&block)
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def input_fields(&block)
|
|
62
|
+
fields = []
|
|
63
|
+
forms do |form|
|
|
64
|
+
form.input_fields do |field|
|
|
65
|
+
yield field if block_given?
|
|
66
|
+
fields << field
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
fields
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def forms(&block)
|
|
74
|
+
fs = []
|
|
75
|
+
doc = Nokogiri::HTML(self.body)
|
|
76
|
+
doc.css('form').each do |f|
|
|
77
|
+
fo = Form.new(f)
|
|
78
|
+
yield fo if block_given?
|
|
79
|
+
end
|
|
80
|
+
fs
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
|
84
|
+
end
|
|
94
85
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Work around error 'FXComposeContext: illegal window parameter'
|
|
2
|
+
# in FXWindow#setFocus of some libfox versions.
|
|
3
|
+
|
|
4
|
+
class Fox::FXWindow
|
|
5
|
+
def setFocus
|
|
6
|
+
app.addChore do
|
|
7
|
+
super
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Fox::FXDialogBox
|
|
13
|
+
def setFocus
|
|
14
|
+
app.addChore do
|
|
15
|
+
super
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Fox::FXTextField
|
|
21
|
+
def setFocus
|
|
22
|
+
app.addChore do
|
|
23
|
+
super
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/watobo/sockets.rb
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
# Copyright 2014 by siberas, http://www.siberas.de
|
|
5
|
-
# This file is part of WATOBO (Web Application Tool Box) http://watobo.sourceforge.com
|
|
6
|
-
# WATOBO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License.
|
|
7
|
-
# WATOBO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
8
|
-
# You should have received a copy of the GNU General Public License along with WATOBO; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
1
|
+
%w( client_socket http_socket ).each do |lib|
|
|
2
|
+
require "watobo/sockets/#{lib}"
|
|
3
|
+
end
|
|
9
4
|
|
|
10
|
-
%w( client_socket http_socket ).each do |lib|
|
|
11
|
-
require "watobo/sockets/#{lib}"
|
|
12
|
-
end
|
|
13
|
-
|
data/lib/watobo/sockets/agent.rb
CHANGED
|
@@ -1,839 +1,830 @@
|
|
|
1
|
-
#.
|
|
2
|
-
# agent.rb
|
|
3
|
-
#.
|
|
4
|
-
# Copyright 2014 by siberas, http://www.siberas.de
|
|
5
|
-
# This file is part of WATOBO (Web Application Tool Box) http://watobo.sourceforge.com
|
|
6
|
-
# WATOBO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License.
|
|
7
|
-
# WATOBO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
8
|
-
# You should have received a copy of the GNU General Public License along with WATOBO; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
9
|
-
|
|
10
1
|
# @private
|
|
11
|
-
module Watobo#:nodoc: all
|
|
12
|
-
module HTTPSocket
|
|
13
|
-
class Agent_UNUSED
|
|
14
|
-
|
|
15
|
-
include Watobo::Constants
|
|
16
|
-
extend Watobo::Subscriber
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def runLogin(chat_list, prefs={})
|
|
20
|
-
@@login_mutex.synchronize do
|
|
21
|
-
begin
|
|
22
|
-
@@login_in_progress = true
|
|
23
|
-
login_prefs = Hash.new
|
|
24
|
-
login_prefs.update prefs
|
|
25
|
-
dummy = {:ignore_logout => true, :update_sids => true, :update_session => true, :update_contentlength => true}
|
|
26
|
-
login_prefs.update dummy
|
|
27
|
-
puts "! Start Login ..." if $DEBUG
|
|
28
|
-
unless chat_list.empty?
|
|
29
|
-
# puts login_prefs.to_yaml
|
|
30
|
-
chat_list.each do |chat|
|
|
31
|
-
print "! LoginRequest: #{chat.id}" if $DEBUG
|
|
32
|
-
test_req = chat.copyRequest
|
|
33
|
-
request, response = doRequest(test_req, login_prefs)
|
|
34
|
-
end
|
|
35
|
-
else
|
|
36
|
-
puts "! no login script configured !"
|
|
37
|
-
end
|
|
38
|
-
rescue => bang
|
|
39
|
-
puts "!ERROR in runLogin"
|
|
40
|
-
puts bang.backtrace if $DEBUG
|
|
41
|
-
ensure
|
|
42
|
-
@@login_in_progress = false
|
|
43
|
-
@@login_cv.signal
|
|
44
|
-
# exit
|
|
45
|
-
# print "L]"
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def connected?
|
|
51
|
-
!@connection.nil?
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
# sendHTTPRequest
|
|
59
|
-
def send(request, prefs={})
|
|
60
|
-
#Watobo.print_debug("huhule", "#{prefs.to_yaml}", "gagagag")
|
|
61
|
-
begin
|
|
62
|
-
@lasterror = nil
|
|
63
|
-
response_header = nil
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
# update current preferences, prefs given here are stronger then global settings!
|
|
67
|
-
current_prefs = Hash.new
|
|
68
|
-
[:update_session, :update_sids, :update_contentlength, :ssl_cipher, :www_auth, :client_certificates].each do |k|
|
|
69
|
-
current_prefs[k] = prefs[k].nil? ? @session[k] : prefs[k]
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
updateSession(request) if current_prefs[:update_session] == true
|
|
73
|
-
|
|
74
|
-
#---------------------------------------
|
|
75
|
-
request.removeHeader("^Proxy-Connection") #if not use_proxy
|
|
76
|
-
#request.removeHeader("^Connection") #if not use_proxy
|
|
77
|
-
request.removeHeader("^Accept-Encoding")
|
|
78
|
-
# If-Modified-Since: Tue, 28 Oct 2008 11:06:43 GMT
|
|
79
|
-
# If-None-Match: W/"3975-1225192003000"
|
|
80
|
-
request.removeHeader("^If-")
|
|
81
|
-
# puts
|
|
82
|
-
# request.each do |line|
|
|
83
|
-
# puts line.unpack("H*")
|
|
84
|
-
#end
|
|
85
|
-
#puts
|
|
86
|
-
if current_prefs[:update_contentlength] == true then
|
|
87
|
-
request.fix_content_length()
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
#request.add_header("Via", "Watobo") if use_proxy
|
|
91
|
-
#puts request
|
|
92
|
-
# puts "=============="
|
|
93
|
-
rescue SocketError
|
|
94
|
-
puts "!!! unknown hostname #{host}"
|
|
95
|
-
puts request.first
|
|
96
|
-
return nil, "WATOBO: Could not resolve hostname #{host}", nil
|
|
97
|
-
rescue => bang
|
|
98
|
-
puts bang
|
|
99
|
-
puts bang.backtrace if $DEBUG
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
begin
|
|
103
|
-
unless proxy.nil?
|
|
104
|
-
# connection requires proxy
|
|
105
|
-
# puts "* use proxy #{proxy.name}"
|
|
106
|
-
|
|
107
|
-
# check for regular proxy authentication
|
|
108
|
-
if request.is_ssl?
|
|
109
|
-
socket, response_header = sslProxyConnect(request, proxy, current_prefs)
|
|
110
|
-
return socket, response_header, error_response("Could Not Connect To Proxy: #{proxy.name} (#{proxy.host}:#{proxy.port})\n", "#{response_header}") if socket.nil?
|
|
111
|
-
|
|
112
|
-
if current_prefs[:www_auth].has_key?(site)
|
|
113
|
-
case current_prefs[:www_auth][site][:type]
|
|
114
|
-
when AUTH_TYPE_NTLM
|
|
115
|
-
# puts "* found NTLM credentials for site #{site}"
|
|
116
|
-
socket, response_header = wwwAuthNTLM(socket, request, current_prefs[:www_auth][site])
|
|
117
|
-
|
|
118
|
-
else
|
|
119
|
-
puts "* Unknown Authentication Type: #{current_prefs[:www_auth][site][:type]}"
|
|
120
|
-
end
|
|
121
|
-
else
|
|
122
|
-
|
|
123
|
-
data = request.join + "\r\n"
|
|
124
|
-
unless socket.nil?
|
|
125
|
-
socket.print data
|
|
126
|
-
response_header = readHTTPHeader(socket, current_prefs)
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
return socket, request, response_header
|
|
130
|
-
end
|
|
131
|
-
# puts "* doProxyRequest"
|
|
132
|
-
socket, response_header = doProxyRequest(request, proxy, current_prefs)
|
|
133
|
-
# puts socket.class
|
|
134
|
-
return socket, response_header, error_response("Could Not Connect To Proxy: #{proxy.name} (#{proxy.host}:#{proxy.port})\n", "#{response_header}") if socket.nil?
|
|
135
|
-
|
|
136
|
-
return socket, request, response_header
|
|
137
|
-
else
|
|
138
|
-
# direct connection to host
|
|
139
|
-
tcp_socket = nil
|
|
140
|
-
# timeout(6) do
|
|
141
|
-
#puts "* no proxy - direct connection"
|
|
142
|
-
tcp_socket = TCPSocket.new( host, port )
|
|
143
|
-
tcp_socket.setsockopt( Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1)
|
|
144
|
-
tcp_socket.sync = true
|
|
145
|
-
|
|
146
|
-
socket = tcp_socket
|
|
147
|
-
if request.is_ssl?
|
|
148
|
-
ssl_prefs = {}
|
|
149
|
-
ssl_prefs[:ssl_cipher] = current_prefs[:ssl_cipher] if current_prefs.has_key? :ssl_cipher
|
|
150
|
-
if current_prefs.has_key? :client_certificates
|
|
151
|
-
if current_prefs[:client_certificates].has_key? request.site
|
|
152
|
-
puts "* use ssl client certificate for site #{request.site}" if $DEBUG
|
|
153
|
-
ssl_prefs[:ssl_client_cert] = current_prefs[:client_certificates][request.site][:ssl_client_cert]
|
|
154
|
-
ssl_prefs[:ssl_client_key] = current_prefs[:client_certificates][request.site][:ssl_client_key]
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
socket = sslConnect(tcp_socket, ssl_prefs)
|
|
158
|
-
end
|
|
159
|
-
#puts socket.class
|
|
160
|
-
# remove URI before sending request but cache it for restoring request
|
|
161
|
-
uri_cache = nil
|
|
162
|
-
uri_cache = request.removeURI #if proxy.nil?
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
# request.addHeader("Proxy-Connection", "Close") unless proxy.nil?
|
|
166
|
-
# request.addHeader("Accept-Encoding", "gzip;q=0;identity; q=0.5, *;q=0") #don't want encoding
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if current_prefs[:www_auth].has_key?(site)
|
|
170
|
-
case current_prefs[:www_auth][site][:type]
|
|
171
|
-
when AUTH_TYPE_NTLM
|
|
172
|
-
# puts "* found NTLM credentials for site #{site}"
|
|
173
|
-
socket, response_header = wwwAuthNTLM(socket, request, current_prefs[:www_auth][site])
|
|
174
|
-
request.restoreURI(uri_cache)
|
|
175
|
-
|
|
176
|
-
else
|
|
177
|
-
puts "* Unknown Authentication Type: #{current_prefs[:www_auth][site][:type]}"
|
|
178
|
-
end
|
|
179
|
-
else
|
|
180
|
-
# puts "========== Add Headers"
|
|
181
|
-
# request.addHeader("Connection", "Close") #if not use_proxy
|
|
182
|
-
|
|
183
|
-
data = request.join
|
|
184
|
-
unless request.has_body?
|
|
185
|
-
data << "\r\n" unless data =~ /\r\n\r\n$/
|
|
186
|
-
end
|
|
187
|
-
# puts "= SESSION ="
|
|
188
|
-
# puts data
|
|
189
|
-
# puts data.unpack("H*")[0].gsub(/0d0a/,"0d0a\n")
|
|
190
|
-
|
|
191
|
-
unless socket.nil?
|
|
192
|
-
socket.print data
|
|
193
|
-
# if socket.is_a? OpenSSL::SSL::SSLSocket
|
|
194
|
-
# socket.io.shutdown(Socket::SHUT_WR)
|
|
195
|
-
# else
|
|
196
|
-
# socket.shutdown(Socket::SHUT_WR)
|
|
197
|
-
# end
|
|
198
|
-
response_header = readHTTPHeader(socket, current_prefs)
|
|
199
|
-
end
|
|
200
|
-
# RESTORE URI FOR HISTORY/LOG
|
|
201
|
-
request.restoreURI(uri_cache)
|
|
202
|
-
|
|
203
|
-
end
|
|
204
|
-
return socket, Watobo::Request.new(request), Watobo::Response.new(response_header)
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
rescue Errno::ECONNREFUSED
|
|
208
|
-
response = error_response "connection refused (#{host}:#{port})"
|
|
209
|
-
puts response
|
|
210
|
-
socket = nil
|
|
211
|
-
rescue Errno::ECONNRESET
|
|
212
|
-
response = error_response "connection reset (#{host}:#{port})"
|
|
213
|
-
socket = nil
|
|
214
|
-
rescue Errno::ECONNABORTED
|
|
215
|
-
response = error_response "connection aborted (#{host}:#{port})"
|
|
216
|
-
socket = nil
|
|
217
|
-
rescue Errno::EHOSTUNREACH
|
|
218
|
-
response = error_response "host unreachable (#{host}:#{port})"
|
|
219
|
-
socket = nil
|
|
220
|
-
rescue Timeout::Error
|
|
221
|
-
#request = "WATOBO: TimeOut (#{host}:#{port})\n"
|
|
222
|
-
response = error_response "TimeOut (#{host}:#{port})"
|
|
223
|
-
socket = nil
|
|
224
|
-
rescue Errno::ETIMEDOUT
|
|
225
|
-
response = error_response "TimeOut (#{host}:#{port})"
|
|
226
|
-
socket = nil
|
|
227
|
-
rescue Errno::ENOTCONN
|
|
228
|
-
puts "!!!ENOTCONN"
|
|
229
|
-
rescue OpenSSL::SSL::SSLError
|
|
230
|
-
response = error_response "SSL-Error", $!.backtrace.join
|
|
231
|
-
socket = nil
|
|
232
|
-
rescue => bang
|
|
233
|
-
response = error_response "ERROR:", "#{bang}\n#{bang.backtrace}"
|
|
234
|
-
socket = nil
|
|
235
|
-
|
|
236
|
-
puts bang
|
|
237
|
-
puts bang.backtrace if $DEBUG
|
|
238
|
-
end
|
|
239
|
-
puts response
|
|
240
|
-
return socket, request, response
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
def sidCache()
|
|
244
|
-
#puts @project
|
|
245
|
-
@session[:valid_sids]
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
def setSIDCache(new_cache = {} )
|
|
249
|
-
@session[:valid_sids] = new_cache if new_cache.is_a? Hash
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
# +++ doRequest(request) +++
|
|
253
|
-
# + function:
|
|
254
|
-
#
|
|
255
|
-
def doRequest(request, opts={} )
|
|
256
|
-
begin
|
|
257
|
-
@session.update opts
|
|
258
|
-
# puts "[doRequest] #{@session.to_yaml}"
|
|
259
|
-
# puts "#[#{self.class}]" + @session[:csrf_requests].first.object_id.to_s
|
|
260
|
-
unless @session[:csrf_requests].empty? or @session[:csrf_patterns].empty?
|
|
261
|
-
csrf_cache = Hash.new
|
|
262
|
-
@session[:csrf_requests].each do |req|
|
|
263
|
-
copy = Watobo::Request.new YAML.load(YAML.dump(req))
|
|
264
|
-
|
|
265
|
-
updateCSRFToken(csrf_cache, copy)
|
|
266
|
-
socket, csrf_request, csrf_response = sendHTTPRequest(copy, opts)
|
|
267
|
-
next if socket.nil?
|
|
268
|
-
# puts "= Response Headers:"
|
|
269
|
-
# puts csrf_response
|
|
270
|
-
# puts "==="
|
|
271
|
-
update_sids(csrf_request.host, csrf_response.headers)
|
|
272
|
-
next if socket.nil?
|
|
273
|
-
# p "*"
|
|
274
|
-
# csrf_response = readHTTPHeader(socket)
|
|
275
|
-
readHTTPBody(socket, csrf_response, csrf_request, opts)
|
|
276
|
-
|
|
277
|
-
next if csrf_response.body.nil?
|
|
278
|
-
update_sids(csrf_request.host, [csrf_response.body])
|
|
279
|
-
|
|
280
|
-
updateCSRFCache(csrf_cache, csrf_request, [csrf_response.body]) if csrf_response.content_type =~ /text\//
|
|
281
|
-
|
|
282
|
-
# socket.close
|
|
283
|
-
closeSocket(socket)
|
|
284
|
-
end
|
|
285
|
-
#p @session[:csrf_requests].length
|
|
286
|
-
updateCSRFToken(csrf_cache, request)
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
socket, request, response = sendHTTPRequest(request, opts)
|
|
290
|
-
|
|
291
|
-
if socket.nil?
|
|
292
|
-
return request, response
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
update_sids(request.host, response.headers) if @session[:update_sids] == true
|
|
296
|
-
|
|
297
|
-
if @session[:follow_redirect]
|
|
298
|
-
# puts response.status
|
|
299
|
-
if response.status =~ /^302/
|
|
300
|
-
response.extend Watobo::Mixin::Parser::Web10
|
|
301
|
-
request.extend Watobo::Mixin::Shaper::Web10
|
|
302
|
-
|
|
303
|
-
loc_header = response.headers("Location:").first
|
|
304
|
-
new_location = loc_header.gsub(/^[^:]*:/,'').strip
|
|
305
|
-
unless new_location =~ /^http/
|
|
306
|
-
new_location = request.proto + "://" + request.site + "/" + request.dir + "/" + new_location.sub(/^[\.\/]*/,'')
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
notify(:follow_redirect, new_location)
|
|
310
|
-
nr = Watobo::Request.new YAML.load(YAML.dump(request))
|
|
311
|
-
|
|
312
|
-
# create GET request for new location
|
|
313
|
-
nr.replaceMethod("GET")
|
|
314
|
-
nr.removeHeader("Content-Length")
|
|
315
|
-
nr.removeBody()
|
|
316
|
-
nr.replaceURL(new_location)
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
socket, request, response = sendHTTPRequest(nr, opts)
|
|
320
|
-
|
|
321
|
-
if socket.nil?
|
|
322
|
-
#return nil, request
|
|
323
|
-
return request, response
|
|
324
|
-
end
|
|
325
|
-
end
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
readHTTPBody(socket, response, request, opts)
|
|
329
|
-
|
|
330
|
-
unless response.body.nil?
|
|
331
|
-
update_sids(request.host, [response.body]) if @session[:update_sids] == true and response.content_type =~ /text\//
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
#socket.close
|
|
335
|
-
closeSocket(socket)
|
|
336
|
-
|
|
337
|
-
rescue => bang
|
|
338
|
-
# puts "! Error in doRequest"
|
|
339
|
-
puts "! Module #{Module.nesting[0].name}"
|
|
340
|
-
puts bang
|
|
341
|
-
# puts bang.backtrace if $DEBUG
|
|
342
|
-
@lasterror = bang
|
|
343
|
-
# raise
|
|
344
|
-
# ensure
|
|
345
|
-
end
|
|
346
|
-
|
|
347
|
-
response.extend Watobo::Mixin::Parser::Web10
|
|
348
|
-
return request, response
|
|
349
|
-
end
|
|
350
|
-
|
|
351
|
-
def addProxy(prefs=nil)
|
|
352
|
-
|
|
353
|
-
proxy = nil
|
|
354
|
-
unless prefs.nil?
|
|
355
|
-
proxy = Proxy.new(prefs)
|
|
356
|
-
# proxy.setCredentials(prefs[:credentials]) unless prefs[:credentials].nil?
|
|
357
|
-
unless prefs[:site].nil?
|
|
358
|
-
@@proxy[prefs[:site]] = proxy
|
|
359
|
-
return
|
|
360
|
-
end
|
|
361
|
-
end
|
|
362
|
-
|
|
363
|
-
@@proxy[:default] = proxy
|
|
364
|
-
end
|
|
365
|
-
|
|
366
|
-
def get_settings
|
|
367
|
-
@@settings
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
def getProxy(site=nil)
|
|
371
|
-
unless site.nil?
|
|
372
|
-
return @@proxy[site] unless @@proxy[site].nil?
|
|
373
|
-
end
|
|
374
|
-
return @@proxy[:default]
|
|
375
|
-
end
|
|
376
|
-
|
|
377
|
-
#
|
|
378
|
-
# INITIALIZE
|
|
379
|
-
#
|
|
380
|
-
# Possible preferences:
|
|
381
|
-
# :proxy => '127.0.0.1:port'
|
|
382
|
-
# :valid_sids => Hash.new,
|
|
383
|
-
# :sid_patterns => [],
|
|
384
|
-
# :logout_signatures => [],
|
|
385
|
-
# :update_valid_sids => false,
|
|
386
|
-
# :update_sids => false,
|
|
387
|
-
# :update_contentlength => true
|
|
388
|
-
def initialize( session_id, prefs={} )
|
|
389
|
-
|
|
390
|
-
@connection = nil
|
|
391
|
-
|
|
392
|
-
session = nil
|
|
393
|
-
|
|
394
|
-
session = ( session_id.is_a? Fixnum ) ? session_id : session_id.object_id
|
|
395
|
-
session = Digest::MD5.hexdigest(Time.now.to_f.to_s) if session_id.nil?
|
|
396
|
-
|
|
397
|
-
unless @@settings.has_key? session
|
|
398
|
-
@@settings[session] = {
|
|
399
|
-
:valid_sids => Hash.new,
|
|
400
|
-
:sid_patterns => [],
|
|
401
|
-
# :valid_csrf_tokens => Hash.new,
|
|
402
|
-
:csrf_patterns => [],
|
|
403
|
-
:csrf_requests => [],
|
|
404
|
-
:logout_signatures => [],
|
|
405
|
-
:logout_content_types => Hash.new,
|
|
406
|
-
:update_valid_sids => false,
|
|
407
|
-
:update_sids => false,
|
|
408
|
-
:update_session => true,
|
|
409
|
-
:update_contentlength => true,
|
|
410
|
-
:login_chats => [],
|
|
411
|
-
:www_auth => Hash.new,
|
|
412
|
-
:client_certificates => {},
|
|
413
|
-
:proxy_auth => Hash.new
|
|
414
|
-
}
|
|
415
|
-
end
|
|
416
|
-
@session = @@settings[session] # shortcut to settings
|
|
417
|
-
@session.update prefs
|
|
418
|
-
|
|
419
|
-
# @valid_csrf_tokens = Hash.new
|
|
420
|
-
|
|
421
|
-
addProxy( prefs[:proxy] ) if prefs.is_a? Hash and prefs[:proxy]
|
|
422
|
-
|
|
423
|
-
@ctx = OpenSSL::SSL::SSLContext.new()
|
|
424
|
-
@ctx.key = nil
|
|
425
|
-
@ctx.cert = nil
|
|
426
|
-
|
|
427
|
-
# TODO: Implement switches for URL-Encoding (http://www.blooberry.com/indexdot/html/topics/urlencoding.htm)
|
|
428
|
-
# TODO: Implement switches for Following Redirects
|
|
429
|
-
# TODO: Implement switches for Logging, Debugging, ...
|
|
430
|
-
end
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
private
|
|
435
|
-
|
|
436
|
-
#def doNtlmAuth(socket, request, ntlm_credentials)
|
|
437
|
-
def wwwAuthNTLM(socket, request, ntlm_credentials)
|
|
438
|
-
response_header = nil
|
|
439
|
-
begin
|
|
440
|
-
auth_request = request.copy
|
|
441
|
-
|
|
442
|
-
ntlm_challenge = nil
|
|
443
|
-
t1 = Watobo::NTLM::Message::Type1.new()
|
|
444
|
-
msg = "NTLM " + t1.encode64
|
|
445
|
-
|
|
446
|
-
auth_request.removeHeader("Connection")
|
|
447
|
-
auth_request.removeHeader("Authorization")
|
|
448
|
-
|
|
449
|
-
auth_request.addHeader("Authorization", msg)
|
|
450
|
-
auth_request.addHeader("Connection", "Keep-Alive")
|
|
451
|
-
|
|
452
|
-
if $DEBUG
|
|
453
|
-
puts "============= T1 ======================="
|
|
454
|
-
puts auth_request
|
|
455
|
-
end
|
|
456
|
-
|
|
457
|
-
data = auth_request.join + "\r\n"
|
|
458
|
-
socket.print data
|
|
459
|
-
|
|
460
|
-
puts "-----------------" if $DEBUG
|
|
461
|
-
|
|
462
|
-
response_header = []
|
|
463
|
-
rcode = nil
|
|
464
|
-
clen = nil
|
|
465
|
-
ntlm_challenge = nil
|
|
466
|
-
response_header = readHTTPHeader(socket)
|
|
467
|
-
response_header.each do |line|
|
|
468
|
-
if line =~ /^HTTP\/\d\.\d (\d+) (.*)/ then
|
|
469
|
-
rcode = $1.to_i
|
|
470
|
-
rmsg = $2
|
|
471
|
-
end
|
|
472
|
-
if line =~ /^WWW-Authenticate: (NTLM) (.+)\r\n/
|
|
473
|
-
ntlm_challenge = $2
|
|
474
|
-
end
|
|
475
|
-
if line =~ /^Content-Length: (\d{1,})\r\n/
|
|
476
|
-
clen = $1.to_i
|
|
477
|
-
end
|
|
478
|
-
break if line.strip.empty?
|
|
479
|
-
end
|
|
480
|
-
# puts "==================="
|
|
481
|
-
|
|
482
|
-
if $DEBUG
|
|
483
|
-
puts "--- T1 RESPONSE HEADERS ---"
|
|
484
|
-
puts response_header
|
|
485
|
-
puts "---"
|
|
486
|
-
end
|
|
487
|
-
if rcode == 401 #Authentication Required
|
|
488
|
-
puts "[NTLM] got ntlm challenge: #{ntlm_challenge}" if $DEBUG
|
|
489
|
-
return socket, response_header if ntlm_challenge.nil?
|
|
490
|
-
elsif rcode == 200 # Ok
|
|
491
|
-
puts "[NTLM] seems request doesn't need authentication" if $DEBUG
|
|
492
|
-
return socket, Watobo::Response.new(response_header)
|
|
493
|
-
else
|
|
494
|
-
if $DEBUG
|
|
495
|
-
puts "[NTLM] ... !#*+.!*peep* ...."
|
|
496
|
-
puts response_header
|
|
497
|
-
end
|
|
498
|
-
return socket, Watobo::Response.new(response_header)
|
|
499
|
-
end
|
|
500
|
-
|
|
501
|
-
# reading rest of response
|
|
502
|
-
rest = ''
|
|
503
|
-
Watobo::HTTPSocket.read_body(socket, :max_bytes => clen){ |d|
|
|
504
|
-
rest += d
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
if $DEBUG
|
|
508
|
-
puts "--- T1 RESPONSE BODY ---"
|
|
509
|
-
puts rest
|
|
510
|
-
puts "---"
|
|
511
|
-
end
|
|
512
|
-
t2 = Watobo::NTLM::Message.decode64(ntlm_challenge)
|
|
513
|
-
t3 = t2.response({:user => ntlm_credentials[:username],
|
|
514
|
-
:password => ntlm_credentials[:password],
|
|
515
|
-
:domain => ntlm_credentials[:domain]},
|
|
516
|
-
{:workstation => ntlm_credentials[:workstation], :ntlmv2 => true})
|
|
517
|
-
|
|
518
|
-
# puts "* NTLM-Credentials: #{ntlm_credentials[:username]},#{ntlm_credentials[:password]}, #{ntlm_credentials[:domain]}, #{ntlm_credentials[:workstation]}"
|
|
519
|
-
auth_request.removeHeader("Authorization")
|
|
520
|
-
auth_request.removeHeader("Connection")
|
|
521
|
-
|
|
522
|
-
auth_request.addHeader("Connection", "Close")
|
|
523
|
-
|
|
524
|
-
msg = "NTLM " + t3.encode64
|
|
525
|
-
auth_request.addHeader("Authorization", msg)
|
|
526
|
-
# puts "============= T3 ======================="
|
|
527
|
-
|
|
528
|
-
data = auth_request.join + "\r\n"
|
|
529
|
-
|
|
530
|
-
if $DEBUG
|
|
531
|
-
puts "= NTLM Type 3 ="
|
|
532
|
-
puts data
|
|
533
|
-
end
|
|
534
|
-
socket.print data
|
|
535
|
-
|
|
536
|
-
response_header = []
|
|
537
|
-
response_header = readHTTPHeader(socket)
|
|
538
|
-
response_header.each do |line|
|
|
539
|
-
|
|
540
|
-
if line =~ /^HTTP\/\d\.\d (\d+) (.*)/ then
|
|
541
|
-
rcode = $1.to_i
|
|
542
|
-
rmsg = $2
|
|
543
|
-
end
|
|
544
|
-
break if line.strip.empty?
|
|
545
|
-
end
|
|
546
|
-
|
|
547
|
-
if rcode == 200 # Ok
|
|
548
|
-
puts "[NTLM] Authentication Successfull" if $DEBUG
|
|
549
|
-
elsif rcode == 401 # Authentication Required
|
|
550
|
-
# TODO: authorization didn't work -> do some notification
|
|
551
|
-
# ...
|
|
552
|
-
puts "[NTLM] could not authenticate. Bad credentials?"
|
|
553
|
-
puts ntlm_credentials.to_yaml
|
|
554
|
-
end
|
|
555
|
-
|
|
556
|
-
return socket, Watobo::Response.new(response_header)
|
|
557
|
-
rescue => bang
|
|
558
|
-
puts "!!! ERROR: in ntlm_auth"
|
|
559
|
-
puts bang
|
|
560
|
-
|
|
561
|
-
puts bang.backtrace if $DEBUG
|
|
562
|
-
return nil, nil
|
|
563
|
-
end
|
|
564
|
-
end
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
##################################################
|
|
568
|
-
# doProxyRequest
|
|
569
|
-
################################################
|
|
570
|
-
def doProxyRequest(request, proxy, prefs={})
|
|
571
|
-
#puts "DO PROXY REQUEST"
|
|
572
|
-
# puts prefs.to_yaml
|
|
573
|
-
begin
|
|
574
|
-
tcp_socket = nil
|
|
575
|
-
site = request.site
|
|
576
|
-
|
|
577
|
-
auth_request = Watobo::Utils::copyObject(request)
|
|
578
|
-
auth_request.extend Watobo::Mixin::Parser::Url
|
|
579
|
-
auth_request.extend Watobo::Mixin::Parser::Web10
|
|
580
|
-
auth_request.extend Watobo::Mixin::Shaper::Web10
|
|
581
|
-
# timeout(6) do
|
|
582
|
-
|
|
583
|
-
tcp_socket = TCPSocket.new( proxy.host, proxy.port)
|
|
584
|
-
tcp_socket.setsockopt( Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1)
|
|
585
|
-
tcp_socket.sync = true
|
|
586
|
-
# end
|
|
587
|
-
|
|
588
|
-
auth_request.removeHeader("Proxy-Connection")
|
|
589
|
-
auth_request.removeHeader("Connection")
|
|
590
|
-
|
|
591
|
-
auth_request.addHeader("Pragma", "no-cache")
|
|
592
|
-
|
|
593
|
-
if proxy.has_login?
|
|
594
|
-
response_header = doProxyAuth(tcp_socket, auth_request, proxy)
|
|
595
|
-
# puts "* got request_header from doProxy Auth"
|
|
596
|
-
# puts request_header.class
|
|
597
|
-
puts "[Proxy Auth] Status: #{response_header.status}" if $DEBUG
|
|
598
|
-
return tcp_socket, response_header unless response_header.status =~ /401/
|
|
599
|
-
return tcp_socket, response_header unless prefs[:www_auth].has_key?(site)
|
|
600
|
-
end
|
|
601
|
-
|
|
602
|
-
# puts "CHECK WWW_AUTH"
|
|
603
|
-
# puts prefs.to_yaml
|
|
604
|
-
if prefs[:www_auth].has_key?(site)
|
|
605
|
-
case prefs[:www_auth][site][:type]
|
|
606
|
-
when AUTH_TYPE_NTLM
|
|
607
|
-
# puts "* found NTLM credentials for site #{site}"
|
|
608
|
-
socket, response_header = wwwAuthNTLM(tcp_socket, request, prefs[:www_auth][site])
|
|
609
|
-
|
|
610
|
-
#response_header.extend Watobo::Mixin::Parser::Url
|
|
611
|
-
#response_header.extend Watobo::Mixin::Parser::Web10
|
|
612
|
-
return socket, response_header
|
|
613
|
-
else
|
|
614
|
-
puts "* Unknown Authentication Type: #{prefs[:www_auth][site][:type]}"
|
|
615
|
-
end
|
|
616
|
-
else
|
|
617
|
-
data = auth_request.join + "\r\n"
|
|
618
|
-
|
|
619
|
-
tcp_socket.print data
|
|
620
|
-
|
|
621
|
-
response_header = readHTTPHeader(tcp_socket)
|
|
622
|
-
return tcp_socket, response_header
|
|
623
|
-
end
|
|
624
|
-
rescue => bang
|
|
625
|
-
puts bang
|
|
626
|
-
puts bang.backtrace if $DEBUG
|
|
627
|
-
|
|
628
|
-
end
|
|
629
|
-
return nil
|
|
630
|
-
end
|
|
631
|
-
|
|
632
|
-
def loggedOut?(response, prefs={})
|
|
633
|
-
begin
|
|
634
|
-
return false if @session[:logout_signatures].empty?
|
|
635
|
-
response.each do |line|
|
|
636
|
-
@session[:logout_signatures].each do |p|
|
|
637
|
-
# puts "!!!*LOGOUT*!!!" if line =~ /#{p}/
|
|
638
|
-
return true if line =~ /#{p}/
|
|
639
|
-
end
|
|
640
|
-
end
|
|
641
|
-
rescue => bang
|
|
642
|
-
puts bang
|
|
643
|
-
puts bang.backtrace if $DEBUG
|
|
644
|
-
end
|
|
645
|
-
return false
|
|
646
|
-
end
|
|
647
|
-
|
|
648
|
-
def error_response(msg, comment=nil)
|
|
649
|
-
er = []
|
|
650
|
-
er << "HTTP/1.1 555 Watobo Error\r\n"
|
|
651
|
-
er << "WATOBO: #{msg.gsub(/\r?\n/," ").strip}\r\n"
|
|
652
|
-
er << "Content-Length: 0\r\n"
|
|
653
|
-
er << "Connection: close\r\n"
|
|
654
|
-
er << "\r\n"
|
|
655
|
-
unless comment.nil?
|
|
656
|
-
body = "<H1>#{msg}</H1></br><H2>#{comment.gsub(/\r?\n/,"</br>")}</H2>"
|
|
657
|
-
er << body
|
|
658
|
-
end
|
|
659
|
-
er.extend Watobo::Mixin::Parser::Url
|
|
660
|
-
er.extend Watobo::Mixin::Parser::Web10
|
|
661
|
-
er.extend Watobo::Mixin::Shaper::Web10
|
|
662
|
-
er.fix_content_length
|
|
663
|
-
er
|
|
664
|
-
end
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
# def read_response(socket)
|
|
669
|
-
|
|
670
|
-
# return response
|
|
671
|
-
# end
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
def updateCSRFCache(csrf_cache, request, response)
|
|
675
|
-
puts "=UPDATE CSRF CACHE" if $DEBUG
|
|
676
|
-
# Thread.new{
|
|
677
|
-
begin
|
|
678
|
-
# site = request.site
|
|
679
|
-
@@csrf_lock.synchronize do
|
|
680
|
-
response.each do |line|
|
|
681
|
-
# puts line
|
|
682
|
-
@session[:csrf_patterns].each do |pat|
|
|
683
|
-
puts pat if $DEBUG
|
|
684
|
-
if line =~ /#{pat}/i then
|
|
685
|
-
token_key = Regexp.quote($1.upcase)
|
|
686
|
-
token_value = $2
|
|
687
|
-
#print "U"
|
|
688
|
-
puts "GOT NEW TOKEN (#{token_key}): #{token_value}" if $DEBUG
|
|
689
|
-
# @session[:valid_csrf_tokens][site] = Hash.new if @session[:valid_csrf_tokens][site].nil?
|
|
690
|
-
# @session[:valid_csrf_tokens][site][token_key] = token_value
|
|
691
|
-
csrf_cache[token_key] = token_value
|
|
692
|
-
end
|
|
693
|
-
end
|
|
694
|
-
|
|
695
|
-
end
|
|
696
|
-
end
|
|
697
|
-
rescue => bang
|
|
698
|
-
puts bang
|
|
699
|
-
if $DEBUG
|
|
700
|
-
puts bang.backtrace
|
|
701
|
-
puts "= Request"
|
|
702
|
-
puts request
|
|
703
|
-
puts "= Response"
|
|
704
|
-
puts response
|
|
705
|
-
puts "==="
|
|
706
|
-
end
|
|
707
|
-
|
|
708
|
-
end
|
|
709
|
-
# }
|
|
710
|
-
end
|
|
711
|
-
|
|
712
|
-
def closeSocket(socket)
|
|
713
|
-
return false if socket.nil?
|
|
714
|
-
begin
|
|
715
|
-
if socket.respond_to? :sysclose
|
|
716
|
-
#socket.io.shutdown(2)
|
|
717
|
-
# puts "sysclose"
|
|
718
|
-
socket.sysclose
|
|
719
|
-
elsif socket.respond_to? :shutdown
|
|
720
|
-
socket.shutdown(2)
|
|
721
|
-
elsif socket.respond_to? :close
|
|
722
|
-
socket.close
|
|
723
|
-
end
|
|
724
|
-
return true
|
|
725
|
-
rescue => bang
|
|
726
|
-
puts bang
|
|
727
|
-
puts bang.backtrace if $DEBUG
|
|
728
|
-
end
|
|
729
|
-
false
|
|
730
|
-
end
|
|
731
|
-
|
|
732
|
-
def updateSessionSettings(settings={})
|
|
733
|
-
[
|
|
734
|
-
:ssl_client_cert,
|
|
735
|
-
:ssl_client_key,
|
|
736
|
-
:ssl_client_pass,
|
|
737
|
-
:csrf_requests,
|
|
738
|
-
:valid_sids,
|
|
739
|
-
:sid_patterns,
|
|
740
|
-
:logout_signatures,
|
|
741
|
-
:logout_content_types,
|
|
742
|
-
:update_valid_sids,
|
|
743
|
-
:update_sids,
|
|
744
|
-
:update_session,
|
|
745
|
-
:update_contentlength,
|
|
746
|
-
:login_chats,
|
|
747
|
-
:follow_redirect
|
|
748
|
-
].each do |k|
|
|
749
|
-
@session[k] = settings[k] if settings.has_key? k
|
|
750
|
-
end
|
|
751
|
-
end
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
def updateCSRFToken(csrf_cache, request)
|
|
756
|
-
# puts "=UPDATE CSRF TOKEN"
|
|
757
|
-
# @session[:valid_csrf_tokens].to_yaml
|
|
758
|
-
# puts request if request.site.nil?
|
|
759
|
-
# puts "= = = = = = "
|
|
760
|
-
@@csrf_lock.synchronize do
|
|
761
|
-
# if @session[:valid_csrf_tokens].has_key?(request.site)
|
|
762
|
-
# puts "* found token for site: #{request.site}"
|
|
763
|
-
|
|
764
|
-
request.map!{ |line|
|
|
765
|
-
res = line
|
|
766
|
-
@session[:csrf_patterns].each do |pat|
|
|
767
|
-
begin
|
|
768
|
-
if line =~ /#{pat}/i then
|
|
769
|
-
key = Regexp.quote($1.upcase)
|
|
770
|
-
old_value = $2
|
|
771
|
-
if csrf_cache.has_key?(key) then
|
|
772
|
-
res = line.gsub!(/#{Regexp.quote(old_value)}/, csrf_cache[key])
|
|
773
|
-
if res.nil? then
|
|
774
|
-
res = line
|
|
775
|
-
puts "!!!could not update token (#{key})"
|
|
776
|
-
end
|
|
777
|
-
end
|
|
778
|
-
end
|
|
779
|
-
rescue => bang
|
|
780
|
-
puts bang
|
|
781
|
-
puts bang.backtrace if $DEBUG
|
|
782
|
-
# puts @session.to_yaml
|
|
783
|
-
end
|
|
784
|
-
end
|
|
785
|
-
res
|
|
786
|
-
}
|
|
787
|
-
end
|
|
788
|
-
# end
|
|
789
|
-
end
|
|
790
|
-
|
|
791
|
-
# this function updates specific patterns of a request, e.g. CSRF Tokens
|
|
792
|
-
# Parameters:
|
|
793
|
-
# request - the request which has to be updated
|
|
794
|
-
# cache - the value store of already collected key-value-pairs
|
|
795
|
-
# patterns - pattern expressions, similar to session-id-patterns, e.g. /name="(sessid)" value="([0-9a-zA-Z!-]*)"/
|
|
796
|
-
def updateRequestPattern(request, cache, patterns)
|
|
797
|
-
|
|
798
|
-
request.map!{ |line|
|
|
799
|
-
res = line
|
|
800
|
-
patterns.each do |pat|
|
|
801
|
-
begin
|
|
802
|
-
if line =~ /#{pat}/i then
|
|
803
|
-
pattern_key = Regexp.quote($1.upcase)
|
|
804
|
-
old_value = Regexp.quote($2)
|
|
805
|
-
if cache.has_key?(sid_key) then
|
|
806
|
-
if not old_value =~ /#{cache[sid_key]}/ then # sid value has changed and needs update
|
|
807
|
-
# print "S"
|
|
808
|
-
# puts "+ update sid #{sid_key}"
|
|
809
|
-
# puts "-OLD: #{old_value}"
|
|
810
|
-
# puts "-NEW: #{@session[:valid_sids][request.site][sid_key]}"
|
|
811
|
-
|
|
812
|
-
# puts "---"
|
|
813
|
-
# dummy = Regexp.quote(old_value)
|
|
814
|
-
res = line.gsub!(/#{old_value}/, cache[sid_key])
|
|
815
|
-
if not res then puts "!!!could not update sid (#{sid_key})"; end
|
|
816
|
-
# puts "->#{line}"
|
|
817
|
-
end
|
|
818
|
-
end
|
|
819
|
-
end
|
|
820
|
-
rescue => bang
|
|
821
|
-
puts bang
|
|
822
|
-
puts bang.backtrace if $DEBUG
|
|
823
|
-
# puts @session.to_yaml
|
|
824
|
-
end
|
|
825
|
-
end
|
|
826
|
-
res
|
|
827
|
-
}
|
|
828
|
-
end
|
|
829
|
-
|
|
830
|
-
def applySessionSettings(prefs)
|
|
831
|
-
[ :update_valid_sids, :update_session, :update_contentlength, :valid_sids, :sid_patterns, :logout_signatures ].each do |v|
|
|
832
|
-
@@settings[v] = prefs[v] if prefs[v]
|
|
833
|
-
end
|
|
834
|
-
end
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
end
|
|
838
|
-
end
|
|
2
|
+
module Watobo#:nodoc: all
|
|
3
|
+
module HTTPSocket
|
|
4
|
+
class Agent_UNUSED
|
|
5
|
+
|
|
6
|
+
include Watobo::Constants
|
|
7
|
+
extend Watobo::Subscriber
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def runLogin(chat_list, prefs={})
|
|
11
|
+
@@login_mutex.synchronize do
|
|
12
|
+
begin
|
|
13
|
+
@@login_in_progress = true
|
|
14
|
+
login_prefs = Hash.new
|
|
15
|
+
login_prefs.update prefs
|
|
16
|
+
dummy = {:ignore_logout => true, :update_sids => true, :update_session => true, :update_contentlength => true}
|
|
17
|
+
login_prefs.update dummy
|
|
18
|
+
puts "! Start Login ..." if $DEBUG
|
|
19
|
+
unless chat_list.empty?
|
|
20
|
+
# puts login_prefs.to_yaml
|
|
21
|
+
chat_list.each do |chat|
|
|
22
|
+
print "! LoginRequest: #{chat.id}" if $DEBUG
|
|
23
|
+
test_req = chat.copyRequest
|
|
24
|
+
request, response = doRequest(test_req, login_prefs)
|
|
25
|
+
end
|
|
26
|
+
else
|
|
27
|
+
puts "! no login script configured !"
|
|
28
|
+
end
|
|
29
|
+
rescue => bang
|
|
30
|
+
puts "!ERROR in runLogin"
|
|
31
|
+
puts bang.backtrace if $DEBUG
|
|
32
|
+
ensure
|
|
33
|
+
@@login_in_progress = false
|
|
34
|
+
@@login_cv.signal
|
|
35
|
+
# exit
|
|
36
|
+
# print "L]"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def connected?
|
|
42
|
+
!@connection.nil?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# sendHTTPRequest
|
|
50
|
+
def send(request, prefs={})
|
|
51
|
+
#Watobo.print_debug("huhule", "#{prefs.to_yaml}", "gagagag")
|
|
52
|
+
begin
|
|
53
|
+
@lasterror = nil
|
|
54
|
+
response_header = nil
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# update current preferences, prefs given here are stronger then global settings!
|
|
58
|
+
current_prefs = Hash.new
|
|
59
|
+
[:update_session, :update_sids, :update_contentlength, :ssl_cipher, :www_auth, :client_certificates].each do |k|
|
|
60
|
+
current_prefs[k] = prefs[k].nil? ? @session[k] : prefs[k]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
updateSession(request) if current_prefs[:update_session] == true
|
|
64
|
+
|
|
65
|
+
#---------------------------------------
|
|
66
|
+
request.removeHeader("^Proxy-Connection") #if not use_proxy
|
|
67
|
+
#request.removeHeader("^Connection") #if not use_proxy
|
|
68
|
+
request.removeHeader("^Accept-Encoding")
|
|
69
|
+
# If-Modified-Since: Tue, 28 Oct 2008 11:06:43 GMT
|
|
70
|
+
# If-None-Match: W/"3975-1225192003000"
|
|
71
|
+
request.removeHeader("^If-")
|
|
72
|
+
# puts
|
|
73
|
+
# request.each do |line|
|
|
74
|
+
# puts line.unpack("H*")
|
|
75
|
+
#end
|
|
76
|
+
#puts
|
|
77
|
+
if current_prefs[:update_contentlength] == true then
|
|
78
|
+
request.fix_content_length()
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
#request.add_header("Via", "Watobo") if use_proxy
|
|
82
|
+
#puts request
|
|
83
|
+
# puts "=============="
|
|
84
|
+
rescue SocketError
|
|
85
|
+
puts "!!! unknown hostname #{host}"
|
|
86
|
+
puts request.first
|
|
87
|
+
return nil, "WATOBO: Could not resolve hostname #{host}", nil
|
|
88
|
+
rescue => bang
|
|
89
|
+
puts bang
|
|
90
|
+
puts bang.backtrace if $DEBUG
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
begin
|
|
94
|
+
unless proxy.nil?
|
|
95
|
+
# connection requires proxy
|
|
96
|
+
# puts "* use proxy #{proxy.name}"
|
|
97
|
+
|
|
98
|
+
# check for regular proxy authentication
|
|
99
|
+
if request.is_ssl?
|
|
100
|
+
socket, response_header = sslProxyConnect(request, proxy, current_prefs)
|
|
101
|
+
return socket, response_header, error_response("Could Not Connect To Proxy: #{proxy.name} (#{proxy.host}:#{proxy.port})\n", "#{response_header}") if socket.nil?
|
|
102
|
+
|
|
103
|
+
if current_prefs[:www_auth].has_key?(site)
|
|
104
|
+
case current_prefs[:www_auth][site][:type]
|
|
105
|
+
when AUTH_TYPE_NTLM
|
|
106
|
+
# puts "* found NTLM credentials for site #{site}"
|
|
107
|
+
socket, response_header = wwwAuthNTLM(socket, request, current_prefs[:www_auth][site])
|
|
108
|
+
|
|
109
|
+
else
|
|
110
|
+
puts "* Unknown Authentication Type: #{current_prefs[:www_auth][site][:type]}"
|
|
111
|
+
end
|
|
112
|
+
else
|
|
113
|
+
|
|
114
|
+
data = request.join + "\r\n"
|
|
115
|
+
unless socket.nil?
|
|
116
|
+
socket.print data
|
|
117
|
+
response_header = readHTTPHeader(socket, current_prefs)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
return socket, request, response_header
|
|
121
|
+
end
|
|
122
|
+
# puts "* doProxyRequest"
|
|
123
|
+
socket, response_header = doProxyRequest(request, proxy, current_prefs)
|
|
124
|
+
# puts socket.class
|
|
125
|
+
return socket, response_header, error_response("Could Not Connect To Proxy: #{proxy.name} (#{proxy.host}:#{proxy.port})\n", "#{response_header}") if socket.nil?
|
|
126
|
+
|
|
127
|
+
return socket, request, response_header
|
|
128
|
+
else
|
|
129
|
+
# direct connection to host
|
|
130
|
+
tcp_socket = nil
|
|
131
|
+
# timeout(6) do
|
|
132
|
+
#puts "* no proxy - direct connection"
|
|
133
|
+
tcp_socket = TCPSocket.new( host, port )
|
|
134
|
+
tcp_socket.setsockopt( Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1)
|
|
135
|
+
tcp_socket.sync = true
|
|
136
|
+
|
|
137
|
+
socket = tcp_socket
|
|
138
|
+
if request.is_ssl?
|
|
139
|
+
ssl_prefs = {}
|
|
140
|
+
ssl_prefs[:ssl_cipher] = current_prefs[:ssl_cipher] if current_prefs.has_key? :ssl_cipher
|
|
141
|
+
if current_prefs.has_key? :client_certificates
|
|
142
|
+
if current_prefs[:client_certificates].has_key? request.site
|
|
143
|
+
puts "* use ssl client certificate for site #{request.site}" if $DEBUG
|
|
144
|
+
ssl_prefs[:ssl_client_cert] = current_prefs[:client_certificates][request.site][:ssl_client_cert]
|
|
145
|
+
ssl_prefs[:ssl_client_key] = current_prefs[:client_certificates][request.site][:ssl_client_key]
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
socket = sslConnect(tcp_socket, ssl_prefs)
|
|
149
|
+
end
|
|
150
|
+
#puts socket.class
|
|
151
|
+
# remove URI before sending request but cache it for restoring request
|
|
152
|
+
uri_cache = nil
|
|
153
|
+
uri_cache = request.removeURI #if proxy.nil?
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# request.addHeader("Proxy-Connection", "Close") unless proxy.nil?
|
|
157
|
+
# request.addHeader("Accept-Encoding", "gzip;q=0;identity; q=0.5, *;q=0") #don't want encoding
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
if current_prefs[:www_auth].has_key?(site)
|
|
161
|
+
case current_prefs[:www_auth][site][:type]
|
|
162
|
+
when AUTH_TYPE_NTLM
|
|
163
|
+
# puts "* found NTLM credentials for site #{site}"
|
|
164
|
+
socket, response_header = wwwAuthNTLM(socket, request, current_prefs[:www_auth][site])
|
|
165
|
+
request.restoreURI(uri_cache)
|
|
166
|
+
|
|
167
|
+
else
|
|
168
|
+
puts "* Unknown Authentication Type: #{current_prefs[:www_auth][site][:type]}"
|
|
169
|
+
end
|
|
170
|
+
else
|
|
171
|
+
# puts "========== Add Headers"
|
|
172
|
+
# request.addHeader("Connection", "Close") #if not use_proxy
|
|
173
|
+
|
|
174
|
+
data = request.join
|
|
175
|
+
unless request.has_body?
|
|
176
|
+
data << "\r\n" unless data =~ /\r\n\r\n$/
|
|
177
|
+
end
|
|
178
|
+
# puts "= SESSION ="
|
|
179
|
+
# puts data
|
|
180
|
+
# puts data.unpack("H*")[0].gsub(/0d0a/,"0d0a\n")
|
|
181
|
+
|
|
182
|
+
unless socket.nil?
|
|
183
|
+
socket.print data
|
|
184
|
+
# if socket.is_a? OpenSSL::SSL::SSLSocket
|
|
185
|
+
# socket.io.shutdown(Socket::SHUT_WR)
|
|
186
|
+
# else
|
|
187
|
+
# socket.shutdown(Socket::SHUT_WR)
|
|
188
|
+
# end
|
|
189
|
+
response_header = readHTTPHeader(socket, current_prefs)
|
|
190
|
+
end
|
|
191
|
+
# RESTORE URI FOR HISTORY/LOG
|
|
192
|
+
request.restoreURI(uri_cache)
|
|
193
|
+
|
|
194
|
+
end
|
|
195
|
+
return socket, Watobo::Request.new(request), Watobo::Response.new(response_header)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
rescue Errno::ECONNREFUSED
|
|
199
|
+
response = error_response "connection refused (#{host}:#{port})"
|
|
200
|
+
puts response
|
|
201
|
+
socket = nil
|
|
202
|
+
rescue Errno::ECONNRESET
|
|
203
|
+
response = error_response "connection reset (#{host}:#{port})"
|
|
204
|
+
socket = nil
|
|
205
|
+
rescue Errno::ECONNABORTED
|
|
206
|
+
response = error_response "connection aborted (#{host}:#{port})"
|
|
207
|
+
socket = nil
|
|
208
|
+
rescue Errno::EHOSTUNREACH
|
|
209
|
+
response = error_response "host unreachable (#{host}:#{port})"
|
|
210
|
+
socket = nil
|
|
211
|
+
rescue Timeout::Error
|
|
212
|
+
#request = "WATOBO: TimeOut (#{host}:#{port})\n"
|
|
213
|
+
response = error_response "TimeOut (#{host}:#{port})"
|
|
214
|
+
socket = nil
|
|
215
|
+
rescue Errno::ETIMEDOUT
|
|
216
|
+
response = error_response "TimeOut (#{host}:#{port})"
|
|
217
|
+
socket = nil
|
|
218
|
+
rescue Errno::ENOTCONN
|
|
219
|
+
puts "!!!ENOTCONN"
|
|
220
|
+
rescue OpenSSL::SSL::SSLError
|
|
221
|
+
response = error_response "SSL-Error", $!.backtrace.join
|
|
222
|
+
socket = nil
|
|
223
|
+
rescue => bang
|
|
224
|
+
response = error_response "ERROR:", "#{bang}\n#{bang.backtrace}"
|
|
225
|
+
socket = nil
|
|
226
|
+
|
|
227
|
+
puts bang
|
|
228
|
+
puts bang.backtrace if $DEBUG
|
|
229
|
+
end
|
|
230
|
+
puts response
|
|
231
|
+
return socket, request, response
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def sidCache()
|
|
235
|
+
#puts @project
|
|
236
|
+
@session[:valid_sids]
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def setSIDCache(new_cache = {} )
|
|
240
|
+
@session[:valid_sids] = new_cache if new_cache.is_a? Hash
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# +++ doRequest(request) +++
|
|
244
|
+
# + function:
|
|
245
|
+
#
|
|
246
|
+
def doRequest(request, opts={} )
|
|
247
|
+
begin
|
|
248
|
+
@session.update opts
|
|
249
|
+
# puts "[doRequest] #{@session.to_yaml}"
|
|
250
|
+
# puts "#[#{self.class}]" + @session[:csrf_requests].first.object_id.to_s
|
|
251
|
+
unless @session[:csrf_requests].empty? or @session[:csrf_patterns].empty?
|
|
252
|
+
csrf_cache = Hash.new
|
|
253
|
+
@session[:csrf_requests].each do |req|
|
|
254
|
+
copy = Watobo::Request.new YAML.load(YAML.dump(req))
|
|
255
|
+
|
|
256
|
+
updateCSRFToken(csrf_cache, copy)
|
|
257
|
+
socket, csrf_request, csrf_response = sendHTTPRequest(copy, opts)
|
|
258
|
+
next if socket.nil?
|
|
259
|
+
# puts "= Response Headers:"
|
|
260
|
+
# puts csrf_response
|
|
261
|
+
# puts "==="
|
|
262
|
+
update_sids(csrf_request.host, csrf_response.headers)
|
|
263
|
+
next if socket.nil?
|
|
264
|
+
# p "*"
|
|
265
|
+
# csrf_response = readHTTPHeader(socket)
|
|
266
|
+
readHTTPBody(socket, csrf_response, csrf_request, opts)
|
|
267
|
+
|
|
268
|
+
next if csrf_response.body.nil?
|
|
269
|
+
update_sids(csrf_request.host, [csrf_response.body])
|
|
270
|
+
|
|
271
|
+
updateCSRFCache(csrf_cache, csrf_request, [csrf_response.body]) if csrf_response.content_type =~ /text\//
|
|
272
|
+
|
|
273
|
+
# socket.close
|
|
274
|
+
closeSocket(socket)
|
|
275
|
+
end
|
|
276
|
+
#p @session[:csrf_requests].length
|
|
277
|
+
updateCSRFToken(csrf_cache, request)
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
socket, request, response = sendHTTPRequest(request, opts)
|
|
281
|
+
|
|
282
|
+
if socket.nil?
|
|
283
|
+
return request, response
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
update_sids(request.host, response.headers) if @session[:update_sids] == true
|
|
287
|
+
|
|
288
|
+
if @session[:follow_redirect]
|
|
289
|
+
# puts response.status
|
|
290
|
+
if response.status =~ /^302/
|
|
291
|
+
response.extend Watobo::Mixin::Parser::Web10
|
|
292
|
+
request.extend Watobo::Mixin::Shaper::Web10
|
|
293
|
+
|
|
294
|
+
loc_header = response.headers("Location:").first
|
|
295
|
+
new_location = loc_header.gsub(/^[^:]*:/,'').strip
|
|
296
|
+
unless new_location =~ /^http/
|
|
297
|
+
new_location = request.proto + "://" + request.site + "/" + request.dir + "/" + new_location.sub(/^[\.\/]*/,'')
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
notify(:follow_redirect, new_location)
|
|
301
|
+
nr = Watobo::Request.new YAML.load(YAML.dump(request))
|
|
302
|
+
|
|
303
|
+
# create GET request for new location
|
|
304
|
+
nr.replaceMethod("GET")
|
|
305
|
+
nr.removeHeader("Content-Length")
|
|
306
|
+
nr.removeBody()
|
|
307
|
+
nr.replaceURL(new_location)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
socket, request, response = sendHTTPRequest(nr, opts)
|
|
311
|
+
|
|
312
|
+
if socket.nil?
|
|
313
|
+
#return nil, request
|
|
314
|
+
return request, response
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
readHTTPBody(socket, response, request, opts)
|
|
320
|
+
|
|
321
|
+
unless response.body.nil?
|
|
322
|
+
update_sids(request.host, [response.body]) if @session[:update_sids] == true and response.content_type =~ /text\//
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
#socket.close
|
|
326
|
+
closeSocket(socket)
|
|
327
|
+
|
|
328
|
+
rescue => bang
|
|
329
|
+
# puts "! Error in doRequest"
|
|
330
|
+
puts "! Module #{Module.nesting[0].name}"
|
|
331
|
+
puts bang
|
|
332
|
+
# puts bang.backtrace if $DEBUG
|
|
333
|
+
@lasterror = bang
|
|
334
|
+
# raise
|
|
335
|
+
# ensure
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
response.extend Watobo::Mixin::Parser::Web10
|
|
339
|
+
return request, response
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def addProxy(prefs=nil)
|
|
343
|
+
|
|
344
|
+
proxy = nil
|
|
345
|
+
unless prefs.nil?
|
|
346
|
+
proxy = Proxy.new(prefs)
|
|
347
|
+
# proxy.setCredentials(prefs[:credentials]) unless prefs[:credentials].nil?
|
|
348
|
+
unless prefs[:site].nil?
|
|
349
|
+
@@proxy[prefs[:site]] = proxy
|
|
350
|
+
return
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
@@proxy[:default] = proxy
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
def get_settings
|
|
358
|
+
@@settings
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
def getProxy(site=nil)
|
|
362
|
+
unless site.nil?
|
|
363
|
+
return @@proxy[site] unless @@proxy[site].nil?
|
|
364
|
+
end
|
|
365
|
+
return @@proxy[:default]
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
#
|
|
369
|
+
# INITIALIZE
|
|
370
|
+
#
|
|
371
|
+
# Possible preferences:
|
|
372
|
+
# :proxy => '127.0.0.1:port'
|
|
373
|
+
# :valid_sids => Hash.new,
|
|
374
|
+
# :sid_patterns => [],
|
|
375
|
+
# :logout_signatures => [],
|
|
376
|
+
# :update_valid_sids => false,
|
|
377
|
+
# :update_sids => false,
|
|
378
|
+
# :update_contentlength => true
|
|
379
|
+
def initialize( session_id, prefs={} )
|
|
380
|
+
|
|
381
|
+
@connection = nil
|
|
382
|
+
|
|
383
|
+
session = nil
|
|
384
|
+
|
|
385
|
+
session = ( session_id.is_a? Fixnum ) ? session_id : session_id.object_id
|
|
386
|
+
session = Digest::MD5.hexdigest(Time.now.to_f.to_s) if session_id.nil?
|
|
387
|
+
|
|
388
|
+
unless @@settings.has_key? session
|
|
389
|
+
@@settings[session] = {
|
|
390
|
+
:valid_sids => Hash.new,
|
|
391
|
+
:sid_patterns => [],
|
|
392
|
+
# :valid_csrf_tokens => Hash.new,
|
|
393
|
+
:csrf_patterns => [],
|
|
394
|
+
:csrf_requests => [],
|
|
395
|
+
:logout_signatures => [],
|
|
396
|
+
:logout_content_types => Hash.new,
|
|
397
|
+
:update_valid_sids => false,
|
|
398
|
+
:update_sids => false,
|
|
399
|
+
:update_session => true,
|
|
400
|
+
:update_contentlength => true,
|
|
401
|
+
:login_chats => [],
|
|
402
|
+
:www_auth => Hash.new,
|
|
403
|
+
:client_certificates => {},
|
|
404
|
+
:proxy_auth => Hash.new
|
|
405
|
+
}
|
|
406
|
+
end
|
|
407
|
+
@session = @@settings[session] # shortcut to settings
|
|
408
|
+
@session.update prefs
|
|
409
|
+
|
|
410
|
+
# @valid_csrf_tokens = Hash.new
|
|
411
|
+
|
|
412
|
+
addProxy( prefs[:proxy] ) if prefs.is_a? Hash and prefs[:proxy]
|
|
413
|
+
|
|
414
|
+
@ctx = OpenSSL::SSL::SSLContext.new()
|
|
415
|
+
@ctx.key = nil
|
|
416
|
+
@ctx.cert = nil
|
|
417
|
+
|
|
418
|
+
# TODO: Implement switches for URL-Encoding (http://www.blooberry.com/indexdot/html/topics/urlencoding.htm)
|
|
419
|
+
# TODO: Implement switches for Following Redirects
|
|
420
|
+
# TODO: Implement switches for Logging, Debugging, ...
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
private
|
|
426
|
+
|
|
427
|
+
#def doNtlmAuth(socket, request, ntlm_credentials)
|
|
428
|
+
def wwwAuthNTLM(socket, request, ntlm_credentials)
|
|
429
|
+
response_header = nil
|
|
430
|
+
begin
|
|
431
|
+
auth_request = request.copy
|
|
432
|
+
|
|
433
|
+
ntlm_challenge = nil
|
|
434
|
+
t1 = Watobo::NTLM::Message::Type1.new()
|
|
435
|
+
msg = "NTLM " + t1.encode64
|
|
436
|
+
|
|
437
|
+
auth_request.removeHeader("Connection")
|
|
438
|
+
auth_request.removeHeader("Authorization")
|
|
439
|
+
|
|
440
|
+
auth_request.addHeader("Authorization", msg)
|
|
441
|
+
auth_request.addHeader("Connection", "Keep-Alive")
|
|
442
|
+
|
|
443
|
+
if $DEBUG
|
|
444
|
+
puts "============= T1 ======================="
|
|
445
|
+
puts auth_request
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
data = auth_request.join + "\r\n"
|
|
449
|
+
socket.print data
|
|
450
|
+
|
|
451
|
+
puts "-----------------" if $DEBUG
|
|
452
|
+
|
|
453
|
+
response_header = []
|
|
454
|
+
rcode = nil
|
|
455
|
+
clen = nil
|
|
456
|
+
ntlm_challenge = nil
|
|
457
|
+
response_header = readHTTPHeader(socket)
|
|
458
|
+
response_header.each do |line|
|
|
459
|
+
if line =~ /^HTTP\/\d\.\d (\d+) (.*)/ then
|
|
460
|
+
rcode = $1.to_i
|
|
461
|
+
rmsg = $2
|
|
462
|
+
end
|
|
463
|
+
if line =~ /^WWW-Authenticate: (NTLM) (.+)\r\n/
|
|
464
|
+
ntlm_challenge = $2
|
|
465
|
+
end
|
|
466
|
+
if line =~ /^Content-Length: (\d{1,})\r\n/
|
|
467
|
+
clen = $1.to_i
|
|
468
|
+
end
|
|
469
|
+
break if line.strip.empty?
|
|
470
|
+
end
|
|
471
|
+
# puts "==================="
|
|
472
|
+
|
|
473
|
+
if $DEBUG
|
|
474
|
+
puts "--- T1 RESPONSE HEADERS ---"
|
|
475
|
+
puts response_header
|
|
476
|
+
puts "---"
|
|
477
|
+
end
|
|
478
|
+
if rcode == 401 #Authentication Required
|
|
479
|
+
puts "[NTLM] got ntlm challenge: #{ntlm_challenge}" if $DEBUG
|
|
480
|
+
return socket, response_header if ntlm_challenge.nil?
|
|
481
|
+
elsif rcode == 200 # Ok
|
|
482
|
+
puts "[NTLM] seems request doesn't need authentication" if $DEBUG
|
|
483
|
+
return socket, Watobo::Response.new(response_header)
|
|
484
|
+
else
|
|
485
|
+
if $DEBUG
|
|
486
|
+
puts "[NTLM] ... !#*+.!*peep* ...."
|
|
487
|
+
puts response_header
|
|
488
|
+
end
|
|
489
|
+
return socket, Watobo::Response.new(response_header)
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
# reading rest of response
|
|
493
|
+
rest = ''
|
|
494
|
+
Watobo::HTTPSocket.read_body(socket, :max_bytes => clen){ |d|
|
|
495
|
+
rest += d
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if $DEBUG
|
|
499
|
+
puts "--- T1 RESPONSE BODY ---"
|
|
500
|
+
puts rest
|
|
501
|
+
puts "---"
|
|
502
|
+
end
|
|
503
|
+
t2 = Watobo::NTLM::Message.decode64(ntlm_challenge)
|
|
504
|
+
t3 = t2.response({:user => ntlm_credentials[:username],
|
|
505
|
+
:password => ntlm_credentials[:password],
|
|
506
|
+
:domain => ntlm_credentials[:domain]},
|
|
507
|
+
{:workstation => ntlm_credentials[:workstation], :ntlmv2 => true})
|
|
508
|
+
|
|
509
|
+
# puts "* NTLM-Credentials: #{ntlm_credentials[:username]},#{ntlm_credentials[:password]}, #{ntlm_credentials[:domain]}, #{ntlm_credentials[:workstation]}"
|
|
510
|
+
auth_request.removeHeader("Authorization")
|
|
511
|
+
auth_request.removeHeader("Connection")
|
|
512
|
+
|
|
513
|
+
auth_request.addHeader("Connection", "Close")
|
|
514
|
+
|
|
515
|
+
msg = "NTLM " + t3.encode64
|
|
516
|
+
auth_request.addHeader("Authorization", msg)
|
|
517
|
+
# puts "============= T3 ======================="
|
|
518
|
+
|
|
519
|
+
data = auth_request.join + "\r\n"
|
|
520
|
+
|
|
521
|
+
if $DEBUG
|
|
522
|
+
puts "= NTLM Type 3 ="
|
|
523
|
+
puts data
|
|
524
|
+
end
|
|
525
|
+
socket.print data
|
|
526
|
+
|
|
527
|
+
response_header = []
|
|
528
|
+
response_header = readHTTPHeader(socket)
|
|
529
|
+
response_header.each do |line|
|
|
530
|
+
|
|
531
|
+
if line =~ /^HTTP\/\d\.\d (\d+) (.*)/ then
|
|
532
|
+
rcode = $1.to_i
|
|
533
|
+
rmsg = $2
|
|
534
|
+
end
|
|
535
|
+
break if line.strip.empty?
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
if rcode == 200 # Ok
|
|
539
|
+
puts "[NTLM] Authentication Successfull" if $DEBUG
|
|
540
|
+
elsif rcode == 401 # Authentication Required
|
|
541
|
+
# TODO: authorization didn't work -> do some notification
|
|
542
|
+
# ...
|
|
543
|
+
puts "[NTLM] could not authenticate. Bad credentials?"
|
|
544
|
+
puts ntlm_credentials.to_yaml
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
return socket, Watobo::Response.new(response_header)
|
|
548
|
+
rescue => bang
|
|
549
|
+
puts "!!! ERROR: in ntlm_auth"
|
|
550
|
+
puts bang
|
|
551
|
+
|
|
552
|
+
puts bang.backtrace if $DEBUG
|
|
553
|
+
return nil, nil
|
|
554
|
+
end
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
##################################################
|
|
559
|
+
# doProxyRequest
|
|
560
|
+
################################################
|
|
561
|
+
def doProxyRequest(request, proxy, prefs={})
|
|
562
|
+
#puts "DO PROXY REQUEST"
|
|
563
|
+
# puts prefs.to_yaml
|
|
564
|
+
begin
|
|
565
|
+
tcp_socket = nil
|
|
566
|
+
site = request.site
|
|
567
|
+
|
|
568
|
+
auth_request = Watobo::Utils::copyObject(request)
|
|
569
|
+
auth_request.extend Watobo::Mixin::Parser::Url
|
|
570
|
+
auth_request.extend Watobo::Mixin::Parser::Web10
|
|
571
|
+
auth_request.extend Watobo::Mixin::Shaper::Web10
|
|
572
|
+
# timeout(6) do
|
|
573
|
+
|
|
574
|
+
tcp_socket = TCPSocket.new( proxy.host, proxy.port)
|
|
575
|
+
tcp_socket.setsockopt( Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1)
|
|
576
|
+
tcp_socket.sync = true
|
|
577
|
+
# end
|
|
578
|
+
|
|
579
|
+
auth_request.removeHeader("Proxy-Connection")
|
|
580
|
+
auth_request.removeHeader("Connection")
|
|
581
|
+
|
|
582
|
+
auth_request.addHeader("Pragma", "no-cache")
|
|
583
|
+
|
|
584
|
+
if proxy.has_login?
|
|
585
|
+
response_header = doProxyAuth(tcp_socket, auth_request, proxy)
|
|
586
|
+
# puts "* got request_header from doProxy Auth"
|
|
587
|
+
# puts request_header.class
|
|
588
|
+
puts "[Proxy Auth] Status: #{response_header.status}" if $DEBUG
|
|
589
|
+
return tcp_socket, response_header unless response_header.status =~ /401/
|
|
590
|
+
return tcp_socket, response_header unless prefs[:www_auth].has_key?(site)
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
# puts "CHECK WWW_AUTH"
|
|
594
|
+
# puts prefs.to_yaml
|
|
595
|
+
if prefs[:www_auth].has_key?(site)
|
|
596
|
+
case prefs[:www_auth][site][:type]
|
|
597
|
+
when AUTH_TYPE_NTLM
|
|
598
|
+
# puts "* found NTLM credentials for site #{site}"
|
|
599
|
+
socket, response_header = wwwAuthNTLM(tcp_socket, request, prefs[:www_auth][site])
|
|
600
|
+
|
|
601
|
+
#response_header.extend Watobo::Mixin::Parser::Url
|
|
602
|
+
#response_header.extend Watobo::Mixin::Parser::Web10
|
|
603
|
+
return socket, response_header
|
|
604
|
+
else
|
|
605
|
+
puts "* Unknown Authentication Type: #{prefs[:www_auth][site][:type]}"
|
|
606
|
+
end
|
|
607
|
+
else
|
|
608
|
+
data = auth_request.join + "\r\n"
|
|
609
|
+
|
|
610
|
+
tcp_socket.print data
|
|
611
|
+
|
|
612
|
+
response_header = readHTTPHeader(tcp_socket)
|
|
613
|
+
return tcp_socket, response_header
|
|
614
|
+
end
|
|
615
|
+
rescue => bang
|
|
616
|
+
puts bang
|
|
617
|
+
puts bang.backtrace if $DEBUG
|
|
618
|
+
|
|
619
|
+
end
|
|
620
|
+
return nil
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
def loggedOut?(response, prefs={})
|
|
624
|
+
begin
|
|
625
|
+
return false if @session[:logout_signatures].empty?
|
|
626
|
+
response.each do |line|
|
|
627
|
+
@session[:logout_signatures].each do |p|
|
|
628
|
+
# puts "!!!*LOGOUT*!!!" if line =~ /#{p}/
|
|
629
|
+
return true if line =~ /#{p}/
|
|
630
|
+
end
|
|
631
|
+
end
|
|
632
|
+
rescue => bang
|
|
633
|
+
puts bang
|
|
634
|
+
puts bang.backtrace if $DEBUG
|
|
635
|
+
end
|
|
636
|
+
return false
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
def error_response(msg, comment=nil)
|
|
640
|
+
er = []
|
|
641
|
+
er << "HTTP/1.1 555 Watobo Error\r\n"
|
|
642
|
+
er << "WATOBO: #{msg.gsub(/\r?\n/," ").strip}\r\n"
|
|
643
|
+
er << "Content-Length: 0\r\n"
|
|
644
|
+
er << "Connection: close\r\n"
|
|
645
|
+
er << "\r\n"
|
|
646
|
+
unless comment.nil?
|
|
647
|
+
body = "<H1>#{msg}</H1></br><H2>#{comment.gsub(/\r?\n/,"</br>")}</H2>"
|
|
648
|
+
er << body
|
|
649
|
+
end
|
|
650
|
+
er.extend Watobo::Mixin::Parser::Url
|
|
651
|
+
er.extend Watobo::Mixin::Parser::Web10
|
|
652
|
+
er.extend Watobo::Mixin::Shaper::Web10
|
|
653
|
+
er.fix_content_length
|
|
654
|
+
er
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
# def read_response(socket)
|
|
660
|
+
|
|
661
|
+
# return response
|
|
662
|
+
# end
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
def updateCSRFCache(csrf_cache, request, response)
|
|
666
|
+
puts "=UPDATE CSRF CACHE" if $DEBUG
|
|
667
|
+
# Thread.new{
|
|
668
|
+
begin
|
|
669
|
+
# site = request.site
|
|
670
|
+
@@csrf_lock.synchronize do
|
|
671
|
+
response.each do |line|
|
|
672
|
+
# puts line
|
|
673
|
+
@session[:csrf_patterns].each do |pat|
|
|
674
|
+
puts pat if $DEBUG
|
|
675
|
+
if line =~ /#{pat}/i then
|
|
676
|
+
token_key = Regexp.quote($1.upcase)
|
|
677
|
+
token_value = $2
|
|
678
|
+
#print "U"
|
|
679
|
+
puts "GOT NEW TOKEN (#{token_key}): #{token_value}" if $DEBUG
|
|
680
|
+
# @session[:valid_csrf_tokens][site] = Hash.new if @session[:valid_csrf_tokens][site].nil?
|
|
681
|
+
# @session[:valid_csrf_tokens][site][token_key] = token_value
|
|
682
|
+
csrf_cache[token_key] = token_value
|
|
683
|
+
end
|
|
684
|
+
end
|
|
685
|
+
|
|
686
|
+
end
|
|
687
|
+
end
|
|
688
|
+
rescue => bang
|
|
689
|
+
puts bang
|
|
690
|
+
if $DEBUG
|
|
691
|
+
puts bang.backtrace
|
|
692
|
+
puts "= Request"
|
|
693
|
+
puts request
|
|
694
|
+
puts "= Response"
|
|
695
|
+
puts response
|
|
696
|
+
puts "==="
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
end
|
|
700
|
+
# }
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
def closeSocket(socket)
|
|
704
|
+
return false if socket.nil?
|
|
705
|
+
begin
|
|
706
|
+
if socket.respond_to? :sysclose
|
|
707
|
+
#socket.io.shutdown(2)
|
|
708
|
+
# puts "sysclose"
|
|
709
|
+
socket.sysclose
|
|
710
|
+
elsif socket.respond_to? :shutdown
|
|
711
|
+
socket.shutdown(2)
|
|
712
|
+
elsif socket.respond_to? :close
|
|
713
|
+
socket.close
|
|
714
|
+
end
|
|
715
|
+
return true
|
|
716
|
+
rescue => bang
|
|
717
|
+
puts bang
|
|
718
|
+
puts bang.backtrace if $DEBUG
|
|
719
|
+
end
|
|
720
|
+
false
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
def updateSessionSettings(settings={})
|
|
724
|
+
[
|
|
725
|
+
:ssl_client_cert,
|
|
726
|
+
:ssl_client_key,
|
|
727
|
+
:ssl_client_pass,
|
|
728
|
+
:csrf_requests,
|
|
729
|
+
:valid_sids,
|
|
730
|
+
:sid_patterns,
|
|
731
|
+
:logout_signatures,
|
|
732
|
+
:logout_content_types,
|
|
733
|
+
:update_valid_sids,
|
|
734
|
+
:update_sids,
|
|
735
|
+
:update_session,
|
|
736
|
+
:update_contentlength,
|
|
737
|
+
:login_chats,
|
|
738
|
+
:follow_redirect
|
|
739
|
+
].each do |k|
|
|
740
|
+
@session[k] = settings[k] if settings.has_key? k
|
|
741
|
+
end
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
def updateCSRFToken(csrf_cache, request)
|
|
747
|
+
# puts "=UPDATE CSRF TOKEN"
|
|
748
|
+
# @session[:valid_csrf_tokens].to_yaml
|
|
749
|
+
# puts request if request.site.nil?
|
|
750
|
+
# puts "= = = = = = "
|
|
751
|
+
@@csrf_lock.synchronize do
|
|
752
|
+
# if @session[:valid_csrf_tokens].has_key?(request.site)
|
|
753
|
+
# puts "* found token for site: #{request.site}"
|
|
754
|
+
|
|
755
|
+
request.map!{ |line|
|
|
756
|
+
res = line
|
|
757
|
+
@session[:csrf_patterns].each do |pat|
|
|
758
|
+
begin
|
|
759
|
+
if line =~ /#{pat}/i then
|
|
760
|
+
key = Regexp.quote($1.upcase)
|
|
761
|
+
old_value = $2
|
|
762
|
+
if csrf_cache.has_key?(key) then
|
|
763
|
+
res = line.gsub!(/#{Regexp.quote(old_value)}/, csrf_cache[key])
|
|
764
|
+
if res.nil? then
|
|
765
|
+
res = line
|
|
766
|
+
puts "!!!could not update token (#{key})"
|
|
767
|
+
end
|
|
768
|
+
end
|
|
769
|
+
end
|
|
770
|
+
rescue => bang
|
|
771
|
+
puts bang
|
|
772
|
+
puts bang.backtrace if $DEBUG
|
|
773
|
+
# puts @session.to_yaml
|
|
774
|
+
end
|
|
775
|
+
end
|
|
776
|
+
res
|
|
777
|
+
}
|
|
778
|
+
end
|
|
779
|
+
# end
|
|
780
|
+
end
|
|
781
|
+
|
|
782
|
+
# this function updates specific patterns of a request, e.g. CSRF Tokens
|
|
783
|
+
# Parameters:
|
|
784
|
+
# request - the request which has to be updated
|
|
785
|
+
# cache - the value store of already collected key-value-pairs
|
|
786
|
+
# patterns - pattern expressions, similar to session-id-patterns, e.g. /name="(sessid)" value="([0-9a-zA-Z!-]*)"/
|
|
787
|
+
def updateRequestPattern(request, cache, patterns)
|
|
788
|
+
|
|
789
|
+
request.map!{ |line|
|
|
790
|
+
res = line
|
|
791
|
+
patterns.each do |pat|
|
|
792
|
+
begin
|
|
793
|
+
if line =~ /#{pat}/i then
|
|
794
|
+
pattern_key = Regexp.quote($1.upcase)
|
|
795
|
+
old_value = Regexp.quote($2)
|
|
796
|
+
if cache.has_key?(sid_key) then
|
|
797
|
+
if not old_value =~ /#{cache[sid_key]}/ then # sid value has changed and needs update
|
|
798
|
+
# print "S"
|
|
799
|
+
# puts "+ update sid #{sid_key}"
|
|
800
|
+
# puts "-OLD: #{old_value}"
|
|
801
|
+
# puts "-NEW: #{@session[:valid_sids][request.site][sid_key]}"
|
|
802
|
+
|
|
803
|
+
# puts "---"
|
|
804
|
+
# dummy = Regexp.quote(old_value)
|
|
805
|
+
res = line.gsub!(/#{old_value}/, cache[sid_key])
|
|
806
|
+
if not res then puts "!!!could not update sid (#{sid_key})"; end
|
|
807
|
+
# puts "->#{line}"
|
|
808
|
+
end
|
|
809
|
+
end
|
|
810
|
+
end
|
|
811
|
+
rescue => bang
|
|
812
|
+
puts bang
|
|
813
|
+
puts bang.backtrace if $DEBUG
|
|
814
|
+
# puts @session.to_yaml
|
|
815
|
+
end
|
|
816
|
+
end
|
|
817
|
+
res
|
|
818
|
+
}
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
def applySessionSettings(prefs)
|
|
822
|
+
[ :update_valid_sids, :update_session, :update_contentlength, :valid_sids, :sid_patterns, :logout_signatures ].each do |v|
|
|
823
|
+
@@settings[v] = prefs[v] if prefs[v]
|
|
824
|
+
end
|
|
825
|
+
end
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
end
|
|
829
|
+
end
|
|
839
830
|
end
|