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
data/lib/watobo/http/xml/xml.rb
CHANGED
|
@@ -1,131 +1,125 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if
|
|
34
|
-
puts "*
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
start
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
end
|
|
126
|
-
nodes
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
end
|
|
130
|
-
end
|
|
1
|
+
# @private
|
|
2
|
+
module Watobo#:nodoc: all
|
|
3
|
+
module HTTP
|
|
4
|
+
class Xml
|
|
5
|
+
|
|
6
|
+
module Mixin
|
|
7
|
+
def xml
|
|
8
|
+
@xml ||= Watobo::HTTP::Xml.new(self)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_s
|
|
13
|
+
s = @root.body.to_s
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def set(parm)
|
|
17
|
+
return false unless parm.location == :xml
|
|
18
|
+
# puts "= set "
|
|
19
|
+
# puts parm.to_yaml
|
|
20
|
+
|
|
21
|
+
doc = Nokogiri::XML(@root.body.strip)
|
|
22
|
+
namespaces = doc.collect_namespaces
|
|
23
|
+
parent = doc.xpath("//#{parm.parent}", namespaces).first
|
|
24
|
+
if parent.nil?
|
|
25
|
+
puts "* could not find parent node #{parm.parent}"
|
|
26
|
+
return false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
parm_name = parm.namespace.nil? ? "" : parm.namespace
|
|
30
|
+
parm_name << parm.name
|
|
31
|
+
# find node
|
|
32
|
+
node = parent.xpath("//#{parm_name}", namespaces).first
|
|
33
|
+
if node.nil?
|
|
34
|
+
puts "* node does not exist #{parm_name}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
child = node.children.first
|
|
38
|
+
if child.nil?
|
|
39
|
+
child = Nokogiri::XML::Text.new(parm.value, node)
|
|
40
|
+
node.add_child child
|
|
41
|
+
else
|
|
42
|
+
child.content = parm.value
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
@root.set_body doc.to_s
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def has_parm?(parm_name)
|
|
50
|
+
false
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def parameters(&block)
|
|
54
|
+
params = []
|
|
55
|
+
|
|
56
|
+
return params unless @root.is_xml?
|
|
57
|
+
leaf_nodes do |n|
|
|
58
|
+
p = { :name => n.name }
|
|
59
|
+
val = n.children.size == 0 ? "" : n.children.first.to_s
|
|
60
|
+
|
|
61
|
+
p[:value] = val
|
|
62
|
+
parent_name = ""
|
|
63
|
+
unless n.parent.namespace.nil?
|
|
64
|
+
parent_name << n.parent.namespace.prefix
|
|
65
|
+
parent_name << ":"
|
|
66
|
+
end
|
|
67
|
+
parent_name << n.parent.name
|
|
68
|
+
p[:parent] = "#{parent_name}"
|
|
69
|
+
|
|
70
|
+
unless n.namespace.nil?
|
|
71
|
+
p[:namespace] = n.namespace.prefix
|
|
72
|
+
end
|
|
73
|
+
param = XmlParameter.new(p)
|
|
74
|
+
yield param if block_given?
|
|
75
|
+
params << param
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
return params
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def initialize(root)
|
|
82
|
+
@root = root
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def leaf_nodes(&block)
|
|
89
|
+
|
|
90
|
+
nodes = []
|
|
91
|
+
return nodes unless @root.has_body?
|
|
92
|
+
begin
|
|
93
|
+
doc = Nokogiri::XML(@root.body.strip)
|
|
94
|
+
#ns = doc.children.first.namespace
|
|
95
|
+
#prefix = ns.nil? ? '' : ns.prefix
|
|
96
|
+
|
|
97
|
+
# check if doc has a body element
|
|
98
|
+
start = doc
|
|
99
|
+
doc.traverse { |node|
|
|
100
|
+
if node.name =~ /^body$/i
|
|
101
|
+
start = node
|
|
102
|
+
end
|
|
103
|
+
}
|
|
104
|
+
start.traverse { |node|
|
|
105
|
+
if node.children.size == 0 and node.is_a? Nokogiri::XML::Element
|
|
106
|
+
yield node if block_given?
|
|
107
|
+
nodes << node
|
|
108
|
+
end
|
|
109
|
+
if node.children.size == 1
|
|
110
|
+
if node.children.first.is_a? Nokogiri::XML::Text
|
|
111
|
+
yield node if block_given?
|
|
112
|
+
nodes << node
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
}
|
|
116
|
+
rescue => bang
|
|
117
|
+
puts bang
|
|
118
|
+
puts bang.backtrace if $DEBUG
|
|
119
|
+
end
|
|
120
|
+
nodes
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
end
|
|
124
|
+
end
|
|
131
125
|
end
|
data/lib/watobo/interceptor.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( proxy transparent ).each do |lib|
|
|
2
|
+
require "watobo/interceptor/#{lib}"
|
|
3
|
+
end
|
|
9
4
|
|
|
10
|
-
%w( proxy transparent ).each do |lib|
|
|
11
|
-
require "watobo/interceptor/#{lib}"
|
|
12
|
-
end
|
|
13
|
-
|
|
@@ -1,760 +1,763 @@
|
|
|
1
|
-
#.
|
|
2
|
-
# proxy.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 Interceptor
|
|
13
|
-
#
|
|
14
|
-
class Proxy
|
|
15
|
-
|
|
16
|
-
include Watobo::Constants
|
|
17
|
-
|
|
18
|
-
attr :port
|
|
19
|
-
|
|
20
|
-
attr_accessor :proxy_mode
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
#attr_accessor :contentTypes
|
|
24
|
-
attr_accessor :target
|
|
25
|
-
#attr :www_auth
|
|
26
|
-
attr_accessor :client_certificates
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return
|
|
2
|
+
module Watobo #:nodoc: all
|
|
3
|
+
module Interceptor
|
|
4
|
+
#
|
|
5
|
+
class Proxy
|
|
6
|
+
|
|
7
|
+
include Watobo::Constants
|
|
8
|
+
|
|
9
|
+
attr :port
|
|
10
|
+
|
|
11
|
+
attr_accessor :proxy_mode
|
|
12
|
+
|
|
13
|
+
# attr_accessor :contentLength
|
|
14
|
+
#attr_accessor :contentTypes
|
|
15
|
+
attr_accessor :target
|
|
16
|
+
#attr :www_auth
|
|
17
|
+
attr_accessor :client_certificates
|
|
18
|
+
|
|
19
|
+
def self.transparent?
|
|
20
|
+
return true if (Watobo::Conf::Interceptor.proxy_mode & Watobo::Interceptor::MODE_TRANSPARENT) > 0
|
|
21
|
+
return false
|
|
30
22
|
end
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
23
|
+
|
|
24
|
+
|
|
34
25
|
def watobo_srv_get(file)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
headers << "Content-Length: #{content.length}"
|
|
50
|
-
r = headers.join("\r\n")
|
|
51
|
-
r << "\r\n\r\n"
|
|
52
|
-
r << content
|
|
53
|
-
return r
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
headers = [ "HTTP/1.0 404 Not Found", "Server: Watobo-Interceptor", "Connection: close", "Content-Type: text/plain; charset=iso-8859-1"]
|
|
57
|
-
content = "The requested file (#{file}) does not exist in the interceptor web folder."
|
|
26
|
+
srv_file = file.empty? ? File.join(@srv_path, 'index.html') : File.join(@srv_path, file)
|
|
27
|
+
if File.exist? srv_file
|
|
28
|
+
ct = case srv_file
|
|
29
|
+
when /\.ico/
|
|
30
|
+
"image/vnd.microsoft.icon"
|
|
31
|
+
when /\.htm/
|
|
32
|
+
'text/html; charset=iso-8859-1'
|
|
33
|
+
else
|
|
34
|
+
'text/plain'
|
|
35
|
+
end
|
|
36
|
+
headers = ["HTTP/1.0 200 OK", "Server: Watobo-Interceptor", "Connection: close", "Content-Type: #{ct}"]
|
|
37
|
+
content = File.open(srv_file, "rb").read
|
|
38
|
+
content.gsub!('WATOBO_VERSION', Watobo::VERSION)
|
|
39
|
+
content.gsub!('WATOBO_HOME', Watobo.working_directory)
|
|
58
40
|
headers << "Content-Length: #{content.length}"
|
|
59
41
|
r = headers.join("\r\n")
|
|
60
42
|
r << "\r\n\r\n"
|
|
61
43
|
r << content
|
|
62
44
|
return r
|
|
63
|
-
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
headers = ["HTTP/1.0 404 Not Found", "Server: Watobo-Interceptor", "Connection: close", "Content-Type: text/plain; charset=iso-8859-1"]
|
|
48
|
+
content = "The requested file (#{file}) does not exist in the interceptor web folder."
|
|
49
|
+
headers << "Content-Length: #{content.length}"
|
|
50
|
+
r = headers.join("\r\n")
|
|
51
|
+
r << "\r\n\r\n"
|
|
52
|
+
r << content
|
|
53
|
+
return r
|
|
54
|
+
|
|
64
55
|
end
|
|
65
|
-
|
|
56
|
+
|
|
66
57
|
def cert_response
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def server
|
|
77
|
-
@bind_addr
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def subscribe(event, &callback)
|
|
81
|
-
(@event_dispatcher_listeners[event] ||= []) << callback
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def clearEvents(event)
|
|
85
|
-
@event_dispatcher_listener[event].clear
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def getResponseFilter()
|
|
89
|
-
YAML.load(YAML.dump(@response_filter_settings))
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def getRequestFilter()
|
|
93
|
-
YAML.load(YAML.dump(@request_filter_settings))
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def setResponseFilter(new_settings)
|
|
97
|
-
@response_filter_settings.update new_settings unless new_settings.nil?
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def setRequestFilter(new_settings)
|
|
101
|
-
@request_filter_settings.update new_settings unless new_settings.nil?
|
|
102
|
-
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def clear_request_carvers
|
|
106
|
-
@request_carvers.clear unless @request_carvers.nil?
|
|
107
|
-
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def clear_response_carvers
|
|
111
|
-
@response_carvers.clear unless @response_carvers.nil?
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def addPreview(response)
|
|
115
|
-
preview_id = Digest::MD5.hexdigest(response.join)
|
|
116
|
-
@preview[preview_id] = response
|
|
117
|
-
return preview_id
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def stop()
|
|
121
|
-
begin
|
|
122
|
-
puts "[#{self.class}] stop"
|
|
123
|
-
if @t_server.respond_to? :status
|
|
124
|
-
puts @t_server.status
|
|
125
|
-
Thread.kill @t_server
|
|
126
|
-
|
|
127
|
-
end
|
|
128
|
-
rescue IOError => bang
|
|
129
|
-
puts bang
|
|
130
|
-
puts bang.backtrace if $DEBUG
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
#
|
|
135
|
-
# R U N
|
|
136
|
-
#
|
|
137
|
-
|
|
138
|
-
def self.start(settings = {})
|
|
139
|
-
proxy = Proxy.new(settings)
|
|
140
|
-
proxy.start
|
|
141
|
-
proxy
|
|
142
|
-
end
|
|
58
|
+
crt_file = File.join(Watobo.working_directory, "CA", "cacert.pem")
|
|
59
|
+
headers = ["HTTP/1.0 200 OK", "Server: Watobo-Interceptor", "Connection: close", "Content-Type: application/x-pem-file"]
|
|
60
|
+
content = File.read(crt_file)
|
|
61
|
+
headers << "Content-Length: #{content.length}"
|
|
62
|
+
r = headers.join("\r\n")
|
|
63
|
+
r << "\r\n\r\n"
|
|
64
|
+
r << content
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def server
|
|
68
|
+
@bind_addr
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def subscribe(event, &callback)
|
|
72
|
+
(@event_dispatcher_listeners[event] ||= []) << callback
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def clearEvents(event)
|
|
76
|
+
@event_dispatcher_listener[event].clear
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def getResponseFilter()
|
|
80
|
+
YAML.load(YAML.dump(@response_filter_settings))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def getRequestFilter()
|
|
84
|
+
YAML.load(YAML.dump(@request_filter_settings))
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def setResponseFilter(new_settings)
|
|
88
|
+
@response_filter_settings.update new_settings unless new_settings.nil?
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def setRequestFilter(new_settings)
|
|
92
|
+
@request_filter_settings.update new_settings unless new_settings.nil?
|
|
93
|
+
# puts @request_filter_settings.to_yaml
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def clear_request_carvers
|
|
97
|
+
@request_carvers.clear unless @request_carvers.nil?
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def clear_response_carvers
|
|
102
|
+
@response_carvers.clear unless @response_carvers.nil?
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def addPreview(response)
|
|
106
|
+
preview_id = Digest::MD5.hexdigest(response.join)
|
|
107
|
+
@preview[preview_id] = response
|
|
108
|
+
return preview_id
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def stop()
|
|
112
|
+
begin
|
|
113
|
+
puts "[#{self.class}] stop"
|
|
114
|
+
if @t_server.respond_to? :status
|
|
115
|
+
puts @t_server.status
|
|
116
|
+
Thread.kill @t_server
|
|
117
|
+
@intercept_srv.close
|
|
118
|
+
end
|
|
119
|
+
rescue IOError => bang
|
|
120
|
+
puts bang
|
|
121
|
+
puts bang.backtrace if $DEBUG
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
#
|
|
126
|
+
# R U N
|
|
127
|
+
#
|
|
128
|
+
|
|
129
|
+
def self.start(settings = {})
|
|
130
|
+
proxy = Proxy.new(settings)
|
|
131
|
+
proxy.start
|
|
132
|
+
proxy
|
|
133
|
+
end
|
|
143
134
|
|
|
144
135
|
def start()
|
|
145
|
-
@wait_queue = Queue.new
|
|
146
|
-
|
|
147
|
-
if transparent?
|
|
148
|
-
Watobo::Interceptor::Transparent.start
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
begin
|
|
152
|
-
@intercept_srv = TCPServer.new(@bind_addr, @port)
|
|
153
|
-
@intercept_srv.setsockopt(
|
|
154
|
-
|
|
155
|
-
rescue => bang
|
|
156
|
-
puts "\n!!!Could not start InterceptProxy"
|
|
157
|
-
puts bang
|
|
158
|
-
return nil
|
|
159
|
-
end
|
|
160
|
-
puts "\n* Intercepor started on #{@bind_addr}:#{@port}"
|
|
161
|
-
session_list = []
|
|
162
|
-
puts "!!! TRANSPARENT MODE ENABLED !!!" if transparent?
|
|
163
|
-
|
|
164
|
-
@t_server = Thread.new(@intercept_srv) { |server|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
136
|
+
@wait_queue = Queue.new
|
|
137
|
+
|
|
138
|
+
if transparent?
|
|
139
|
+
Watobo::Interceptor::Transparent.start
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
begin
|
|
143
|
+
@intercept_srv = TCPServer.new(@bind_addr, @port)
|
|
144
|
+
@intercept_srv.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1)
|
|
145
|
+
|
|
146
|
+
rescue => bang
|
|
147
|
+
puts "\n!!!Could not start InterceptProxy"
|
|
148
|
+
puts bang
|
|
149
|
+
return nil
|
|
150
|
+
end
|
|
151
|
+
puts "\n* Intercepor started on #{@bind_addr}:#{@port}"
|
|
152
|
+
session_list = []
|
|
153
|
+
puts "!!! TRANSPARENT MODE ENABLED !!!" if transparent?
|
|
154
|
+
|
|
155
|
+
@t_server = Thread.new(@intercept_srv) { |server|
|
|
156
|
+
while (new_session = server.accept)
|
|
157
|
+
# new_session.sync = true
|
|
158
|
+
new_sender = Watobo::Session.new(@target)
|
|
159
|
+
Thread.new(new_sender, new_session) { |sender, session|
|
|
160
|
+
#puts "* got new request from client"
|
|
161
|
+
c_sock = Watobo::HTTPSocket::ClientSocket.connect(session)
|
|
162
|
+
|
|
163
|
+
#puts "ClientSocket: #{c_sock}"
|
|
164
|
+
Thread.exit if c_sock.nil?
|
|
165
|
+
|
|
166
|
+
#
|
|
167
|
+
# loop for reusing client connections
|
|
168
|
+
|
|
169
|
+
max_loop = 0
|
|
170
|
+
loop do
|
|
171
|
+
flags = []
|
|
172
|
+
begin
|
|
173
|
+
|
|
174
|
+
# puts "#{c_sock} - read request"
|
|
175
|
+
request = c_sock.request
|
|
176
|
+
|
|
177
|
+
#if request.is_multipart?
|
|
178
|
+
# puts request
|
|
179
|
+
# puts request.body.to_s.length
|
|
180
|
+
# puts request.body.to_s.unpack("H*")[0]
|
|
181
|
+
#end
|
|
182
|
+
|
|
183
|
+
if request.nil? or request.empty? then
|
|
184
|
+
print "c/"
|
|
185
|
+
c_sock.close
|
|
186
|
+
Thread.exit
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
url = (request.url.to_s.length > 65) ? request.url.to_s.slice(0, 65) + "..." : request.url.to_s
|
|
190
|
+
puts "\n[I] #{url}"
|
|
191
|
+
|
|
192
|
+
rescue => bang
|
|
193
|
+
puts "!!! Error reading client request "
|
|
194
|
+
puts bang
|
|
195
|
+
puts bang.backtrace
|
|
196
|
+
# puts request.class
|
|
197
|
+
# puts request
|
|
198
|
+
c_sock.close
|
|
199
|
+
Thread.exit
|
|
200
|
+
#break
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
#if request.host =~ /safebrowsing.*google\.com/
|
|
204
|
+
# c_sock.close
|
|
205
|
+
# Thread.exit
|
|
206
|
+
#end
|
|
207
|
+
|
|
208
|
+
# check if preview is requested
|
|
209
|
+
if request.host =='watobo.localhost' or request.first =~ /WATOBOPreview/ then
|
|
210
|
+
if request.first =~ /WATOBOPreview=([0-9a-zA-Z]*)/ then
|
|
211
|
+
hashid = $1
|
|
212
|
+
response = @preview[hashid]
|
|
213
|
+
|
|
214
|
+
if response then
|
|
215
|
+
c_sock.write response.join
|
|
216
|
+
c_sock.close
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
#next
|
|
220
|
+
Thread.exit
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# check for watobo info page
|
|
224
|
+
if request.host =~ /^watobo$/
|
|
225
|
+
if request.path =~ /watobo\.pem/
|
|
226
|
+
response = cert_response
|
|
227
|
+
else
|
|
228
|
+
response = watobo_srv_get(request.path)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
c_sock.write response
|
|
232
|
+
c_sock.close
|
|
233
|
+
Thread.exit
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
request_intercepted = false
|
|
237
|
+
# no preview, check if interception request is turned on
|
|
238
|
+
if Watobo::Interceptor.rewrite_requests? then
|
|
239
|
+
Interceptor::RequestCarver.shape(request, flags)
|
|
240
|
+
puts "FLAGS >>"
|
|
241
|
+
puts flags
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
if @target and Watobo::Interceptor.intercept_requests? then
|
|
245
|
+
if matchRequestFilter(request)
|
|
246
|
+
@awaiting_requests += 1
|
|
247
|
+
request_intercepted = true
|
|
248
|
+
|
|
249
|
+
if @target.respond_to? :addRequest
|
|
250
|
+
Watobo.print_debug "send request to target"
|
|
251
|
+
@target.addRequest(request, Thread.current)
|
|
252
|
+
Thread.stop
|
|
253
|
+
else
|
|
254
|
+
p "! no target for editing request"
|
|
255
|
+
end
|
|
256
|
+
@awaiting_requests -= 1
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
begin
|
|
261
|
+
s_sock, req, resp = sender.sendHTTPRequest(request, :update_sids => true,
|
|
262
|
+
:update_session => false,
|
|
263
|
+
:update_contentlength => true,
|
|
264
|
+
:www_auth => @www_auth
|
|
265
|
+
# :client_certificates => @client_certificates
|
|
266
|
+
)
|
|
267
|
+
if s_sock.nil? then
|
|
268
|
+
puts "s_sock is nil! bye, bye, ..."
|
|
269
|
+
puts request if $DEBUG
|
|
270
|
+
c_sock.write resp.join unless resp.nil?
|
|
271
|
+
c_sock.close
|
|
272
|
+
Thread.exit
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
rescue => bang
|
|
276
|
+
puts bang
|
|
277
|
+
puts bang.backtrace if $DEBUG
|
|
278
|
+
c_sock.close
|
|
279
|
+
Thread.exit
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# check if response should be passed through
|
|
283
|
+
#Thread.current.exit if isPassThrough?(req, resp, s_sock, c_sock)
|
|
284
|
+
if isPassThrough?(req, resp, s_sock, c_sock)
|
|
285
|
+
#puts "[Interceptor] PassThrough >> #{req.url}"
|
|
286
|
+
Watobo::HTTPSocket.close s_sock
|
|
287
|
+
c_sock.close
|
|
288
|
+
Thread.exit
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
begin
|
|
292
|
+
missing_credentials = false
|
|
293
|
+
rs = resp.status
|
|
294
|
+
auth_type = AUTH_TYPE_NONE
|
|
295
|
+
if rs =~ /^(401|407)/ then
|
|
296
|
+
|
|
297
|
+
missing_credentials = true
|
|
298
|
+
|
|
299
|
+
resp.each do |rl|
|
|
300
|
+
if rl =~ /^(Proxy|WWW)-Authenticate: Basic/i
|
|
301
|
+
auth_type = AUTH_TYPE_BASIC
|
|
302
|
+
break
|
|
303
|
+
elsif rl =~ /^(Proxy|WWW)-Authenticate: NTLM/i
|
|
304
|
+
auth_type = AUTH_TYPE_NTLM
|
|
305
|
+
break
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
# when auth type not basic assume it's ntlm -> ntlm credentials must be set in watobo
|
|
309
|
+
unless auth_type == AUTH_TYPE_NONE
|
|
310
|
+
if auth_type == AUTH_TYPE_NTLM
|
|
311
|
+
if rs =~ /^401/ then
|
|
312
|
+
resp.push "WATOBO: Server requires (NTLM) authorization, please set WWW_Auth Credentials!"
|
|
313
|
+
resp.shift
|
|
314
|
+
resp.unshift "HTTP/1.1 200 OK\r\n"
|
|
315
|
+
else
|
|
316
|
+
resp.push "WATOBO: Proxy requires (NTLM) authorization, please set Proxy Credentials!"
|
|
317
|
+
resp.shift
|
|
318
|
+
resp.unshift "HTTP/1.1 200 OK\r\n"
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# don't try to read body if request method is HEAD
|
|
325
|
+
unless auth_type == AUTH_TYPE_UNKNOWN or req.method =~ /^head/i
|
|
326
|
+
sender.readHTTPBody(s_sock, resp, req, :update_sids => true)
|
|
327
|
+
Watobo::HTTPSocket.close s_sock
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
rescue => bang
|
|
331
|
+
puts "!!! could not send request !!!"
|
|
332
|
+
puts bang
|
|
333
|
+
puts bang.backtrace if $DEBUG
|
|
334
|
+
# puts "* Error sending request"
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
begin
|
|
338
|
+
# Watobo::Response.create resp
|
|
339
|
+
#resp = Watobo::Response.new resp
|
|
340
|
+
# puts "* unchunk response ..."
|
|
341
|
+
resp.unchunk!
|
|
342
|
+
# puts "* unzip response ..."
|
|
343
|
+
resp.unzip!
|
|
344
|
+
|
|
345
|
+
if Watobo::Interceptor.rewrite_responses? then
|
|
346
|
+
Interceptor::ResponseCarver.shape(resp, flags)
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
if @target and Watobo::Interceptor.intercept_responses? then
|
|
350
|
+
if matchResponseFilter(resp)
|
|
351
|
+
# if resp.content_type =~ /text/ or resp.content_type =~ /application\/javascript/ then
|
|
352
|
+
if @target.respond_to? :modifyResponse
|
|
353
|
+
@target.modifyResponse(resp, Thread.current)
|
|
354
|
+
Thread.stop
|
|
355
|
+
else
|
|
356
|
+
p "! no target for editing response"
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
# puts ">> SEND TO CLIENT"
|
|
362
|
+
# puts ">>C<< - Close: #{request.connection_close?}"
|
|
363
|
+
# request.headers("Connection"){ |h| puts h }
|
|
364
|
+
|
|
365
|
+
if missing_credentials
|
|
366
|
+
resp.set_header("Connection", "close")
|
|
367
|
+
elsif request.connection_close? or resp.content_length < 0 or max_loop > 4
|
|
368
|
+
# resp.set_header("Proxy-Connection","close")
|
|
369
|
+
resp.set_header("Connection", "close")
|
|
370
|
+
else
|
|
371
|
+
resp.set_header("Connection", "keep-alive")
|
|
372
|
+
resp.set_header("Keep-Alive", "max=4, timeout=120")
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
resp_data = resp.join
|
|
376
|
+
c_sock.write resp_data
|
|
377
|
+
|
|
378
|
+
chat = Chat.new(request.copy, resp.copy, :source => CHAT_SOURCE_INTERCEPT)
|
|
379
|
+
Watobo::Chats.add chat
|
|
380
|
+
|
|
381
|
+
rescue Errno::ECONNRESET
|
|
382
|
+
print "x"
|
|
383
|
+
# puts "!!! ERROR (Reset): reading body"
|
|
384
|
+
# puts "* last data seen on socket: #{buf}"
|
|
385
|
+
#return
|
|
386
|
+
c_sock.close
|
|
387
|
+
Thread.exit
|
|
388
|
+
rescue Errno::ECONNABORTED
|
|
389
|
+
print "x"
|
|
390
|
+
#return
|
|
391
|
+
c_sock.close
|
|
392
|
+
Thread.exit
|
|
393
|
+
rescue => bang
|
|
394
|
+
puts "!!! Error (???) in Client Communication:"
|
|
395
|
+
puts bang
|
|
396
|
+
puts bang.class
|
|
397
|
+
puts bang.backtrace #if $DEBUG
|
|
398
|
+
#return
|
|
399
|
+
c_sock.close
|
|
400
|
+
Thread.exit
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
# TODO: place check into ClientSocket, because headers must be checked and changed too
|
|
405
|
+
# e.g. if c_sock.open?
|
|
406
|
+
if missing_credentials or request.connection_close? or resp.content_length < 0 or max_loop > 4
|
|
407
|
+
c_sock.close
|
|
408
|
+
Thread.exit
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
max_loop += 1
|
|
412
|
+
|
|
337
413
|
end
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
if @target and Watobo::Interceptor.intercept_responses? then
|
|
359
|
-
if matchResponseFilter(resp)
|
|
360
|
-
# if resp.content_type =~ /text/ or resp.content_type =~ /application\/javascript/ then
|
|
361
|
-
if @target.respond_to? :modifyResponse
|
|
362
|
-
@target.modifyResponse(resp, Thread.current)
|
|
363
|
-
Thread.stop
|
|
364
|
-
else
|
|
365
|
-
p "! no target for editing response"
|
|
366
|
-
end
|
|
367
|
-
end
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
# puts ">> SEND TO CLIENT"
|
|
371
|
-
# puts ">>C<< - Close: #{request.connection_close?}"
|
|
372
|
-
# request.headers("Connection"){ |h| puts h }
|
|
373
|
-
|
|
374
|
-
if missing_credentials
|
|
375
|
-
resp.set_header("Connection", "close")
|
|
376
|
-
elsif request.connection_close? or resp.content_length < 0 or max_loop > 4
|
|
377
|
-
# resp.set_header("Proxy-Connection","close")
|
|
378
|
-
resp.set_header("Connection","close")
|
|
379
|
-
else
|
|
380
|
-
resp.set_header("Connection","keep-alive")
|
|
381
|
-
resp.set_header("Keep-Alive", "max=4, timeout=120")
|
|
382
|
-
end
|
|
383
|
-
|
|
384
|
-
resp_data = resp.join
|
|
385
|
-
c_sock.write resp_data
|
|
386
|
-
|
|
387
|
-
# puts "---"
|
|
388
|
-
# puts resp_data.unpack("H*")[0]
|
|
389
|
-
# puts "==="
|
|
390
|
-
|
|
391
|
-
rescue Errno::ECONNRESET
|
|
392
|
-
print "x"
|
|
393
|
-
# puts "!!! ERROR (Reset): reading body"
|
|
394
|
-
# puts "* last data seen on socket: #{buf}"
|
|
395
|
-
#return
|
|
396
|
-
rescue Errno::ECONNABORTED
|
|
397
|
-
print "x"
|
|
398
|
-
#return
|
|
399
|
-
rescue => bang
|
|
400
|
-
puts "!!! Error (???) in Client Communication:"
|
|
401
|
-
puts bang
|
|
402
|
-
puts bang.class
|
|
403
|
-
puts bang.backtrace #if $DEBUG
|
|
404
|
-
#return
|
|
405
|
-
end
|
|
406
|
-
|
|
407
|
-
chat = Chat.new(request.copy, resp.copy, :source => CHAT_SOURCE_INTERCEPT)
|
|
408
|
-
|
|
409
|
-
Watobo::Chats.add chat
|
|
410
|
-
|
|
411
|
-
# TODO: place check into ClientSocket, because headers must be checked and changed too
|
|
412
|
-
# e.g. if c_sock.open?
|
|
413
|
-
if missing_credentials or request.connection_close? or resp.content_length < 0 or max_loop > 4
|
|
414
|
-
c_sock.close
|
|
415
|
-
Thread.exit
|
|
416
|
-
end
|
|
417
|
-
print "o"
|
|
418
|
-
max_loop += 1
|
|
419
|
-
|
|
420
|
-
end
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
end
|
|
424
|
-
}
|
|
425
|
-
end
|
|
426
|
-
|
|
427
|
-
def refresh_www_auth
|
|
428
|
-
@www_auth = Watobo::Conf::Scanner.www_auth
|
|
429
|
-
end
|
|
430
|
-
|
|
431
|
-
def initialize(settings=nil)
|
|
432
|
-
@event_dispatcher_listeners = Hash.new
|
|
433
|
-
begin
|
|
434
|
-
|
|
435
|
-
puts
|
|
436
|
-
puts "=== Initialize Interceptor/Proxy ==="
|
|
437
|
-
|
|
438
|
-
#Watobo::Interceptor.proxy_mode = INTERCEPT_NONE
|
|
439
|
-
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
end
|
|
417
|
+
}
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def refresh_www_auth
|
|
421
|
+
@www_auth = Watobo::Conf::Scanner.www_auth
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
def initialize(settings=nil)
|
|
425
|
+
@event_dispatcher_listeners = Hash.new
|
|
426
|
+
@pass_through_hosts = ['safebrowsing.*google\.com', 'download.cdn.mozilla.net', 'shavar.services.mozilla.com']
|
|
427
|
+
begin
|
|
428
|
+
|
|
429
|
+
puts
|
|
430
|
+
puts "=== Initialize Interceptor/Proxy ==="
|
|
431
|
+
|
|
432
|
+
#Watobo::Interceptor.proxy_mode = INTERCEPT_NONE
|
|
433
|
+
|
|
440
434
|
init_instance_vars
|
|
441
|
-
|
|
442
|
-
@srv_path = File.join(File.dirname(__FILE__),'html')
|
|
443
|
-
|
|
444
|
-
@awaiting_requests = 0
|
|
445
|
-
@awaiting_responses = 0
|
|
446
|
-
|
|
447
|
-
@request_filter_settings = {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
@response_filter_settings = {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
@preview = Hash.new
|
|
473
|
-
@preview['ProxyTest'] = ["HTTP/1.0 200 OK\r\nServer: Watobo-Interceptor\r\nConnection: close\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n<html><body>PROXY_OK</body></html>"]
|
|
474
|
-
|
|
475
|
-
@dh_key = Watobo::CA.dh_key
|
|
476
|
-
|
|
477
|
-
rescue => bang
|
|
478
|
-
puts "!!!could not read certificate files:"
|
|
479
|
-
puts bang
|
|
480
|
-
puts bang.backtrace if $DEBUG
|
|
481
|
-
end
|
|
482
|
-
|
|
483
|
-
end
|
|
484
|
-
|
|
485
|
-
private
|
|
486
|
-
|
|
487
|
-
def init_instance_vars
|
|
488
|
-
@www_auth = Watobo::Conf::Scanner.www_auth
|
|
489
|
-
@fake_certs = {}
|
|
490
|
-
@client_certificates = {}
|
|
491
|
-
@target = nil
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
@bind_addr = Watobo::Conf::Interceptor.bind_addr
|
|
495
|
-
|
|
496
|
-
@port = Watobo::Conf::Interceptor.port
|
|
497
|
-
|
|
498
|
-
@proxy_mode = Watobo::Conf::Interceptor.proxy_mode
|
|
499
|
-
|
|
500
|
-
pt = Watobo::Conf::Interceptor.pass_through
|
|
501
|
-
@contentLength = pt[:content_length]
|
|
502
|
-
|
|
503
|
-
@contentTypes = pt[:content_types]
|
|
504
|
-
|
|
505
|
-
end
|
|
506
|
-
|
|
507
|
-
#
|
|
508
|
-
#
|
|
509
|
-
# matchContentType(content_type)
|
|
510
|
-
#
|
|
511
|
-
#
|
|
512
|
-
def matchContentType?(content_type)
|
|
513
|
-
@contentTypes.each do |p|
|
|
514
|
-
return true if content_type =~ /#{p}/
|
|
515
|
-
end
|
|
516
|
-
return false
|
|
517
|
-
end
|
|
518
|
-
|
|
519
|
-
#
|
|
520
|
-
#
|
|
521
|
-
# matchRequestFilter(request)
|
|
522
|
-
#
|
|
523
|
-
#
|
|
524
|
-
def matchRequestFilter(request)
|
|
525
|
-
match_url = true
|
|
526
|
-
# puts @request_filter_settings.to_yaml
|
|
527
|
-
url_filter = @request_filter_settings[:url_filter]
|
|
528
|
-
if url_filter != ''
|
|
529
|
-
match_url = false
|
|
530
|
-
if request.url.to_s =~ /#{url_filter}/i
|
|
531
|
-
|
|
532
|
-
end
|
|
533
|
-
if @request_filter_settings[:negate_url_filter] == true
|
|
534
|
-
|
|
535
|
-
end
|
|
536
|
-
end
|
|
537
|
-
|
|
538
|
-
return false if match_url == false
|
|
539
|
-
|
|
540
|
-
match_method = true
|
|
541
|
-
method_filter = @request_filter_settings[:method_filter]
|
|
542
|
-
if method_filter != ''
|
|
543
|
-
match_method = false
|
|
544
|
-
if request.method =~ /#{method_filter}/i
|
|
545
|
-
|
|
546
|
-
end
|
|
547
|
-
|
|
548
|
-
if @request_filter_settings[:negate_method_filter] == true
|
|
549
|
-
|
|
550
|
-
end
|
|
551
|
-
end
|
|
552
|
-
|
|
553
|
-
return false if match_method == false
|
|
554
|
-
|
|
555
|
-
match_ftype = true
|
|
556
|
-
ftype_filter = @request_filter_settings[:file_type_filter]
|
|
557
|
-
if ftype_filter != ''
|
|
558
|
-
match_ftype = false
|
|
559
|
-
if request.doctype != '' and request.doctype =~ /#{ftype_filter}/i
|
|
560
|
-
|
|
561
|
-
end
|
|
562
|
-
if @request_filter_settings[:negate_file_type_filter] == true
|
|
563
|
-
|
|
564
|
-
end
|
|
565
|
-
end
|
|
566
|
-
return false if match_ftype == false
|
|
567
|
-
|
|
568
|
-
match_parms = true
|
|
569
|
-
parms_filter = @request_filter_settings[:parms_filter]
|
|
570
|
-
if parms_filter != ''
|
|
571
|
-
|
|
572
|
-
match_parms = false
|
|
573
|
-
puts request.parms
|
|
574
|
-
match_parms = request.parms.find {|x| x =~ /#{parms_filter}/ }
|
|
575
|
-
match_parms = (
|
|
576
|
-
if @request_filter_settings[:negate_parms_filter] == true
|
|
577
|
-
|
|
578
|
-
end
|
|
579
|
-
end
|
|
580
|
-
return false if match_parms == false
|
|
581
|
-
|
|
582
|
-
true
|
|
583
|
-
end
|
|
584
|
-
|
|
585
|
-
#
|
|
586
|
-
#
|
|
587
|
-
# matchResponseFilter(response)
|
|
588
|
-
#
|
|
589
|
-
#
|
|
590
|
-
|
|
591
|
-
def matchResponseFilter(response)
|
|
592
|
-
match_ctype = true
|
|
593
|
-
ct_filter = @response_filter_settings[:content_type_filter]
|
|
594
|
-
unless ct_filter.empty?
|
|
595
|
-
match_ctype = false
|
|
596
|
-
negate = @response_filter_settings[:negate_content_type_filter]
|
|
597
|
-
if response.content_type =~ /#{ct_filter}/
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
end
|
|
601
|
-
if negate == true
|
|
602
|
-
|
|
603
|
-
end
|
|
604
|
-
end
|
|
605
|
-
return false if match_ctype == false
|
|
606
|
-
#puts "* pass ctype filter"
|
|
607
|
-
match_rcode = true
|
|
608
|
-
rcode_filter = @response_filter_settings[:response_code_filter]
|
|
609
|
-
negate = @response_filter_settings[:negate_response_code_filter]
|
|
610
|
-
unless rcode_filter.empty?
|
|
611
|
-
match_rcode = false
|
|
612
|
-
puts rcode_filter
|
|
613
|
-
puts response.responseCode
|
|
614
|
-
if response.responseCode =~ /#{rcode_filter}/
|
|
615
|
-
|
|
616
|
-
end
|
|
617
|
-
if negate == true
|
|
618
|
-
|
|
619
|
-
end
|
|
620
|
-
end
|
|
621
|
-
return false if match_rcode == false
|
|
622
|
-
#puts "* pass rcode filter"
|
|
623
|
-
true
|
|
624
|
-
end
|
|
625
|
-
|
|
626
|
-
#
|
|
627
|
-
#
|
|
628
|
-
# pass_through(server, client, maxbytes)
|
|
629
|
-
#
|
|
630
|
-
#
|
|
631
|
-
def pass_through(server, client, maxbytes = 0)
|
|
632
|
-
|
|
633
|
-
bytes_read = 0
|
|
634
|
-
while 1
|
|
635
|
-
begin
|
|
636
|
-
|
|
637
|
-
buf = nil
|
|
638
|
-
buf = server.readpartial(2048)
|
|
639
|
-
|
|
640
|
-
rescue EOFError
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
return if buf.nil?
|
|
647
|
-
rescue Errno::ECONNRESET
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
return if buf.nil?
|
|
656
|
-
rescue Timeout::Error
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
print "T"
|
|
661
|
-
return
|
|
662
|
-
rescue => bang
|
|
663
|
-
puts "!!! could not read body !!!"
|
|
664
|
-
puts bang
|
|
665
|
-
puts bang.class
|
|
666
|
-
puts bang.backtrace if $DEBUG
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
end
|
|
672
|
-
|
|
673
|
-
begin
|
|
674
|
-
return if buf.nil?
|
|
675
|
-
|
|
676
|
-
client.write buf
|
|
677
|
-
bytes_read += buf.length
|
|
678
|
-
|
|
679
|
-
if maxbytes > 0 and bytes_read >= maxbytes
|
|
680
|
-
#print "~]"
|
|
681
|
-
|
|
682
|
-
end
|
|
683
|
-
rescue Errno::ECONNRESET
|
|
684
|
-
#print "~x]"
|
|
685
|
-
# puts "!!! ERROR (Reset): reading body"
|
|
686
|
-
# puts "* last data seen on socket: #{buf}"
|
|
687
|
-
return
|
|
688
|
-
rescue Errno::ECONNABORTED
|
|
689
|
-
|
|
690
|
-
return
|
|
691
|
-
rescue Errno::EPIPE
|
|
692
|
-
|
|
693
|
-
return
|
|
694
|
-
rescue => bang
|
|
695
|
-
puts "!!! client communication broken !!!"
|
|
696
|
-
puts bang
|
|
697
|
-
puts bang.class
|
|
698
|
-
puts bang.backtrace if $DEBUG
|
|
699
|
-
|
|
700
|
-
end
|
|
701
|
-
end
|
|
702
|
-
end
|
|
703
|
-
|
|
704
|
-
def transparent?
|
|
705
|
-
(
|
|
706
|
-
end
|
|
707
|
-
|
|
708
|
-
|
|
435
|
+
|
|
436
|
+
@srv_path = File.join(File.dirname(__FILE__), 'html')
|
|
437
|
+
|
|
438
|
+
@awaiting_requests = 0
|
|
439
|
+
@awaiting_responses = 0
|
|
440
|
+
|
|
441
|
+
@request_filter_settings = {
|
|
442
|
+
:site_in_scope => false,
|
|
443
|
+
:method_filter => '(get|post|put)',
|
|
444
|
+
:negate_method_filter => false,
|
|
445
|
+
:negate_url_filter => false,
|
|
446
|
+
:url_filter => '',
|
|
447
|
+
:file_type_filter => '(jpg|gif|png|jpeg|bmp)',
|
|
448
|
+
:negate_file_type_filter => true,
|
|
449
|
+
|
|
450
|
+
:parms_filter => '',
|
|
451
|
+
:negate_parms_filter => false
|
|
452
|
+
#:regex_location => 0, # TODO: HEADER_LOCATION, BODY_LOCATION, ALL
|
|
453
|
+
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
@response_filter_settings = {
|
|
457
|
+
:content_type_filter => '(text|script)',
|
|
458
|
+
:negate_content_type_filter => false,
|
|
459
|
+
:response_code_filter => '2\d{2}',
|
|
460
|
+
:negate_response_code_filter => false,
|
|
461
|
+
:request_intercepted => false,
|
|
462
|
+
:content_printable => true,
|
|
463
|
+
:enable_printable_check => false
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
@preview = Hash.new
|
|
467
|
+
@preview['ProxyTest'] = ["HTTP/1.0 200 OK\r\nServer: Watobo-Interceptor\r\nConnection: close\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n<html><body>PROXY_OK</body></html>"]
|
|
468
|
+
|
|
469
|
+
@dh_key = Watobo::CA.dh_key
|
|
470
|
+
|
|
471
|
+
rescue => bang
|
|
472
|
+
puts "!!!could not read certificate files:"
|
|
473
|
+
puts bang
|
|
474
|
+
puts bang.backtrace if $DEBUG
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
private
|
|
480
|
+
|
|
481
|
+
def init_instance_vars
|
|
482
|
+
@www_auth = Watobo::Conf::Scanner.www_auth
|
|
483
|
+
@fake_certs = {}
|
|
484
|
+
@client_certificates = {}
|
|
485
|
+
@target = nil
|
|
486
|
+
# @sender = Watobo::Session.new(@target)
|
|
487
|
+
|
|
488
|
+
@bind_addr = Watobo::Conf::Interceptor.bind_addr
|
|
489
|
+
# puts "> Server: #{@bind_addr}"
|
|
490
|
+
@port = Watobo::Conf::Interceptor.port
|
|
491
|
+
# puts "> Port: #{@port}"
|
|
492
|
+
@proxy_mode = Watobo::Conf::Interceptor.proxy_mode
|
|
493
|
+
|
|
494
|
+
pt = Watobo::Conf::Interceptor.pass_through
|
|
495
|
+
@contentLength = pt[:content_length]
|
|
496
|
+
# puts "> PT-ContentLength: #{@contentLength}"
|
|
497
|
+
@contentTypes = pt[:content_types]
|
|
498
|
+
# puts "> PT-ContentTypes: #{@contentTypes}"
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
#
|
|
502
|
+
#
|
|
503
|
+
# matchContentType(content_type)
|
|
504
|
+
#
|
|
505
|
+
#
|
|
506
|
+
def matchContentType?(content_type)
|
|
507
|
+
@contentTypes.each do |p|
|
|
508
|
+
return true if content_type =~ /#{p}/
|
|
509
|
+
end
|
|
510
|
+
return false
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
#
|
|
514
|
+
#
|
|
515
|
+
# matchRequestFilter(request)
|
|
516
|
+
#
|
|
517
|
+
#
|
|
518
|
+
def matchRequestFilter(request)
|
|
519
|
+
match_url = true
|
|
520
|
+
# puts @request_filter_settings.to_yaml
|
|
521
|
+
url_filter = @request_filter_settings[:url_filter]
|
|
522
|
+
if url_filter != ''
|
|
523
|
+
match_url = false
|
|
524
|
+
if request.url.to_s =~ /#{url_filter}/i
|
|
525
|
+
match_url = true
|
|
526
|
+
end
|
|
527
|
+
if @request_filter_settings[:negate_url_filter] == true
|
|
528
|
+
match_url = (match_url == true) ? false : true
|
|
529
|
+
end
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
return false if match_url == false
|
|
533
|
+
|
|
534
|
+
match_method = true
|
|
535
|
+
method_filter = @request_filter_settings[:method_filter]
|
|
536
|
+
if method_filter != ''
|
|
537
|
+
match_method = false
|
|
538
|
+
if request.method =~ /#{method_filter}/i
|
|
539
|
+
match_method = true
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
if @request_filter_settings[:negate_method_filter] == true
|
|
543
|
+
match_method = (match_method == true) ? false : true
|
|
544
|
+
end
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
return false if match_method == false
|
|
548
|
+
|
|
549
|
+
match_ftype = true
|
|
550
|
+
ftype_filter = @request_filter_settings[:file_type_filter]
|
|
551
|
+
if ftype_filter != ''
|
|
552
|
+
match_ftype = false
|
|
553
|
+
if request.doctype != '' and request.doctype =~ /#{ftype_filter}/i
|
|
554
|
+
match_ftype = true
|
|
555
|
+
end
|
|
556
|
+
if @request_filter_settings[:negate_file_type_filter] == true
|
|
557
|
+
match_ftype = (match_ftype == true) ? false : true
|
|
558
|
+
end
|
|
559
|
+
end
|
|
560
|
+
return false if match_ftype == false
|
|
561
|
+
|
|
562
|
+
match_parms = true
|
|
563
|
+
parms_filter = @request_filter_settings[:parms_filter]
|
|
564
|
+
if parms_filter != ''
|
|
565
|
+
# puts "!PARMS FILTER: #{parms_filter}"
|
|
566
|
+
match_parms = false
|
|
567
|
+
puts request.parms
|
|
568
|
+
match_parms = request.parms.find { |x| x =~ /#{parms_filter}/ }
|
|
569
|
+
match_parms = (match_parms.nil?) ? false : true
|
|
570
|
+
if @request_filter_settings[:negate_parms_filter] == true
|
|
571
|
+
match_parms = (match_parms == true) ? false : true
|
|
572
|
+
end
|
|
573
|
+
end
|
|
574
|
+
return false if match_parms == false
|
|
575
|
+
|
|
576
|
+
true
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
#
|
|
580
|
+
#
|
|
581
|
+
# matchResponseFilter(response)
|
|
582
|
+
#
|
|
583
|
+
#
|
|
584
|
+
|
|
585
|
+
def matchResponseFilter(response)
|
|
586
|
+
match_ctype = true
|
|
587
|
+
ct_filter = @response_filter_settings[:content_type_filter]
|
|
588
|
+
unless ct_filter.empty?
|
|
589
|
+
match_ctype = false
|
|
590
|
+
negate = @response_filter_settings[:negate_content_type_filter]
|
|
591
|
+
if response.content_type =~ /#{ct_filter}/
|
|
592
|
+
match_ctype = true
|
|
593
|
+
|
|
594
|
+
end
|
|
595
|
+
if negate == true
|
|
596
|
+
match_ctype = (match_ctype == true) ? false : true
|
|
597
|
+
end
|
|
598
|
+
end
|
|
599
|
+
return false if match_ctype == false
|
|
600
|
+
#puts "* pass ctype filter"
|
|
601
|
+
match_rcode = true
|
|
602
|
+
rcode_filter = @response_filter_settings[:response_code_filter]
|
|
603
|
+
negate = @response_filter_settings[:negate_response_code_filter]
|
|
604
|
+
unless rcode_filter.empty?
|
|
605
|
+
match_rcode = false
|
|
606
|
+
puts rcode_filter
|
|
607
|
+
puts response.responseCode
|
|
608
|
+
if response.responseCode =~ /#{rcode_filter}/
|
|
609
|
+
match_rcode = true
|
|
610
|
+
end
|
|
611
|
+
if negate == true
|
|
612
|
+
match_rcode = (match_rcode == true) ? false : true
|
|
613
|
+
end
|
|
614
|
+
end
|
|
615
|
+
return false if match_rcode == false
|
|
616
|
+
#puts "* pass rcode filter"
|
|
617
|
+
true
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
#
|
|
621
|
+
#
|
|
622
|
+
# pass_through(server, client, maxbytes)
|
|
623
|
+
#
|
|
624
|
+
#
|
|
625
|
+
def pass_through(server, client, maxbytes = 0)
|
|
626
|
+
|
|
627
|
+
bytes_read = 0
|
|
628
|
+
while 1
|
|
629
|
+
begin
|
|
630
|
+
#timeout(2) do
|
|
631
|
+
buf = nil
|
|
632
|
+
buf = server.readpartial(2048)
|
|
633
|
+
#end
|
|
634
|
+
rescue EOFError
|
|
635
|
+
#client.write buf if buf
|
|
636
|
+
#print "~]"
|
|
637
|
+
# msg = "\n[pass_through] EOF - "
|
|
638
|
+
# msg += buf.nil? ? "nil" : buf.size
|
|
639
|
+
# puts msg
|
|
640
|
+
return if buf.nil?
|
|
641
|
+
rescue Errno::ECONNRESET
|
|
642
|
+
# puts "!!! ERROR (Reset): reading body"
|
|
643
|
+
# puts "* last data seen on socket: #{buf}"
|
|
644
|
+
# msg = "!R - "
|
|
645
|
+
# msg += buf.nil? ? "nil" : buf.size
|
|
646
|
+
# msg << " !\n"
|
|
647
|
+
# puts msg
|
|
648
|
+
|
|
649
|
+
return if buf.nil?
|
|
650
|
+
rescue Timeout::Error
|
|
651
|
+
#puts "!!! ERROR (Timeout): reading body"
|
|
652
|
+
#puts "* last data seen on socket:"
|
|
653
|
+
#client.write buf if buf
|
|
654
|
+
print "T"
|
|
655
|
+
return
|
|
656
|
+
rescue => bang
|
|
657
|
+
puts "!!! could not read body !!!"
|
|
658
|
+
puts bang
|
|
659
|
+
puts bang.class
|
|
660
|
+
puts bang.backtrace if $DEBUG
|
|
661
|
+
# puts "* last data seen on socket:"
|
|
662
|
+
# print "~]"
|
|
663
|
+
#client.write buf if buf
|
|
664
|
+
return
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
begin
|
|
668
|
+
return if buf.nil?
|
|
669
|
+
# print "~"
|
|
670
|
+
client.write buf
|
|
671
|
+
bytes_read += buf.length
|
|
672
|
+
# puts "#{server} #{bytes_read} of #{maxbytes}"
|
|
673
|
+
if maxbytes > 0 and bytes_read >= maxbytes
|
|
674
|
+
#print "~]"
|
|
675
|
+
return
|
|
676
|
+
end
|
|
677
|
+
rescue Errno::ECONNRESET
|
|
678
|
+
#print "~x]"
|
|
679
|
+
# puts "!!! ERROR (Reset): reading body"
|
|
680
|
+
# puts "* last data seen on socket: #{buf}"
|
|
681
|
+
return
|
|
682
|
+
rescue Errno::ECONNABORTED
|
|
683
|
+
# print "~x]"
|
|
684
|
+
return
|
|
685
|
+
rescue Errno::EPIPE
|
|
686
|
+
# print "~x]"
|
|
687
|
+
return
|
|
688
|
+
rescue => bang
|
|
689
|
+
puts "!!! client communication broken !!!"
|
|
690
|
+
puts bang
|
|
691
|
+
puts bang.class
|
|
692
|
+
puts bang.backtrace if $DEBUG
|
|
693
|
+
return
|
|
694
|
+
end
|
|
695
|
+
end
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
def transparent?
|
|
699
|
+
(@proxy_mode & Watobo::Interceptor::MODE_TRANSPARENT) > 0
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
def isPassThrough?(request, response, s_sock, c_sock)
|
|
709
703
|
begin
|
|
710
|
-
|
|
711
|
-
reason = nil
|
|
704
|
+
# return false if true
|
|
705
|
+
reason = nil
|
|
712
706
|
clen = response.content_length
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
#
|
|
720
|
-
|
|
721
|
-
reason
|
|
722
|
-
reason.push "
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
#
|
|
726
|
-
|
|
727
|
-
reason
|
|
728
|
-
reason.push "
|
|
729
|
-
|
|
730
|
-
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
# no pass-through necessary if request method is HEAD
|
|
710
|
+
return false if request.method =~ /^head/i
|
|
711
|
+
|
|
712
|
+
if matchContentType?(response.content_type) then
|
|
713
|
+
# first forward headers
|
|
714
|
+
#c_sock.write response.join
|
|
715
|
+
reason = []
|
|
716
|
+
reason.push "---> WATOBO: PASS_THROUGH <---"
|
|
717
|
+
reason.push "Reason: Content-Type = #{response.content_type}"
|
|
718
|
+
elsif clen > @contentLength
|
|
719
|
+
# puts "PASS-THROUGH: #{response.content_length}"
|
|
720
|
+
#c_sock.write response.join
|
|
721
|
+
reason = []
|
|
722
|
+
reason.push "---> WATOBO: PASS_THROUGH <---"
|
|
723
|
+
reason.push "Reason: Content-Length > #{@contentLength} (#{response.content_length})"
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
@pass_through_hosts.each do |p|
|
|
727
|
+
if request.host =~ /#{p}/
|
|
728
|
+
c_sock.write response.join
|
|
729
|
+
pass_through(s_sock, c_sock, clen)
|
|
730
|
+
return true
|
|
731
|
+
end
|
|
732
|
+
end
|
|
733
|
+
|
|
731
734
|
return false if reason.nil?
|
|
732
|
-
|
|
735
|
+
|
|
733
736
|
response.remove_header("Keep-Alive")
|
|
734
737
|
response.set_header("Connection", "close")
|
|
735
|
-
|
|
738
|
+
|
|
736
739
|
c_sock.write response.join
|
|
737
|
-
|
|
738
|
-
reason.push "* DO MANUAL REQUEST TO GET FULL RESPONSE *"
|
|
739
|
-
response.push reason.join("\n")
|
|
740
|
-
chat = Watobo::Chat.new(request, response, :source => CHAT_SOURCE_INTERCEPT)
|
|
741
|
-
#notify(:new_interception, chat)
|
|
742
|
-
Watobo::Chats.add chat
|
|
743
|
-
|
|
744
|
-
pass_through(s_sock, c_sock, clen)
|
|
745
|
-
# puts "* Close Server Socket..."
|
|
746
|
-
#closeSocket(c_sock)
|
|
747
|
-
# puts "* Close Client Socket..."
|
|
748
|
-
#closeSocket(s_sock)
|
|
749
|
-
# puts "... done."
|
|
750
|
-
return true
|
|
751
|
-
rescue => bang
|
|
752
|
-
puts bang
|
|
753
|
-
puts bang.backtrace if $DEBUG
|
|
740
|
+
|
|
741
|
+
reason.push "* DO MANUAL REQUEST TO GET FULL RESPONSE *"
|
|
742
|
+
response.push reason.join("\n")
|
|
743
|
+
chat = Watobo::Chat.new(request, response, :source => CHAT_SOURCE_INTERCEPT)
|
|
744
|
+
#notify(:new_interception, chat)
|
|
745
|
+
Watobo::Chats.add chat
|
|
746
|
+
|
|
747
|
+
pass_through(s_sock, c_sock, clen)
|
|
748
|
+
# puts "* Close Server Socket..."
|
|
749
|
+
#closeSocket(c_sock)
|
|
750
|
+
# puts "* Close Client Socket..."
|
|
751
|
+
#closeSocket(s_sock)
|
|
752
|
+
# puts "... done."
|
|
753
|
+
return true
|
|
754
|
+
rescue => bang
|
|
755
|
+
puts bang
|
|
756
|
+
puts bang.backtrace if $DEBUG
|
|
754
757
|
end
|
|
755
|
-
return false
|
|
756
|
-
end
|
|
757
|
-
|
|
758
|
-
end
|
|
759
|
-
end
|
|
760
|
-
end
|
|
758
|
+
return false
|
|
759
|
+
end
|
|
760
|
+
|
|
761
|
+
end
|
|
762
|
+
end
|
|
763
|
+
end
|