作者:Ricter Z@360高級攻防實驗室
原文鏈接:http://noahblog.#/tex-restricted-mode-bypass/

漏洞時間線:

  • 2021/03/08 - 提交漏洞至 TeX 官方;
  • 2021/03/27 - 漏洞修復,安全版本:TeX Live 2021;
  • 2021/06/06 - 漏洞分析公開。

I. Tex 安全限制概述

TeX 提供了 \write18 原語以執行命令。為了提高安全性,TexLive 的配置文件(texmf.cnf)提供了配置項(shell_escape、shell_escape_commands)去配置 \write18 能否執行命令以及允許執行的命令列表。

其中 shell_escape 有三種配置值,分別為:

  • f:不允許執行任何命令
  • t:允許執行任何命令
  • p:支持執行白名單內的命令(默認)

白名單命令列表可以通過如下命令查詢:

kpsewhich --var-value shell_escape_commands

shell_escape 配置值可以通過如下命令查詢:

kpsewhich --var-value shell_escape

本文涉及的 CVE 如下:沒 advisory 懶得申請了。

II. 挖掘思路

TeX 提供了一個默認的白名單命令列表,如若在調用過程中,這些命令出現安全問題,則會導致 TeX 本身在調用命令的時候出現相同的安全問題。

可以假設:在命令調用的過程中,由于開發者對于命令參數的不完全掌握,有可能存在某個命令參數最終會作為系統命令進行調用的情況。依據這個思路,挖掘白名單內的命令以及白名單內命令的內部調用,并最終得到一個調用鏈以及相關的參數列表,依據研究人員的經驗去判斷是否存在安全問題。

III. 在 *nix 下的利用方式

通過針對命令的深入挖掘,發現白名單內的 repstopdf 命令存在安全問題,通過精心構造參數可以執行任意系統命令。

repstopdf 意為 restricted epstopdf,epstopdf 是一個 Perl 開發的腳本程序,可以將 eps 文件轉化為 pdf 文件。repstopdf 強制開啟了 epstopdf 的 --safer 參數,同時禁用了 --gsopt/--gsopts/--gscmd 等 GhostScript 相關的危險參數,以防止在 TeX 中調用此命令出現安全問題。repstopdf 調用方式如下:

repstopdf [options] [epsfile [pdffile.pdf]]

repstopdf 會調用 GhostScript 去生成 pdf 文件(具體調用參數可以用過 strace 命令進行跟蹤),其中傳入的 epsfile 參數會成為 GhostScript 的 -sOutputFile= 選項的參數。

通過查閱 GhostScript 的文檔可知,GhostScript 的此項參數支持管道操作。當我們傳入文件名為:|id 時,GhostScript 會執行 id 命令。于是我們可以構造 repstopdf 的參數實現任意的命令執行操作,不受前文所提及的限制條件限制。利用方式如下所示:

repstopdf '|id #'

在 TeX 內的利用方式為:

\write18{repstopdf "|id #"}

IV. 在 Windows 下的利用方式

Windows 平臺下,白名單內存在的是 epstopdf 而非 repstopdf,且相關參數選項與 *nix 平臺下不相同,但仍舊存在 --gsopt 選項。利用此選項可以控制調用 GhostScript 時的參數。

此參數只支持設定調用 GhostScript 時的參數選項。參考 GhostScript 的文檔,指定參數 -sOutputFile 及其他相關參數即可。利用方式為:

epstopdf 1.tex "--gsopt=-sOutputFile=%pipe%calc" "--gsopt=-sDEVICE=pdfwrite" "--gsopt=-"

V. LuaLaTeX 的安全問題

LuaLaTex 內置了 Lua 解釋器,可以在編譯時執行 Lua 代碼,原語為:\directlua。LuaLaTeX 支持調用系統命令,但是同樣地受到 shell_escape 的限制。如在受限(f)模式下,不允許執行任意命令;默認情況下只允許執行白名單內的命令。由于可以調用白名單內的命令,LuaLaTeX 同樣可以利用 III、IV 內描述的方式進行利用,在此不做進一步贅述。

LuaLaTeX 的 Lua 解釋器支持如下風險功能:

  • 命令執行(io.popen 等函數)
  • 文件操作(lfs 庫函數)
  • 環境變量設置(os.setenv)
  • 內置了部分自研庫(fontloader)

1. 環境變量劫持導致命令執行

通過修改 PATH 環境變量,可以達到劫持白名單內命令的效果。PATH 環境變量指定了可執行文件所在位置的目錄路徑,當在終端或者命令行輸入命令時,系統會依次查找 PATH 變量中指定的目錄路徑,如果該命令存在與目錄中,則執行此命令(https://en.wikipedia.org/wiki/PATH_(variable))。

將 PATH 變量修改為攻擊者可控的目錄,并在該目錄下創建與白名單內命令同名的惡意二進制文件后,攻擊者通過正常系統功能調用白名單內的命令后,可以達到任意命令執行的效果。

2. fontloader 庫安全問題

fontloader 庫存在典型的命令注入問題,問題代碼如下:

// texk/web2c/luatexdir/luafontloader/fontforge/fontforge/splinefont.c
char *Decompress(char *name, int compression) {
    char *dir = getenv("TMPDIR");
    char buf[1500];
    char *tmpfile;

    if ( dir==NULL ) dir = P_tmpdir;
    tmpfile = galloc(strlen(dir)+strlen(GFileNameTail(name))+2);
    strcpy(tmpfile,dir);
    strcat(tmpfile,"/");
    strcat(tmpfile,GFileNameTail(name));
    *strrchr(tmpfile,'.') = '\0';
#if defined( _NO_SNPRINTF ) || defined( __VMS )
    sprintf( buf, "%s < %s > %s", compressors[compression].decomp, name, tmpfile );
#else
    snprintf( buf, sizeof(buf), "%s < %s > %s", compressors[compression].decomp, name, tmpfile );
#endif
    if ( system(buf)==0 )
return( tmpfile );
    free(tmpfile);
return( NULL );
}
12345678910111213141516171819202122

調用鏈為:

ff_open -> ReadSplineFont -> _ReadSplineFont -> Decompress -> system

通過 Lua 調用 fontloader.open 函數即可觸發。此方式可以在受限(f)模式下執行命令。

VI. DVI 的安全問題

DVI(Device independent file)是一種二進制文件格式,可以由 TeX 生成。在 TeX 中,可以利用 \special 原語嵌入圖形。TeX 內置了 DVI 查看器,其中 *nix 平臺下為 xdvi 命令,Windows 平臺下通常為 YAP(Yet Another Previewer)。

1. xdvi 命令的安全問題

xdvi 在處理超鏈接時,調用了系統命令啟動新的 xdvi,存在典型的命令注入問題。問題代碼如下:

// texk/xdvik/hypertex.c
void
launch_xdvi(const char *filename, const char *anchor_name)
{
#define ARG_LEN 32
    int i = 0;
    const char *argv[ARG_LEN];
    char *shrink_arg = NULL;

    ASSERT(filename != NULL, "filename argument to launch_xdvi() mustn't be NULL");

    argv[i++] = kpse_invocation_name;
    argv[i++] = "-name";
    argv[i++] = "xdvi";

    /* start the new instance with the same debug flags as the current instance */
    if (globals.debug != 0) {
    argv[i++] = "-debug";
    argv[i++] = resource.debug_arg;
    }

    if (anchor_name != NULL) {
    argv[i++] = "-anchorposition";
    argv[i++] = anchor_name;
    }

    argv[i++] = "-s";
    shrink_arg = XMALLOC(shrink_arg, LENGTH_OF_INT + 1);
    sprintf(shrink_arg, "%d", currwin.shrinkfactor);
    argv[i++] = shrink_arg;

    argv[i++] = filename; /* FIXME */

    argv[i++] = NULL;

...
        execvp(argv[0], (char **)argv);

1234567891011121314151617181920212223242526272829303132333435363738

2. YAP 安全問題

YAP 在處理 DVI 內置的 PostScripts 腳本時調用了 GhostScript,且未開啟安全模式(-dSAFER),可以直接利用內嵌的 GhostScript 進行命令執行。

VII. 漏洞利用

TeX 底層出現安全問題時,可以影響基于 TeX 的相關在線平臺、TeX 編輯器以及命令行。下面以 MacOS 下比較知名的 Texpad 進行演示:

img

VIII. 參考文章


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1596/