0


【CTF】命令执行RCE

【CTF】命令执行RCE

文章目录

一、命令执行几种payload写法

image-20230402152352392

方法一

查看靶场内容,其中过滤了flag字样,那么也就是说可以执行phpinfo()、system()等的命令。一般目标的敏感文件位于tmp目录下,使用命令c=system(“ls /tmp”)查看tmp目录下的文件,由结果可看出其中有flag.php文件。然后使用命令system(“cat /tmp/flag.php”)即理论上可以查看flag文件,由于该页面过滤了flag字样,那么即可使用通配符的方式也就可以得到题目的flag值。

方法二

可以在页面代码内部的c执行时,在c中再执行一次eval函数,语句如下:

img

可以看到,命令内部是有flag的,但是为何没有被过滤呢,这是由于页面代码对c中的flag进行了过滤,但是c的整体仅是一个内部是GET语句的eval语句,而flag并不属于c中的内容,自然也不会被过滤。也就是说传输到命令内,格式为eval(“eval($_GET[w])”),也就是说外层的eval执行的是内部字符串表达式的结果,eval会将内部的整体作为代码执行。

eval功能:返回传入字符串的表达式的结果。

所以,如果将c=eval(…)内部的eval除去后,无法正常显示flag文件,因为没有eval函数后,格式为eval(“($_GET[w])”),eval内部没有任何命令可执行,只是普普通通的接受了一个GET传输入的w的值,而对他没有任何处理。

同理还可以在c后使用system命令。

也还可以使用P7-4节学习的php伪协议,通过语句来获得:

c=include($_GET[w]);&w=php://filter/convert.base64-encode/resource=/tmp/flag.php

通过该语句得到的是flag文件内容的base64编码形式的结果。

方法三
还可使用命令echo

ls

先查看当前目录下的文件,``反引号是一个操作系统层面的命令,与system函数同级,但是他执行的结果不打印,结果不会回显出来,所以使用了echo命令。

打开靶场后,查看靶场所显示的源代码:

img

其中if语句内表示,当执行一个GET传入的内容c中没有flag/system/php时,才会执行刚刚输入的c命令。其中preg_match表示做正则匹配的函数。一般目标的敏感文件存放于tmp目录下,tmp目录是linux的临时文件,一般是可读可写的。

那么直接可以使用c=eval($_GET[w]);&w=system(“cat /tmp/flag.php”);即可得到flag。

二、payload命令执行

首先可以查看,页面,可以发现被过滤的字符:

img

最简单的一种方式,img,使用该语句即可得到flag。或者使用

c=include($_GET[w]);&w=php://filter/convert.base64-encode/resource=/tmp/flag.php

也可以得到flag

除了这两种方法,还有什么高阶的方式呢。

由于本题过滤了flag和php,首先使用echo

ls

,并且注意,此处的代码内是过滤了空格的,对于空格的跳过,此处不可以使用$IFS

     9 
    
   
     的形式来绕过空格,因为 
    
   
  
    9的形式来绕过空格,因为 
   
  
9的形式来绕过空格,因为IFS$9是在操作系统中使用的,但是本题是代码层面的命令,就只能使用%09来绕过空格。首先,为了查看以下本题的tmp目录下的文件,想要使用echo 
ls /tmp

命令,即echo%09

ls%09/tmp

,即可发现tmp目录下的flag文件:

img

但是能够发现,本题的过滤时十分严格的,cat等命令都无法使用。既然cat无法使用,那么尝试命令more/tac等,得到flag:

c=echo%09

tac%09/tmp/f*

;

等价于c=echo

tac /tmp/flag.php

img

三、命令执行和通配符的绕过

从本题来看,此处过滤的命令更多了,在之前学习的命令都无法使用

img

查看过滤了的字符,其中%、数字9和空格都被过滤,那么还可以使用${IFS}来绕过空格,然后还可以使用通配符‘?’来绕过对flag的限制。发现cat也被过滤了,那么可以使用单引号绕过的方式:

c=c'a't${IFS}/tmp/fla?.php 

即可得到:img

注:此处为什么不能够写为f*代表flag.php文件呢,因为通配符中,可以表示一个或多个字符,但是‘?’只能代表一个字符,并且本题的被过滤,无法使用。

还可以使用另一种命令来绕过对cat的过滤,即c=/bin/c?t${IFS}/tmp/fla?.php

也可以:img,也能够执行,因为tmp目录下只有flag一个文件

四、php中读文件、命令执行的函数

参考博客:

https://blog.csdn.net/weixin_39687736/article/details/123862218

**1.**system

system(

     c 
    
   
     o 
    
   
     m 
    
   
     m 
    
   
     a 
    
   
     n 
    
   
     d 
    
   
     , 
    
   
  
    command, 
   
  
command,return)

执行系统命令/php自定义命令,并将相应的执行结果输出,同步进程,执行完后进行后续代码执行。

**2.**exec
exec(

     c 
    
   
     o 
    
   
     m 
    
   
     m 
    
   
     a 
    
   
     n 
    
   
     d 
    
   
     , 
    
   
  
    command, 
   
  
command,outpub,$return)

exec输出的是命令执行结果的最后一行内容。如果你需要获取未经处理的全部输出数据,请使用passthru()函数。如果想要使用exec显示当前目录下的所有文件的话,可以使用语句:exec(command:“ls >> 1.txt”);来将exec读取到的当前目录下的所有文件名导入到一个新创建的1.txt文件中。
<< : 叠加; < : 覆盖

**3.**passthru

passthru(

     c 
    
   
     o 
    
   
     m 
    
   
     m 
    
   
     a 
    
   
     n 
    
   
     d 
    
   
     , 
    
   
  
    command, 
   
  
command,return_var)

与system函数同级,若今后题目中system函数被过滤了,即可使用它。

**4.**shell_exec
shell_exec($command)
与exec一样,无回显,需要使用echo显示结果。

5. 反引号 echocommand`

反引号和shell_exec意思相同
在php中称之为执行运算符,PHP 将尝试将反引号中的内容作为 shell 命令来执行,并将其输出信息返回

6. …(见上方连接)

php中读文件函数

可使用echo fiel_get_contents(“flag.php”)该语句是以流的形式读取文件,需要在查看页面源代码中查看读取到的接果。

hightlight_file(“flag.php”),不需要使用echo

五、intval函数绕过:

img

函数:

① isset():用于检测变量是否已设置并且非NULL。

② preg_match():正则匹配,前一参数放要搜索的内容,后一参数是需要被匹配的内容,测试被匹配内容中是否存在要搜索的内容。例如本题即num中不能有数字。

③ die():函数输出一条消息,并退出当前脚本。本题中即当num中有数字,输出nonono。

④ intval():用于获取变量的整数值。

intval函数

语法

int intval ( mixed $var [, int $base = 10 ] )

参数说明

$var:要转换成 integer 的数量值。

$base:转化所使用的进制。

如果 base 是 0,通过检测 var 的格式来决定使用的进制

如果字符串包括了 “0x” (或 “0X”) 的前缀,使用 16 进制 (hex);否则,

如果字符串以 “0” 开始,使用 8 进制(octal);否则,

将使用 10 进制 (decimal)。

返回值

成功时返回 var 的 integer 值,失败时返回 0。 空的 array 返回 0,非空的 array 返回 1。

最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。举例,在这样的系统上, intval(‘1000000000000’) 会返回 2147483647。64 位系统上,最大带符号的 integer 值是 9223372036854775807。

字符串有可能返回 0,虽然取决于字符串最左侧的字符。

在对intval函数的返回值处,发现如果传入空的array(数组),则会返回0,非空的array则会返回1,那么只需要传入一个非空的数组,即可实现让本程序输出flag值。

要如何传入一个数组呢,格式:num[]=w,即在需要传入的num后加上方括号,即代表此时传入的是一个数组,并且使传入的数组为非空且无数字,即可得到flag。

img

并且,本题如果直接书写为num[]=或者num[]也可以得到flag,因为如果不定义num的值的话,默认num有一个值为空,也满足条件。

例题:

得到代码后,分析代码:

img

分析本题,当num为4476时,程序会die,并输出nonono,但是想要获得flag的话,又需要num为4476。

那么这里就涉及到intval函数的一个知识点,当int intval ( mixed $var [, int $base = 10 ] )中的base为0时,通过检测 var 的格式来决定使用的进制,
如果字符串包括了 “0x” (或 “0X”) 的前缀,使用 16 进制 (hex);否则,

如果字符串以 “0” 开始,使用 8 进制(octal);否则,

将使用 10 进制 (decimal)。

那么推测,是否可以通过输入16进制或者8进制的num值,来绕过本程序的检验,先进行进制转换

4476的16进制:0x117c,8进制:010574

尝试将上述两种进制以格式传入,

十六进制:num=0x117c

八进制:num=010574

使用以上两种方式,都成功的获取到了本题的flag。

img

除了以上的方法,由于intval会取整,可以使用小数的方式来得到,例如输入4476.1、4476w等方式,都能够得到flag。

六、php弱类型特性

**属于弱类型校验,只校验值是否一样,不校验类型,而=**属于强类型校验,不仅校验值,还校验类型。

img

本题及表示,当a与b同时都有POST输入,而a与b的传输不相同,但是a和b的md5值相同,才能够得到flag,否则输出wrong。

方法一

md5()函数

语法:

md5(string,raw) 

定义和用法:

md5() 函数计算字符串的 MD5 散列。

md5() 函数使用 RSA 数据安全,包括 MD5 报文摘要算法。

来自 RFC 1321 的解释 - MD5 报文摘要算法:MD5 报文摘要算法将任意长度的信息作为输入值,并将其换算成一个 128 位长度的"指纹信息"或"报文摘要"值来代表这个输入值,并以换算后的值作为结果。MD5 算法主要是为数字签名应用程序而设计的;在这个数字签名应用程序中,较大的文件将在加密(这里的加密过程是通过在一个密码系统下[如:RSA]的公开密钥下设置私有密钥而完成的)之前以一种安全的方式进行压缩。

如需计算文件的 MD5 散列,请使用 md5_file() 函数。

md5() 函数不能处理数组,数组都返回 null,md5(a[]) 结果为 null。

本题运用到了md5()函数的不能处理数组,数组都返回 null,md5(a[]) 结果为 null的特性,当给a和b传入不同两个数组时,在第一步判断时不会认定a与b相同,但是在第二步判断时,由于md5函数不能处理数组,所以会返回null那么即可传输:a[]=1&b[]=2,即可得到flag:
image-20230402154209038

方法二

PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每个以”0E”开头的哈希值都解释为0,因此若是两个不一样的密码通过哈希之后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。

因为php中0e代表0的科学计数法,无论后面的数字跟的是多少,结果都等于0。

http://www.javashuo.com/article/p-adowhkuk-q.html

然后在本题中,利用一些经过md5加密后开头为0e的原始值,来对a和b进行赋值,即可成功绕过:
img

a=s878926199a&b=s155964671a

img

七、变量覆盖

img

函数

定义和用法

parse_str() 函数把查询字符串解析到变量中。

注释:如果未设置 array 参数,由该函数设置的变量将覆盖已存在的同名变量。

注释:php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么 在 parse_str() 解析之前,变量会被 addslashes() 转换。

语法

parse_str(string,array)
参数****描述string必需。规定要解析的字符串。array可选。规定存储变量的数组名称。该参数指示变量存储到数组中。
方法一****

结合parse_str()函数的性质,本题需要传入两个值,一个是post传输的v1和一个GET传输的v3,也就是说本题需要传入一个v1=‘flag’=(v3的md5加密后的值)。

img

接下来执行后即可获得本题的flag。

img

方法二

运用md5()函数对数组进行操作后结果为null的性质,对v3当作数组进行传入值,然后不对v1传入任何值也可获得本题的flag。

$$变量覆盖

img

foreach有两种语法:

第一种:遍历给定的 数组语句 array_expression 数组。每次循环中,当前单元的值被赋给 $value 并且数组内部的指针向前移一步(因此下一次循环中将会得到下一个单元)。

foreach (array_expression as $value)

第二种:同上,同时当前单元的键名也会在每次循环中被赋给变量 $key。

foreach (array_expression as $key => $value)

本题的foreach函数里有GET和POST两个参数,那么也就是证明,可以自定义的通过GET/POST的方式传输进几个变量,并通过键值对的形式赋值。


        k 
       
      
        e 
       
      
        y 
       
      
        = 
       
      
     
       key= 
      
     
   key=value****:

当传入一个a=1时,此时变为了$a=

     1 
    
   
     ,也就是把 
    
   
     a 
    
   
     变换为了变量 
    
   
  
    1,也就是把a变换为了变量 
   
  
1,也就是把a变换为了变量a,把1变为了变量$1,并把 
 
  
   
   
     1 
    
   
     赋值给 
    
   
  
    1赋值给 
   
  
1赋值给a。这与$ 
 
  
   
   
     k 
    
   
     e 
    
   
     y 
    
   
     = 
    
   
  
    key= 
   
  
key=value有何区别呢,当value传入一个值后,其由于$value本身就是一个变量,他就会表示一个具体的变量的值。

那么对于本题而言,出现了两次

      k 
     
    
      e 
     
    
      y 
     
    
      = 
     
    
   
     key= 
    
   
 key=value,再结合下方的if语句:

img

只要阻止这一步执行了die命令,就可以获得flag,但是想要使传入的flag等于题目的flag显然是不现实的,也就是说在最后一个if语句处,一定会die,但是可以通过变量相等的传递,来逐步实现。比如对于本题,在第一个foreach处先传入一个suces=flag,然后在第二个foreach处通过error=suces的形式,即可实现对flag和error两个字符串的过滤(因为他们变成变量的形式了)。在最后一个if语句,执行了die(

     e 
    
   
     r 
    
   
     r 
    
   
     o 
    
   
     r 
    
   
     ) 
    
   
     ,但是此时的 
    
   
     e 
    
   
     r 
    
   
     r 
    
   
     o 
    
   
     r 
    
   
     已经等于了 
    
   
  
    error),但是此时的error已经等于了 
   
  
error),但是此时的error已经等于了flag,也就是说,输出的会是flag。

那么经过两次传参,也就是说

第一次:

     s 
    
   
     u 
    
   
     c 
    
   
     e 
    
   
     s 
    
   
     = 
    
   
  
    suces= 
   
  
suces=flag

第二次:

     e 
    
   
     r 
    
   
     r 
    
   
     o 
    
   
     r 
    
   
     = 
    
   
  
    error= 
   
  
error=suces

也就是说,此时的

     e 
    
   
     r 
    
   
     r 
    
   
     o 
    
   
     r 
    
   
     在值上等于 
    
   
  
    error在值上等于 
   
  
error在值上等于flag,那么即可通过die($error)语句,获得flag。

img

标签: web web安全 安全

本文转载自: https://blog.csdn.net/qq_53099119/article/details/129912016
版权归原作者 Sunny-Dog 所有, 如有侵权,请联系我们删除。

“【CTF】命令执行RCE”的评论:

还没有评论