天天看點

利用Python pickle實作任意代碼執行

大量實踐證明建構惡意的pickle非常容易,而對惡意pickle進行unpickle操作将可能會産生一個shell,甚至是一個遠端shell。是以,本文中将向大家介紹如何利用Python pickle進行任意代碼執行操作。

0×00 Python pickle禁忌

0×01 pickle舉例

首先,我們以Python pickle shellcode的canonical開始,我将其儲存為canonical.pickle。

接着,我們試着解包這個pickle,看看會産生什麼結果。

0×02 pickle簡介

Pickle是一種堆棧語言,這意味着pickle指令将資料壓入堆棧或者将資料彈出堆棧,并以某種方式操作它。為了了解canonical pickle是如何工作的,我們隻需要了解6條pickle指令:

為了執行任意Python代碼,以上指令是我們需要掌握的所有指令。

0×03 代碼分析

接着,看一下canonical pickle shellcode。我們看到,内建函數os.system首先被壓入了堆棧中。接着,一個标記對象和字元串“/bin/sh”也被壓入堆棧。指令t産生了一個隻包含1個元素的元組(’/bin/sh’,)。此時,堆棧中包含了兩個元素:

os.system和(’/bin/sh’,)。指令R将以上兩個元素都彈出堆棧,并調用os.system(‘/bin/sh’),然後将執行結果(shell傳回值)壓入堆棧中。

0×04 擷取shell示例

對于我們的任意計算,我們先慢慢地計算10階斐波那契數,并将其列印出來,然後得到一個shell。

注意,因為Python允許我們導入子產品,以及在函數内部定義函數,是以我們可以在我們的foo函數中編寫想要的任何代碼。

運作此代碼生成以下内容:

0×05 建立通用pickle

我們想要建立一個通用的pickle,這樣我們可以向其中插入任意base64編碼的函數并運作它們,比如上面編寫的函數。從本質上講,我們希望産生一個可以執行下面的Python代碼的pickle,其中的code_enc就是我們編碼後的函數。

為了讓其具有更好的可讀性,調整其格式如下:

接着,讓我們一點一點建構這部分。為了調用base64.b64decode(code_enc),我們模仿前面用os.system做的操作。

我們可以以相同的方式将調用對象添加到marshal.loads中:

通過使用__builtin__子產品,可以以相同的方式調用函數globals:

為了建構函數,我們可以将這些結合到一起,然後得到:

最後,我們需要通過附加“(tR.”(其中句号結束了pickle)來調用堆棧頂部的函數。

将這些片段組合在一起,我們就得到了一個通用的pickle。

0×06 模闆代碼

另外,改變可執行代碼僅僅需要改變foo函數,運作列印出marshal處理過和編碼後的函數的Python程式,然後在替換generic.pickle中base64編碼的字元串。

下面是一個很友善的模闆。

本文轉自fatshi51CTO部落格,原文連結:http://blog.51cto.com/duallay/1858300 ,如需轉載請自行聯系原作者