关于“进销存”系统的登录方法——利用SQL注入进行登录“进销存”系统的登录存在着SQL注入的漏洞,利用这个漏洞可以绕过用户名和密码的判断,从而进入“进销存”系统。下面,对于这个漏洞进行具体的说明。(注:由于系统源代码可见,于是可以直接通过代码来分析SQL注入,因此不在这里进行源代码语句漏洞试探。)1、首先打开登录页面,找到源代码地址。图1——登录页面的源代码地址2、打开源代码,找到有关登录语句验证的代码,代码如下(重要部分已给出注释):<%elsenowusername=request.form('username')//声明一个变量nowusername,把页面中的登录名内容传值给此变量。nowpwd=request.form('pwd')//声明一个变量nowpwd,把页面中的密码内容传值给此变量。userip = Request.ServerVariables('HTTP_X_FORWARDED_FOR')If userip = '' Thenuserip = Request.ServerVariables('REMOTE_ADDR')end ifsql='select * from login where (username=' '&nowusername&'' and pwd=' '&md5(nowpwd)&' ') or (bianhao=' '&nowusername&'' and pwd=' '&md5(nowpwd)&' ')' //声明一个sql语句,条件是调用login表中的username字段为页面中的登录名内容值且pwd字段为页面中的密码内容值,或者调用login表中的bianhao字段为页面中的登录名内容值且pwd字段为页面中的密码内容值。//从这里还可以看出,登录方式为两种:输入用户名和密码;输入用户编号和密码。//username=''&nowusername&''此段代码的意思为:把用户输入的登录名内容替换如下代码——'&nowusername&'。//例:登录时登录名输入admin,运行时,username=' '&nowusername&''将被编译为username=’admin’。set rs=conn.execute(sql)//创建一个对象rs,运行上面的sql语句。if rs.eof Then//如果没有查询结果。//rs.eof的意思是rs对象移动到最后一行,如果rs对象在最后一行,说明没有查询结果,因为如果有查询结果,rs对象将是查询结果。conn.execute('insert into rizi(username,class,address)values(''&nowusername&'','登陆失败',''&userip&'')')//在rizi表中添加记录,记录username登录失败的信息。%>3、由代码中可以看到,关键的登录判断语句为: sql='select * from login where(username=' '&nowusername&' ' and pwd=' '&md5(nowpwd)&'') or (bianhao=' '&nowusername&' ' and pwd=' '&md5(nowpwd)&'')'这段语句会判断login表中是否存在输入的用户名和密码,或者用户编号和密码。下面,提出sql语句进行具体分析: SQL语句1: select * from login where (username=' '&nowusername&'' and pwd=' '&md5(nowpwd)&' ') or (bianhao=' '&nowusername&'' and pwd=' '&md5(nowpwd)&' ')可见,where条件有两大部分,用or进行连接(形式为:select * from login where条件1 or条件2)。因此,or后面的语句是否为真不重要,只要前面(条件1)为真即可。再拿出前面的(条件1)语句进行分析: SQL语句2:username=' '&nowusername&' ' and pwd=' '&md5(nowpwd)&''由这段代码中可以看到,此部分又分为两个条件判断,用and进行连接(形式为:条件1and条件2)。4、进行SQL注入分析由上面的登录代码分析可见,如果SQL语句2为真,那么SQL语句1也为真。现在的问题是如何让SQL语句2恒为真。现在SQL语句2的形式为:条件1 and条件2,根据SQL语句1的提示,可以看出,如果SQL语句2形式变成:条件1or条件3 or条件4and条件2,那么可见,即使条件2不为真,如果条件1或者条件3有一个为真,那么SQL语句2就为真。因此,目的就是要添加or条件3 or条件4到语句中,使SQL语句2恒为真。5、SQL注入语句构造username=’ “&nowusername&” ‘ and pwd=’ “&md5(nowpwd)&”‘由前面代码分析看出,如果输入登录名为admin,密码为12345,运行时,此段代码被编译为:username=’ admin ‘ and pwd=’ admin ‘通过编译后的代码与后台数据库进行数据对比,判断是否存在该用户。可见,输入的内容首先将被替换为相应的sql语句内容,再进行sql语句的执行。先假设一下,如果运行时,代码被编译为:username=’ admin ‘or 1=1 or 1=1andpwd=’ admin ‘形式为:条件1or条件3 or条件4and条件2,可见条件3恒成立,因此不论条件1和条件2是否为真,此段代码恒为真。再把源代码拿出来进行对比:预想结果:username=’ admin ’or 1=1 or 1=1and pwd=’admin ‘相关代码:username=’“&nowusername&”’ and pwd=’ “&md5(nowpwd)&”‘代码中标红的内容是用户输入的内容,需要注意的是,在标红的内容后面有一个’对应着前面的’。如果输入的内容为:admin’ or 1=1 or 1=1代入到标红内容,代码为:username=’admin’ or 1=1 or 1=1’ andpwd=’ “&md5(nowpwd)&” ‘可见,username=’ admin’为条件1,1=1为条件2,pwd=’ “&md5(nowpwd)&” ‘为条件3,但是需要注意的是1=1后面有一个“’”,是源代码中存在的,如果在输入的时候,输入了一个“’”,那么源代码中的“’”将缺少对应。SQL语句3:username=’admin’or 1=1 or 1=1’and pwd=’“&md5(nowpwd)&”‘可见,如果输入内容为:admin’ or 1=1,将导致内容替换代码后,“’”会缺少一个对应。原因就是我们在输入的时候输入了一个“’”。因此,为了让“’”不缺少对应,我们在输入的时候再输入一个“’”。输入内容为:admin’ or 1=1’这时,再代入到相应代码中,编译后的代码为:源代码:username=’“&nowusername&”’ and pwd=’ “&md5(nowpwd)&”‘代入后:username=’admin’ or 1=1 or 1=1 ’ ’ and pwd=’ “&md5(nowpwd)&” ‘可见,这回“’”已经不缺少对应了:SQL语句4:username=’admin’or 1=1 or 1=1’’and pwd=’“&md5(nowpwd)&”‘形式为:条件1 or条件2or条件3and条件4这时,又出现了一个问题,条件3为:1=1’ ’,这不是正确的条件语句,还要修改一下,改为:SQL语句5:username=’admin’or 1=1or1=1’’and pwd=’“&md5(nowpwd)&”‘删除1=1使形式改变为我们需要的:条件1 or条件2or条件3 and条件4可见,条件2为:1=1,恒为真,条件3为:’’,是一个不进行判断的空条件。因此,SQL语句5因为有条件2恒为真,所以SQL语句5恒为真。6、总结分析SQL注入的目的是让SQL语句1恒成立。SQL语句1:select * from login where (username=' '&nowusername&'' and pwd=' '&md5(nowpwd)&' ') or (bianhao=' '&nowusername&'' and pwd=' '&md5(nowpwd)&' ')如果其中的username=' '&nowusername&'' and pwd=' '&md5(nowpwd)&' '恒成立,那么SQL语句1即恒成立。语句中的username=''&nowusername&'' and pwd=' '&md5(nowpwd)&''标红部分是用户输入的内容。现在输入内容:’ or 1=1 or ‘替换后为:username=‘’ or 1=1 or ‘’ and pwd=' '&md5(nowpwd)&''此语句变为恒成立。(还可以看出来,如果输入helloworld’ or 1=1 or ‘,系统一样可以登录,原因就是前面输入的都是条件1的内容,无所谓真假,因为1=1的条件恒为真。)7、测试结果:登录名为:’ or 1=1 or ‘密码不为空图2——SQL注入点击登录,登录成功。8、查看登录日志:图3——登录日志可见,使用SQL注入成功登录后的用户标识为“-1”,登录日志页面的登录用户调用的是rizi表中的username字段,为什么会是“-1”,原因留给大家去思考。^_^
上一篇:UWB超宽带定位技术原理
下一篇:有关以太网交换机问题全解析
