قسمت سی و سوم بافر اورفلو
Taint Analysis on Binary
در Assembly از کجا بفهمیم داده کجا میره
میخوایم Taint Analysis رو روی باینری اجرا کنیم
اینجا دیگه خبری از اسم متغیر های مثل
input و buffer نیستباید با Registerها و ادرسهای حافظه کار کنیم
پیدا کردن Source
اول باید بفهمیم داده از کجا وارد برنامه شده مثلا داخل یک برنامه لینوکسی ممکنه به این برسیم
call read
یا
call recv
فرض کنید قبلش اینو داریم
lea rsi,[rbp-40h]
mov edx,40h
call read
اینجا میتونیم مسیر سادهای داشته باشیم
External Input
↓
read()
↓
[rbp-40h]
پس داده ورودی داخل
[rbp-40h] قرار میگیرهاین نقطه میتونه Source ما باشه
دنبال کردن داده
حالا چند دستور پایین تر میبینیم
mov rax,[rbp-40h]
mov rcx,rax
پس مقدار از حافظه اومده داخل
RAXبعد وارد
RCX شدهمسیر فعلا اینه
[rbp-40h]
↓
RAX
↓
RCX
دنبال کردن انتقال داده
فرض کنید بعدش اینو ببینیم
mov rdx,rcx
call process_data
حالا
[rbp-40h]
↓
RAX
↓
RCX
↓
RDX
↓
process_data()
یعنی دادهای که از بیرون اومده وارد
process_data شدهحالا باید داخل اون تابع ادامه مسیر رو دنبال کنیم
رسیدن به Sink
فرض کنید داخل تابع به این برسیم
mov [rdi],rax
اینجا یک Memory Write داریم
پس مسیر کلی ما میشه
Input
↓
read()
↓
Stack / Memory
↓
Register
↓
Function
↓
Memory Write
این نقطه میتونه Sink موردنظر ما باشه
البته رسیدن داده به یک Write به تنهایی به معنی وجود آسیب پذیری نیست
باید اندازه و محدوده دسترسی هم بررسی بشه
Taint
کردن Register ها
فرض کنید
mov rax,[rbp-40h]
و [rbp-40h] شامل داده خارجی باشه
پس
RAX = Tainted
بعد
mov rcx,rax
حالا
RCX = Tainted
بعد
add rcx,8
مقدار RCX تغییر کرده ولی همچنان به داده اولیه وابسته است
پس مسیر Taint قطع نشده
اما یک نکته مهم
همه دستورها باعث انتقال ساده Taint نمیشن
مثلا:
cmp rax,10h
اینجا داده مستقیما به Register دیگری منتقل نشده
ولی مقدار RAX روی تصمیم برنامه تاثیر گذاشته
مثلا:
cmp rax,10h
ja invalid
پس اینجا یک Control Dependency داریم یعنی داده خارجی روی مسیر اجرای برنامه اثر گذاشته
یک مثال کامل تر:
lea rsi,[rbp-40h]
mov edx,40h
call read
movzx eax,byte ptr [rbp-40h]
cmp eax,20h
ja invalid
mov edi,eax
call process_data
مسیر رو مرحله به مرحله ببینید
read()
↓
[rbp-40h]
↓
EAX
↓
cmp
↓
Control Flow
↓
process_data()
اینجا مقدار ورودی هم روی داده تاثیر گذاشته
هم روی مسیر اجرای برنامه
در Ghidra چه کار میکنیم
وقتی به یک مقدار مشکوک رسیدیم
اول References اون مقدار رو بررسی میکنیم بعد استفادههای بعدی رو پیدا میکنیم
مثلا:
Source
↓
Reference
↓
Register
↓
Memory Access
↓
Function Call
بعد همین کار رو برای تابع بعدی ادامه میدیم تا مسیر کامل مشخص بشه یک نکته مهم لازم نیست همیشه کل Taint Analysis رو دستی انجام بدید
در برنامه های بزرگ این کار خیلی سخت میشه برای همین ابزارهای مختلفی وجود دارن که میتونن این کار رو تا حدی خودکار کنن
مثلا:
angr
Triton
DynamoRIO
Intel Pin
هرکدوم روش و کاربرد خودشون رو دارن
@reverseengine