دنبال کردن یک داده در کل برنامه
تا اینجا با Forward Slicing و Backward Slicing یاد گرفتیم چطور مسیر داده رو پیدا کنیم
حالا یه قدم جلوتر میریم
Taint Analysis
یعنی یه داده مشخص رو علامت گذاری کنیم و بعد ببینیم این داده توی ادامه برنامه کجاها میره و روی چه چیزهایی تاثیر میذاره
فرض کنید برنامه یه ورودی میگیره:
C
int input = get_input();
ما
input رو Tainted در نظر میگیریمیعنی فعلا فرض میکنیم
input = TAINTED
حالا اگه این مقدار وارد یه محاسبه بشه
int x = input + 10;
پس
input
↓
x
x هم Tainted حساب میشهاگه بعدا داشته باشیم
C
int y = x * 5;
مسیر میشه
input
↓
x
↓
y
پس
y هم تحت تاثیر ورودی اولیه قرار گرفتهحالا اگه داشته باشیم
C
int result = y ^ 0x55;
مسیر میشه
input
↓
x
↓
y
↓
result
و اگه آخرش داشته باشیم
if (result == 100)
میفهمیم ورودی اولیه روی این شرط تاثیر گذاشته
این یکی از کاربردهای مهم Taint Analysis هست
یک مثال ساده:
C
int check(int input)
{
int x = input ^ 0x55;
int y = x + 10;
int temp = 500;
temp *= 20;
if (y == 100)
return 1;
return 0;
}
ما
input رو Tainted میکنیمپس مسیرش میشه
input
↓
x
↓
y
↓
comparison
ولی این قسمت
temp
↓
temp * 20
به شرط نهایی وصل نیست
پس Taint هم بهش منتقل نمیشه
یعنی
temp همچنان Clean هستTaint
توی Assembly
وقتی وارد Reverse Engineering میشیم معمولا دیگه متغیری به اسم
input نداریمممکنه چیزی شبیه این ببینیم
mov eax, [rbp-20h]
xor eax, 55h
add eax, 10
cmp eax, 100
فرض کنیم
json
[rbp-20h] = ورودی
پس مسیر داده میشه
[rbp-20h]
↓
EAX
↓
XOR 55h
↓
ADD 10
↓
CMP 100
اینجا میتونیم ببینیم ورودی مستقیم وارد محاسبات شده و در نهایت به مقایسه رسیده
Taint
فقط برای ورودی کاربر نیست
هر داده ای میتونه نقطه شروع Taint باشه
مثلا:
Powershell
File Data
Network Data
Configuration
Function Argument
Registry Value
Environment Variable
مثلا اگه یه تابع اینو بگیره
C
void process(char *data)
میتونیم
data رو نقطه شروع قرار بدیمبعد دنبال کنیم که این داده توی ادامه برنامه وارد چه توابعی میشه
ممکنه مسیرش این شکلی باشه
Input
↓
Parser
↓
Transformation
↓
Function A
↓
Function B
↓
Comparison
یا حتی
Input
↓
Buffer
↓
Memory
↓
Function
↓
Output
یه نکته مهم
Taint Analysis
یعنی لزوما مقدار دقیق اولیه همونطوری باقی مونده نه
ممکنه مقدار چند بار تغییر کنه
مثلا:
Input
↓
XOR
↓
ADD
↓
SHIFT
↓
SUB
↓
Comparison
چیزی که دنبال میکنیم اینه که ببینیم مقدار جدید هنوز به داده اولیه وابسته هست یا نه
یعنی سؤال اصلی اینه
آیا این مقدار تحت تاثیر داده Tainted قرار گرفته
نه اینکه
آیا مقدار دقیقا همون مقدار اولیه عسا
به انتقال Taint از یه مقدار به مقدار دیگه میگیم
Taint Propagation
مثلا
a = input;
b = a + 5;
c = b ^ 0x44;
مسیرش میشه
input
↓
a
↓
b
↓
c
یعنی Taint همراه داده حرکت میکنه
ولی اگه داشته باشیم
C++
int x = 100;
int y = x + 20;
چون
x از Input نیومدهx = CLEAN
y = CLEAN
پس Taint وارد این مسیر نمیشه
حالا یه مثال واقعی تر
فرض کنید یه تابع پیچیده داریم
Function
│
├── Input
├── Calculation A
├── Junk Code
├── Function B
├── Calculation C
├── Comparison
└── Return
اگه ورودی رو Tainted کنیم ممکنه بعد از تحلیل به این نتیجه برسیم
Input
↓
Calculation A
↓
Function B
↓
Calculation C
↓
Comparison
و بخش Junk Code اصلاً توی مسیر Taint نباشه
اینجا دقیقا میبینیم چرا Taint Analysis در کنار Slicing خیلی قدرتمنده
Slicing میگه
چه چیزهایی به این نقطه مربوط میشن
Taint Analysis میگه
این داده مشخص کجاها رفته و روی چه چیزهایی تاثیر گذاشته
این دوتا خیلی به هم نزدیکن ولی دقیقا یکی نیستن
تمرین:
این تابع رو بررسی کنید
C
int verify(int input)
{
int a = input ^ 0x31;
int junk = 900;
junk *= 5;
int b = a + 20;
int temp = 100;
temp ^= 55;
int result = b * 3;
return result == 300;
}
فرض کنید فقط
input رو Tainted کردیمحالا مسیر Taint رو مشخص کنید
input
↓
?
↓
?
↓
?
↓
comparison
و مشخص کنید کدوم متغیرها اصلا نباید Tainted بشن
@reverseengine