成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

深入考察解釋型語言背后隱藏的攻擊面,Part 2(三)

安全 應用安全
在本文中,我們將深入地探討,在通過外部函數接口(Foreign Function Interface,FFI)將基于C/C++的庫“粘合”到解釋語言的過程中,安全漏洞是如何產生的。

接上文:

在本文中,我們將深入地探討,在通過外部函數接口(Foreign Function Interface,FFI)將基于C/C++的庫“粘合”到解釋語言的過程中,安全漏洞是如何產生的。

[[373759]]

決定最終的漏洞利用策略

為了弄清楚如何在觸發我們的堆內存覆蓋之前對data_數組進行最佳定位,我們需要檢查一下堆的狀態。到目前為止,我們有兩個感興趣的目標:png_ptr結構體和運行時解析器正在使用的動態鏈接器數據。

如果我們檢查png_ptr結構體數據所在的堆分塊,我們就會發現,它是一個大小為0x530的main arena分塊。

  1. Thread 1 "node" hit Breakpoint 2, 0x00007ffff40309b4 in png_read_row () from /home/anticomputer/node_modules/png-img/build/Release/png_img.node 
  2. gef?  i r rdi 
  3. rdi            0x2722ef0        0x2722ef0 
  4. gef?  heap chunk $rdi 
  5. Chunk(addr=0x2722ef0size=0x530flags=PREV_INUSE
  6. Chunk size: 1328 (0x530) 
  7. Usable size: 1320 (0x528) 
  8. Previous chunk size: 25956 (0x6564) 
  9. PREV_INUSE flag: On 
  10. IS_MMAPPED flag: Off 
  11. NON_MAIN_ARENA flag: Off 
  12.   
  13.   
  14. gef? 

此前,我們已經研究了png_ptr結構體本身,以及如何利用它來顛覆node進程,現在,讓我們仔細考察_dl_fixup,以及在解析器代碼中發生崩潰的具體原因。

當我們觸發崩潰時,我們注意到:

  1. 0x00007ffff7de2fb2 in _dl_fixup (l=0x2722a10reloc_arg=0x11d) at ../elf/dl-runtime.c:69 
  2. 69        const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); 
  3. gef?  p *l 
  4. $5 = { 
  5.   l_addr = 0x4141414141414141
  6. ... 
  7.   l_info = {0x4141414141414141 
  8. ... 
  9. gef?  p l 
  10. $6 = (struct link_map *) 0x2722a10 
  11. gef? 

這意味著,我們已經破壞了用于解析png-img庫函數的linkmap。實際上,linkmap是一個數據結構,用于保存動態鏈接器執行運行時解析和重定位所需的所有信息。

下面,我們來看一下linkmap堆塊和數據結構未被破壞之前的樣子:

  1. gef?  heap chunk 0x2722a10 
  2. Chunk(addr=0x2722a10size=0x4e0flags=PREV_INUSE
  3. Chunk size: 1248 (0x4e0) 
  4. Usable size: 1240 (0x4d8) 
  5. Previous chunk size: 39612548531313 (0x240703e24471) 
  6. PREV_INUSE flag: On 
  7. IS_MMAPPED flag: Off 
  8. NON_MAIN_ARENA flag: Off 
  9.   
  10.   
  11. gef?  p *l 
  12. $7 = { 
  13.   l_addr = 0x7ffff400f000
  14.   l_name = 0x2718010 "/home/anticomputer/node_modules/png-img/build/Release/png_img.node", 
  15.   l_ld = 0x7ffff4271c40
  16.   l_next = 0x0
  17.   l_prev = 0x7ffff7ffd9f0 
  18.   l_real = 0x2722a10
  19.   l_ns = 0x0
  20.   l_libname = 0x2722e88
  21.   l_info = {0x0, 0x7ffff4271c70, 0x7ffff4271d50, 0x7ffff4271d40, 0x0, 0x7ffff4271d00, 0x7ffff4271d10, 0x7ffff4271d80, 0x7ffff4271d90, 0x7ffff4271da0, 0x7ffff4271d20, 0x7ffff4271d30, 0x7ffff4271c90, 0x7ffff4271ca0, 0x7ffff4271c80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7ffff4271d60, 0x0, 0x0, 0x7ffff4271d70, 0x0, 0x7ffff4271cb0, 0x7ffff4271cd0, 0x7ffff4271cc0, 0x7ffff4271ce0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7ffff4271dc0, 0x7ffff4271db0, 0x0, 0x0, 0x0, 0x0, 0x7ffff4271de0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7ffff4271dd0, 0x0 
  22. ... 
  23. gef? 

當我們檢查png_ptr chunk和linkmap chunk的地址和大小時,注意到它們所在的內存不僅是相鄰的,并且是連續內存。png_ptr chunk位于地址0x2722ef0處,而大小為0x4e0的linkmap chunk則位于它之前的地址0x2722a10處。由于是連續內存,因此,兩者之間不存在分塊。

當從攻擊者的角度評估堆狀態時,我們總是同時考慮連續內存布局和邏輯內存布局(例如鏈表)。

因為linkmap和png_ptr的內存在我們開始影響目標node進程之前分配的,并且在漏洞利用過程中都處于使用狀態,所以,我們似乎不太可能在這兩個分塊之間挪動我們的data_ chunk,以暢通無阻地破壞png_ptr數據。此外,我們貌似可以通過例如PNG文件大小來影響早期的堆狀態,但這似乎無法得到可靠的結果。

這意味著我們將必須對linkmap進行破壞,以獲取對node進程的控制權。

深入考察解釋型語言背后隱藏的攻擊面,Part 2(三)

攻擊運行時解析器

作為攻擊者,我們經常要從系統代碼中提煉出非預期的、但有用的行為。這里的挑戰是:不要被那些我們不關心的東西所干擾,而要專注于那些在特定的漏洞利用場景中可資利用的行為。

那么,運行時解析器代碼的哪些行為可能對攻擊者有用呢?

要回答這個問題,我們必須了解運行時解析器是如何使用linkmap的。簡而言之,它將從linkmap中抓取已加載的庫的基地址,然后檢查各種二進制段,以確定從庫的基地址到要解析的函數起始地址的正確偏移量。一旦計算出這個偏移量,把它加到庫的基地址上,用解析函數地址更新函數的GOT條目,然后跳轉到解析函數的起始地址即可。

作為攻擊者,我們從中提煉出以下有用的原語:向動態鏈接器的運行時解析器提供一個精心設計的linkmap,將它們加在一起,然后將執行流重定向到生成的地址處。加法的第一個操作數是直接從linkmap中得到的,而加法的第二個操作數可以通過linkmap中提供的指針從二進制段中獲取。我們注意到,根據包含在某個解除引用的二進制段中的數據,在執行被重定向之前,解析的值將被寫入一個內存位置。

實際上,通過破壞動態鏈接器來發動攻擊并不是一個新主意,其中,所謂的“ret2dlresolve”攻擊就是一種流行的方式,它可以在不知道libc本身在內存中的位置的情況下,將執行重定向到所需的libc函數中。在Nergal發布在Phrack上的“The advanced return-into-lib(c) exploits: PaX case study”一文中,就公開討論過這個概念。

當PLT處于目標二進制文件的已知位置時,就像非PIE二進制文件的情況一樣,ret2dlresolve攻擊就是一個非常有吸引力的選擇,它可以將執行重定向到任意庫偏移處,而無需知道所需的目標庫實際加載到內存的具體位置。這是因為解析器代碼會替我們完成所有繁重的工作。

濫用運行時解析器的主流方法,通常會假設攻擊者已經能夠重定向進程的執行流,并通過PLT返回到解析器代碼中,以便為_dl_runtime_resolve提供攻擊者控制的參數。因此,這種方法被稱為“ret2dlresolve”(即return to dl resolve的縮寫形式)。他們的想法是,隨后可以利用解析器與現有的或精心制作的linkmap數據和重定位數據的交互,推導出攻擊者控制的偏移量,即到達內存中的現有指針值的偏移。例如,他們可以欺騙解析器,讓解析器將攻擊者控制的偏移量應用到一個已經建立的libc地址上,以便從那里偏移到一個任意的libc函數上,比如system(3)。在不知道libc基地址且無法直接返回libc的情況下,上面這種方法的一個變體是使用解析器邏輯來解析libc函數。

當然,這個技術還存在其他變體,例如在內存中的已知位置提供一個完全精心制作的linkmap,用相對尋址來偽造重定位和符號數據。這里的目標同樣是濫用運行時解析器,從已知的內存位置偏移到攻擊者想要轉移執行的位置。

然而,雖然在我們的例子中,我們能夠提供一個精心制作的linkmap,但我們并不能控制運行時解析器的參數。此外,我們也還沒有掌握執行控制權,而是旨在“策反”運行時解析器,通過我們精心制作的linkmap數據,以繞過ASLR機制并實現執行重定向。由于堆的基地址是隨機的,而且我們是通過PNG文件來攻擊進程的,所以,我們沒有辦法泄露linkmap的位置,因此我們只能基于非PIE節點二進制文件來進行內存布局和內容假設。

為了更好地了解如何實現攻擊者的目標,讓我們來看看_dl_fixup的工作原理。在這里,所有的代碼引用都來自glibc-2.27。

  1. elf/dl-runtime.c: 
  2.   
  3.   
  4. #ifndef reloc_offset 
  5. # define reloc_offset reloc_arg 
  6. # define reloc_index  reloc_arg / sizeof (PLTREL) 
  7. #endif 
  8.   
  9.   
  10. /* This function is called through a special trampoline from the PLT the 
  11.    first time each PLT entry is called.  We must perform the relocation 
  12.    specified in the PLT of the given shared object, and return the resolved 
  13.    function address to the trampoline, which will restart the original call 
  14.    to that address.  Future calls will bounce directly from the PLT to the 
  15.    function.  */ 
  16.   
  17.   
  18. DL_FIXUP_VALUE_TYPE 
  19. attribute_hidden __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE 
  20. _dl_fixup ( 
  21. # ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS 
  22.            ELF_MACHINE_RUNTIME_FIXUP_ARGS, 
  23. # endif 
  24.            struct link_map *l, ElfW(Word) reloc_arg) 
  25.   const ElfW(Sym) *const symtab 
  26.     = (const void *) D_PTR (l, l_info[DT_SYMTAB]); 
  27.   const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); 
  28.   
  29.   
  30. [1] 
  31.   const PLTREL *const reloc 
  32.     = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset); 
  33. [2] 
  34.   const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)]; 
  35.   const ElfW(Sym) *refsym = sym; 
  36. [3] 
  37.   void *const rel_addr = (void *)(l->l_addr + reloc->r_offset); 
  38.   lookup_t result; 
  39.   DL_FIXUP_VALUE_TYPE value; 
  40.   
  41.   
  42.   /* Sanity check that we're really looking at a PLT relocation.  */ 
  43.   assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT); 
  44.   
  45.   
  46.    /* Look up the target symbol.  If the normal lookup rules are not 
  47.       used don't look in the global scope.  */ 
  48.   if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0) 
  49.     { 
  50.       const struct r_found_version *version = NULL
  51.   
  52.   
  53.       if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) 
  54.         { 
  55.           const ElfW(Half) *vernum = 
  56.             (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]); 
  57.           ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff; 
  58.           version = &l->l_versions[ndx]; 
  59.           if (version->hash == 0) 
  60.             version = NULL
  61.         } 
  62.   
  63.   
  64.       /* We need to keep the scope around so do some locking.  This is 
  65.          not necessary for objects which cannot be unloaded or when 
  66.          we are not using any threads (yet).  */ 
  67.       int flags = DL_LOOKUP_ADD_DEPENDENCY
  68.       if (!RTLD_SINGLE_THREAD_P) 
  69.         { 
  70.           THREAD_GSCOPE_SET_FLAG (); 
  71.           flags |= DL_LOOKUP_GSCOPE_LOCK; 
  72.         } 
  73.   
  74.   
  75. #ifdef RTLD_ENABLE_FOREIGN_CALL 
  76.       RTLD_ENABLE_FOREIGN_CALL; 
  77. #endif 
  78.   
  79.   
  80.       result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, l->l_scope, 
  81.                                     version, ELF_RTYPE_CLASS_PLT, flags, NULL); 
  82.   
  83.   
  84.       /* We are done with the global scope.  */ 
  85.       if (!RTLD_SINGLE_THREAD_P) 
  86.         THREAD_GSCOPE_RESET_FLAG (); 
  87.   
  88.   
  89. #ifdef RTLD_FINALIZE_FOREIGN_CALL 
  90.       RTLD_FINALIZE_FOREIGN_CALL; 
  91. #endif 
  92.   
  93.   
  94.       /* Currently result contains the base load address (or link map) 
  95.          of the object that defines sym.  Now add in the symbol 
  96.          offset.  */ 
  97.       value = DL_FIXUP_MAKE_VALUE (result, 
  98.                                    sym ? (LOOKUP_VALUE_ADDRESS (result) 
  99.                                           + sym->st_value) : 0); 
  100.     } 
  101.   else 
  102.     { 
  103.       /* We already found the symbol.  The module (and therefore its load 
  104.          address) is also known.  */ 
  105.       value = DL_FIXUP_MAKE_VALUE (l, l->l_addr + sym->st_value); 
  106.       result = l; 
  107.     } 
  108.   
  109.   
  110.   /* And now perhaps the relocation addend.  */ 
  111.   value = elf_machine_plt_value (l, reloc, value); 
  112.   
  113.   
  114.   if (sym != NULL 
  115.       && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)) 
  116.     value = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value)); 
  117.   
  118.   
  119.   /* Finally, fix up the plt itself.  */ 
  120.   if (__glibc_unlikely (GLRO(dl_bind_not))) 
  121.     return value; 
  122.   
  123.   
  124.   return elf_machine_fixup_plt (l, result, refsym, sym, reloc, rel_addr, value); 

復雜,但我們只需要關注以下幾點:_dl_fixup是如何通過與我們控制的linkmap中的三個主要指針進行交互,來解析和重定位函數地址的,所有這些指針都是從linkmap的l_info數組中提取的:

  • l_info[DT_SYMTAB],指向符號表的.dynamic條目的指針。
  • l_info[DT_STRTAB],指向字符串表的.dynamic條目的指針。
  • l_info[DT_JMPREL],指向PLT重定位記錄數組的.dynamic條目的指針。

Elf二進制文件中的.dynamic段用于保存解析器需要獲取的各個段的信息。在我們的例子中,.dynstr (STRTAB)、.dynsym (SYMTAB)和.rela.plt (JMPREL)段都是解析和重定位函數所需要的。

動態條目(Dynamic entry)的結構如下所示:

  1. typedef struct 
  2.   Elf64_Sxword d_tag;                        /* Dynamic entry type */ 
  3.   union 
  4.     { 
  5.       Elf64_Xword d_val;                     /* Integer value */ 
  6.       Elf64_Addr  d_ptr;                     /* Address value */ 
  7.     } d_un; 
  8. } Elf64_Dyn; 

用于訪問l_info條目的D_PTR宏定義為:

  1. /* All references to the value of l_info[DT_PLTGOT], 
  2.   l_info[DT_STRTAB], l_info[DT_SYMTAB], l_info[DT_RELA], 
  3.   l_info[DT_REL], l_info[DT_JMPREL], and l_info[VERSYMIDX (DT_VERSYM)] 
  4.   have to be accessed via the D_PTR macro.  The macro is needed since for 
  5.   most architectures the entry is already relocated - but for some not 
  6.   and we need to relocate at access time.  */ 
  7. #ifdef DL_RO_DYN_SECTION 
  8. # define D_PTR(map, i) ((map)->i->d_un.d_ptr + (map)->l_addr) 
  9. #else 
  10. # define D_PTR(map, i) (map)->i->d_un.d_ptr 
  11. #endif 

請注意,在大多數情況下,D_PTR只是從.dynamic段條目中獲取d_ptr字段,以檢索相關段的運行時重定位地址。例如,const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);將按照提供的指向.dynstr (STRTAB)段的.dynamic條目的指針,在l_info數組的索引DT_STRTAB處,獲取上述條目的d_ptr字段。

在指針方面,這里比較讓人頭疼,但我們只要記住一點就行了:我們并不是通過控制linkmap中的l_info數組來提供直接指向解析器所需要的各個段的指針,而是指向(假定的).dynamic條目的指針,這些條目在偏移量+8處應該包含一個指向相關段的指針。

深入考察解釋型語言背后隱藏的攻擊面,Part 2(三)

前面,我們介紹了如何通過精心制作的linkmap數據為解析器提供偽造的二進制段,接下來,我們快速了解一下_dl_fixup中的實際解析和重定位邏輯。

在我們的測試平臺上,重定位記錄的定義如下所示:

  1. elf.h: 
  2.   
  3.   
  4. typedef struct 
  5.   Elf64_Addr   r_offset;        /* Address */ 
  6.   Elf64_Xword  r_info;            /* Relocation type and symbol index */ 
  7.   Elf64_Sxword r_addend;        /* Addend */ 
  8. } Elf64_Rela; 

在我們的測試平臺上,這些符號的定義如下所示:

  1. elf.h: 
  2.   
  3.   
  4. typedef struct 
  5.   Elf64_Word    st_name;                /* Symbol name (string tbl index) */ 
  6.   unsigned char st_info;                /* Symbol type and binding */ 
  7.   unsigned char st_other;               /* Symbol visibility */ 
  8.   Elf64_Section st_shndx;               /* Section index */ 
  9.   Elf64_Addr    st_value;               /* Symbol value */ 
  10.   Elf64_Xword   st_size;                /* Symbol size */ 
  11. } Elf64_Sym; 

我們再來回顧一下_dl_fixup的代碼,注意在[1]處,_dl_fixup的reloc_arg參數重定位記錄表的索引,來讀取重定位記錄。這個重定位記錄提供了一個reloc->r_info字段,該字段通過宏分為高32位的符號表索引和低32位的重定位類型。

在[2]處,_dl_fixup利用reloc->r_info索引從符號表中獲取相應的符號條目,在reloc->r_info處的ELF_MACHINE_JMP_SLOT類型斷言和sym->st_other處的符號查找范圍檢查之前,實際的函數解析以一種非常簡單的方式進行。首先,通過將linkmap中的l->l_addr字段和符號表項的sym->st_value字段相加來解析函數地址。然后將解析后的值寫入rel_addr中,rel_addr是在[3]處計算出來的,也就是l->l_addr和reloc->r_offset相加的結果。

linkmap中的l->l_addr字段是用來存放加載庫的基地址,任何解析的偏移值都會被加入其中。

綜上所述,sym->st_value + l->l_addr是解析函數的地址,l->l_addr + reloc->r_offset是重定位目標,也就是GOT條目,將用解析函數地址進行更新。

所以,從我們攻擊者的角度來看,既然我們控制了l->l_addr,以及指向符號表和重定位記錄的.dynamic段的指針,我們就可以將執行重定向到對我們有利的地方。

小結

在本文中,我們將深入地探討,在通過外部函數接口(Foreign Function Interface,FFI)將基于C/C++的庫“粘合”到解釋語言的過程中,安全漏洞是如何產生的。由于篇幅過長,我們將分為多篇進行介紹,更多精彩內容敬請期待!

本文翻譯自:https://securitylab.github.com/research/now-you-c-me-part-two

 

責任編輯:趙寧寧 來源: 嘶吼網
相關推薦

2020-12-30 10:26:47

攻擊面語言安全漏洞

2021-01-03 10:44:45

攻擊面語言安全漏洞

2021-01-07 09:19:00

攻擊面語言安全漏洞

2020-12-10 14:37:43

攻擊面語言安全漏洞

2020-12-15 13:24:41

攻擊面語言安全漏洞

2022-04-27 05:36:51

攻擊面網絡攻擊網絡安全

2020-06-02 09:50:40

信息安全數據技術

2021-01-21 21:07:03

信息安全漏洞治理

2021-07-09 09:09:47

ASM攻擊面管理安全觀察

2022-02-14 17:13:46

攻擊面管理網絡安全

2022-06-16 10:02:39

EASM攻擊面管理

2022-07-29 12:42:35

攻擊面管理

2018-11-03 05:00:29

微隔離網絡攻擊漏洞

2018-11-19 22:59:31

2014-03-19 10:25:14

2023-08-24 12:13:40

2021-06-30 10:10:01

企業攻擊漏洞網絡安全

2021-11-29 18:13:31

攻擊面漏洞網絡攻擊

2020-08-31 10:54:05

勒索軟件漏洞網絡安全

2023-11-10 09:54:32

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 色综合美女 | 国产精品一区二区在线播放 | 亚洲视频一区在线观看 | 亚洲小视频在线播放 | 精品国产久| 免费在线观看av网站 | 九九热精品视频在线观看 | 精品国产欧美一区二区三区成人 | 日韩成人免费视频 | 欧美激情va永久在线播放 | 亚洲欧美综合精品久久成人 | 欧美日韩国产一区二区三区 | 亚洲视频欧美视频 | 欧美成人手机视频 | 在线免费视频一区 | 岛国av一区二区 | 成人免费黄视频 | 91精品麻豆日日躁夜夜躁 | 蜜桃免费一区二区三区 | 亚洲一区二区三区免费视频 | 日韩精品视频在线观看一区二区三区 | 成年无码av片在线 | 影音先锋中文在线 | 精品久久久久久久久久久久 | a毛片视频网站 | 欧美中文在线 | 午夜影院网站 | 精品欧美二区 | 中文字幕免费视频 | 欧美日韩亚洲一区 | www.亚洲免费 | 国产精品欧美一区二区三区不卡 | 国产香蕉视频在线播放 | 欧美日韩中文字幕在线 | 99精品在线| 黑人中文字幕一区二区三区 | 色www精品视频在线观看 | 在线日韩视频 | 看片国产 | 国产精品美女一区二区 | 日韩精品视频在线 |