當前位置:
首頁 > 新聞 > 如何使用Ghostscript調試PostScript

如何使用Ghostscript調試PostScript

我最近接觸了威脅研究領域的一位朋友,他正在研究PostScript中shellcode提取的問題。PostScript是一種由Adobe Systems開發的簡單的解釋性編程語言,具有強大的圖形功能,已集成到當今大多數現代印表機中。在過去幾年中,該軟體一直是攻擊者的目標,進行了多次臭名昭著的攻擊,包括FortiGuard Labs去年發現的利用CVE-2015-2545 Encapsulated PostScript(EPS)漏洞一項行動。攻擊者利用PostScript中發現的漏洞通常會使用編碼演算法對其進行混淆,從而使分析人員的工作更加艱難。因此,如果你是那些只具有PostScript基本知識的分析人員,那麼可能會發現靜態地理解混淆代碼很難。如果確實存在這種情況,也很平常。這就是為什麼我決定寫一篇關於如何分析PostScript的快速指南。

PostScript 101

有些讀者可能會問,如果只是想知道它的行為的話,為什麼需要靜態分析PostScript。不幸的是,一些惡意樣本在執行時不能動態工作,可能是由於各種原因,包括不同的測試環境,如不兼容的操作系統或軟體版本,損壞或截斷的文件等。那些黑盒分析是不可行的,分析人員需要能夠對惡意樣本靜態分析。在我的朋友引介下,我看到了一個shellcode,其中包含用PostScript編寫的解碼常式,如清單1所示。乍一看,我認為靜態解碼很容易,但經過幾次試錯嘗試我沒有獲得解碼的shellcode。顯然,主要原因是因為首先我不了解PostScript。所以我決定玩玩PostScript,這是我一直想嘗試的東西。

Line 1:/shellcode def

Line 2:0 1 shellcode length 1

Line 3:{

Line 4: /xor_proc exch def shellcode dup

Line 5: xor_proc get 16#29 xor

Line 6: xor_proc xor 255 and xor_proc exch put

Line 7:} for

清單1: PostScript寫的shellcode

也許在搜索查詢中沒有使用正確的關鍵字,因為在找到Ghostscript之前我找不到任何關於PostScript shellcode分析的有用文章,Ghostscript是PostScript和PDF文件的解釋器。

當我啟動Ghostscript時,我很高興看到類似於Python的互動式控制台的互動式shell提示符,這讓我覺得我可以調試遇到的shellcode。如果剛開始嘗試使用PostScript,可能會對PostScript命令的語法和順序感到困惑,如清單1所示。幸運的是,一旦將命令輸入Ghostscript的控制台,將獲得更好的視感。值得一提的是,Adobe Systems對PostScript命令進行了詳細記錄。

您可能聽說PostScript被描述為基於堆棧的語言,並想知道這意味著什麼。這是清單2中的線索:

$ gs -dNODISPLAY

GPL Ghostscript 9.18 (2015-10-05)

Copyright (C) 2015 Artifex Software,

Inc. All rights reserved.

This software comes with NO WARRANTY:

see the file PUBLIC for details.

GS>1

GS2

GSstack

2

1

GS

清單2: Ghostscript 交互shell

你明白了嗎?PostScript中的每個命令都被推送到操作數堆棧。換句話說,在PostScript中使用的最後一個命令將始終位於堆棧的頂部。如果熟悉逆向工程,我相信這個概念對你來說很熟悉。Ghostscript也足夠用戶友好,通過「」括弧之間的數字來顯示堆棧中的命令/元素數量。當想要清除堆棧時,可以使用clear命令,根據Adobe的術語,它也稱為堆棧運算符。

$ gs -dNODISPLAY

GPL Ghostscript 9.18 (2015-10-05) Copyright (C) 2015 Artifex Software,

Inc. All rights reserved.

This software comes with NO WARRANTY:

see the file PUBLIC for details.

GS>1

GS2

GSstack

2

1

GSclear

GS>

清單3: Ghostscript堆棧操作符 - clear

之所以提到這一點,是因為在開始調試之前確保堆棧clear是很重要的,確保您不會弄亂要調試的內容。

PostScript Debugging 101

接下來我們準備查看清單4中顯示的shellcode:

GS>/shellcode

def

GS>stack

GS>

清單4: 將文本名稱定義為變數

可以看出,在Ghostscript中輸入的命令定義一個名為shellcode的變數。當名稱附加正斜杠「/」並以def運算符結束時,它是一個文本名稱。雖然括弧「」中的數據被定義為十六進位字元串,但在此示例中,我們使用虛擬shellcode位元組進行演示,因為我們獲取的實際shellcode數據大約為10千位元組。不幸的是,Ghostscript很難解析大數據,可能是由於內存溢出。

GS>shellcode ==(AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)GS>shellcode =AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGS>shellcode printAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

清單5: 檢查變數值的運算符

基本上,如果我們將清單5中的命令分開,它們可以被讀作

1.在操作數堆棧中推送shellcode值

2.Pop(==)來自操作數堆棧的值

值得一提的是「==」運算符類似於「=」,但它擴展了數組的值,如清單5所示。

到目前為止,我們已經討論了如何解釋PostScript命令,以及一些有助於調試PostScript的運算符。我們現在可以進入清單1中的第2行。它是"for循環"控制結構的開始。本質上,for循環控制結構的語法類似於「初始 增量 限制 for」:

GS>0 1 shellcode length 1

GSstack

1

48

1

清單6: for loop控制結構

當我們分解清單6中的命令時,可以解釋為:

1.將0推送到操作數堆棧,這是初始值

2.將1推送到操作數堆棧,這是增量值

3.將shellcode對象推送到操作數堆棧。將length運算符(數組/字元串對象的特殊運算符)推送到操作數堆棧。它從前一個操作數獲取一個參數,並返回元素數,即限制值。

4.將1推到操作數堆棧

GS/xor_proc exch def shellcode dup

GSstack

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

48

1

GSxor_proc ==

1

GS

清單7: 清單1中的第4行命令

清單7中的命令可以如下定義:

1./xor_proc exch def =>定義變數xor_proc並將變數推送到操作數堆棧。然後它交換堆棧頂部兩個元素的位置(xor_proc, 1, 48, 1, 0) - >(1, xor_proc, 48, 1, 0)。最後,def運算符獲取堆棧頂部的值,將其分配給xor_proc,然後從堆棧中刪除這兩個值

2.將shellcode對象推送到操作數堆棧

3.複製shellcode對象

第5行和第6行,如清單1所示,包含實際的解碼命令。執行第5行的命令後,會產生如下結果:

GSxor_proc get 16#29 xor

GSstack

104

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

48

1

清單8: 清單1中第五行的命令

1.將xor_proc值推送到操作數堆棧,該堆棧用作shellcode數組對象的索引

2.將GET運算符(數組/字元串對象的特殊運算符)推送到操作數堆棧,以獲取前一個操作數堆棧中指定的索引值。結果,shellcode [1]的值將被推送到操作數堆棧

3.將十六進位0x29壓入操作數堆棧,然後將其用作XOR密鑰。請注意,可以通過在數字前使用#標籤符號來定義整數的基數(例如:16#表示十六進位數字,8#表示八進位數字)

4.將XOR運算符推送到操作數堆棧,從前兩個操作數堆棧中獲取值進行算術運算。結果為104(0x29 ^ 0x41)

如果我們擴展第6行中的命令,可以看到解碼常式執行另一個XOR操作,該操作獲取數組的當前索引XOR在清單8中的堆棧頂部中的值:

GSxor_proc stack

1

104

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

48

1

GSxor stack

105

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

48

1

GS255 stack

255

105

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

48

1

GSand stack

105

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

48

1

GSxor_proc stack

1

105

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

48

1

GSexch stack

105

1

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

48

1

GSput stack

48

1

GSshellcode ==

(AiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)

清單9: 情單1中第6行的命令

最後,如清單9所示,PUT運算符從堆棧中取出三個值(105,1,shellcode),並將第一個參數中指定的元素(105)存儲到第二個參數中指定的數組/字元串對象(shellcode)的索引(1)。

通過分析,我們可以在Python腳本中演示清單1中的PostScript解碼常式的更高層次表示,它包含兩輪XOR操作,一個靜態密鑰0x29和一個動態密鑰(它是以下字元串的索引):

#!/bin/python

shellcode_fn ="postcript_shellcode.bin"

buff = open(shellcode_fn,"rb").read()

buff_len = len(buff)

shellcode_defn ="postscript_shellcode_de.bin"

out = open(shellcode_defn, "wb")

for i in range(1, buff_len):

[3 spaces indentation]res =ord(buff[i]) ^ 0x29

[3 spaces indentation]res = (res ^ i)& 0xff

out.write(chr(res))

out.close()

總結

希望這篇對PostScript的介紹以及一些常見的PostScript操作符在調試PostScript時會有所幫助。也希望這可以讓你了解在將來遇到時如何分析PostScript shellcode。最後一點,由於學習解碼PostScript的原因,我能夠通過檢測從shellcode下載的有效載荷來幫助我的朋友。

IOC

Payload URLs:

[1] hxxps://tpddata[.]com/skins/skin-8.thm

[2] https://tpddata[.]com/skins/skin-6.thm

Payloads detections:

skin-8.thm - 4838f85499e3c68415010d4f19e83e2c9e3f2302290138abe79c380754f97324

(W32/Manuscrypt.BA!tr)

skin-6.thm - c10363059c57c52501c01f85e3bb43533ccc639f0ea57f43bae5736a8e7a9bc8

(W64/Manuscrypt.BA!tr)


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 嘶吼RoarTalk 的精彩文章:

美國政府最新技術警報:警惕朝鮮黑客組織Hidden Cobra正在使用的兩款RAT和蠕蟲病毒
黑客無處不在:美國軍用收割者無人機文件在暗網泄露

TAG:嘶吼RoarTalk |