Atak SQL Injection w usłudze Power BI
Zdaję sobie sprawę, że taki temat może być oczywistością dla wielu doświadczonych inżynierów danych czy SQLowców, ale mnie mocno zaskoczył. Nasz architekt Paweł Potasiński zwrócił mi uwagę na taką możliwość. W kontrolowanym środowisku Power BI pozwala na wstrzyknięcie kodu SQL poprzez parametr i robienie (prawie) wszystkiego na co ma się ochotę – nawet usunięcie bazy danych! O SQL Injection można poczytać tutaj lub obejrzeć ten filmik. A o moich skryptach w M tu lub tu.
Pierwotnie zadanie polegało na umożliwieniu zmiany liczby pobieranych wierszy z bazy. Mając możliwość modyfikacji parametrów w usłudze Power BI, nie wydawało się to trudne. Aby zadeklarować parametr wyklikałem taki kod:
1 |
"1" meta [IsParameterQuery=true, Type="Number", IsParameterQueryRequired=true] |
Ważne jest ustawienie tego jako liczbę albo inny typ. Tylko wtedy jest możliwość zmiany parametru w usłudze Power BI.
Następnie w M dodałem zapytanie SQL:
1 2 3 4 5 |
let Source = Sql.Database("", "", [Query="SELECT TOP " & Text.From(Number_of_rows)&" * FROM [dbo].[tblAuthors]"]) in Source |
Działało to dobrze. Następnie razem z Pawłem zmieniliśmy typ parametru na “Text” i ustawiliśmy jego wartość na :
1 |
100 * FROM Sys.Tables-- |
Dodam, że login i hasło w wykorzystywanym środowisku miały pełny dostęp, więc rezultat łatwy do przewidzenia:
Postanowiłem eksperymentować dalej i zobaczyć, jak daleko zajdę. Po opublikowaniu raportu do usługi, zmieniłem wartość parametru tak jak to zrobiłem w Power BI Desktop:
I otrzymałem błąd:
Wydaje się, że Power BI oczekuje takich samych kolumn podczas odświeżania danych. Oczywiście spróbowałem obejść to ograniczenie. W tym wypadku można użyć też zwykłego UNIONa.
1 |
100 name as Author_name, object_id as id, schema_id as country FROM Sys.tables--" |
Parametr nie będzie zawsze przed “FROM”. Czasami będzie w procedurze składowanej albo w części WHERE. Co się dzieje kiedy dodamy drugie zapytania po średniku? Jeśli damy zapytanie SELECT, dostaniemy tylko pierwszy jako wynik. Natomiast innego rodzaju zapytania zostaną wykonane, ale bez widocznej informacji zwrotnej. Bez większych oczekiwań zacząłem od największego kalibru:
I to zadziałało:
Zapytanie wykonuje się bez żadnych błędów, co jest niepokojące. Zgodnie z dokumentacją “Musisz być podłączony do bazy danych master, żeby usunąć bazę danych” i “Zapytanie DROP DATABASE musi być jedynym zapytaniem jakie jest wykonywane w danej transzy”. Ani pierwsza, ani druga rzecz się nie sprawdzają w tym wypadku. Będę jeszcze analizował, jak Power BI wysyła zapytania do bazy. Nie mniej jednak, można całą sprawę traktować jako ciekawostkę, ponieważ nie można zmieniać wartości parametru bez dostępu do bazy. Będę jeszcze się eksperymentował w wolnym czasie, ale proszę o kontakt w wypadku podobnego oszukania Power BI!
Dzięki