PHP Tricks
Last updated
Last updated
学习与实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE) 学习与实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)
从黑客的角度看待您的网络应用、网络和云
发现并报告具有实际商业影响的关键可利用漏洞。 使用我们 20 多个自定义工具来映射攻击面,查找让您提升权限的安全问题,并使用自动化利用收集重要证据,将您的辛勤工作转化为有说服力的报告。
这同样适用于 phpMyAdmin cookies。
Cookies:
位置:
如果在 PHP 中使用 ==
,则会出现一些意想不到的情况,比较的行为并不如预期。这是因为 "==" 只比较转换为相同类型的值,如果你还想比较被比较数据的类型是否相同,你需要使用 ===
。
PHP 比较表: https://www.php.net/manual/en/types.comparisons.php
"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
字符串中的任何字母等于 int 0
更多信息请见 https://medium.com/swlh/php-type-juggling-vulnerabilities-3e28c4ed5c09
类型转换 也默认影响 in_array()
函数(你需要将第三个参数设置为 true 以进行严格比较):
如果此函数用于任何身份验证检查(如检查密码),并且用户控制比较的一侧,他可以发送一个空数组而不是字符串作为密码的值(https://example.com/login.php/?username=admin&password[]=
),从而绕过此检查:
相同的错误发生在 strcasecmp()
即使使用了 ===
,也可能出现错误,使得比较容易受到类型转换的影响。例如,如果比较在比较之前将数据转换为不同类型的对象:
preg_match()
可以用来 验证用户输入(它 检查 是否有任何 单词/正则表达式 在 黑名单 中 存在 于 用户输入 中,如果没有,代码可以继续执行)。
然而,当限定正则表达式的开始时,preg_match()
只检查用户输入的第一行,因此如果你能够以 多行 发送输入,你可能能够绕过这个检查。示例:
要绕过此检查,您可以发送带有换行符的 URL 编码值(%0A
),或者如果您可以发送JSON 数据,则将其分成多行:
找到一个示例在这里: https://ramadistra.dev/fbctf-2019-rceservice
(这个绕过显然是在 PHP 5.2.5 上尝试的,我无法在 PHP 7.3.15 上使其工作)
如果你可以发送一个有效的非常 大的输入 给 preg_match()
,它 将无法处理它,你将能够 绕过 检查。例如,如果它正在黑名单一个 JSON,你可以发送:
From: https://medium.com/bugbountywriteup/solving-each-and-every-fb-ctf-challenge-part-1-4bce03e2ecb0
Trick from: https://simones-organization-4.gitbook.io/hackbook-of-a-hacker/ctf-writeups/intigriti-challenges/1223 and https://mizu.re/post/pong
简而言之,问题发生是因为 PHP 中的 preg_*
函数基于 PCRE 库。在 PCRE 中,某些正则表达式通过大量递归调用进行匹配,这会消耗大量的堆栈空间。可以设置允许的递归次数限制,但在 PHP 中,这个限制 默认为 100,000,这超过了堆栈的容量。
这个 Stackoverflow 线程 也在帖子中被链接,深入讨论了这个问题。我们的任务现在很明确:
发送一个输入,使正则表达式进行 100_000+ 次递归,导致 SIGSEGV,使得 preg_match()
函数返回 false
,从而使应用程序认为我们的输入不是恶意的,在有效负载的最后抛出一个类似 {system(<verybadcommand>)}
的惊喜以获得 SSTI --> RCE --> flag :)。
好吧,在正则表达式术语中,我们实际上并没有进行 100k 次“递归”,而是计算“回溯步骤”,正如 PHP 文档 所述,它在 pcre.backtrack_limit
变量中默认为 1_000_000(1M)。
要达到这个,'X'*500_001
将导致 100 万个回溯步骤(50万向前和50万向后):
如果 PHP 正在重定向到另一个页面,但在设置头部 Location
之后没有调用 die
或 exit
函数,PHP 将继续执行并将数据附加到主体:
检查:
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 中用于 从密码生成哈希 并 检查 密码是否与哈希相符。
支持的算法有:PASSWORD_DEFAULT
和 PASSWORD_BCRYPT
(以 $2y$
开头)。请注意,PASSWORD_DEFAULT 通常与 PASSWORD_BCRYPT 相同。 目前,PASSWORD_BCRYPT 对输入有 72字节的大小限制。因此,当你尝试用此算法对大于 72 字节的内容进行哈希时,仅使用前 72B:
从 这个推特线程 你可以看到,发送超过 1000 个 GET 参数或 1000 个 POST 参数或 20 个文件时,PHP 不会在响应中设置头部。
这允许绕过例如在代码中设置的 CSP 头部,如:
如果一个 PHP 页面正在打印错误并回显用户提供的一些输入,用户可以使 PHP 服务器打印出一些 足够长的内容,以便在尝试 将头部 添加到响应时,服务器会抛出错误。 在以下场景中,攻击者使服务器抛出了一些大错误,正如您在屏幕上看到的,当 PHP 尝试 修改头部信息时,它无法(例如 CSP 头部没有发送给用户):
查看页面:
system("ls"); &#xNAN;`ls`; shell_exec("ls");
要在“replace”参数中执行代码,至少需要一个匹配项。 此preg_replace选项在PHP 5.5.0中已被弃用。
此函数在 php 中允许您 执行以字符串编写的代码 以 返回 true 或 false(并根据此改变执行)。通常用户变量会插入在字符串中间。例如:
assert("strpos($_GET['page']),'..') === false")
--> 在这种情况下,要获得 RCE,您可以这样做:
您需要破坏代码语法,添加您的有效负载,然后再次修复它。您可以使用逻辑运算,例如“and”或“%26%26”或“|”。请注意,“or”和“||”不起作用,因为如果第一个条件为真,我们的有效负载将不会被执行。同样,“;”也不起作用,因为我们的有效负载不会被执行。
另一个选项是将命令的执行添加到字符串中:'.highlight_file('.passwd').'
另一个选项(如果您有内部代码)是修改某个变量以改变执行:$file = "hola"
此函数用于使用特定函数对项目数组进行排序。 要滥用此函数:
您还可以使用 // 注释代码的其余部分。
要发现您需要关闭的括号数量:
?order=id;}//
:我们收到一条错误消息(Parse error: syntax error, unexpected ';'
)。我们可能缺少一个或多个括号。
?order=id);}//
:我们收到一个 警告。这似乎是正确的。
?order=id));}//
:我们收到一条错误消息(Parse error: syntax error, unexpected ')' i
)。我们可能有太多的闭合括号。
如果您可以 上传 一个 .htaccess,那么您可以 配置 多个内容,甚至执行代码(配置具有 .htaccess 扩展名的文件可以被 执行)。
不同的 .htaccess shell 可以在 这里 找到。
如果您发现一个漏洞,允许您 修改 PHP 中的环境变量(还有另一个上传文件的漏洞,尽管经过更多研究可能可以绕过),您可以利用这种行为获得 RCE。
LD_PRELOAD
:此环境变量允许您在执行其他二进制文件时加载任意库(尽管在这种情况下可能不起作用)。
PHPRC
:指示 PHP 在哪里查找其配置文件,通常称为 php.ini
。如果您可以上传自己的配置文件,则使用 PHPRC
指向它。添加一个 auto_prepend_file
条目,指定第二个上传的文件。这个第二个文件包含正常的 PHP 代码,然后由 PHP 运行时执行,在任何其他代码之前。
上传一个包含我们的 shellcode 的 PHP 文件
上传第二个文件,包含一个 auto_prepend_file
指令,指示 PHP 预处理器执行我们在步骤 1 中上传的文件
将 PHPRC
变量设置为我们在步骤 2 中上传的文件。
获取更多关于如何执行此链的信息 来自原始报告。
PHPRC - 另一个选项
如果您 无法上传文件,您可以在 FreeBSD 中使用 "file" /dev/fd/0
,它包含 stdin
,即发送到 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=="'
技术 来自此报告。
Web 服务器解析 HTTP 请求并将其传递给执行请求的 PHP 脚本,例如 http://host/cgi.php?foo=bar
,作为 php.exe cgi.php foo=bar
,这允许参数注入。这将允许注入以下参数以从主体加载 PHP 代码:
此外,由于 PHP 后来的规范化,可以使用 0xAD 字符注入 "-" 参数。检查来自 这篇文章 的漏洞示例:
在这篇文章中 可以找到生成脑残 PHP 代码的好主意,允许的字符非常少。 此外,还提出了一种有趣的方法来执行函数,使它们能够绕过多个检查:
查看您是否可以在对这些函数的调用中插入代码(来自 这里):
如果您正在调试一个 PHP 应用程序,可以在 /etc/php5/apache2/php.ini
中全局启用错误打印,添加 display_errors = On
并重启 apache: sudo systemctl restart apache2
您可以使用 web www.unphp.net 来反混淆 php 代码。
PHP 包装器和协议可能允许您 绕过系统中的读写保护 并危害系统。有关 更多信息,请查看此页面。
如果您在 phpconfig()
输出中看到 Xdebug 已 启用,您应该尝试通过 https://github.com/nqxcode/xdebug-exploit 获取 RCE。
如果在一个页面中你可以创建一个任意类的新对象,你可能能够获得 RCE,查看以下页面以了解如何:
https://securityonline.info/bypass-waf-php-webshell-without-numbers-letters/
根据这篇文章,可以通过这种方式生成一个简单的 shellcode: