Skip to content

处理命令行过滤(Pwnable.kr cmd 系列)

复制本地路径 | 在线编辑

cmd1

题目规定需要绝对路径,简化的源代码如下

bool filter(char* cmd) {
    // strstr(),0 表示没有找到子字符串
    retrun strstr(cmd, "flag") || strstr(cmd, "sh") || strstr(cmd, "tmp");
}
int main(int argc, char* argv[], char** envp){
        if( filter(argv[1]) ) return 0;
        system( argv[1] );
        return 0;
}

可以看到,如果单纯地使用/bin/sh会失败,使用/bin/cat flag也会失败,所以怎么办呢?

解决方法: /bin/cat fla* 或者 /bin/cat 'f'lag

cmd2

题目规定需要绝对路径,简化的源代码如下

int filter(char* cmd){
    return strstr(cmd, "=")!=0 || strstr(cmd, "PATH")!=0 || strstr(cmd, "export")!=0
            || strstr(cmd, "/") || strstr(cmd, "`")!=0 || strstr(cmd, "flag")!=0;
}

int main(int argc, char* argv[], char** envp){
    if( filter(argv[1]) ) return 0;
    system( argv[1] );
    return 0;
}

首先一个问题:需要使用绝对路径,那么cdpwd需要绝对路径吗?

答案:不需要,因为pwdshell built-in command. 使用which pwd,输出就是shell built-in command

现在坏了,直接不能输入/了,这可怎么办?解决办法如下

  1. 使用pwd命令,执行./cmd2 'cd .. && pwd',结果为/home;执行./cmd2 'cd .. && cd .. && pwd',结果为/,此时我们就可以用$(pwd)来代替/了。

    所以最后我们的输入为./cmd2 'cd .. && cd .. && $(pwd)bin$(pwd)cat $(pwd)home$(pwd)cmd2$(pwd)fla*'

  2. 因为限制了binflag这些字段,所以我们新建文件/tmp/cmd2/allen,里面存/bin/sh,这样我们只要把那个文件改成可执行,然后执行这个文件即可,通过文件来绕过命令行过滤

    所以最后我们的输入为/home/cmd2/cmd2 '$(pwd)tmp$(pwd)allen',其中当前目录为/

cmd3

源代码是很长的 python 文件,这里就简单说一下。

首先是文件存储情况,有两个文件夹,flagboxjailjail中提供三个执行文件: ls, cat, idflagbox中在程序运行是会存储一个随机命名文件,如KG3TSCVOPHSPINJD1N3MOD3T637CLX5L,程序运行时会告诉我们,然后我们要输出这个文件里的内容,然后会得到flag。

要求只可以使用以下字符:()[]{}<>#$%,?;_。不要求绝对路径,但是在rbash这个 shell 下执行的,关于这个 shell,可以参考[1],比较重要的一点,是不允许执行带有/的命令,但是除了命令是可以的。也即是说/bin/ls不可以,但是cat test/test.txt是可以的!

乍一看这道题,这怎么做嘛,就这几个破字符,连字母数字都不能输入,这怎么搞?所以,要慢慢来。下面都是利用 shell 的特性。

  1. 第一要解决cat

知识点一:shell 中 ? 匹配。比如当前文件夹有test.sh,如果我使用???????,那么 shell 就会匹配到test.sh,自动将我们输入转为匹配到的。本题目cat存放在jail目录中,所以我们使用????/???就可以匹配到了(有问题往下看)。

知识点二:shell 中 $_ 变量。上一步很好, 但 rbash 不允许使用/,所以命令会失败。但是 SHELL 有变量 $_ 表示上一次的 argv[-1], 所以我们仍然得到了变量$_ = jail/cat

知识点三:shell 如何进行截断赋值。现在就是怎么处理这个变量, 使用____=${_#?????},这样$____变量就会丢弃$_变量的前面5个字符(因为?有5个),所以经过这样的赋值我们得到了变量$____ = cat

  1. 第二要解决空格。

知识点四:shell 中有好几种方式可以代替空格。参考[2],现在我们可以用<>或者>来代替空格。但是,对于rbash,应该只能使用<而不能使用<>

答案一

刚开始告诉我们存储密码的文件: flag/xxx(32bits), 此时我们新建 /tmp/__/1 文件, 其中内容即为 flag/xxx(32bits).

  • ????/???

    匹配到 jail/cat, 即 _jail/cat.

  • __=${_#?????}

    __ 等于 cat, 由于 PATH=jail, 所以执行 cat 是可以的.

  • $($__</???/__/?)

    括号里面相当于 cat /tmp/__/1, 里面是 flag/xxxx, 最终相当于我们执行了 flag/xxxx 命令.

  • $__<$_

    由于上一条执行了 flag/xxx 命令, 所以 $_ 等于 flag/xxx, 所以最终相当于 cat flag/xxxx.

答案二

唯一的不同点是第三条, 干脆直接输入 ? * 7 / ? * 32, 我在这里用 * 7 缩写, 实际情况要全部写上, 最后同样会匹配到文件 flagbox/xxx(32bits).

重要说明

上面的两个答案, 一定要一起执行, 即最终输入为 cmd1; cmd2; cmd3; cmd4, 分开写是错的.

为什么是错的?

以第一句和第二句为例. 第一句 ????/??? 想匹配 jail/cat, 此时命令行最后会输出错误信息: /bin/rbash: line 1: jail/cat: ....

如果单独写这一句后回车, 此时的 $_/bin/rbash!!! 但如果不是单独一句, 比如 cmd1; cmd2, 在执行 cmd2 的时候, $_jail/cat!!!

仔细体会这之间的差异, 原因就是由于回车后, rbash 发现错误后相当于执行了 rbash 命令, 导致 $_ 成了 /bin/rbash.

总结

  • 有一些命令是自带命令,这些并不是执行 /bin 目录中的可执行文件, 比如pwd,不确定的话可以使用which命令查看一下

  • 以例子来谈,使用fla*来解决 flag 的限制,使用$(pwd)来解决 / 的限制

  • SHELL 特殊用法: ?, $_, <, <>

  • cmd3 可以好好看看, 以及一定要注意 $_ 可能会被最后的报警产生意外的错误

参考

[1] https://xz.aliyun.com/t/7642

[2] https://www.cnblogs.com/sevck/p/6072721.html