1
利用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
舉個例子:
但是對于64位的來說 ROPgadget預設的長度是不夠的。
所以,我們可以使用ROPgadget --binary ./b --depth 100來加深他的搜索深度。
2
利用_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
另外,我們可以從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 = 0x04006AA
gadget2 = 0x0400690
//控制rbx、rbp、r12、r13、r14、r15
csu_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、rdi
csu_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
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,但是似乎不可能有什么要同時控制這么多寄存器的,寫出來腳本也沒有什么意義。
3
其他控制寄存器的方法
控制rax
- gets、fgets回傳buff(rax=rdi)
- strcpy,strncpy
- alarm
控制rcx
- strcpy可能會讓ecx = 輸入字串
有些函數的返回值可能會影響寄存器,這些地方還是比較隱蔽的。
參考:
ctf-wiki*(https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/medium-rop/)*
-
寄存器
+關注
關注
31文章
5317瀏覽量
120006 -
引擎
+關注
關注
1文章
360瀏覽量
22531 -
地址
+關注
關注
1文章
31瀏覽量
10748
發布評論請先 登錄
相關推薦
評論