1、sql注入环境搭建
为了方便对sql注入学习,我们首先搭建一个简单的web页面,数据库使用postgresql,具体页面如下
需要这个页面源码的可以去关注页面底部公众号后台回复获取
2、使用sql注入进行登录
数据库的用户信息如下
看下登录的一个主要逻辑,登录成功后前端页面显示当前用户所拥有的权限,登录失败则显示permission denied
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
1) change to directory containing
login.html
cgi-bin/login.py
2) run server with one of
python -m CGIHTTPServer 8247
python -m http.server --cgi 8247
python3 -m http.server --cgi 8247
3) point browser at
http://localhost:8247/login.html
"""
# specify custom path for python modules, e.g. for installs without admin rights
import sys
# TODO 交付时修改
# sys.path.append("H:\\apps\\Python27\\lib\\site-packages")
import cgi
import psycopg2
print("Content-type: text/html\n")
print("<title>Login Result</title>")
print("<body><center>")
try:
# get post data
form = cgi.FieldStorage()
name = form['name'].value if 'name' in form else ''
pwd = form['pwd'].value if 'pwd' in form else ''
permissions = []
# query to check password and get permissions
query = "select permissions from users where name='{}' and pwd='{}'".format(name, pwd)
# connect to database
conn = psycopg2.connect("dbname='158.247' user='158.247-app' host='127.0.0.1' password='foobar'")
cursor = conn.cursor()
cursor.execute(query)
permissions = cursor.fetchall()
if len(permissions) > 0:
print("<H1>Access granted. You have the following permissions: {}.</H1>".format(permissions[0][0]))
else:
print("<H1>Access denied.</H1>")
except psycopg2.Error as e:
# for ease of debugging
import traceback
traceback.print_exc()
print("Database Error: {}".format(e))
print("<br>Query: {}".format(query))
print("""
<form action="../login.html" method="GET">
<input type="submit" value="Back to Login">
</form>
""")
print('</center></body>')
# Q1 'or '1'='1
首先在我们的看代码在登录校验时,使用了最简单的sql语句拼接select permissions from users where name='{}' and pwd='{}'
所以我们在前端输入框输入的Name与Password会填充在上面两个值当中。为了跳过这两个值的校验,我们在输入框中使用or
语句,or 后面的条件使之恒成立 ,比如1=1
。考虑到字符判断时会使用单引号,因此在输入时需要在语句开头将单引号带入,语句结尾舍弃一个单引号。
那么我们在用户名框中填入任意值,密码框中输入' or '1'='1
便可成功登录
3、使用union进行攻击注入
union
操作符用于合并一个或者多个select语句拼接的结果集合,并且
上述的场景中,使用' or '1'='1
时拿到了整张用户表,但是我们这里设计的登录成功的页面上面仅展示所有用户的第一个用户的权限信息。但是当我们需要获取指定用户的信息的时候,可以使用union对sql语句进行拼接。
我们观察上图中登录成功的结果可以看到,登录成功之后展示的主要内容是permissions字段,此时我们希望每次登录成功后界面上显示的权限信息都是admin用户所属的权限,这时可以在密码的输入框中使用union对条件进行拼接即' UNION SELECT permissions FROM users WHERE name='admin'
当这条语句输入完成后后台实际执行的sql语句如下所示
SELECT permissions from users WHERE name='' and pwd='' UNION SELECT permissions FROM users WHERE name='admin'
最后在页面跳转时就可以看到登录成功的提示信息了
4、sql注入的防御
为了防御sql语句的注入,最简单的方法就是对于一些sql语句中的特殊字符进行识别并转义。
Python的一些库中提供了相对应的方法,比如操作mysql数据库的MySQLdb,操作postgresql数据库的psycopg等等。
附录
获取这个页面的源码可以通过关注以下公众号回复0060