watobo 0.9.8.677

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.
Files changed (260) hide show
  1. data/bin/watobo_gui.rb +39 -0
  2. data/certificates/cert.pem +19 -0
  3. data/certificates/privkey.pem +15 -0
  4. data/certificates/watobo_dh.key +5 -0
  5. data/config/datastore.yml +5 -0
  6. data/config/forwarding_proxy.yml +12 -0
  7. data/config/general.yml +4 -0
  8. data/config/gui.yml +23 -0
  9. data/config/interceptor.yml +16 -0
  10. data/config/scan_policy.yml +13 -0
  11. data/config/scanner.yml +34 -0
  12. data/icons/Add.ico +0 -0
  13. data/icons/Add_24x24.ico +0 -0
  14. data/icons/Bandwidth.ico +0 -0
  15. data/icons/Bandwidth_24x24.ico +0 -0
  16. data/icons/Mr. Bomb.ico +0 -0
  17. data/icons/Mr. Bomb_16x16.ico +0 -0
  18. data/icons/Mr. Bomb_24x24.ico +0 -0
  19. data/icons/Orange Ball.ico +0 -0
  20. data/icons/Orange Ball_16x16.ico +0 -0
  21. data/icons/Orange Ball_24x24.ico +0 -0
  22. data/icons/Pause.ico +0 -0
  23. data/icons/Play.ico +0 -0
  24. data/icons/Play_24x24.ico +0 -0
  25. data/icons/Red Ball.ico +0 -0
  26. data/icons/Red Ball_16x16.ico +0 -0
  27. data/icons/Red Ball_24x24.ico +0 -0
  28. data/icons/Run.ico +0 -0
  29. data/icons/Stop.ico +0 -0
  30. data/icons/Stop_24x24.ico +0 -0
  31. data/icons/Terminal.ico +0 -0
  32. data/icons/Transfer.ico +0 -0
  33. data/icons/Transfer_16x16.ico +0 -0
  34. data/icons/User.ico +0 -0
  35. data/icons/User_16x16.ico +0 -0
  36. data/icons/User_24x24.ico +0 -0
  37. data/icons/Web Browser.ico +0 -0
  38. data/icons/Web Browser_16x16.ico +0 -0
  39. data/icons/Write Document.ico +0 -0
  40. data/icons/Yellow Ball.ico +0 -0
  41. data/icons/Yellow Ball_16x16.ico +0 -0
  42. data/icons/Yellow Ball_24x24.ico +0 -0
  43. data/icons/advanced.ico +0 -0
  44. data/icons/advanced_16x16.ico +0 -0
  45. data/icons/advanced_24x24.ico +0 -0
  46. data/icons/applications.ico +0 -0
  47. data/icons/applications_16x16.ico +0 -0
  48. data/icons/applications_24x24.ico +0 -0
  49. data/icons/browser_16x16.ico +0 -0
  50. data/icons/browser_24x24.ico +0 -0
  51. data/icons/burn.ico +0 -0
  52. data/icons/burn_16x16.ico +0 -0
  53. data/icons/burn_24x24.ico +0 -0
  54. data/icons/calculator.ico +0 -0
  55. data/icons/calculator_24x24.ico +0 -0
  56. data/icons/cb_checked.ico +0 -0
  57. data/icons/cb_checked_orange.ico +0 -0
  58. data/icons/cb_unchecked.ico +0 -0
  59. data/icons/coin_24x24.ico +0 -0
  60. data/icons/conversation.ico +0 -0
  61. data/icons/conversation_24x24.ico +0 -0
  62. data/icons/engine.ico +0 -0
  63. data/icons/filter.ico +0 -0
  64. data/icons/folder.ico +0 -0
  65. data/icons/folder_16x16.ico +0 -0
  66. data/icons/fuzzer_16x16.ico +0 -0
  67. data/icons/fuzzer_24x24.ico +0 -0
  68. data/icons/go-down_16x16.png +0 -0
  69. data/icons/go-up_16x16.png +0 -0
  70. data/icons/help.ico +0 -0
  71. data/icons/help_16x16.ico +0 -0
  72. data/icons/help_24x24.ico +0 -0
  73. data/icons/iChat.ico +0 -0
  74. data/icons/iChat_16x16.ico +0 -0
  75. data/icons/iChat_24x24.ico +0 -0
  76. data/icons/icons.txt +3 -0
  77. data/icons/info.ico +0 -0
  78. data/icons/info_16x16.ico +0 -0
  79. data/icons/info_24x24.ico +0 -0
  80. data/icons/interceptor_24x24.ico +0 -0
  81. data/icons/lock.ico +0 -0
  82. data/icons/lock_12x12.ico +0 -0
  83. data/icons/lock_16x16.ico +0 -0
  84. data/icons/monitor.ico +0 -0
  85. data/icons/plugin.ico +0 -0
  86. data/icons/plugin_24x24.ico +0 -0
  87. data/icons/scan_16x16.png +0 -0
  88. data/icons/send.ico +0 -0
  89. data/icons/server.ico +0 -0
  90. data/icons/server_16x16.ico +0 -0
  91. data/icons/siberas_logo_x24.gif +0 -0
  92. data/icons/tag_blue_32x32.ico +0 -0
  93. data/icons/watobo-48x48.png +0 -0
  94. data/icons/watobo-logo.png +0 -0
  95. data/icons/watobo.ico +0 -0
  96. data/lib/watobo/adapters/data_store.rb +38 -0
  97. data/lib/watobo/adapters/file/file_store.rb +211 -0
  98. data/lib/watobo/adapters/session_store.rb +27 -0
  99. data/lib/watobo/adapters.rb +26 -0
  100. data/lib/watobo/config.rb +143 -0
  101. data/lib/watobo/constants.rb +92 -0
  102. data/lib/watobo/core/active_check.rb +404 -0
  103. data/lib/watobo/core/cookie.rb +69 -0
  104. data/lib/watobo/core/fuzz_gen.rb +160 -0
  105. data/lib/watobo/core/http_socket.rb +142 -0
  106. data/lib/watobo/core/interceptor.rb +729 -0
  107. data/lib/watobo/core/passive_check.rb +141 -0
  108. data/lib/watobo/core/project.rb +1058 -0
  109. data/lib/watobo/core/scanner.rb +396 -0
  110. data/lib/watobo/core/session.rb +1320 -0
  111. data/lib/watobo/core/simple_ca.rb +393 -0
  112. data/lib/watobo/core.rb +34 -0
  113. data/lib/watobo/defaults.rb +40 -0
  114. data/lib/watobo/external/diff/lcs/array.rb +42 -0
  115. data/lib/watobo/external/diff/lcs/block.rb +72 -0
  116. data/lib/watobo/external/diff/lcs/callbacks.rb +343 -0
  117. data/lib/watobo/external/diff/lcs/change.rb +190 -0
  118. data/lib/watobo/external/diff/lcs/hunk.rb +279 -0
  119. data/lib/watobo/external/diff/lcs/ldiff.rb +247 -0
  120. data/lib/watobo/external/diff/lcs/string.rb +40 -0
  121. data/lib/watobo/external/diff/lcs.rb +1124 -0
  122. data/lib/watobo/external/ntlm/ntlm.rb +797 -0
  123. data/lib/watobo/externals.rb +28 -0
  124. data/lib/watobo/framework/create_project.rb +55 -0
  125. data/lib/watobo/framework/init.rb +149 -0
  126. data/lib/watobo/framework/init_modules.rb +116 -0
  127. data/lib/watobo/framework/license_text.rb +50 -0
  128. data/lib/watobo/framework.rb +26 -0
  129. data/lib/watobo/gui/about_watobo.rb +68 -0
  130. data/lib/watobo/gui/browser_preview.rb +460 -0
  131. data/lib/watobo/gui/certificate_dialog.rb +132 -0
  132. data/lib/watobo/gui/chat_diff.rb +415 -0
  133. data/lib/watobo/gui/chatviewer_frame.rb +427 -0
  134. data/lib/watobo/gui/checkboxtree.rb +221 -0
  135. data/lib/watobo/gui/checks_policy_frame.rb +123 -0
  136. data/lib/watobo/gui/client_cert_dialog.rb +227 -0
  137. data/lib/watobo/gui/confirm_scan_dialog.rb +67 -0
  138. data/lib/watobo/gui/conversation_table.rb +386 -0
  139. data/lib/watobo/gui/conversation_table_ctrl.rb +175 -0
  140. data/lib/watobo/gui/csrf_token_dialog.rb +446 -0
  141. data/lib/watobo/gui/dashboard.rb +341 -0
  142. data/lib/watobo/gui/define_scope_frame.rb +380 -0
  143. data/lib/watobo/gui/edit_comment.rb +70 -0
  144. data/lib/watobo/gui/edit_scope_dialog.rb +69 -0
  145. data/lib/watobo/gui/finding_info.rb +212 -0
  146. data/lib/watobo/gui/findings_tree.rb +459 -0
  147. data/lib/watobo/gui/full_scan_dialog.rb +269 -0
  148. data/lib/watobo/gui/fuzzer_gui.rb +1522 -0
  149. data/lib/watobo/gui/hex_viewer.rb +106 -0
  150. data/lib/watobo/gui/interceptor_gui.rb +994 -0
  151. data/lib/watobo/gui/interceptor_settings_dialog.rb +201 -0
  152. data/lib/watobo/gui/log_viewer.rb +97 -0
  153. data/lib/watobo/gui/login_wizzard.rb +301 -0
  154. data/lib/watobo/gui/main_window.rb +1815 -0
  155. data/lib/watobo/gui/manual_request_editor.rb +1105 -0
  156. data/lib/watobo/gui/master_pw_dialog.rb +142 -0
  157. data/lib/watobo/gui/password_policy_dialog.rb +98 -0
  158. data/lib/watobo/gui/plugin/base.rb +82 -0
  159. data/lib/watobo/gui/plugin_board.rb +95 -0
  160. data/lib/watobo/gui/preferences_dialog.rb +116 -0
  161. data/lib/watobo/gui/progress_window.rb +102 -0
  162. data/lib/watobo/gui/project_wizzard.rb +369 -0
  163. data/lib/watobo/gui/proxy_dialog.rb +550 -0
  164. data/lib/watobo/gui/quick_scan_dialog.rb +242 -0
  165. data/lib/watobo/gui/request_editor.rb +480 -0
  166. data/lib/watobo/gui/save_chat_dialog.rb +158 -0
  167. data/lib/watobo/gui/scanner_settings_dialog.rb +360 -0
  168. data/lib/watobo/gui/select_chat_dialog.rb +169 -0
  169. data/lib/watobo/gui/session_management_dialog.rb +688 -0
  170. data/lib/watobo/gui/sites_tree.rb +347 -0
  171. data/lib/watobo/gui/status_bar.rb +88 -0
  172. data/lib/watobo/gui/table_editor.rb +445 -0
  173. data/lib/watobo/gui/tagless_viewer.rb +62 -0
  174. data/lib/watobo/gui/templates/plugin.rb +80 -0
  175. data/lib/watobo/gui/templates/plugin2.rb +103 -0
  176. data/lib/watobo/gui/text_viewer.rb +247 -0
  177. data/lib/watobo/gui/transcoder_window.rb +215 -0
  178. data/lib/watobo/gui/utils/gui_utils.rb +129 -0
  179. data/lib/watobo/gui/utils/init_icons.rb +106 -0
  180. data/lib/watobo/gui/utils/load_icons.rb +54 -0
  181. data/lib/watobo/gui/utils/load_plugins.rb +94 -0
  182. data/lib/watobo/gui/utils/master_password.rb +90 -0
  183. data/lib/watobo/gui/utils/save_default_settings.rb +99 -0
  184. data/lib/watobo/gui/utils/save_project_settings.rb +21 -0
  185. data/lib/watobo/gui/utils/save_proxy_settings.rb +45 -0
  186. data/lib/watobo/gui/utils/save_session_settings.rb +21 -0
  187. data/lib/watobo/gui/utils/session_history.rb +134 -0
  188. data/lib/watobo/gui/workspace_dialog.rb +89 -0
  189. data/lib/watobo/gui/www_auth_dialog.rb +348 -0
  190. data/lib/watobo/gui/xml_viewer_frame.rb +114 -0
  191. data/lib/watobo/gui.rb +139 -0
  192. data/lib/watobo/mixins/httpparser.rb +664 -0
  193. data/lib/watobo/mixins/request_parser.rb +210 -0
  194. data/lib/watobo/mixins/shapers.rb +345 -0
  195. data/lib/watobo/mixins/transcoders.rb +88 -0
  196. data/lib/watobo/mixins.rb +32 -0
  197. data/lib/watobo/utils/check_regex.rb +36 -0
  198. data/lib/watobo/utils/copy_object.rb +29 -0
  199. data/lib/watobo/utils/crypto.rb +74 -0
  200. data/lib/watobo/utils/expand_range.rb +45 -0
  201. data/lib/watobo/utils/file_management.rb +73 -0
  202. data/lib/watobo/utils/load_chat.rb +219 -0
  203. data/lib/watobo/utils/load_icon.rb +47 -0
  204. data/lib/watobo/utils/print_debug.rb +34 -0
  205. data/lib/watobo/utils/response_hash.rb +143 -0
  206. data/lib/watobo/utils/secure_eval.rb +57 -0
  207. data/lib/watobo/utils/text2request.rb +96 -0
  208. data/lib/watobo/utils.rb +32 -0
  209. data/lib/watobo.rb +76 -0
  210. data/modules/active/Apache/mod_status.rb +123 -0
  211. data/modules/active/Flash/crossdomain.rb +102 -0
  212. data/modules/active/directories/dirwalker.rb +89 -0
  213. data/modules/active/discovery/fileextensions.rb +151 -0
  214. data/modules/active/discovery/http_methods.rb +135 -0
  215. data/modules/active/domino/domino_db.lst +164 -0
  216. data/modules/active/domino/domino_db.rb +128 -0
  217. data/modules/active/fileinclusion/lfi_simple.rb +134 -0
  218. data/modules/active/jboss/jboss_basic.rb +119 -0
  219. data/modules/active/sap/business_objects.rb +73 -0
  220. data/modules/active/sap/its_commands.rb +101 -0
  221. data/modules/active/sap/its_service_parameter.rb +105 -0
  222. data/modules/active/sap/its_services.rb +103 -0
  223. data/modules/active/sap/its_xss.rb +98 -0
  224. data/modules/active/sqlinjection/sql_boolean.rb +262 -0
  225. data/modules/active/sqlinjection/sqli_simple.rb +205 -0
  226. data/modules/active/xss/xss_simple.rb +179 -0
  227. data/modules/passive/cookie_options.rb +97 -0
  228. data/modules/passive/cookie_xss.rb +85 -0
  229. data/modules/passive/detect_code.rb +89 -0
  230. data/modules/passive/detect_fileupload.rb +80 -0
  231. data/modules/passive/detect_infrastructure.rb +98 -0
  232. data/modules/passive/detect_one_time_tokens.rb +86 -0
  233. data/modules/passive/dirindexing.rb +81 -0
  234. data/modules/passive/disclosure_emails.rb +82 -0
  235. data/modules/passive/disclosure_ipaddr.rb +87 -0
  236. data/modules/passive/filename_as_parameter.rb +85 -0
  237. data/modules/passive/form_spotter.rb +75 -0
  238. data/modules/passive/hotspots.rb +86 -0
  239. data/modules/passive/in_script_parameter.rb +92 -0
  240. data/modules/passive/multiple_server_headers.rb +98 -0
  241. data/modules/passive/possible_login.rb +134 -0
  242. data/modules/passive/redirect_url.rb +88 -0
  243. data/modules/passive/redirectionz.rb +96 -0
  244. data/modules/passive/xss_dom.rb +91 -0
  245. data/plugins/catalog/catalog.ico +0 -0
  246. data/plugins/catalog/catalog.rb +726 -0
  247. data/plugins/catalog/db_tests +6483 -0
  248. data/plugins/catalog/db_variables +29 -0
  249. data/plugins/filefinder/dbs/hbci.db +12 -0
  250. data/plugins/filefinder/filefinder.rb +602 -0
  251. data/plugins/sslchecker/cli/sslchecker_cli.rb +21 -0
  252. data/plugins/sslchecker/gui/cipher_table.rb +260 -0
  253. data/plugins/sslchecker/gui/gui.rb +245 -0
  254. data/plugins/sslchecker/gui/sslchecker.rb +26 -0
  255. data/plugins/sslchecker/icons/green_16x16.ico +0 -0
  256. data/plugins/sslchecker/icons/grey_16x16.ico +0 -0
  257. data/plugins/sslchecker/icons/red_16x16.ico +0 -0
  258. data/plugins/sslchecker/icons/sslchecker.ico +0 -0
  259. data/plugins/sslchecker/lib/check.rb +117 -0
  260. metadata +317 -0
@@ -0,0 +1,797 @@
1
+ # .
2
+ # ntlm.rb
3
+ #
4
+ # Copyright 2012 by siberas, http://www.siberas.de
5
+ #
6
+ # This file is part of WATOBO (Web Application Tool Box)
7
+ # http://watobo.sourceforge.com
8
+ #
9
+ # WATOBO is free software; you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation version 2 of the License.
12
+ #
13
+ # WATOBO is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with WATOBO; if not, write to the Free Software
20
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+ # .
22
+ #
23
+ # = net/ntlm.rb
24
+ #
25
+ # An NTLM Authentication Library for Ruby
26
+ #
27
+ # This code is a derivative of "dbf2.rb" written by yrock
28
+ # and Minero Aoki. You can find original code here:
29
+ # http://jp.rubyist.net/magazine/?0013-CodeReview
30
+ # -------------------------------------------------------------
31
+ # Copyright (c) 2005,2006 yrock
32
+ #
33
+ # This program is free software.
34
+ # You can distribute/modify this program under the terms of the
35
+ # Ruby License.
36
+ #
37
+ # 2006-02-11 refactored by Minero Aoki
38
+ # -------------------------------------------------------------
39
+ #
40
+ # All protocol information used to write this code stems from
41
+ # "The NTLM Authentication Protocol" by Eric Glass. The author
42
+ # would thank to him for this tremendous work and making it
43
+ # available on the net.
44
+ # http://davenport.sourceforge.net/ntlm.html
45
+ # -------------------------------------------------------------
46
+ # Copyright (c) 2003 Eric Glass
47
+ #
48
+ # Permission to use, copy, modify, and distribute this document
49
+ # for any purpose and without any fee is hereby granted,
50
+ # provided that the above copyright notice and this list of
51
+ # conditions appear in all copies.
52
+ # -------------------------------------------------------------
53
+ #
54
+ # The author also looked Mozilla-Firefox-1.0.7 source code,
55
+ # namely, security/manager/ssl/src/nsNTLMAuthModule.cpp and
56
+ # Jonathan Bastien-Filiatrault's libntlm-ruby.
57
+ # "http://x2a.org/websvn/filedetails.php?
58
+ # repname=libntlm-ruby&path=%2Ftrunk%2Fntlm.rb&sc=1"
59
+ # The latter has a minor bug in its separate_keys function.
60
+ # The third key has to begin from the 14th character of the
61
+ # input string instead of 13th:)
62
+ #--
63
+ # $Id: ntlm.rb,v 1.1 2006/10/05 01:36:52 koheik Exp $
64
+ #++
65
+
66
+ require 'base64'
67
+ require 'openssl'
68
+ require 'openssl/digest'
69
+
70
+ require 'kconv'
71
+
72
+ module Net #:nodoc:
73
+ module NTLM
74
+
75
+ module VERSION #:nodoc:
76
+ MAJOR = 0
77
+ MINOR = 1
78
+ TINY = 1
79
+ STRING = [MAJOR, MINOR, TINY].join('.')
80
+ end
81
+
82
+ SSP_SIGN = "NTLMSSP\0"
83
+ BLOB_SIGN = 0x00000101
84
+ LM_MAGIC = "KGS!@\#$%"
85
+ TIME_OFFSET = 11644473600
86
+ MAX64 = 0xffffffffffffffff
87
+
88
+ FLAGS = {
89
+ :UNICODE => 0x00000001,
90
+ :OEM => 0x00000002,
91
+ :REQUEST_TARGET => 0x00000004,
92
+ # :UNKNOWN => 0x00000008,
93
+ :SIGN => 0x00000010,
94
+ :SEAL => 0x00000020,
95
+ # :UNKNOWN => 0x00000040,
96
+ :NETWARE => 0x00000100,
97
+ :NTLM => 0x00000200,
98
+ # :UNKNOWN => 0x00000400,
99
+ # :UNKNOWN => 0x00000800,
100
+ :DOMAIN_SUPPLIED => 0x00001000,
101
+ :WORKSTATION_SUPPLIED => 0x00002000,
102
+ :LOCAL_CALL => 0x00004000,
103
+ :ALWAYS_SIGN => 0x00008000,
104
+ :TARGET_TYPE_DOMAIN => 0x00010000,
105
+ :TARGET_INFO => 0x00800000,
106
+ :NTLM2_KEY => 0x00080000,
107
+ :KEY128 => 0x20000000,
108
+ :KEY56 => 0x80000000
109
+ }
110
+
111
+ FLAG_KEYS = FLAGS.keys.sort{|a, b| FLAGS[a] <=> FLAGS[b] }
112
+
113
+ DEFAULT_FLAGS = {
114
+ :TYPE1 => FLAGS[:UNICODE] | FLAGS[:OEM] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY],
115
+ :TYPE2 => FLAGS[:UNICODE],
116
+ :TYPE3 => FLAGS[:UNICODE] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY]
117
+ }
118
+
119
+ # module functions
120
+ class << self
121
+ def decode_utf16le(str)
122
+ Kconv.kconv(swap16(str), Kconv::ASCII, Kconv::UTF16)
123
+ end
124
+
125
+ def encode_utf16le(str)
126
+ swap16(Kconv.kconv(str, Kconv::UTF16, Kconv::ASCII))
127
+ end
128
+
129
+ def pack_int64le(val)
130
+ [val & 0x00000000ffffffff, val >> 32].pack("V2")
131
+ end
132
+
133
+ def swap16(str)
134
+ str.unpack("v*").pack("n*")
135
+ end
136
+
137
+ def split7(str)
138
+ s = str.dup
139
+ until s.empty?
140
+ (ret ||= []).push s.slice!(0, 7)
141
+ end
142
+ ret
143
+ end
144
+
145
+ def gen_keys(str)
146
+ split7(str).map{ |str7|
147
+ bits = split7(str7.unpack("B*")[0]).inject('')\
148
+ {|ret, tkn| ret += tkn + (tkn.gsub('1', '').size % 2).to_s }
149
+ [bits].pack("B*")
150
+ }
151
+ end
152
+
153
+ def apply_des(plain, keys)
154
+ dec = OpenSSL::Cipher::DES.new
155
+ keys.map {|k|
156
+ dec.key = k
157
+ dec.encrypt.update(plain)
158
+ }
159
+ end
160
+
161
+ def lm_hash(password)
162
+ keys = gen_keys password.upcase.ljust(14, "\0")
163
+ apply_des(LM_MAGIC, keys).join
164
+ end
165
+
166
+ def ntlm_hash(password, opt = {})
167
+ pwd = password.dup
168
+ unless opt[:unicode]
169
+ pwd = encode_utf16le(pwd)
170
+ end
171
+ OpenSSL::Digest::MD4.digest pwd
172
+ end
173
+
174
+ def ntlmv2_hash(user, password, target, opt={})
175
+ ntlmhash = ntlm_hash(password, opt)
176
+ userdomain = (user + target).upcase
177
+ unless opt[:unicode]
178
+ userdomain = encode_utf16le(userdomain)
179
+ end
180
+ OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmhash, userdomain)
181
+ end
182
+
183
+ # responses
184
+ def lm_response(arg)
185
+ begin
186
+ hash = arg[:lm_hash]
187
+ chal = arg[:challenge]
188
+ rescue
189
+ raise ArgumentError
190
+ end
191
+ chal = NTL::pack_int64le(chal) if chal.is_a?(Integer)
192
+ keys = gen_keys hash.ljust(21, "\0")
193
+ apply_des(chal, keys).join
194
+ end
195
+
196
+ def ntlm_response(arg)
197
+ hash = arg[:ntlm_hash]
198
+ chal = arg[:challenge]
199
+ chal = NTL::pack_int64le(chal) if chal.is_a?(Integer)
200
+ keys = gen_keys hash.ljust(21, "\0")
201
+ apply_des(chal, keys).join
202
+ end
203
+
204
+ def ntlmv2_response(arg, opt = {})
205
+ begin
206
+ key = arg[:ntlmv2_hash]
207
+ chal = arg[:challenge]
208
+ ti = arg[:target_info]
209
+ rescue
210
+ raise ArgumentError
211
+ end
212
+ chal = NTL::pack_int64le(chal) if chal.is_a?(Integer)
213
+
214
+ if opt[:client_challenge]
215
+ cc = opt[:client_challenge]
216
+ else
217
+ cc = rand(MAX64)
218
+ end
219
+ cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer)
220
+
221
+ if opt[:timestamp]
222
+ ts = opt[:timestamp]
223
+ else
224
+ ts = Time.now.to_i
225
+ end
226
+ # epoch -> milsec from Jan 1, 1601
227
+ ts = 10000000 * (ts + TIME_OFFSET)
228
+
229
+ blob = Blob.new
230
+ blob.timestamp = ts
231
+ blob.challenge = cc
232
+ blob.target_info = ti
233
+
234
+ bb = blob.serialize
235
+ OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, key, chal + bb) + bb
236
+ end
237
+
238
+ def lmv2_response(arg, opt = {})
239
+ key = arg[:ntlmv2_hash]
240
+ chal = arg[:challenge]
241
+
242
+ chal = NTLM::pack_int64le(chal) if chal.is_a?(Integer)
243
+
244
+ if opt[:client_challenge]
245
+ cc = opt[:client_challenge]
246
+ else
247
+ cc = rand(MAX64)
248
+ end
249
+ cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer)
250
+
251
+ OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, key, chal + cc) + cc
252
+ end
253
+
254
+ def ntlm2_session(arg, opt = {})
255
+ begin
256
+ passwd_hash = arg[:ntlm_hash]
257
+ chal = arg[:challenge]
258
+ rescue
259
+ raise ArgumentError
260
+ end
261
+
262
+ if opt[:client_challenge]
263
+ cc = opt[:client_challenge]
264
+ else
265
+ cc = rand(MAX64)
266
+ end
267
+ cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer)
268
+
269
+ keys = gen_keys passwd_hash.ljust(21, "\0")
270
+ session_hash = OpenSSL::Digest::MD5.digest(chal + cc).slice(0, 8)
271
+ response = apply_des(session_hash, keys).join
272
+ [cc.ljust(24, "\0"), response]
273
+ end
274
+ end
275
+
276
+
277
+ # base classes for primitives
278
+ class Field
279
+ attr_accessor :active, :value
280
+
281
+ def initialize(opts)
282
+ @value = opts[:value]
283
+ @active = opts[:active].nil? ? true : opts[:active]
284
+ end
285
+
286
+ def size
287
+ @active ? @size : 0
288
+ end
289
+ end
290
+
291
+ class String < Field
292
+ def initialize(opts)
293
+ super(opts)
294
+ @size = opts[:size]
295
+ end
296
+
297
+ def parse(str, offset=0)
298
+ if @active and str.size >= offset + @size
299
+ @value = str[offset, @size]
300
+ @size
301
+ else
302
+ 0
303
+ end
304
+ end
305
+
306
+ def serialize
307
+ if @active
308
+ @value
309
+ else
310
+ ""
311
+ end
312
+ end
313
+
314
+ def value=(val)
315
+ @value = val
316
+ @size = @value.nil? ? 0 : @value.size
317
+ @active = (@size > 0)
318
+ end
319
+ end
320
+
321
+
322
+ class Int16LE < Field
323
+ def initialize(opt)
324
+ super(opt)
325
+ @size = 2
326
+ end
327
+ def parse(str, offset=0)
328
+ if @active and str.size >= offset + @size
329
+ @value = str[offset, @size].unpack("v")[0]
330
+ @size
331
+ else
332
+ 0
333
+ end
334
+ end
335
+
336
+ def serialize
337
+ [@value].pack("v")
338
+ end
339
+ end
340
+
341
+ class Int32LE < Field
342
+ def initialize(opt)
343
+ super(opt)
344
+ @size = 4
345
+ end
346
+
347
+ def parse(str, offset=0)
348
+ if @active and str.size >= offset + @size
349
+ @value = str.slice(offset, @size).unpack("V")[0]
350
+ @size
351
+ else
352
+ 0
353
+ end
354
+ end
355
+
356
+ def serialize
357
+ [@value].pack("V") if @active
358
+ end
359
+ end
360
+
361
+ class Int64LE < Field
362
+ def initialize(opt)
363
+ super(opt)
364
+ @size = 8
365
+ end
366
+
367
+ def parse(str, offset=0)
368
+ if @active and str.size >= offset + @size
369
+ d, u = str.slice(offset, @size).unpack("V2")
370
+ @value = (u * 0x100000000 + d)
371
+ @size
372
+ else
373
+ 0
374
+ end
375
+ end
376
+
377
+ def serialize
378
+ [@value & 0x00000000ffffffff, @value >> 32].pack("V2") if @active
379
+ end
380
+ end
381
+
382
+ # base class of data structure
383
+ class FieldSet
384
+ class << FieldSet
385
+ def define(&block)
386
+ c = Class.new(self)
387
+ def c.inherited(subclass)
388
+ proto = @proto
389
+ subclass.instance_eval {
390
+ @proto = proto
391
+ }
392
+ end
393
+ c.module_eval(&block)
394
+ c
395
+ end
396
+
397
+ def string(name, opts)
398
+ add_field(name, String, opts)
399
+ end
400
+
401
+ def int16LE(name, opts)
402
+ add_field(name, Int16LE, opts)
403
+ end
404
+
405
+ def int32LE(name, opts)
406
+ add_field(name, Int32LE, opts)
407
+ end
408
+
409
+ def int64LE(name, opts)
410
+ add_field(name, Int64LE, opts)
411
+ end
412
+
413
+ def security_buffer(name, opts)
414
+ add_field(name, SecurityBuffer, opts)
415
+ end
416
+
417
+ def prototypes
418
+ @proto
419
+ end
420
+
421
+ def names
422
+ @proto.map{|n, t, o| n}
423
+ end
424
+
425
+ def types
426
+ @proto.map{|n, t, o| t}
427
+ end
428
+
429
+ def opts
430
+ @proto.map{|n, t, o| o}
431
+ end
432
+
433
+ private
434
+
435
+ def add_field(name, type, opts)
436
+ (@proto ||= []).push [name, type, opts]
437
+ define_accessor name
438
+ end
439
+
440
+ def define_accessor(name)
441
+ module_eval(<<-End, __FILE__, __LINE__ + 1)
442
+ def #{name}
443
+ self['#{name}'].value
444
+ end
445
+
446
+ def #{name}=(val)
447
+ self['#{name}'].value = val
448
+ end
449
+ End
450
+ end
451
+ end
452
+
453
+ def initialize
454
+ @alist = self.class.prototypes.map{ |n, t, o| [n, t.new(o)] }
455
+ end
456
+
457
+ def serialize
458
+ @alist.map{|n, f| f.serialize }.join
459
+ end
460
+
461
+ def parse(str, offset=0)
462
+ @alist.inject(offset){|cur, a| cur += a[1].parse(str, cur)}
463
+ end
464
+
465
+ def size
466
+ @alist.inject(0){|sum, a| sum += a[1].size}
467
+ end
468
+
469
+ def [](name)
470
+ a = @alist.assoc(name.to_s.intern)
471
+ raise ArgumentError, "no such field: #{name}" unless a
472
+ a[1]
473
+ end
474
+
475
+ def []=(name, val)
476
+ a = @alist.assoc(name.to_s.intern)
477
+ raise ArgumentError, "no such field: #{name}" unless a
478
+ a[1] = val
479
+ end
480
+
481
+ def enable(name)
482
+ self[name].active = true
483
+ end
484
+
485
+ def disable(name)
486
+ self[name].active = false
487
+ end
488
+ end
489
+
490
+
491
+ Blob = FieldSet.define {
492
+ int32LE :blob_signature, {:value => BLOB_SIGN}
493
+ int32LE :reserved, {:value => 0}
494
+ int64LE :timestamp, {:value => 0}
495
+ string :challenge, {:value => "", :size => 8}
496
+ int32LE :unknown1, {:value => 0}
497
+ string :target_info, {:value => "", :size => 0}
498
+ int32LE :unknown2, {:value => 0}
499
+ }
500
+
501
+ SecurityBuffer = FieldSet.define {
502
+ int16LE :length, {:value => 0}
503
+ int16LE :allocated, {:value => 0}
504
+ int32LE :offset, {:value => 0}
505
+ }
506
+
507
+ class SecurityBuffer
508
+ attr_accessor :active
509
+ def initialize(opts)
510
+ super()
511
+ @value = opts[:value]
512
+ @active = opts[:active].nil? ? true : opts[:active]
513
+ @size = 8
514
+ end
515
+
516
+ def parse(str, offset=0)
517
+ if @active and str.size >= offset + @size
518
+ super(str, offset)
519
+ @value = str[self.offset, self.length]
520
+ @size
521
+ else
522
+ 0
523
+ end
524
+ end
525
+
526
+ def serialize
527
+ super if @active
528
+ end
529
+
530
+ def value
531
+ @value
532
+ end
533
+
534
+ def value=(val)
535
+ @value = val
536
+ self.length = self.allocated = val.size
537
+ end
538
+
539
+ def data_size
540
+ @active ? @value.size : 0
541
+ end
542
+ end
543
+
544
+ class Message < FieldSet
545
+ class << Message
546
+ def parse(str)
547
+ m = Type0.new
548
+ m.parse(str)
549
+ case m.type
550
+ when 1
551
+ t = Type1.parse(str)
552
+ when 2
553
+ t = Type2.parse(str)
554
+ when 3
555
+ t = Type3.parse(str)
556
+ else
557
+ raise ArgumentError, "unknown type: #{m.type}"
558
+ end
559
+ t
560
+ end
561
+
562
+ def decode64(str)
563
+ parse(Base64.decode64(str))
564
+ end
565
+ end
566
+
567
+ def has_flag?(flag)
568
+ (self[:flag].value & FLAGS[flag]) == FLAGS[flag]
569
+ end
570
+
571
+ def set_flag(flag)
572
+ self[:flag].value |= FLAGS[flag]
573
+ end
574
+
575
+ def dump_flags
576
+ FLAG_KEYS.each{ |k| print(k, "=", flag?(k), "\n") }
577
+ end
578
+
579
+ def serialize
580
+ deflag
581
+ super + security_buffers.map{|n, f| f.value}.join
582
+ end
583
+
584
+ def encode64
585
+ Base64.encode64(serialize).gsub(/\n/, '')
586
+ end
587
+
588
+ def decode64(str)
589
+ parse(Base64.decode64(str))
590
+ end
591
+
592
+ alias head_size size
593
+
594
+ def data_size
595
+ security_buffers.inject(0){|sum, a| sum += a[1].data_size}
596
+ end
597
+
598
+ def size
599
+ head_size + data_size
600
+ end
601
+
602
+
603
+ private
604
+
605
+ def security_buffers
606
+ @alist.find_all{|n, f| f.instance_of?(SecurityBuffer)}
607
+ end
608
+
609
+ def deflag
610
+ security_buffers.inject(head_size){|cur, a|
611
+ a[1].offset = cur
612
+ cur += a[1].data_size
613
+ }
614
+ end
615
+
616
+ def data_edge
617
+ security_buffers.map{ |n, f| f.active ? f.offset : size}.min
618
+ end
619
+
620
+ # sub class definitions
621
+
622
+ Type0 = Message.define {
623
+ string :sign, {:size => 8, :value => SSP_SIGN}
624
+ int32LE :type, {:value => 0}
625
+ }
626
+
627
+ Type1 = Message.define {
628
+ string :sign, {:size => 8, :value => SSP_SIGN}
629
+ int32LE :type, {:value => 1}
630
+ int32LE :flag, {:value => DEFAULT_FLAGS[:TYPE1] }
631
+ security_buffer :domain, {:value => "", :active => false}
632
+ security_buffer :workstation, {:value => "", :active => false}
633
+ string :padding, {:size => 0, :value => "", :active => false }
634
+ }
635
+
636
+ class Type1
637
+ class << Type1
638
+ def parse(str)
639
+ t = new
640
+ t.parse(str)
641
+ t
642
+ end
643
+ end
644
+
645
+ def parse(str)
646
+ super(str)
647
+ enable(:domain) if has_flag?(:DOMAIN_SUPPLIED)
648
+ enable(:workstation) if has_flag?(:WORKSTATION_SUPPLIED)
649
+ super(str)
650
+ if ( (len = data_edge - head_size) > 0)
651
+ self.padding = "\0" * len
652
+ super(str)
653
+ end
654
+ end
655
+ end
656
+
657
+ Type2 = Message.define{
658
+ string :sign, {:size => 8, :value => SSP_SIGN}
659
+ int32LE :type, {:value => 2}
660
+ security_buffer :target_name, {:size => 0, :value => ""}
661
+ int32LE :flag, {:value => DEFAULT_FLAGS[:TYPE2]}
662
+ int64LE :challenge, {:value => 0}
663
+ int64LE :context, {:value => 0, :active => false}
664
+ security_buffer :target_info, {:value => "", :active => false}
665
+ string :padding, {:size => 0, :value => "", :active => false }
666
+ }
667
+
668
+ class Type2
669
+ class << Type2
670
+ def parse(str)
671
+ t = new
672
+ t.parse(str)
673
+ t
674
+ end
675
+ end
676
+
677
+ def parse(str)
678
+ super(str)
679
+ if has_flag?(:TARGET_INFO)
680
+ enable(:context)
681
+ enable(:target_info)
682
+ super(str)
683
+ end
684
+ if ( (len = data_edge - head_size) > 0)
685
+ self.padding = "\0" * len
686
+ super(str)
687
+ end
688
+ end
689
+
690
+ def response(arg, opt = {})
691
+ usr = arg[:user]
692
+ pwd = arg[:password]
693
+ if usr.nil? or pwd.nil?
694
+ raise ArgumentError, "user and password have to be supplied"
695
+ end
696
+
697
+ if opt[:workstation]
698
+ ws = opt[:workstation]
699
+ else
700
+ ws = ""
701
+ end
702
+
703
+ if opt[:client_challenge]
704
+ cc = opt[:client_challenge]
705
+ else
706
+ cc = rand(MAX64)
707
+ end
708
+ cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer)
709
+ opt[:client_challenge] = cc
710
+
711
+ if has_flag?(:OEM) and opt[:unicode]
712
+ usr = NTLM::decode_utf16le(usr)
713
+ pwd = NTLM::decode_utf16le(pwd)
714
+ ws = NTLM::decode_utf16le(ws)
715
+ opt[:unicode] = false
716
+ end
717
+
718
+ if has_flag?(:UNICODE) and !opt[:unicode]
719
+ usr = NTLM::encode_utf16le(usr)
720
+ pwd = NTLM::encode_utf16le(pwd)
721
+ ws = NTLM::encode_utf16le(ws)
722
+ opt[:unicode] = true
723
+ end
724
+
725
+ tgt = self.target_name
726
+ ti = self.target_info
727
+
728
+ chal = self[:challenge].serialize
729
+
730
+ if opt[:ntlmv2]
731
+ ar = {:ntlmv2_hash => NTLM::ntlmv2_hash(usr, pwd, tgt, opt), :challenge => chal, :target_info => ti}
732
+ lm_res = NTLM::lmv2_response(ar, opt)
733
+ ntlm_res = NTLM::ntlmv2_response(ar, opt)
734
+ elsif has_flag?(:NTLM2_KEY)
735
+ ar = {:ntlm_hash => NTLM::ntlm_hash(pwd, opt), :challenge => chal}
736
+ lm_res, ntlm_res = NTLM::ntlm2_session(ar, opt)
737
+ else
738
+ lm_res = NTLM::lm_response(pwd, chal)
739
+ ntlm_res = NTLM::ntlm_response(pwd, chal)
740
+ end
741
+
742
+ Type3.create({
743
+ :lm_response => lm_res,
744
+ :ntlm_response => ntlm_res,
745
+ :domain => tgt,
746
+ :user => usr,
747
+ :workstation => ws,
748
+ :flag => self.flag
749
+ })
750
+ end
751
+ end
752
+
753
+
754
+ Type3 = Message.define{
755
+ string :sign, {:size => 8, :value => SSP_SIGN}
756
+ int32LE :type, {:value => 3}
757
+ security_buffer :lm_response, {:value => ""}
758
+ security_buffer :ntlm_response, {:value => ""}
759
+ security_buffer :domain, {:value => ""}
760
+ security_buffer :user, {:value => ""}
761
+ security_buffer :workstation, {:value => ""}
762
+ security_buffer :session_key, {:value => "", :active => false }
763
+ int64LE :flag, {:value => 0, :active => false }
764
+ }
765
+
766
+ class Type3
767
+ class << Type3
768
+ def parse(str)
769
+ t = new
770
+ t.parse(str)
771
+ t
772
+ end
773
+
774
+ def create(arg, opt ={})
775
+ t = new
776
+ t.lm_response = arg[:lm_response]
777
+ t.ntlm_response = arg[:ntlm_response]
778
+ t.domain = arg[:domain]
779
+ t.user = arg[:user]
780
+ t.workstation = arg[:workstation]
781
+
782
+ if arg[:session_key]
783
+ t.enable(:session_key)
784
+ t.session_key = arg[session_key]
785
+ end
786
+ if arg[:flag]
787
+ t.enable(:session_key)
788
+ t.enable(:flag)
789
+ t.flag = arg[:flag]
790
+ end
791
+ t
792
+ end
793
+ end
794
+ end
795
+ end
796
+ end
797
+ end