Đánh giá sơ lược về binary:
~/Sources/CTFs/hackim » file mixme peternguyen@peternguyen mixme: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=b93d20dd523097dd7d53a7fda265a2d977d29c30, stripped
Checksec:
Chương trình có 3 lệnh chính: (store/edit/get)
Phân tích hàm edit
Đựa trên hàm store, mình có thể reverse lại được cấu trúc lưu trữ của chương trình như sau:
struct node{ char name[16]; int size; char *data; struct node *next; struct node *prev; }
size là khích cỡ vùng nhớ được malloc cho data.
Các node được lưu trữ bằng một danh sách double linked list circular
Vùng nhớ tổ chức trong mem như sau (tạo 2 block với data size = 16:
Gồm 3 block: block head được khởi tạo mặc định khi chạy chương trình.
Để ý phần data của block được cấp phát là 1 đoạn đằng sau block, tôi sẽ đề cập sau ở phần khai thác lỗi.
Phân tích hàm edit
Nhập name,và size, hàm sẽ duyệt qua linked list để tìm ra block có tên tương ứng, và cập nhật lại phần data.
Để ý phần sau:
Chương trình đọc từ stdin vào data nbytes, mà nbytes không check length.
Nếu tạo 2 block liền nihau thì, phần tiếp theo phần data của block 1 là block2 nên ta có thể overwrite được cái block 2.
Phân tích hàm get:
Nhập vào tên block và size, tìm ra block tương ứng, in phần data ra màn hình, free vùng data và block, cập nhật lại linked list. Để ý write(1,node->data,n); mình sẽ dùng nó để leak addr
Khai thác lỗi.
Ở đây mình sẽ overwrite địa chỉ data bằng địa chỉ của một hàm trong bảng got bằng cách lợi dụng phần read(0,node->data,node->size)
Để ý hàm free(node->data) nhận input là phần data nhập vào, ý tưởng là overwrite free trong bảng got là system và ta có, system(node->data).
Payload của mình làm theo các bước như sau:
- Tạo ra 2 block peter123,lol123 với data size của mỗi block là 16 bytes
- edit block peter123: với size 56, 'D'*28 + '\x00' * 16 + 'CCCC', với CCCC => địa chỉ hàm free, sở dĩ mình padd '\x00'*16 byte để làm name của block2 = 'DDDD'.
- edit block 2 ('DDDD') với size 4 bytes để ghi đè free trong bảng got ở đây mình ghi đè got bằng địa chỉ của lệnh ret, mục đích là để bypass qua hàm free, vì mình lợi dụng lệnh ret để leak 1 địa chỉ trong bảng GOT.
- get block 2('DDDD') minh sẽ leak được 1 địa chỉ trong bảng GOT, từ đó tính được địa chỉ hàm system.
- Tạo tiếp 2 block bất kì (b1,b2) với data size của mỗi block là 16 bytes
- edit block1('b1') ghi đè địa chỉ data của block 2 bằng địa chỉ free một lần nữa
- edit block2() để ghi đè free bằng system.
- Tạo ra block 'shell' với phần data='/bin/sh'
- get block('shell') và boom đã có được shell
Payload: http://pastebin.com/n2G30Fk4