Pikachu靶机通关和源码分析

6 分钟

前言

Pikachu靶场拥有各类简单的漏洞,能掌握基本的漏洞利用。


提示:以下是本篇文章正文内容,下面案例可供参考

一、暴力破解关

1,基于表单的暴力破解

没什么好说的,直接burpsuite的intruder模块进行字典爆破。

爆出账号为admin,密码是123456

源码:



if(isset($_POST['submit']) && $_POST['username'] && $_POST['password']){

    $username = $_POST['username'];
    $password = $_POST['password'];
    $sql = "select * from users where username=? and password=md5(?)";
    $line_pre = $link->prepare($sql);


    $line_pre->bind_param('ss',$username,$password);

    if($line_pre->execute()){
        $line_pre->store_result();
        if($line_pre->num_rows>0){
            $html.= '

 login success

';

        } else{
            $html.= '

 username or password is not exists~

';
        }

    } else{
        $html.= '

执行错误:'.$line_pre->errno.'错误信息:'.$line_pre->error.'

';
    }

}

提交的username和password与数据库users表的username和password字段作比较,相同则登录成功。

2,基于验证码绕过的爆破(on server)

用同一个验证码,进行爆破试试。

验证码一直有效,爆破出密码依旧为admin,123456。

源码:



if(isset($_POST['submit'])) {
    if (empty($_POST['username'])) {
        $html .= "

用户名不能为空

";
    } else {
        if (empty($_POST['password'])) {
            $html .= "

密码不能为空

";
        } else {
            if (empty($_POST['vcode'])) {
                $html .= "

验证码不能为空哦!

";
            } else {
                if (strtolower($_POST['vcode']) != strtolower($_SESSION['vcode'])) {
                    $html .= "

验证码输入错误哦!

";
           
                }else{

                    $username = $_POST['username'];
                    $password = $_POST['password'];
                    $vcode = $_POST['vcode'];

                    $sql = "select * from users where username=? and password=md5(?)";
                    $line_pre = $link->prepare($sql);

                    $line_pre->bind_param('ss',$username,$password);

                    if($line_pre->execute()){
                        $line_pre->store_result();
                        if($line_pre->num_rows()==1){
                            $html.='

 login success

';
                        }else{
                            $html.= '

 username or password is not exists~

';
                        }
                    }else{
                        $html.= '

执行错误:'.$line_pre->errno.'错误信息:'.$line_pre->error.'

';
                    }
                }
            }
        }
    }
}
增加了验证码的应用,将POST请求的验证码与session[vode]作比较,不相等即不正确,关键在于没有在每一次请求后销毁session[code]并重新生成,导致了验证码一直有效。应当在login
success以及else后都进行session[vode]的销毁,并重新生成。

3,验证码绕过(on client)

源代码:



if(isset($_POST['submit'])){
    if($_POST['username'] && $_POST['password']) {
        $username = $_POST['username'];
        $password = $_POST['password'];
        $sql = "select * from users where username=? and password=md5(?)";
        $line_pre = $link->prepare($sql);


        $line_pre->bind_param('ss', $username, $password);

        if ($line_pre->execute()) {
            $line_pre->store_result();
            if ($line_pre->num_rows > 0) {
                $html .= '

 login success

';

            } else {
                $html .= '

 username or password is not exists~

';
            }

        } else {
            $html .= '

执行错误:' . $line_pre->errno . '错误信息:' . $line_pre->error . '

';
        }


    }else{
        $html .= '

 please input username and password~

';
    }


}

前端:



 var code; //在全局 定义验证码
    function createCode() {
        code = "";
        var codeLength = 5;//验证码的长度
        var checkCode = document.getElementById("checkCode");
        var selectChar = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9,'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');//所有候选组成验证码的字符,当然也可以用中文的

        for (var i = 0; i < codeLength; i++) {
            var charIndex = Math.floor(Math.random() * 36);
            code += selectChar[charIndex];
        }
        //alert(code);
        if (checkCode) {
            checkCode.className = "code";
            checkCode.value = code;
        }
    }

    function validate() {
        var inputCode = document.querySelector('#bf_client .vcode').value;
        if (inputCode.length <= 0) {
            alert("请输入验证码!");
            return false;
        } else if (inputCode != code) {
            alert("验证码输入错误!");
            createCode();//刷新验证码
            return false;
        }
        else {
            return true;
        }
    }


    createCode();


后端并没有出现验证码,仅进行登录,前端通过floor函数生成5个随机数字取数组中对应的索引值作为验证码,validate()保证每次提交验证码都会刷新,并且验证验证码的正确性。禁用掉validate()函数进行抓包爆破或将提交的vode直接去掉进行爆破都可以。

四、Token防爆破?

存在token,并且每次提交后token都会刷新,先看看HTML页面的源码。

页面中隐藏了下一次token的值,可以进行爆破,可使用burpsuite的宏或者正则匹配,这里我使用python脚本。



import requests
from bs4 import BeautifulSoup

s = requests.session()
password = []
f = open('password.txt', encoding='utf-8')
while 1:
    num = f.readline().rstrip()
    password.append(num)
    if not num:
        break
header = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0',
    'Cookie': 'PHPSESSID=782u3n1vs7s22l76u4vphhjidu'

}
req = s.get('http://6d0545c2b5a341ccb49fb8844d0a4d02.app.mituan.zone/vul/burteforce/bf_token.php')
# print(req.text)
token = BeautifulSoup(req.text, 'lxml').find('input', type='hidden').get('value')

for pa in password:
    req = s.post(url='http://6d0545c2b5a341ccb49fb8844d0a4d02.app.mituan.zone/vul/burteforce/bf_token.php',
                 data={'username': 'admin', 'password': pa, 'token': token, 'submit': 'Login'})
    if 'success' in req.text:
        print("爆破成功,用户名:admin,密码为:%s" % pa)
        break
    else:
        req = s.get('http://6d0545c2b5a341ccb49fb8844d0a4d02.app.mituan.zone/vul/burteforce/bf_token.php')
        token = BeautifulSoup(req.text, 'lxml').find('input', type='hidden').get('value')

源码分析:



if(isset($_POST['submit']) && $_POST['username'] && $_POST['password'] && $_POST['token']){

    $username = $_POST['username'];
    $password = $_POST['password'];
    $token = $_POST['token'];

    $sql = "select * from users where username=? and password=md5(?)";
    $line_pre = $link->prepare($sql);


    $line_pre->bind_param('ss',$username,$password);

    if($token == $_SESSION['token']){

        if($line_pre->execute()){
            $line_pre->store_result();
            if($line_pre->num_rows>0){
                $html.= '

 login success

';

            } else{
                $html.= '

 username or password is not exists~

';
            }

        }else{
            $html.= '

执行错误:'.$line_pre->errno.'错误信息:'.$line_pre->error.'

';
        }


    }else{
        $html.= '

 csrf token error

';
    }




}
set_token();

HTML:


通过比较Session[token]的值,并且每次请求后都会利用set_token()刷新token,若不显示刷新后的token值,确实是可以防暴力破解。

二、Cross-Site-Scripting

1,反射型(get)

前端设置了字符串的长度限制,直接去掉就好。

源码分析:



$html='';
if(isset($_GET['submit'])){
    if(empty($_GET['message'])){
        $html.="

输入'kobe'试试-_-

";
    }else{
        if($_GET['message']=='kobe'){
            $html.="

愿你和{$_GET['message']}一样,永远年轻,永远热血沸腾!

![]({$PIKA_ROOT_DIR}assets/images/nbaplayer/kobe.png)";
        }else{
            $html.="

who is {$_GET['message']},i don't care!

";
        }
    }
}



?>
扫描过滤都没有,直接message=等都能取出cookie

2,反射型(POST)

这里有post登录页,应该要先登录,使用admin/123456登录。

使用上面相同的payload即可。

源码分析:



登录:
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);

            //登录时,生成cookie,1个小时有效期,供其他页面判断
            setcookie('ant[uname]',$_POST['username'],time()+3600);
            setcookie('ant[pw]',sha1(md5($_POST['password'])),time()+3600);


            header("location:xss_reflected_post.php");
//            echo '"';

        }else{
            $html ="

username or password error!

";
        }

    }else{
        $html ="

please input username and password!

";
    }
}







登录后:
if(isset($_POST['submit'])){
    if(empty($_POST['message'])){
        $html.="

输入'kobe'试试-_-

";
    }else{

        //下面直接将前端输入的参数原封不动的输出了,出现xss
        if($_POST['message']=='kobe'){
            $html.="

愿你和{$_POST['message']}一样,永远年轻,永远热血沸腾!

![]({$PIKA_ROOT_DIR}assets/images/nbaplayer/kobe.png)";
        }else{
            $html.="

who is {$_POST['message']},i don't care!

";
        }
    }
}



if(isset($_GET['logout']) && $_GET['logout'] == '1'){
    setcookie('ant[uname]','');
    setcookie('ant[pw]','');
    header("location:post_login.php");

}


function escape($link,$data){
    if(is_string($data)){
        return mysqli_real_escape_string($link,$data);
    }
    if(is_array($data)){
        foreach ($data as $key=>$val){
            $data[$key]=escape($link,$val);
        }
    }
    return $data;
}
登录时,使用了escape()进行特殊字符如换行符,单引号,双引号,空格进行转义,防止SQL注入,登录成功后,会生成有效期为1小时的cookie,依旧未对信息做任何过滤。

3,存储型

![]()

源码分析:



$link=connect();
$html='';
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.="

数据库出现异常,提交失败!

";
    }
}
if(array_key_exists('id', $_GET) && is_numeric($_GET['id'])){

    $query="delete from message where id={$_GET['id']}";
    $result=execute($link, $query);
    if(mysqli_affected_rows($link)==1){
        echo "";
    }else{
        $html.="

删除失败,请重试并检查数据库是否还好!

";

    }

}
对传入的message数据经过特殊字符转义后(主要针对SQL)插入数据库,导致了存储型的xss,第二个if是进行删除的按钮,通过索引ID进行message的删除,删除成功则立刻跳转到原页面,删除时也未经过任何转义,能够进行sql的盲注。

4,DOM型

输入的信息text会从前端通过javascript生成what do you see

'> 先将生成的

源码:

5,DOM-X型

输入的信息text会出现在URL中

'οnclick="alert(document.cookie)">

源码:



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






function domxss(){
                        var str = window.location.search;
                        var txss = decodeURIComponent(str.split("text=")[1]);
                        var xss = txss.replace(/\+/g,' ');

                        document.getElementById("dom").innerHTML = "[就让往事都随风,都随风吧]("+xss+")";
                    }
                

alert(document.cookie)

alert(document.cookie)

alert(document.cookie)
~  ~  The   End  ~  ~


 赏 
承蒙厚爱,倍感珍贵,我会继续努力哒!
logo图像
tips
文章二维码 分类标签:Web安全CTF
文章标题:Pikachu靶机通关和源码分析
文章链接:https://aiwin.fun/index.php/archives/1021/
最后编辑:2024 年 1 月 5 日 21:04 By Aiwin
许可协议: 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
(*) 6 + 8 =
快来做第一个评论的人吧~