Chủ Nhật, 3 tháng 6, 2018

Tản mạn về lỗi Format String


 Hôm nay tôi sẽ nói với mấy ông về lỗ hổng format string. Đây là bài đầu tiên trong blog nên tôi sẽ viết một bài khá đơn giản. Tôi cũng không chắc chắn tất cả xưới đây là đúng. Chỉ là những gì tôi hiểu về kiến thức này và tôi sẽ nói hết với mấy ông.

Lỗi Fmt xuất hiện khi ở các họ printf. Nếu như ta truyền trực tiếp địa chỉ của biến vào hàm printf thay vì truyền định dạng+ địa chỉ thì chương trình của ta sẽ bị lỗi Fmt.

Tác hại của nó ntn à. Hacker có thể thay đổi code của trương trình và có thể nhảy tới các hàm mà hacker muôn nếu có thể. Nguy hiểm hơn là có thể chiếm quyền điều khiển máy có dịch vụ bị lỗi FmT

Làm tý ví dụ nhé :3


Code chương trình
Đây là khi thực thi
Nó đã leak ra 1 số địa chỉ rồi kìa LUL
Vậy %p là gì ??
Nôm na là kiểm định dạng dữ liệu đầu ra của C.(đọc thêm ở đây: http://www.cplusplus.com/reference/cstdio/printf/ )
Nhưng theo tôi thì chỉ nên chú ý tới 3 thứ đó là:
%p: con trỏ địa chỉ
$: offset
%n: in ra số kí tự đã xuất ra từ trước tới giờ. Và thật chùng hợp là nó lại lưu kết quả lại offset mà $ trỏ tới.

Giới thiệu thế thôi. Debug nào. Mình dùng GDB.
Tôi compile file dạng 64bit nên các tham số truyền vào khi gọi lệnh call là trên thanh ghi. (tham khảo ở đây http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/

Break tại hàm printf


Bây giờ đến đoạn sử dụng mấy cái % kia này.
Giả sử tôi chuyền vào “%1$p” tham số đầu tiên là RDI thì RDi sẽ lưu ‘%1$p’ như hình ở trên.
Tiếp theo đến phần offset thì 1$ nghĩa là offset thứ nhất kể từ RDI đi. Và theo bảng thì nó chính là RSI. Và cuối cùng là “p” nghĩa là xuất đầu ra dưới dạng 1 con trỏ. Vậy sau khi truyền vào “%1$p” thì chương trình sẽ in ra địa chỉ mà thanh ghi RSI lúc đó.

Nhưng vấn đề là thì sao ??
Sau khi offset chỏ hết các thanh ghi. Thì nó sẽ bắt đầu quay về stack. Để đơn gian thì tôi sẽ giải thích bằng ví dụ.
Mấy ông có thấy trên kia là trên kia có 5 thanh ghi không. Bây giờ tôi sẽ tang giá trị offset lên là 7 xem nó trả về gì nhé.

Thấy không nó trỏ đến đầu của đoạn mình nhập vào rồi. nhưng mà sao ta lại muốn xem thứ mình đã nhập vào làm gì @@
Thì câu trả lời là %n: như đã giải thích ở trên (in ra số kí tự đã xuất ra từ trước tới giờ. Và thật chùng hợp là nó lại lưu kết quả lại offset mà $ trỏ tới.) thì nghĩa là nếu thứ mà offset trở tới là 1 địa chỉ thay vì ‘’ 0x6161616162626262” thì ta có thể sửa giá trị ở địa chỉ đó bằng độ dài đoạn đã in từ trước đến %n
Khó hiểu nhỉ. Thử tiếp này.
Dùng python để truyền địa chỉ vào.

%9c là để in ra 1 đoạn độ dài = 9. Kết hợp với %n và trỏ tớ offset thứ 7 là địa chỉ “0x00601000” thì nghĩa là nó sẽ ghi 9 vào địa chỉ đó thỉ nhé.

Thì đây là kết quả sau khi chạy xong

Thấy hay chưa :3 nghĩa là từ cái này, mấy ông có thể sửa trực tiếp địa chỉ chương trình các vùng có quyền ghi. Thì có thể điều khiên chương trình theo ý muốn của mình rồi.
Ý tưởng là mình sẽ ghi đè vào bang GOT (tham khảo ở đây https://en.wikipedia.org/wiki/Global_Offset_Table)
Nôm na là 1 cái bảng chưa những địa chỉ mà khi dùng lệnh call nó sẽ nhảy vào địa chỉ đó.
Ví dụ của printf nhé
Nó call đến 0x400470

và nó lại nhảy đến 0x601018 (đây là bảng GOT)

Nếu như ghi đè vào đây thì khi gọi đến printf thì chương trình sẽ nhảy đến 1 chỗ khác thay vì 0x400476
Thử luôn nhé.
Tôi thử với got của hàm exit 0x601030

Kết quả:

Chương trình bị lỗi do nó nhảy đến GOT của exit và ở đây chỉ lưu giá trị 0x9

Xong kiến thức cơ bản của FmT. Bài tiếp theo sẽ là sriteup của 1 bài CTF có lỗi này. Bye!

Không có nhận xét nào:

Đăng nhận xét