1 web渗透入门系列-SQL注入


前言

提示:这里可以添加本文要记录的大概内容:

本文开始一系列的web渗透入门系列,帮助新手快速入门,其实最开始应该先介绍信息收集,信息收集-渗透测试的灵魂,这里的话我打算放到系列最后讲。

学习之前需要有php编程基础,sql基础,需要知道怎么从php执行sql语句,本系列教程重点会在细节上把原理讲的很仔细。也就是会经常扯得比较远,会把涉及到的很多概念(主要是一些自己刚开始学习的时候没懂或者被人经常问到的概念)都仔细说明一下。

php: 变量,$_GET,$_POST 这些传参,再加上php连接数据库执行数据库代码这些知识

学习目标: 知道sql注入中为什么用户输入的数据能够被当做sql代码执行

进阶目标: 在总结中发的靶场地址里能够通过sql注入得到当前数据库库名,库名是 maoshe


一、Sql注入是什么?

一句话,sql注入的本质就是:将用户输入的代码当做sql代码执行。

这里可以理解为:我们就是用户,把我们提交给服务器的数据,在服务器的数据库中被当做了数据库代码执行。

二、注入流程分析

1.为什么用户的代码能够被当做sql代码执行?

代码如下(示例):

<?php
$id = $_GET['id'];
$sql = "select * from article where id = $id";
$conn->query($sql);
?>

分析一下上面这段代码

首先 $conn 没有定义,这段代码直接复制粘贴肯定报错

但是这个不是我们要分析的问题的关键,$conn是一个 mysqli_connect() 的连接对象

用来进行数据库连接的。自己写代码的时候一定要写上。

第一行代码 从 get 传参中获取了 id 的值赋值给 $id

get传参

get传参怎么传?

在url后面加问号

http://url/?id=123

这样的形式

那么想要传两个怎么办?

http://url/?id=123&name=qwe

这样就传了两个,也就是用&符号连接

回到正题

假设这里我们get传参传了id=123

那么对于$id变量,$id=$_GET['id']=123

这样的写法在代码中可不可行我没试过,感兴趣的可以自己试试。

再下一句

$sql = "select * from article where id = $id ";

双引号变量解析

众所周知,在php中 双引号("") 里面的内容中的变量会被解析

也就是说,比如

$a = "吃饭";
$b = '我在$a';
echo $b;

这段代码的运行结果会是: 我在$a

大家可以自己试试

$a = "吃饭";
$b = "我在$a";
echo $b;

上面这段代码的运行结果会是: 我在吃饭

因为是用双引号包起来的,所以变量会被解析

好的,回到正题

那么上面我们的代码中

$sql最后的结果就应该是:

select * from acticle where id = 123

大家可以把这段代码放到 sql 中去执行一下

执行的时候记得加分号

当然,如果你真的执行了,你会发现要么报错,要么没结果

什么情况下会报错呢?

1 没有创建 article 这个表

2 创建了这个表,但是表里没有id字段

那什么情况下什么结果都没有?

当然是表里面没有数据或者没有id等于123的数据的时候。

那么我们换一种思路

id=123是我们传上去的吧

那么我们可不可以传一些其他东西呢?

例如说,我们传上去的是这么一串

id=1 union select 1,2,database()

那么最后执行的sql语句会是什么?

我们来拼接一下

select * from article where id = 1 union select 1,2,database()

最后就变成了这样

这时候可能会有小伙伴好奇

database() 我知道,会输出当前库名嘛

那前面加个1,2是干啥?

这就要说到联合查询的特性了

联合查询

联合查询可以用作查询两个表的内容联合输出

注意!!! 我这里只弄内容,字段名啥的我就不写了

假设表1的内容是

123
abc

表2 的内容是

56

如果联合查询这两个表

最后的结果,显而易见,就是把他们联合起来输出

那么哪个在前面呢?

我们来看下联合查询的语法

select 字段 from 表 union select 字段 from 表

哪个表写在前面,哪个表的内容先输出

那么我们继续

联合查询有一个必要的要求

就是前后两个查询的字段数必须要相同

我们一般写sql怎么写

select * from 表;

那这里的 * 是什么

这里的 * 代表所有字段

也就是根据后面要查询的表来判断的

那个表里的字段是什么,这里的*就是什么

这样的话可以省略

也就是说假设有一个表名字叫 user ,长这样

那么对于它而言

select * from user

 等价于

select id,name,age,sex from user

这二者是等价的

那么假设我要用这个表联合查询查询出来当前库名

我直接这样可以吗?

select * from user union select database()

当然不可以

因为前后字段数不一致

可以自己试一下,对了,记得加分号

那么我们就需要补位

user表一共四个字段

我们要查database() 有一个字段了

那就再加个1,2,3用来补一下就可以了

也就是

select * from user union select 1,2,3,database()

诶,database()我一定要写在最后吗?

那肯定不是,在平常的联合查询中

这四个位置我想写在哪都行

但是如果在SQL注入中呢?

在sql注入中要根据回显点在哪里去判断

回显点又是什么鬼东西?我们后面讲到注入的时候会提到

2.注入原理

那么根据上面的知识,我们是不是可以查询到库名了?

当然不太行

再回顾一下原本的用来注入的代码

<?php
$id = $_GET['id'];
$sql = "select * from article where id = $id";
$conn->query($sql);
?>

这里我们想要联合查询,是不是必须要知道 article 表的字段才可以?

两种方法

第一种方法

id=1 union select database()

id=1 union select 1,database()

id=1 union select 1,2,database()

一个一个测试

这样效率很显然太慢了

我们可以借助: order by 语法

order by 语法可以这么用

比如说

select * from user order by 1

如果不报错,说明至少有一个字段

select * from user order by 10

如果报错说明没有10个字段

这话说的可能有点别扭,我们来做一个小实验

这个表一共是4个字段,当我们测试到 order by 5的时候报错了

4 不报错,5报错,这样就可以得到一共就5个字段了

这时候可能有小伙伴要问了,你这不是还跟上面那个一个一个试差不多吗?

别急,上面的方法,不管少了,还是多了,都会报错

但是这个方法,少了不会报错

我们可以利用2分法嘛

先 oder by 1

order by 10

oder by 50

直到它报错

测试出来范围

然后减半缩小去进行测试

用算法中的思想来看

前一个需要测试 n 次(n代表字段数)

这个只需要 logn次(底是2)


总结

以上就是今天要讲的内容,本文仅仅简单介绍了sql注入的原理,没有进行实战,这里的话放一个掌控安全的公开靶场 宠物猫 异国短毛猫 纯种猫 加菲猫 波斯猫 辛巴猫舍 纯种双色/梵文波斯、异国小猫 CFA注册猫舍

就上面这个连接,大家可以试试自己根据上面的原理去尝试注入一下得到库名

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值