Mirror of metasploit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

login.rb 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. # -*- coding: binary -*-
  2. module Msf
  3. ###
  4. #
  5. # This module exposes methods that may be useful to exploits that deal with
  6. # servers that require authentication via /bin/login
  7. #
  8. ###
  9. module Auxiliary::Login
  10. NULL = "\000"
  11. CR = "\r"
  12. LF = "\n"
  13. EOL = CR + LF
  14. #
  15. # Creates an instance of a login negotiation module.
  16. #
  17. def initialize(info = {})
  18. super
  19. create_login_ivars
  20. end
  21. def create_login_ivars
  22. # Appended to by each read and gets reset after each send. Doing it
  23. # this way lets us deal with partial reads in the middle of expect
  24. # strings, e.g., the first recv returns "Pa" and the second returns
  25. # "ssword: "
  26. @recvd = ''
  27. @trace = ''
  28. #
  29. # Some of these regexes borrowed from NeXpose, others added from datasets
  30. #
  31. @login_regex = /(?:log[io]n( name|)|user( ?name|id|))\s*\:/i
  32. @password_regex = /(?:password|passwd)\s*\:/i
  33. @false_failure_regex = /(?:(^\s*last)\ login *\:|allows only\ .*\ Telnet\ Client\ License)/i
  34. @failure_regex = /(?:
  35. Incorrect | Unknown | Fail | Invalid |
  36. Login | Password | Passwd | Username |
  37. Unable | Error | Denied | Reject |
  38. Refuse | Close | Closing | %\ Bad |
  39. Sorry |
  40. Not\ on\ system\ console |
  41. Enter\ username\ and\ password |
  42. Auto\ Apply\ On |
  43. YOU\ LOGGED\ IN\ USING\ ALL\ UPPERCASE\ CHARACTERS|
  44. \n\*$ |
  45. (Login ?|User ?)(name|): |
  46. ^\s*\<[a-f0-9]+\>\s*$ |
  47. ^\s*220.*FTP|
  48. not\ allowed\ to\ log\ in
  49. )/mix
  50. @waiting_regex = /(?:
  51. .*please\ wait.* |
  52. .*one\ minute.*
  53. )/mix
  54. @busy_regex = /(?:
  55. Another\ telnet\ session\ is\ in\ progress | Disconnecting\.\.\.
  56. )/mix
  57. @success_regex = /(?:
  58. list\ of\ built-in |
  59. sh.*[\#\$]\s*$ |
  60. \[\/\]\s*$ |
  61. or\ the\ MENU\ system |
  62. Password\ is\ not\ set |
  63. logging\ in\ as\ visitor |
  64. Login\ successful
  65. )/mix
  66. end
  67. #
  68. # Appends to the @recvd buffer which is used to tell us whether we're at a
  69. # login prompt, a password prompt, or a working shell.
  70. #
  71. def recv(fd=self.sock, timeout=10)
  72. data = ''
  73. begin
  74. data = fd.get_once(-1, timeout)
  75. return nil if not data or data.length == 0
  76. # combine EOL into "\n"
  77. data.gsub!(/#{EOL}/no, "\n")
  78. @trace << data
  79. @recvd << data
  80. fd.flush
  81. rescue ::EOFError, ::Errno::EPIPE
  82. end
  83. data
  84. end
  85. def login_prompt?
  86. return true if @recvd =~ @login_regex
  87. return false
  88. end
  89. def command_echo?(cmd)
  90. recvn = @recvd.gsub(/^(\s*#{cmd}\r?\n\s*|\s*\*+\s*)/, '')
  91. if(recvn != @recvd)
  92. @recvd = recvn
  93. return true
  94. end
  95. false
  96. end
  97. def waiting_message?
  98. recvn = @recvd.gsub(@waiting_regex, '')
  99. if(recvn != @recvd)
  100. @recvd = recvn.strip
  101. return true
  102. end
  103. false
  104. end
  105. def busy_message?
  106. recvn = @recvd.gsub(@busy_regex, '')
  107. if(recvn != @recvd)
  108. @recvd = recvn.strip
  109. return true
  110. end
  111. false
  112. end
  113. def password_prompt?(username=nil)
  114. return true if(@recvd =~ @password_regex)
  115. if username
  116. return true if( !(username.empty?) and @recvd =~ /#{username}'s/)
  117. end
  118. return false
  119. end
  120. def login_failed?
  121. # Naively, failure means matching the failure regex.
  122. #
  123. # However, this leads to problems with false positives in the case of
  124. # "login:" because unix systems commonly show "Last login: Sat Jan 3
  125. # 20:22:52" upon successful login, so check against a false-positive
  126. # regex, also.
  127. #
  128. # Empty strings should not count
  129. if @recvd.strip.length == 0
  130. return true
  131. end
  132. # If we have not seen a newline, this is likely an echo'd prompt
  133. if ! @recvd.index("\n")
  134. return true
  135. end
  136. # We do have a set of highly-accurate success patterns
  137. if (@recvd =~ @success_regex)
  138. return false
  139. end
  140. if @recvd =~ @failure_regex
  141. if @recvd !~ @false_failure_regex
  142. return true
  143. end
  144. end
  145. return false
  146. end
  147. def login_succeeded?
  148. # Much easier to test for failure than success because a few key words
  149. # mean failure whereas all kinds of crap is used for success, much of
  150. # which also shows up in failure messages.
  151. return (not login_failed?)
  152. end
  153. #
  154. # This method logs in as the supplied user by transmitting the username
  155. #
  156. def send_user(user, nsock = self.sock)
  157. got_prompt = wait_for(@login_regex)
  158. if not got_prompt
  159. print_error("#{rhost} - Something is wrong, didn't get a login prompt")
  160. end
  161. return send_recv("#{user}\r\n")
  162. end
  163. #
  164. # This method completes user authentication by sending the supplied password
  165. #
  166. def send_pass(pass, nsock = self.sock)
  167. got_prompt = wait_for(@password_regex)
  168. if not got_prompt
  169. print_error("#{rhost} - Something is wrong, didn't get a password prompt")
  170. end
  171. return send_recv("#{pass}\r\n")
  172. end
  173. def send_recv(msg, nsock = self.sock)
  174. raw_send(msg, nsock)
  175. recv_all(nsock)
  176. return @recvd
  177. end
  178. def recv_all(nsock = self.sock, timeout = 10)
  179. # Make sure we read something in
  180. wait_for(/./)
  181. end
  182. #
  183. # This method transmits a telnet command and does not wait for a response
  184. #
  185. # Resets the @recvd buffer
  186. #
  187. def raw_send(cmd, nsock = self.sock)
  188. @recvd = ''
  189. @trace << cmd
  190. nsock.put(cmd)
  191. end
  192. #
  193. # Wait for the supplied string (or Regexp) to show up on the socket, or a
  194. # timeout
  195. #
  196. def wait_for(expect, nsock = self.sock)
  197. if expect.kind_of? Regexp
  198. regx = expect
  199. else
  200. regx = /#{Regexp.quote(expect)}/i
  201. end
  202. return true if @recvd =~ regx
  203. resp = ''
  204. while (resp and not @recvd =~ regx)
  205. resp = recv(nsock)
  206. end
  207. return (@recvd =~ regx)
  208. end
  209. end
  210. end