入手的第一道CTF题目:护网杯的一道二阶注入;让我挖到了ZZCMS的一个二阶注入。

而这第二道CTF题目,让我懂得了最短字符写SHELL。

简易版v01

访问题目,提示give me ip。于是加ip参数给它。

可以看到成功执行了ping命令

考虑拼接其他命令,直接来枚举

可以看到最后一条使用%0a来分割命令,成功了

然后通过cat命令读取该文件即可获得flag

源码

<?php
echo "give me ip";
$flag = "flag{exec1111111exec}";
$t = $_REQUEST['ip'];
$t = trim($t);
$sub = array(
    '&' => '',
    ';' => '',
    '|' => '',
    '-' => '',
    '$' => '',
    '(' => '',
    ')' => '',
    '`' => '',
    '||' => '',
);

$t = str_replace(array_keys($sub), $sub, $t);

if (stristr(php_uname('s'), 'Windows NT')) {

    $c = shell_exec('ping  ' . $t);

} else {

    $c = shell_exec('ping  -c 1 ' . $t);

}

echo "<pre>{$c}</pre>";

?>

接收到ip参数后,直接对该参数进行了黑名单校验:

将敏感字符全部替换为空。

此时由于校验不严,导致我们可以通过%0a来绕过校验,成功执行其他命令。

知识点补充

  1. 分号(;)

    使用分号来分割命令时,相当于将命令分割在了不同的行;无论前一行的命令成功还是失败,都不影响下一条命令的执行。

  2. && 符号

    只有前面的命令执行成功了,那么才会执行&&后面的命令。
    

  3. & 符号

    &  表示任务在后台执行
    

  4. || 符号

    只有前面命令执行失败了,才会执行后面的命令
    

  5. | 符号

    | 表示管道,上一条命令的输出,作为下一条命令的输入
    

    
    都会执行,但是输出时只会输出最右边的。
    

  6. %0a

    在传入服务端命令执行函数时,可以使用%0a来分割命令。
    效果与分号相同。相当于一行一个命令。

简易版v02

访问题目,页面依旧提示 give me ip。

但是这次只接受POST数据。

当输入一个命令时,发现这次没有过滤连接符,但是却限制了字符长度

测试一下是限制了多少字符

经测试总长度限制为21个字符,分号后面只能输入13个字符

cat exec02.php 命令正好14个字符

两个思路解答题目:

  1. 利用通配符

    cat exec*

    那么便会输出当前目录下所有以exec开头的文件的内容
    最短模式:

    cat *
  2. 写 shell

    利用 echo 语句多次写入

    方法一: 直接写shell

    假设一次写入一个字符,那么也需要额外写16个字符。

    echo -n w>>t.php 

    方法二:利用sh/bash命令来结合写入shell

    思路是:先利用echo语句写入shell命令到文件,然后再利用sh命令执行该命令

    使用这个方法的原因是,linux操作系统根据文件特征而不会根据后缀来识别文件类型。

    sh命令默认一行是一个命令

    但是echo 命令在输出时默认会在后面添加换行符,可以使用 -n 选项来禁止输出换行符。

    1. 使用echo -n 将命令写入一行
    2. 使用反斜杠让shell识别为一行命令

    第二个方法比第一个方法还要少两个字符

    看一下写的脚本:

    这里有三个细节:

    1. echo后面使用了双引号包裹
    2. data变量value前面添加了一个r
    3. Payload里面的$符号,没有在前面添加反斜杠进行转义

    第一个细节,shell脚本中,在读到单引号时,后面的字符全部认为是普通字符,因此反斜杠失去了连接命令的功能,也就保持了原有的换行符

    第二个细节,python脚本中,会将反斜杠识别为转义字符。可以使用多加一个反斜杠的方式来标志是普通字符;也可以是在字符串前面添加r字符,表示是原始字符串,在原始字符串中所有的字符均视为普通字符。

    第三个细节,我们都知道,$符号在shell内是特殊符号,$符号后面跟字符串时,会认为是一个变量。但是如果只是一个单独的$符号,那么则认为是一个普通字符。

    因此一般使用命令在linux服务器上写shell时,大多在$符号前面添加反斜杠。但是此处之所以不加,是因为在读到$符号后,后面只有一个反斜杠,而反斜杠被认为了命令拼接符,所以最终$符号被原样输出

源码

<?php
$flag = "flag{flag2exec2flag}";
$ipipip = isset($_POST['ip']) ? $_POST['ip'] : die("give me ip please"icon_question.gif;

if (!preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/i', $ipipip)) {
    die("ip format error!"icon_question.gif;
}

echo strlen($ipipip);

if (strlen($ipipip) < 7 || strlen($ipipip) > 21) {
    die("ip length error!"icon_question.gif;
}

if (stristr(php_uname('s'), 'Windows NT')) {

    $cmd = shell_exec('ping  ' . $ipipip);
} else {
    $cmd = shell_exec('ping  -c 1 ' . $ipipip);
}

echo "<pre>{$cmd}</pre>";

进阶版

这次可以看到竟然限制为了7个字符

按照之前题目学习的姿势,直接 cat * ,GET到flag。

后来分享给我题目的人说:这题要求是GETSHELL。因此有了下面的研究学习。

  1. 知识点一:
    whoami>t 这条命令大家都知道,是将whoami的输出重定向到文件t

    whoami>t\\ 这条命令则是将输出重定向到文件 t\,因为反斜杠是特殊字符,所以需要再加一个反斜杠进行转义

    >t\\ 而这条命令依旧是将输出重定向到文件 t\,但是由于没有输出,所以文件t\内是空

  2. 知识点二:
    关于ls命令

    -t 选项 :按照从新到旧的方式排序文件

    -r 选项 :反向排序

那么便可以利用这样极短的方式进行GETSHELL。

但是由于 ls -tr>g 命令有8个字符,超了,所以我们只是抛弃-r选项, 逆向输入,顺序输出。

只是用ls -t命令又会暴露新的问题。

如图可以看到,使用 ls -t>g 命令时,会先创建文件g` , 然后再执行ls -t命令

而sh/bash命令,在遇到错误时便会终止程序,因此会以失败告终。

因此最后的这个文件名也需要特定

直接上脚本

最终以失败告终,经过反复观察,得出了结论;

这一句话这么多英文字母p,而生成文件名时只会生成一个,所以肯定失败

所以这条路没法走了,使用生成文件名的方式写shell时,要保证文件名不重复才行

解决方式:

  1. 尽可能的拼接出完全不同的文件名
  2. 使用wget去下载文件

第一种方式:

  1. 细节一:是为了保证最后面的文件名没有反斜杠,否则使用sh命令执行时,会连接后面的exec3.php字符
  2. 细节二:是为了保证无重复的文件名,需要着重注意的是空格、问号、引号等特殊符号都需要在前面添加转义符号

所以最终的Payload就成了这么乱糟糟的样子了

第二种方式:

这样看的话,便会更加容易分辨一些

需要注意的是index.html里面的Payload,$符号前面需要加反斜杠

也可以不使用index.html文件,可以指定为任意文件,只是在构造文件名的时候着重留意不要重复、特殊字符记得转义、不要超过字符限制就好

源码

<?php
error_reporting(0);
$flag="flag{8bytes-get-flag}";
if(strlen($_GET[1])<2016db.gif{
     echo shell_exec($_GET[1]);
}

?>

$flag="flag{xxx}";
if(strlen($_GET[1])<2016db.gif{
     echo shell_exec($_GET[1]);
}

临别

感谢maplege分享的题目。

感谢团队HeatSky师傅、Thinking师傅的对我疑惑的解答。


本文由 TEag1e 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gificon_mrgreen.pngicon_neutral.pngicon_twisted.pngicon_arrow.pngicon_eek.pngicon_smile.pngicon_confused.pngicon_cool.pngicon_evil.pngicon_biggrin.pngicon_idea.pngicon_redface.pngicon_razz.pngicon_rolleyes.pngicon_wink.pngicon_cry.pngicon_surprised.pngicon_lol.pngicon_mad.pngicon_sad.pngicon_exclaim.pngicon_question.pngicon_rolleyes.gif2016gz.gif2016kun.gif2016zhem.gif2016am.gif2016kel.gificon_twisted.gif2016lh.gificon_neutral.gif2016ka.gif2016tx.gificon_evil.gif2016bb.gif2016yun.gif2016qq.gif2016baojin.gificon_confused.gif2016kk.gif2016zk.gif2016kb.gificon_mad.gif2016yhh.gificon_exclaim.gif2016xia.gif2016gg.gif2016qd.gificon_smile.gif2016lengh.gificon_biggrin.gif2016bz.gif2016wq.gificon_eek.gificon_arrow.gificon_wink.gif2016tuu.gif