最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

二進(jìn)制安全之棧溢出

2020-04-16 14:11 作者:匯智知了堂  | 我要投稿

本文主要介紹二進(jìn)制安全的棧溢出內(nèi)容。

棧基礎(chǔ)
內(nèi)存四區(qū)

  • 代碼區(qū)(.text):這個(gè)區(qū)域存儲著被裝入執(zhí)行的二進(jìn)制機(jī)器代碼,處理器會到這個(gè)區(qū)域取指令執(zhí)行。

  • 數(shù)據(jù)區(qū)(.data):用于存儲全局變量和靜態(tài)變量等。

  • 堆區(qū):動(dòng)態(tài)地分配和回收內(nèi)存,進(jìn)程可以在堆區(qū)動(dòng)態(tài)地請求一定大小的內(nèi)存,并在用完后歸還給堆區(qū)。地址由高到低生長

  • 棧區(qū):用于動(dòng)態(tài)地存儲函數(shù)之間的調(diào)用關(guān)系,以保證被調(diào)用函數(shù)在返回時(shí)恢復(fù)到母函數(shù)中繼續(xù)執(zhí)行;此外局部變量也存儲在棧區(qū)。地址由低到高生長

BSS段:(bss segment)通常是指用來存放程序中未初始化的全局變量的一塊內(nèi)存區(qū)域,屬于靜態(tài)內(nèi)存分配。

棧的概念

  • 一種數(shù)據(jù)結(jié)構(gòu),數(shù)據(jù)存儲方式為先進(jìn)后出,壓棧(push)和出棧(pop)

  • 每個(gè)程序都有自己的進(jìn)程地址空間,進(jìn)程地址空間中的某一部分就是該程序的棧,用于保存函數(shù)調(diào)用信息和局部變量

  • 程序的棧是從進(jìn)程空間的高地址向低地址增長的,數(shù)據(jù)是從低地址向高地址存放的



函數(shù)調(diào)用

  • 函數(shù)調(diào)用經(jīng)常嵌套,在同一時(shí)刻,堆棧中會有多個(gè)函數(shù)的信息。

棧幀

  • 每個(gè)未完成運(yùn)行的函數(shù)占用一個(gè)獨(dú)立的連續(xù)區(qū)域,稱作棧幀。


基本流程

;調(diào)用前 push arg3 ? ? ? ? ? ? ? ;32位esp-4,64位esp-8 push arg2 push arg1 call func ? ? ? ? ? ? ? ;1. 壓入當(dāng)前指令的地址,即保存返回地址 2. jmp到調(diào)用函數(shù)的入口地址 push ebp ? ? ? ? ? ? ? ?;保存舊棧幀的底部,在func執(zhí)行完成后在pop ebp mov ebp,esp ? ? ? ? ;設(shè)置新棧幀的底部 sub esp,xxx ? ? ? ? ;設(shè)置新棧幀的頂部


    詳細(xì)流程

    int func_b(int b1,int b2) { ?int var_b1,var_b2; ?var_b1 = b1+b2; ?var_b2 = b1-b2; ?return var_b1 * var_b2; } int func_a(int a1,int a2) { ?int var_a; ?var_a = fuc_b(a1+a2); ?return var_a; } int main(int argc,char** argv,char **envp) { ?int var_main; ?var_main = func_A(4,3); ?return 0; }


      參數(shù)傳遞

      x86

      通過棧傳參 先壓入最后一個(gè)參數(shù)

      x64

      rdi rsi rdx rcx r8 r9 接收后六個(gè)參數(shù) 之后的參數(shù)通過棧傳參

      64位的利用方式

      構(gòu)造rop鏈 ROPgadget –binary level3_x64 –only ‘pop|ret’ # Gadgets information 0x00000000004006ac : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004006ae : pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004006b0 : pop r14 ; pop r15 ; ret ? ? ? ? ? ? 0x00000000004006b2 : pop r15 ; ret 0x00000000004006ab : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004006af : pop rbp ; pop r14 ; pop r15 ; ret 0x0000000000400550 : pop rbp ; ret 0x00000000004006b3 : pop rdi ; ret 0x00000000004006b1 : pop rsi ; pop r15 ; ret 0x00000000004006ad : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret 0x0000000000400499 : ret 依次找pop rdi,pop rsi..,pop r9 ,這些寄存器里面存放的是參數(shù),可以通過pop覆蓋其中的內(nèi)容

      棧溢出

      棧溢出指的是程序向棧中某個(gè)變量寫入的字節(jié)數(shù)超過了這個(gè)變量本身申請的字節(jié)數(shù),因而導(dǎo)致棧中與之相鄰的變量的值被改變。

      棧溢出目的

      • 破壞程序內(nèi)存結(jié)構(gòu)

      • 執(zhí)行system(/bin/sh)

      • 執(zhí)行shellcode

      棧溢出思路

      判斷溢出點(diǎn)

      常見的危險(xiǎn)函數(shù): 輸入:gets scanf vscanf 輸出:sprintf 字符串:strcpy strcat bcopy

      判斷padding

      計(jì)算我們所要操作的地址和所要覆蓋的地址的距離 IDA靜態(tài)分析中常見的三種索引方式 a. 相對于?;刂返乃饕?通過查看EBP相對偏移獲得 char name[32]; [esp+0h] [ebp-28h] ==> 0×28+0×4 b. 相對于棧頂指針的索引,需要加上ESP到EBP的偏移,然后轉(zhuǎn)換為a方式 c. 直接地址索引,相當(dāng)于直接給出了地址

      覆寫內(nèi)容

      覆蓋函數(shù)返回地址 覆蓋棧上某個(gè)變量的內(nèi)容,如局部變量和參數(shù)

      Ret2text

      返回到某個(gè)代碼段的地址,如.text:0804863A mov dword ptr [esp], offset command ; "/bin/sh"要求我們控制程序執(zhí)行程序本身已有的代碼

      Ret2shellocde

      跳轉(zhuǎn)到我們在棧中輸入的代碼,一般在沒有開啟NX保護(hù)的時(shí)候使用. ret2shellcode的目標(biāo)即在棧上寫入布局好的shellcode,利用ret_address返回到shellcode處執(zhí)行代碼。

      Ret2syscal

      讓程序返回到系統(tǒng)調(diào)用,調(diào)用syscall或execve執(zhí)行某個(gè)程序,對于靜態(tài)編譯的程序,沒有l(wèi)ibc,只好通過execve執(zhí)行shellcode了。 syscall ?--->rax syscall 0x3b ?==>execve rax ? ? ? ? ? ? ? --->rdi ?path ?==> /bin/sh ? ? ? ? ?rdi ? ? ? ? ? ? ? --->rsi ?argv ?/ ? ? ? ? ? ? ? ? ? ? ? ? ? rsi ? ? ? ? ? ? ? --->rdx env ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?rdx int execve(const char *filename, char *const argv[],char *const envp[]); ? ? ? ?execve("/bin/sh",null.null) 等同于system("bin/sh") syscall(32位程序?yàn)閕nt80)會根據(jù)系統(tǒng)調(diào)用號查找syscall_table,execve對應(yīng)的系統(tǒng)調(diào)用號是0x3b。 當(dāng)我們給syscall的第一個(gè)參數(shù)即rax中寫入0x3b時(shí)(32位程序?yàn)?xb),就會找到syscall_table[0x3b],即syscall_execve,然后通過execve啟動(dòng)程序。 找syscall和int 80的方法:ROPgadget –binary test –only ‘int/syscall’ 靜態(tài)編譯的程序沒有system等函數(shù)的鏈接支持,故一般利用ret2syscall構(gòu)造棧溢出

      Ret2libc

      如找到system函數(shù)在動(dòng)態(tài)鏈接庫libc中的地址,將return的內(nèi)容覆蓋為該地址,跳轉(zhuǎn)執(zhí)行 leak出libc_addr + call system + 執(zhí)行system(‘/bin/sh’) 難點(diǎn):libc動(dòng)態(tài)加載,每次基址都會變化,如何泄露libc的地址? 思路:got —> read_addr() —>libc read_addr – libc_base = offsset (不變) libc_base = read_addr – offset bin/sh的來源 : 程序本身或libc或者寫一個(gè)/bin/sh到bss段 binsh = libc.search(“/bin/sh”).next()

      其它

      判斷是否是否為動(dòng)態(tài)編譯 ? ?  ~/stack/day_4  ldd ret2text ? ?linux-gate.so.1 => ?(0xf7f36000) ? ?libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d60000) ?-->libc的版本,也可以vmmap查看 ? ?/lib/ld-linux.so.2 (0xf7f38000) 判斷l(xiāng)ibc的版本 a. 本地直接通過vmmap查看 b. 遠(yuǎn)程的根據(jù)函數(shù)后幾位的偏移得到 ? ? ? ?libc-database ? ? ? ? ? ?link:https://github.com/lieanu/libc-database.git ? ? ? ? ? ?usage: ./find func_name offset ? ? ? ? ? ?exemplify: ./find gets 5a0 ? ? ? ? ? ?effection: ? ? ? ? ? ? ? ? ? ?? ?libc-database git :( master) ./find gets 5a0 ? ? ? ? ? ? ? ? ? ?archive-eglibc (id libc6_2.17-93ubuntu4_i386) c: 5a0怎么來的? ? ?.got.plt:0804A010 off_804A010 ? ? dd offset gets ? ?pwndbg> x/20gz 0x0804a010 0x804a010 <gets@got.plt>: ? 0x08048476f7e643e0 ?0x08048496f7e64ca0 0x804a020 <__gmon_start__@got.plt>: 0x080484b6080484a6 ?0xf7e65360f7e1d540 0x804a030 <rand@got.plt>: ? 0x080484f6080484e6 ?0x0000000000000000 0x804a040 <stdin@@GLIBC_2.0>: ? 0x00000000f7fb75a0 ?0x0000000000000000 0x804a050: ?0x0000000000000000 ?0x0000000000000000 0x804a060 <stdout@@GLIBC_2.0>: ?0x00000000f7fb7d60 ?0x0000000000000000 0x804a070: ?0x0000000000000000 ?0x0000000000000000 0x804a080: ?0x0000000000000000 ?0x0000000000000000 0x804a090: ?0x0000000000000000 ?0x0000000000000000 0x804a0a0: ?0x0000000000000000 ?0x0000000000000000 64位程序和32位程序的區(qū)別 1. 傳參方式 ? ? ? ?64位:rdi rsi rdx rcx r8 r9 ? ? ? ?32位:通過棧傳參 2. syscall & int 80

      ??臻g布局

      // 偽代碼 A(int arg_a1,int arg_a2) B(int arg_b1,int arg_b2,int arg_b3) C() ------------------------------------- // B的壓棧流程 ---> ESP ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //指向棧頂,隨著壓棧不斷抬高 ? ? ? ?buf[128] ? ? ? ? ? ? ? ? ? ?//局部變量 ? ? ? ?EBP ? ? ? ? ? ? ? ? ? ? ? ? //保存舊棧幀的底部,4字節(jié) ? ? ? ?return ? ? ? ? ? ? ? ? ? ? ?//這是B的返回地址,即C ? ? ? ?arg_b1 ? ? ? ?arg_b2 ? ? ? ?arg_b3 ? ? ? ? ? ? ?-->EBP ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //指向當(dāng)前棧幀的底部,隨著壓棧不斷抬高,指向舊棧幀

      棧溢出原理

      • 當(dāng)局部變量buf超過128字節(jié),會向下覆蓋EBP,return以及參數(shù)的內(nèi)容。

      • 構(gòu)造return

      將buf 的 132到136字節(jié)的空間輸入shellcode的地址 會跳轉(zhuǎn)執(zhí)行shellcode

      保護(hù)機(jī)制

      NX

      • 保護(hù)原理

      堆棧不可執(zhí)行保護(hù),bss段也不可執(zhí)行,windows下為DEP,可通過gcc -z execstack關(guān)閉 開啟NX后再把return的內(nèi)容覆蓋為一段shellcode,在開啟NX的時(shí)候,不能執(zhí)行。

      繞過原理 : 32位

      實(shí)現(xiàn)A函數(shù)執(zhí)行的方法,即構(gòu)建ROP鏈 return —> fake_addr —> A 將B的參數(shù)從arg_b2到arg_b3也覆蓋成A的參數(shù)


      // 偽代碼 A(int arg_a1,int arg_a2) B(int arg_b1,int arg_b2,int arg_b3) C(int arg_c1,int arg_c2) ------------------------------------- // B的壓棧流程 ---> ESP ? ? ? ? ?buf[128] ? ? ? ?EBP ? ? ? ? ?return //把return的內(nèi)容覆蓋為A的地址 ? ? ? ?arg_b1 //程序在調(diào)用A函數(shù)的時(shí)候,把下一個(gè)棧數(shù)據(jù)當(dāng)作A的返回地址,因此需要在再下一條語句的時(shí)候開始覆蓋參數(shù) ? ? ? ?arg_b2 ?arg_a2 //將B的參數(shù)用A的參數(shù)覆蓋掉 ? ? ? ?arg_b3 arg_a1 -->EBP


      借鑒上面的方法,在調(diào)用A之后,再調(diào)用C,構(gòu)建ROP鏈 這時(shí)不能把系統(tǒng)認(rèn)為的A的返回地址的arg_b1覆蓋為C的返回地址,不然會向上覆蓋arg_a2和arg_a2,導(dǎo)致A無法正常執(zhí)行。 這時(shí)需要再找一個(gè)return語句,程序里面通常含有pop-pop-ret的鏈 ROPgadget –binary –only ‘pop|ret’ : 自動(dòng)尋找rop鏈 Gadgets information ============================================================ 0x00000000004006ac : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004006ae : pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004006b0 : pop r14 ; pop r15 ; ret //選擇這個(gè)地址,代碼段無NX 0x00000000004006b2 : pop r15 ; ret 0x00000000004006ab : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004006af : pop rbp ; pop r14 ; pop r15 ; ret 0x0000000000400550 : pop rbp ; ret 0x00000000004006b3 : pop rdi ; ret 0x00000000004006b1 : pop rsi ; pop r15 ; ret 0x00000000004006ad : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret 0x0000000000400499 : ret 將arg_b1覆蓋為addr_pop_pop_ret的地址:4006b0 此時(shí)將將arg_a1 pop到r14,arg_a2 pop到r15,然后ret 將ret的內(nèi)容覆蓋為C的入口地址,即可! 程序執(zhí)行如下代碼: // 偽代碼 A(int arg_a1,int arg_a2) B(int arg_b1,int arg_b2,int arg_b3) C(int arg_c1,int arg_c2) ------------------------------------- // B的壓棧流程 ---> ESP ? ? ? ? ?buf[128] ? ? ? ?EBP ? ? ? ? ?return //-->fake_addr_A ? ? ? ?arg_b1 //-->4006b0 ?addr_pop_pop_ret ? ? ? ?arg_b2 ?arg_a1 //pop r14 ? ? ? ?arg_b3 arg_a2 //pop r15 ? ? ? ?ret // --->fake_addr_C ? ? ? ?0 // --->C的返回地址,現(xiàn)在沒用了 ? ? ? ?arg_c1 ? ? ? ?arg_c2 -->EBP

      完整流程

      使用buf將??臻g覆蓋 在B退出的時(shí)候ret到A 依次取覆蓋之后的A的兩個(gè)參數(shù),執(zhí)行A函數(shù) 返回到pop_pop_ret的地址 將ret的地址覆蓋為C的地址 將C的返回地址置空 寫入C的參數(shù) 執(zhí)行C函數(shù)

      總結(jié)

      A函數(shù)的功能通常時(shí)”/bin/sh” C函數(shù)的功能為system 上述流程執(zhí)行完則可以達(dá)到反彈shell的目的 由于程序不在棧上執(zhí)行而是在代碼段中執(zhí)行,所有可以繞過NX保護(hù)機(jī)制。

      Canary(金絲雀)

      • 保護(hù)原理

      開啟canary后,會在程序的EBP與ESP之間的位置隨機(jī)插入一段md5值,占4字節(jié)或8字節(jié)。 canary為一段以 /0 結(jié)尾的一串md5值,如123456/0,起截?cái)嘧饔?,防止打印? 在程序return之前與內(nèi)核地址[fs:0x28]異或校驗(yàn)md5值 異或結(jié)果為1時(shí)報(bào)錯(cuò)退出,為0時(shí)正常ret。 幾種思路 如果能在棧中拿到md5值,在指定位置可以精準(zhǔn)覆蓋之。 將從內(nèi)核中取的md5值,設(shè)置為自己定義的值,覆蓋的時(shí)候覆蓋自己定義的值。

      gcc開啟canary

      參數(shù):-fstack-protector :啟用保護(hù),不過只為局部變量中含有數(shù)組的插入保護(hù) 參數(shù):-fstack-protector-all :為所有函數(shù)插入保護(hù) 參數(shù):-fstack-protector-strong -fstack-protector-explicit :只對明確有stack-protect 屬性的函數(shù)啟用保護(hù) 參數(shù):-fo-stack-protector :禁用保護(hù)

      3種利用方法利用

      覆蓋canary的最后一個(gè)字節(jié) 利用棧溢出將”\0″覆蓋掉,則可以將canary打印出來。 smash leak stackguard — top

      查看開啟的保護(hù)機(jī)制

      ? > ~/stack/day_1> checksec leak_canary [*] '/root/stack/day_1/leak_canary' ? ?Arch: ? ? i386-32-little ? ?RELRO: ? ?Partial RELRO ? ?Stack: ? ?Canary found ? ?NX: ? ? ? NX enabled ? ?PIE: ? ? ?No PIE (0x8048000)

      PIE

      • 保護(hù)原理

      讓程序能裝載在隨機(jī)的地址,主要是代碼段的地址隨機(jī)化,改變的是高位的基地址。 gdb中使用show proc info 可以顯示代碼段的基地址 –enabled-default-pie開啟 -no-pie關(guān)閉

      • 通常與ALSR聯(lián)合使用

      ALSR

      • 保護(hù)原理

      每次加載程序,使其地址空間分布隨機(jī)化,即使可執(zhí)行文件開啟PIE保護(hù),還需要系統(tǒng)開啟ASLR才會真正打亂基址。主要是堆棧和libc的地址隨機(jī)化。 修改/proc/sys/kernel/randommize_va_space來控制ASLR的開關(guān)。

      棧溢出進(jìn)階

      pwntools

      # Pwntools環(huán)境預(yù)設(shè) from pwn import * context.arch = "amd64/i386" #指定系統(tǒng)架構(gòu) context.terminal = ["tmux,"splitw","-h"] #指定分屏終端 context.os = "linux" ? ? #context用于預(yù)設(shè)環(huán)境 # 庫信息 elf = ELF('./PWNME') # ELF載入當(dāng)前程序的ELF,以獲取符號表,代碼段,段地址,plt,got信息 libc = ELF('lib/i386-linux-gnu/libc-2.23.so') ?# 載入libc的庫,可以通過vmmap查看 /* 首先使用ELF()獲取文件的句柄,然后使用這個(gè)句柄調(diào)用函數(shù),如 >>> e = ELF('/bin/cat') >>> print hex(e.address) # 文件裝載的基地址 >>> print hex(e.symbols['write']) # plt中write函數(shù)地址 >>> print hex(e.got['write']) ?# GOT表中write符號的地址 >>> print hex(e.plt['write']) # PLT表中write符號的地址 ? ? ? ? ? ? ? ? ? ? */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? # Pwntools通信 ? ? ? ? ? ? ? ? ? ? p = process('./pwnme') # 本地 process與程序交互 r = remote('exploitme.example.com',3333) ? ?# 遠(yuǎn)程 ? ? ? ? ? ? ? ? ? ? # 交互 recv() # 接收數(shù)據(jù),一直接收 recv(numb=4096,timeout=default) # 指定接收字節(jié)數(shù)與超時(shí)時(shí)間 ? ? ? ? ? ? ? ? ? ? recvuntil("111") # 接收到111結(jié)束,可以裁剪,如.[1:4] recbline() # 接收到換行結(jié)束 recvline(n) # 接收到n個(gè)換行結(jié)束 recvall() # 接收到EOF recvrepeat(timeout=default) #接收到EOF或timeout send(data) # 發(fā)送數(shù)據(jù) sendline(data) # 發(fā)送一行數(shù)據(jù),在末尾會加\n sendlineafter(delims,data) # ? 在程序接收到delims再發(fā)送data ? ? ? ? ? ? ? ? ? r.send(asm(shellcraft.sh())) ?# 信息通信交互 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? r.interactive() # send payload后接收當(dāng)前的shell ? ? ? ? ? ? ? ? ? # 字符串與地址的轉(zhuǎn)換 p64(),p32() ?#將字符串轉(zhuǎn)化為ascii字節(jié)流 u64(),u32() ?#將ascii的字節(jié)流解包為字符串地址 ? ? ? ? ?

      got & plt

      在IDA中選擇view-open subview - segment可以直接查看到got和plt段

      .plt:08048440 ; __unwind { .plt:08048440 ? ? ? ? ? ? ? ? push ? ?ds:dword_804A004 .plt:08048446 ? ? ? ? ? ? ? ? jmp ? ? ds:dword_804A008 ;804A008是got表的地址 .plt:08048446 sub_8048440 ? ? endp


      plt段的某個(gè)地址存放著指令 jmp got


      .got.plt:0804A00C off_804A00C ? ? dd offset printf ? ? ? ?; DATA XREF: _printf↑r .got.plt:0804A010 off_804A010 ? ? dd offset gets ? ? ? ? ?; DATA XREF: _gets↑r .got.plt:0804A014 off_804A014 ? ? dd offset time ? ? ? ? ?; DATA XREF: _time↑r .got.plt:0804A018 off_804A018 ? ? dd offset puts ? ? ? ? ?; DATA XREF: _puts↑r .got.plt:0804A01C off_804A01C ? ? dd offset system ? ? ? ?; DATA XREF: _system↑r .got.plt:0804A020 off_804A020 ? ? dd offset __gmon_start__ .got.plt:0804A020 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; DATA XREF: ___gmon_start__↑r .got.plt:0804A024 off_804A024 ? ? dd offset srand ? ? ? ? ; DATA XREF: _srand↑r .got.plt:0804A028 off_804A028 ? ? dd offset __libc_start_main .got.plt:0804A028 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; DATA XREF: ___libc_start_main↑r .got.plt:0804A02C off_804A02C ? ? dd offset setvbuf ? ? ? ; DATA XREF: _setvbuf↑r .got.plt:0804A030 off_804A030 ? ? dd offset rand ? ? ? ? ?; DATA XREF: _rand↑r .got.plt:0804A034 off_804A034 ? ? dd offset __isoc99_scanf


      got段中存放著程序中函數(shù)的地址,可以避免每次調(diào)用某個(gè)函數(shù)的時(shí)候去libc庫中尋找。


      函數(shù)調(diào)用流程

      找到plt表.plt表存放指令 跳轉(zhuǎn)到got表,got表存放地址,不能填在return的位置 找到對應(yīng)的func_addr 沒有的時(shí)候跳轉(zhuǎn)到libc中取出函數(shù),并緩存到got表


      plt2leakgot

      plt["write"](1,got("write"),4) 通過plt的write函數(shù)leak出got的地址


      libc_csu_init

      • 在所有的64位程序中都含有l(wèi)ibc_csu_init函數(shù)

      .text:0000000000400650 __libc_csu_init proc near ? ? ? ? ? ? ? ; DATA XREF: _start+16↑o .text:0000000000400650 ; __unwind { .text:0000000000400690 .text:0000000000400690 loc_400690: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; CODE XREF: __libc_csu_init+54↓j .text:0000000000400690 ? ? ? ? ? ? ? ? mov ? ? rdx, r13 // 4. 利用點(diǎn),將r13給到了rdx .text:0000000000400693 ? ? ? ? ? ? ? ? mov ? ? rsi, r14 // 5. 控制rsi .text:0000000000400696 ? ? ? ? ? ? ? ? mov ? ? edi, r15d // 6. 控制rdi的低四位 .text:0000000000400699 ? ? ? ? ? ? ? ? call ? ?qword ptr [r12+rbx*8] //7. 給rbx賦0,相當(dāng)于call [r12] .text:000000000040069D ? ? ? ? ? ? ? ? add ? ? rbx, 1 .text:00000000004006A1 ? ? ? ? ? ? ? ? cmp ? ? rbx, rbp .text:00000000004006A4 ? ? ? ? ? ? ? ? jnz ? ? short loc_400690 .text:00000000004006A6 .text:00000000004006A6 loc_4006A6: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; CODE XREF: __libc_csu_init+36↑j .text:00000000004006A6 ? ? ? ? ? ? ? ? add ? ? rsp, 8 .text:00000000004006AA ? ? ? ? ? ? ? ? pop ? ? rbx //1. 控制函數(shù)從這里執(zhí)行 .text:00000000004006AB ? ? ? ? ? ? ? ? pop ? ? rbp .text:00000000004006AC ? ? ? ? ? ? ? ? pop ? ? r12 //8. 給r12添一個(gè)main_addr .text:00000000004006AE ? ? ? ? ? ? ? ? pop ? ? r13 //2. 通過??刂苧13 .text:00000000004006B0 ? ? ? ? ? ? ? ? pop ? ? r14 .text:00000000004006B2 ? ? ? ? ? ? ? ? pop ? ? r15 .text:00000000004006B4 ? ? ? ? ? ? ? ? retn ? //3. ret到 mov ?rdx, r13 .text:00000000004006B4 ; } // starts at 400650 .text:00000000004006B4 __libc_csu_init endp //實(shí)現(xiàn)通過??刂苧dx


      • 目的

        • 在64位提供三個(gè)參數(shù)的用法


      • 利用原理

      程序在啟動(dòng)main函數(shù)之前,都由glibc的標(biāo)準(zhǔn)c庫啟動(dòng),即由libc_csu_init啟動(dòng)main函數(shù) libc_csu_init可以獲得一個(gè)有4個(gè)參數(shù)調(diào)用的地方,比如系統(tǒng)調(diào)用函數(shù)syscall 如syscall—>rax syacall 0x3b ==>execve —>rdi path “/bin/sh” —>rsi argv —>rdx env 通過syscall調(diào)用execve,執(zhí)行execve(“/bin/sh”,null,null),等價(jià)于system(“/bin/sh”) syscall(32位程序?yàn)閕nt80)會根據(jù)系統(tǒng)調(diào)用號查找syscall_table,execve對應(yīng)的系統(tǒng)調(diào)用號是0x3b。 當(dāng)我們給syscall的第一個(gè)參數(shù)即rax中寫入0x3b時(shí)(32位程序?yàn)?xb),就會找到syscall_table[0x3b],即syscall_execve,然后通過execve啟動(dòng)程序。 找syscall和int 80的方法:ROPgadget –binary test –only ‘int/syscall’


      ret2_dl_runtime_resolve

      解決32位無輸出函數(shù)的情況,64位使用IOfile的方式。 找對應(yīng)的plt中的地址 跳轉(zhuǎn)到對應(yīng)的got表中,got中如果有,則執(zhí)行對應(yīng)函數(shù) 如果跳轉(zhuǎn)到的got對應(yīng)位置沒有值,got會向后累加一個(gè)地址,然后跳轉(zhuǎn)到plt[0],壓入兩個(gè)參數(shù),一個(gè)是index,一個(gè)是與DYNAMIC有關(guān)的參數(shù),稱為link_map(動(dòng)態(tài)鏈接用到的名字,如puts),然后再調(diào)用dl_runtime_resolve(link_map_obj,reloc_index) push ? ?cs:qword_602008 .plt:00000000004007A6 ? ? ? ? ? ? ? ? jmp ? ? cs:qword_602010 dl_runtime_resolve實(shí)際上是一個(gè)解析實(shí)際地址的函數(shù),根據(jù)函數(shù)名稱做解析,然后寫回到plt的index對應(yīng)的got 調(diào)用完之后,會根據(jù)參數(shù)調(diào)用解析出來的地址,比如解析出來的puts函數(shù),那么會調(diào)用puts函數(shù),并且寫入puts_got中 結(jié)束后,接著運(yùn)行程序 因此,我們向DYNAMIC中寫入puts字符串就可以了


      二進(jìn)制安全之棧溢出的評論 (共 條)

      分享到微博請遵守國家法律
      伊金霍洛旗| 宜城市| 昌宁县| 邓州市| 喀喇沁旗| 井冈山市| 德江县| 昭觉县| 名山县| 石渠县| 松阳县| 旺苍县| 宁国市| 邵东县| 泾源县| 双峰县| 潼关县| 贵阳市| 普安县| 大埔县| 大方县| 鄂托克旗| 昌吉市| 卢龙县| 龙陵县| 彩票| 广汉市| 景谷| 隆林| 屏东市| 曲沃县| 巴南区| 张家港市| 通州市| 五常市| 五原县| 会泽县| 太仓市| 九江县| 东丰县| 炎陵县|