WEB安全笔记(四)

170 阅读6分钟

字符型注入

接下来讲一下字符型注入,相比于整数型注入只难那么一点点。

我们来看一下为什么:

image-20230819232639169

我们可以看到与整数型注入相比,它后面的条件查询where后面添加的是字符串类型的数值。这在sql查找当中很常见,那此时如果写一些其他的信息都会被加入到两个单引号里面,最后都变成一个字符串,那就查不到数据。

现在我们就用到了注释符了,我们先自行把前面的那个单引号给闭合了,随后因为后面多出来一个单引号(网站自己添加的,因为我们自己在想要的地方加入了一个单引号导致这个单出来了),这时候使用#就可以将后面的单引号注释掉,注释掉mysql就不会去执行它了。

image-20230819232721496

就是如此,之后的就和之前的那个整数型注入一模一样了,我们直接跳到最后:

image-20230819232839783

我不确定flag是否相同,不过希望大家可以自己动手做一下,光看觉得都明白(没有瞧不起的意思)。

对了还有一个要补充的东西

某些安全性比较低的网站,可能可以使用万能账户或者万能密码完成登录。这个就是后台在判断是否允许你登录的时候直接在数据库里面使用条件查询把用户名和密码一输入如果返回就同意你登录。这个是不准确的,如果你可以在自己用户名或者密码上面构造永真条件那么就会被同意登录。

账户: admin' or 1=1 #

密码:随便填点什么

或者

账户: admin

密码:1'or 1=1#

还有一些简单的绕过

有时候后端会检查一下返回给用户的字符串是否合规或者检查输入的信息是否合规。

  • 如果是过滤空格的话,我们可以:使用注释符/**/、制表符%09、换页符%0c。后面两个是因为他们是控制字符,不能直接在URL当中使用,应该使用其的URL编码。
  • 如果关键字大小写检查,那我们可以任意改变关键字的大小写。
  • 如果对返回值当中的flag信息敏感,可以使用hex()、to_base_64()等函数来绕过。
  • 过滤orand,我们可以使用||&&来进行绕过。前者可以直接在URL上面使用,但是后者因为传参的时候就会用到&,所以如果我们想要传输的就是这个符号,需要它的URL编码%26
  • 还有的会把关键词替换成空字符串,这个时候如果不严格,我们可以进行双写绕过,比如在select里面任意位置再写一次select
  • GET请求当中#不能直接写,需要写它的url编码%23来替换。具体我来讲一下原因,因为在URL当中#被用作片段标识符。它可以在WEB页面当中指向特定的部分,我们称为锚点(其实就是一个前端代码当中的id属性)。所以它不会被发送给后端服务器,这就导致了#后面的所有信息都会被屏蔽,用于浏览器滚动到特定位置。
  • 顺便说一下空格的URL编码为%20或者+

一个要说的就是UA字段里面的数据不会进行编解码,井号和加号是正常的,可以直接写。

SQL报错注入

这种注入我感觉就是加入了另外的一些东西,事实上还是要依靠之前的那个逻辑来进行注入。

它引入了一个新的函数叫做:updatexml(),这是mysql的一个函数,经常在与xml数据处理相关的场景使用。因为它具有报错功能,所以很常被用在SQL注入当中。

1' and updatexml(1, concat(0x7e, (SELECT database()), 0x7e), 1) and '1'='1

是一个很常见的写法,根据不同情况选择不同的改变。例如后面的and '1'='1有时候就是不用去写的,写这个是为了让整体恒为真,保证整体仍然有数据返回。

还有一个值得注意的是,由于语法问题,有些报错的回显拥有长度限制(32位?),我们即使使用group_concat()来使用也没办法看全内容,这个时候需要进行字符串截取。

接下来通过一个入门题看一下:

image-20230823164710728

还是先输入一个1来看看:

image-20230823164743903

这次它并没有返回任何的数据给我们,只是告诉我们查询正确。

通过看上面的语法,是整数型注入。对了可以说一下判断到底是什么类型的注入,如果x是可以查到的数据,当使用id = x and 1=1能够返回数据的时候,可以确定是一个整数型注入,但是id = x and 1 =2会影响数据查询。如果是字符型会因为引号的包裹,一般不能查到数据。 (但是不是报错)

如果是x' and '1' = '1可以查询正确,如果最后面改成2则不会返回数据。数字型的话会直接产生语法错误。

接着说回来,那我们可以使用上面那个updatexml()来进行报错注入。其实有两种写法,一种就是直接在条件查询后面写and updatexml() balabala,另外的一种写法就是下面的写法:

image-20230823170245461

现在出现了一个新的问题,就是报错里面出来的信息很少,它很明显是没有给全。为了能够可以看清,我们需要使用到字符截取函数,挺别人有很多。比如:substr(字符串,起始位置,截取长度)还有mid(字符串,起始位置,截取长度)。这里面和写代码的那个有些区别,其实位置是1的话那就是字符串的第一位,而不是第二位。

image-20230823170610954

后面那两个参数没有严格的要求,只要你能够看清楚你想要的信息就可以,大不了多来几次。当然你愿意算一下位数之类的也可以,看自己。

因为是同一个界面,之后的注入过程也是相同的,都是先查数据库名然后表明然后字段名......

image-20230823170700326

那我就把其他过程省略掉了,最后查到了我们想要的flag信息,同样利用字符串截取,调整参数大小获得所有信息。

image-20230823170741239

随后在自己的文本编辑器里面拼接起来就可以了。值得注意的是,在concat()里面都是字符串,而select查询出来的并不是一个字符串,需要括号括起来才能拼接(注意到了吗?)。

以下是另外一种写法:

image-20230823171704358

另外还有一个xml的函数可以使用,叫做extractvalue(想要截取的文本,截取位置路径),其实不同的地方就是一个是替换,一个是提取。