2013-07-21 29 views
31

Tôi đang dùng CentOS 6.4 32 bit và đang cố gắng gây tràn bộ đệm trong chương trình. Trong GDB nó hoạt động. Đây là kết quả đầu ra:Lỗi tràn bộ đệm hoạt động trong gdb nhưng không có nó

[[email protected] bufferoverflow]# gdb stack 
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1) 
Copyright (C) 2010 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law. Type "show copying" 
and "show warranty" for details. 
This GDB was configured as "i686-redhat-linux-gnu". 
For bug reporting instructions, please see: 
<http://www.gnu.org/software/gdb/bugs/>... 
Reading symbols from /root/bufferoverflow/stack...done. 
(gdb) r 
Starting program: /root/bufferoverflow/stack 
process 6003 is executing new program: /bin/bash 
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.107.el6_4.2.i686 
sh-4.1# 

Tuy nhiên khi tôi chạy ngăn xếp chương trình chỉ trên riêng nó, nó bị lỗi. Tại sao điều này có thể?

+0

'seg faults' là do tràn bộ nhớ đệm, bạn đã làm, chính xác Khi bạn chạy hệ điều hành mã của bạn gửi SIGSEGV đến quá trình của bạn (= chương trình trong thực hiện) về vi phạm bộ nhớ mà cung cấp cho bạn thông điệp Segmentation Fault - tín hiệu này là do để bạn đang truy cập không hợp lệ vào bộ nhớ hợp lệ. (Tôi đoán bạn đang cố gắng để viết/sửa đổi trên '" constantstring "' ở cuối) –

+0

... Tôi biết điều đó. Nó là vụ phải thực hiện một vỏ. Trong GDB nó thực thi shell. Khi tôi chạy chương trình bên ngoài GDB nó không chạy vỏ, do đó segfault – thaweatherman

+0

điều này là bởi vì khi bạn chạy mã của bạn bên ngoài GDB nó - nó không xác định hành vi trong tiêu chuẩn C. Trong khi GDB xử lý tín hiệu SIGSEGV để nó có thể cho bạn điểm đến lỗi phân đoạn –

Trả lời

77

Phát triển khai thác có thể dẫn đến những cơn đau đầu nghiêm trọng nếu bạn không tính toán đầy đủ các yếu tố giới thiệu e không xác định vào quá trình gỡ lỗi. Cụ thể, địa chỉ ngăn xếp trong trình gỡ lỗi có thể không khớp với địa chỉ trong quá trình thực thi thông thường. hiện tượng này xảy ra bởi vì hệ điều hành nạp đặt cả hai biến môi trường và lập luận chương trình trước đầu của ngăn xếp:

Process layout

Kể từ khi chương trình dễ bị tổn thương của bạn không mất bất kỳ đối số, các biến môi trường có nhiều khả năng thủ phạm . Mare chắc chắn rằng họ là như nhau trong cả hai invocations, trong vỏ và trong trình gỡ lỗi. Để kết thúc này, bạn có thể quấn gọi của bạn trong env:

env - /path/to/stack 

Và với trình gỡ lỗi:

env - gdb /path/to/stack 
($) show env 
LINES=24 
COLUMNS=80 

Trong ví dụ trên, có hai biến môi trường được thiết lập bởi gdb, mà bạn có thể tiếp tục vô hiệu hóa :

unset env LINES 
unset env COLUMNS 

Bây giờ show env phải trả về danh sách trống. Tại thời điểm này, bạn có thể bắt đầu quá trình gỡ lỗi để tìm địa chỉ ngăn xếp tuyệt đối mà bạn hình dung để nhảy tới (ví dụ: 0xbffffa8b) và mã hóa nó vào khai thác của bạn.

Một chi tiết tinh tế nhưng quan trọng khác: có sự khác biệt giữa việc gọi ./stack/path/to/stack: vì argv[0] giữ chương trình chính xác cách bạn gọi, bạn cần đảm bảo chuỗi yêu cầu bằng nhau. Đó là lý do tại sao tôi đã sử dụng /path/to/stack trong các ví dụ trên và không chỉ là ./stackgdb stack.

Khi học tập để khai thác với các lỗ hổng an toàn trí nhớ, tôi khuyên bạn nên sử dụng chương trình wrapper dưới đây, mà làm việc nặng nhọc và đảm bảo ngăn xếp offsets bằng:

$ invoke stack   # just call the executable 
$ invoke -d stack  # run the executable in GDB 

Đây là kịch bản:

#!/bin/sh 

while getopts "dte:h?" opt ; do 
    case "$opt" in 
    h|\?) 
     printf "usage: %s -e KEY=VALUE prog [args...]\n" $(basename $0) 
     exit 0 
     ;; 
    t) 
     tty=1 
     gdb=1 
     ;; 
    d) 
     gdb=1 
     ;; 
    e) 
     env=$OPTARG 
     ;; 
    esac 
done 

shift $(expr $OPTIND - 1) 
prog=$(readlink -f $1) 
shift 
if [ -n "$gdb" ] ; then 
    if [ -n "$tty" ]; then 
    touch /tmp/gdb-debug-pty 
    exec env - $env TERM=screen PWD=$PWD gdb -tty /tmp/gdb-debug-pty --args $prog "[email protected]" 
    else 
    exec env - $env TERM=screen PWD=$PWD gdb --args $prog "[email protected]" 
    fi 
else 
    exec env - $env TERM=screen PWD=$PWD $prog "[email protected]" 
fi 
+1

tôi đã làm như bạn đề nghị và chạy chương trình như là/root/bufferflow/chồng và nó làm việc đúng cách. Cảm ơn – thaweatherman

+0

Ví dụ là sai. Thay vì '--gdb' thì phải có '-d'. – molnarg

+0

@molnarg: Cảm ơn, đã sửa. – mavam

0

Một trong những điều chính mà gdb thực hiện không xảy ra bên ngoài gdb là bộ nhớ zero. Nhiều hơn khả năng một nơi nào đó trong mã bạn không khởi tạo bộ nhớ của bạn và nó đang nhận được giá trị rác thải. Gdb tự động xóa tất cả bộ nhớ mà bạn phân bổ ẩn các loại lỗi đó.

Ví dụ: sau nên làm việc trong gdb, nhưng không phải bên ngoài nó:

int main(){ 
    int **temp = (int**)malloc(2*sizeof(int*)); //temp[0] and temp[1] are NULL in gdb, but not outside 
    if (temp[0] != NULL){ 
     *temp[0] = 1; //segfault outside of gdb 
    } 
    return 0; 
}

Thử chạy chương trình của bạn dưới valgrind để xem nếu nó có thể phát hiện vấn đề này.

+0

Chương trình dễ bị tổn thương thực sự đọc trong một tệp vào bộ đệm, do đó tệp là chuỗi khai thác. Sau đó nó gọi một hàm thực hiện một strcpy của bộ đệm gốc thành một bộ đệm nhỏ hơn nhiều. Vì vậy, nó không bao giờ khởi tạo bộ nhớ bên ngoài các chức năng đó – thaweatherman

6

Lý do tràn bộ đệm của bạn hoạt động theo gdb và segfaults nếu không, gdb sẽ tắt ngẫu nhiên bố cục không gian địa chỉ. Tôi tin rằng điều này đã được bật theo mặc định trong phiên bản gdb 7.

Bạn có thể kiểm tra điều này bằng cách chạy lệnh này:

show disable-randomization 

Và thiết lập nó với

set disable-randomization on 

hoặc

set disable-randomization off 
+1

Nó bị tắt trong GDB. Tôi cũng nghĩ rằng tôi tắt nó đi trong OS với sysctl -w kernel.randomize_va_space = 0 – thaweatherman

0

Tôi đang dùng CentOS 6.4 32 bit và đang cố gắng gây tràn bộ đệm trong một chương trình ... Tuy nhiên, khi tôi chạy chương trình ngăn xếp, chỉ có lỗi seg.

Bạn cũng nên đảm bảo FORTIFY_SOURCE không ảnh hưởng đến kết quả của bạn. Lỗi seg có vẻ như FORTIFY_SOURCE có thể là vấn đề vì FORTIFY_SOURCE sẽ chèn các cuộc gọi hàm "an toàn hơn" để bảo vệ chống lại một số loại tràn bộ đệm. Nếu trình biên dịch có thể suy ra kích thước bộ đệm đích, thì kích thước được chọn và abort() được gọi là vi phạm (tức là lỗi seg của bạn).

Để tắt FORTIFY_SOURCE để thử nghiệm, bạn nên biên dịch với -U_FORTIFY_SOURCE hoặc -D_FORTIFY_SOURCE=0.

6

Địa chỉ của con trỏ khung ngăn xếp khi chạy mã trong gdb khác với chạy bình thường. Vì vậy, bạn có thể làm hỏng địa chỉ trả về ngay trong chế độ gdb, nhưng nó có thể không đúng khi chạy ở chế độ bình thường. Lý do chính cho điều đó là các biến môi trường khác nhau giữa hai tình huống.

Vì đây chỉ là bản trình diễn, bạn có thể thay đổi mã nạn nhân và in địa chỉ của bộ đệm. Sau đó thay đổi địa chỉ trả về của bạn để bù đắp + địa chỉ của bộ đệm.

Trong thực tế, tuy nhiên, bạn cần phải đoán địa chỉ trả lại thêm NOP sled trước mã độc hại của bạn. Và bạn có thể đoán nhiều lần để có được một địa chỉ chính xác, vì dự đoán của bạn có thể không chính xác.

Hy vọng điều này có thể giúp bạn.

1

Tôi đã thử giải pháp được chấp nhận ở đây và nó không hoạt động (đối với tôi). Tôi biết rằng gdb thêm biến môi trường và vì lý do đó địa chỉ ngăn xếp không khớp, nhưng thậm chí loại bỏ các biến đó tôi không thể khai thác mà không có gdb (tôi cũng đã thử kịch bản được đăng trong giải pháp được chấp nhận).

Nhưng tìm kiếm trong các trang web tôi thấy kịch bản khác mà làm việc cho tôi: https://github.com/hellman/fixenv/blob/master/r.sh

Việc sử dụng về cơ bản là giống nhau mà kịch bản trong các giải pháp được chấp nhận:

  • r.sh gdb ./program [ args] để chạy các chương trình trong gdb
  • r.sh ./program [args] để chạy chương trình mà không cần gdb

Và kịch bản này làm việc cho tôi.

1

Đây là một cách đơn giản chạy chương trình của bạn với ngăn xếp giống hệt nhau trong nhà ga và trong gdb:

tiên, đảm bảo chương trình của bạn được biên dịch mà không bảo vệ chồng,

gcc -m32 -fno-stack-protector -z execstack -o shelltest shelltest.c -g

và và ASLR bị tắt:

echo 0 > /proc/sys/kernel/randomize_va_space

GHI CHÚ: giá trị mặc định trên máy của tôi là 2, lưu ý trước khi thay đổi giá trị này.

Sau đó chạy chương trình của bạn như vậy (thiết bị đầu cuối và gdb tương ứng):

env -i PWD="/root/Documents/MSec" SHELL="/bin/bash" SHLVL=0 /root/Documents/MSec/shelltest 
env -i PWD="/root/Documents/MSec" SHELL="/bin/bash" SHLVL=0 gdb /root/Documents/MSec/shelltest 

Trong gdb, hãy chắc chắn để unsetLINESCOLUMNS.

Lưu ý: Tôi đã nhận những biến môi trường bằng cách chơi xung quanh với một test program.

Hai lần chạy này sẽ cung cấp cho bạn các con trỏ giống hệt nhau ở đầu ngăn xếp, vì vậy không cần phải viết lệnh từ xa nếu bạn đang cố gắng khai thác một tệp nhị phân được lưu trữ từ xa.

Các vấn đề liên quan