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