🏀PHP特性知识点总结
专门出的关于php的特性比较,后面好像也有java的特性。
最后更新于
专门出的关于php的特性比较,后面好像也有java的特性。
最后更新于
之前提到过的是字符串转为整型。其实php手册里面提到了各种类型的转换。先把他放在这里。
https://www.php.net/manual/zh/language.types.type-juggling.php#language.types.typecasting
我们按照php手册上的顺序来介绍,只介绍几个比较常用的。
false为0,true为1
向下取整(直接舍去小数位)
如果 string 是 numeric(数字字符串) 或者前导数字, 则将它解析为相应的 int 值,否则将转换为零(0
)
数字字符串: 这只是一个字符串,其开头类似于数字字符串,后跟任何字符。但是如果含 e 的字符串转换成 int 类型时会被当做科学计数法处理,
123e456
表示 123 的 456 次方。
为0
0x01:从string转换为float
如果 string 是 numeric(数字字符串) 或者前导数字, 则将它解析为相应的 int 值,否则将转换为零(0
)
0x02:其他类型转换为float
先将其他类型转换为int,再由int转换为float。(而其他类型转换为float,就在上面的②)
== 弱类型比较, 仅要求两边变量类型转换后的值相等
=== 强类型比较, 不仅要求两个变量的值相等, 还要求变量的类型相同
同理 != 是弱类型比较, 而 !== 是强类型比较
首先我们去php手册了解这是什么东西。
intval()
获取变量的整数值。下面的base是转换的进制,默认是0
intval主要利用有三个。
这个重点在非空的数组会返回1。
这里想提醒一下['']
这个不是数组为空,这个数组有一个元素,元素为空元素。要是[]
才是空数组
前提是base是0的时候,由value来决定。其他几个情况比较熟悉,0开头是8进制需要好好记忆一下。
这个是说在弱类型比较的前提下,本来在base=0的情况下,要看value的结果来判断,这个判断是从数字或者正负号开始才做转换,直到遇到非数字,或者字符串的结束符(\0)结束转换。开始我还理解错了。这句话的意思是比如我们要得到带4476的字符串,应该是4476abc这种。不然以abc4476是被转换为0的。
空格和+(表示正号)
preg_match(): 执行匹配正则表达式
上面显示subject得是字符串,也就是说如果是数组,会返回false。
换行符这个大部分都只有一个,但是其实在做题之类的看到了两个。
首先我们需要知道这个/m是什么
手册上太复杂了,所以我直接用自己的理解来理解吧。就是m代表multiline mode,是多行模式。这个多行模式是什么意思呢。我们在正则表达式里面有说过^代表匹配开头,$代表匹配结尾。但是如果没有/m就是单纯的单行的匹配,如果我们开启了/m就是可以多行的匹配。就是每一行都可以匹配由^开头,以$结尾的。
我们接下来继续举例理解。比如我们有字符串
我们如果用正则表达式/^line/m,如果开启了多行,就每一行都可以匹配,就是能匹配到line1,line2,line3,如果我们没开就是只能匹配搭配line1。
但是我们可以截断这个m的作用。利用%0a
当出现%0a的时候它会被认为是一个换行符,是什么意思呢,就是从字符串的开头到%0a作为了第一行,从%0a到字符串末尾变成了第二行。就是说我们如果第一行匹配不了,但是第二行匹配成功了也行。
.也是截断输入,这个输入的原理是因为。.可以匹配除换行符(\n)之外的任意单个字符。举个例子,我们比如我们有一个字符串/hello\nworld这个字符串,然后我们正则表达式/h.llo/会得到的是hello,这个.匹配到了一个e。但是他不能匹配\n。这个\n我们要用%0a来表示。
我们可以实验一下。
所以我们传入%0aflag之后
%0a即换行符的url编码,在preg_match没启动/s模式(单行匹配模式)时,正则表达式是无法匹配换行符(%0a,\n)的,且会自动忽略末尾的换行符。但是我们可以用这个去绕过一些限制
p神的讲解我放在最后的传送门了。
这里推荐一个工具https://blog.robertelder.org/regular-expression-visualizer/
这个工具可以展示正则表达式的详细匹配过程。我们就用这个工具来理解p神的回溯过程也不失为一种高效的办法。
所以回溯绕过就是利用的PHP的PCRE库也是利用的NFA为正则引擎,这样就要回溯找到其他状态。
同样的正则表达式<?.*
[(`;?>].* ,要匹配的字符串是<?php phpinfor();//aaaa
自行利用上面的工具进行测试。
可以看到当执行到*的时候他分成了两条路,一条是greedy的,就是把后面所有的都匹配了,还有一条是懒惰的,匹配到后面有(`;?>就不匹配了。
直接进行lazy的path的就是p神文章里提到的DFA模式,而且我们说的NFA模式,就是先greedy,也就是把整个字符串都先匹配了。like this
这个时候他匹配进入到了failure的步骤,失败了,我们就要去看看能不能走lazy path了,发现到了末尾了,走不了。
这个时候我们就尝试一种新的路径。
另一种路径当然是lazy 路径,我们就在元素列表里看看能不能找到匹配lazy path的元素,发现不行,因为已经到末尾了,所以这个时候我们就可以弹出栈顶元素然后看看能不能尝试lazy path。发现还是因为a不能匹配(·;?>中的一个,所以我们就继续吐出来。
吐着吐着吐到了;发现匹配成功了。我们就继续下一个任意匹配了。又是从greedy开始。这样。
以上一共回溯了7次。
接下来我们将讲解一个php配置里面的pcre.backtrack_limit
p神的文章里也说了,中文版和英文版不一样,英文版是1000000,我们以1000000为准。我们可以通过下面的代码去查看当前环境的限制值
现在我们将试验一下如果超过这个回溯限制的话,会发生什么情况呢。
可以看到返回的是bool值false。正则执行失败。
所以这个绕过脚本大致是
需要特别注意的是,顺序是从0开始的。如果找到了就返回位置。如果没有找到就是返回false。
如果对八进制(首位是0)遇到了if(!strpos($string,0))进行过滤,我们想让八进制还能成功通过的话,需要在首位想想办法。一般是在前面加空格和加号。我们可以进行实验
并且空格还可以用%20,%0a,%09来代替,加号可以用%2b代替。
对于如果strpos传递的不是字符串,而是数组的话,返回值为null。
结论对strrpos() stripos() strripos()
同理
我们知道科学计数法是含有e的数字字符串,对于is_numeric来说,他是能识别科学计数法的,并且能返回true。试验一下
所以,对于某些字符串,我们可以尝试利用 base64 + bin2hex 找到一些只含 e 和数字的 payload
在数字前面加上/n,/t等这种特殊字符仍然可以返回true,但是放在数字后面就不行了。
如果找到了返回true,没找到返回false。
函数在作用时会将needle的值自动转化为和array一个类型。
其实这个实验在我的环境下失败了,这结论也不在成立。后面我看了手册,发现了还是版本问题。
返回值是过滤后的字符串。
我们可以看到,上面写了去除\t,\n,\r,\0,\v但是他没有过滤\f(换页符),他的url编码是%0c36
返回值sha1的散列值的字符串形式。
以 32 字符的十六进制数形式返回散列值。
两函数的性质啥的都是一样的。所以我们直接一起说了,有些情况只列举了一个,但是对两个函数都是一样的。
PHP
在处理哈希字符串时,通过!=
或==
来对哈希值进行比较,它把每一个以0e
开头的哈希值都解释为0
,所以如果两个不同的密码经过哈希以后,其哈希值都是以0e
开头的,那么PHP
将会认为他们相同,都是0。这个通常是对于科学计数法的时候会遇到0e漏洞。
可以实验一下。
可以看到在php解释其中,他们会认为0e开头的都相等。
所以我们如果如果我们要绕过if(md5($a)==md5($b))这个条件的话。我们可以选择一些md5编码后都为0e的a,b字符串。
所以这里介绍一些。
注意这个特性是在弱类型的条件下。
在强类型的条件下,我们特性一就失效了,这时候我们可以用数组绕过。我们知道md5和sha1是对字符串起的作用,如果我们传入的是数组:
md5()
函数获取不到数组的值,默认数组为0
sha1()
函数无法处理数组类型,将报错并返回false
所以我们可以对于if(md5($a)===md5($b)),可以用取a,b为数组
来绕过。
这个对于强类型和弱类型比较都可以成功。
这个应该有版本要求,我是8.3的版本实验的时候发现全部都是报错,无法执行我最后预期的结果。
路径绕过就是通过绝对路径或者相对路径去绕过正则对文件名的检测。比如preg_match('/flag.php/', $str)
(关于路径的知识忘记的,可以去看我们当时在讲file://协议中讲过的。这里放一个传送门 ①file:// )
我们可以写
我们首先介绍一下什么叫软链接。
软链接:软链接文件有类似于 Windows 的快捷方式。它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。其实我的理解是他很像c语言的指针的作用,软链接是一个指向某个特定文件的指针,指针的数据块内包含的是文件的位置信息。如果文件被删除了,但是指针还存在,只是指向的位置是个无效的罢了。
其实这个博主的解答这个地方我没有看懂,有看懂的小伙伴可以解答一下
没啥好讲的,直接贴图
构造不带分号的payload需要用到
这样就永远都会执行phpinfo(),这个phpinfo可以替换为其他的代码。
在php中,函数和数字一起运算,函数能被正常执行。比如
phpinfo()能被正常执行。以下符号都能够正常执行。
其实这个是做题目的时候,其实知道是伪随机数,但是自己爆破根本爆破不动。
其实就是爆破出种子的具体值,这里主要是用一个php_mt_seed的脚本。
我们学c语言的时候就已经学过真随机数,伪随机数,这里就不赘述了。
产生随机数的发生器
产生种子的发生器
php每次调用mt_rand()函数时,都会先检查是否已经播种,如果已经播种,就直接产生随机数,否则调用php_mt_srand来播种,也就是说每个php cgi进程期间,只有第一次调用mt_rand()自动播种,接下来都会根据这个第一次播种的种子来生成随机数。
其实就是一个穷举脚本,只不过这个比我们自己写的要快很多。这里就讲解它的用法,下载在linux里面,其实windows也是可以的。
输入指令
后面是得到的数列。
然后得到结果
所以我们的种子是880310233
然后就可以了。