Mostrando entradas con la etiqueta nc. Mostrar todas las entradas
Mostrando entradas con la etiqueta nc. Mostrar todas las entradas

martes, 15 de marzo de 2016

TCP Keep Alive - how it works

Besides being a short entry this will be the first one in English. Why? mmmm, good question, not sure to be honest. I suppose English will make the entries accessible to more people and that is good reason enough :D to me, I'm not saying all of them will be in English from now on (who knows haha).

So a few days ago I faced an awkward situation that kind of pushed me to see how the TCP keep alive feature works on the Linux Kernel. Nothing life changing, but I wanted to share it here for you out there and for me as well xD, is fun how many times I come back to my old entries looking for commands or answers :D.

The problem was quite simple, on the server side a simple netstat showed more than 20k TCP connections on ESTABLISHED state. However all the clients that had started these connections were shutdown... yes, shutdown, they weren't even online. So, how is this possible? Well, you will understand it after this entry, hopefully XD.

Kernel TCP keep-alive configuration


Our lovely Kernel provides 3 parameters to handle TCP keep-alive behavior:
  • tcp_keepalive_time: number of seconds a connection needs to be idle before keep-alive tests begin. The default value is 7200 (2 h), this parameter is valid ONLY if the option SO_KEEPALIVE is set on the socket.
  • tcp_keepalive_intvl: once the keep-alive tests begin, this value states the number of seconds between each test. The default value is 75 (1min 15 sec).
  • tcp_keepalive_probes: the number of probes that must fail before the connection gets terminated. The default value is 9.
Like every Kernel parameter we can access these 3 guys through the /proc FS, here you have them on one of the test instances:

[root@ip-172-31-24-218 ec2-user]# cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75
[root@ip-172-31-24-218 ec2-user]# cat /proc/sys/net/ipv4/tcp_keepalive_probes
9
[root@ip-172-31-24-218 ec2-user]# cat /proc/sys/net/ipv4/tcp_keepalive_time
7200
[root@ip-172-31-24-218 ec2-user]#


 The test scenario is the following:

The test scenario consists of basically 2 EC2 instances:
  • A, IP 172.31.24.219. This will be the source of the connections.
  • B, IP 172.31.24.218. This will be the so called server instance.
to speed up the tests I reduced, on instance B, tcp_keepalive_time from 7200 to 10, the following way:

[root@ip-172-31-24-218 ec2-user]# echo 10 > /proc/sys/net/ipv4/tcp_keepalive_time
[root@ip-172-31-24-218 ec2-user]# cat /proc/sys/net/ipv4/tcp_keepalive_time
10
[root@ip-172-31-24-218 ec2-user]#


Test 1 "Testing keep-alive"


To simulate the server I used the well known TCP swiss army knife, nc :P (same on the client side nc 172.31.24.218 3333). Basically started nc in background listening on port 3333 on instance B and then started tcpdump to capture the traffic coming to that port from instance A:

[ec2-user@ip-172-31-24-218 ~]$ nc -l 3333 &
[1] 2536
[ec2-user@ip-172-31-24-218 ~]$ sudo tcpdump -nn port 3333
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
19:27:27.477761 IP 172.31.24.219.42115 > 172.31.24.218.3333: Flags [S], seq 2777265429, win 26883, options [mss 8961,sackOK,TS val 260487 ecr 0,nop,wscale 6], length 0
19:27:27.477983 IP 172.31.24.218.3333 > 172.31.24.219.42115: Flags [S.], seq 2747775912, ack 2777265430, win 26847, options [mss 8961,sackOK,TS val 260850 ecr 260487,nop,wscale 6], length 0
19:27:27.478456 IP 172.31.24.219.42115 > 172.31.24.218.3333: Flags [.], ack 1, win 421, options [nop,nop,TS val 260488 ecr 260850], length 0



^C
3 packets captured
3 packets received by filter
0 packets dropped by kernel

[1]+  Stopped                 nc -l 3333
[ec2-user@ip-172-31-24-218 ~]$ date
Tue Mar 15 19:33:09 UTC 2016
[ec2-user@ip-172-31-24-218 ~]$


mmmm, I've colored with blue the TCP Handshake, and you can see that between the time the connection was established 19:27:27 and the date command 19:33:09 we have more than 5 minutes. Not even one single packet was exchanged between the instances, so why didn't the keep-alive process kick in considering we set it to 20 seconds? Well, perhaps nc is not setting SO_KEEPALIVE on the socket when it opens it? What does strace have to say about it:

[ec2-user@ip-172-31-24-218 ~]$ strace nc -l 3333
execve("/usr/bin/nc", ["nc", "-l", "3333"], [/* 32 vars */]) = 0
brk(0)                                  = 0xff9000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff071850000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
...

blah blah blah
...
blah blah blah
...
set_robust_list(0x7ff071847a20, 24)     = 0
rt_sigaction(SIGRTMIN, {0x7ff070d30780, [], SA_RESTORER|SA_SIGINFO, 0x7ff070d39100}, NULL, 8) = 0
rt_sigaction(SIGRT_1, {0x7ff070d30810, [], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x7ff070d39100}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
brk(0)                                  = 0xff9000
brk(0x101a000)                          = 0x101a000
brk(0)                                  = 0x101a000
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
 

bind(3, {sa_family=AF_INET, sin_port=htons(3333), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 1)                            = 0
accept(3, ^CProcess 2690 detached
 
[1]+  Killed                  nc -l 3333
[ec2-user@ip-172-31-24-218 ~]$


Cool, I've highlighted the lines where the socket is created and you can see SO_KEEPALIVE is not being set as an option. So... what now? Lets get dirty!!!

Test 2 "If you don't like it, change it!"


So, why don't we just force nc to use SO_KEEPALIVE option? Hell yeah!!! I downloaded netcat source from the official website and did the following changes on network.c file:

[ec2-user@ip-172-31-24-218 ~]$ diff netcat-0.7.1/src/network.c netcat-0.7.1_juan/src/network.c
374a375,383
>   sockopt = 1;
>   if (type == SOCK_STREAM){
>      ret = setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,&sockopt,sizeof(sockopt));
>      if(ret < 0){
>        close(sock);
>        return -2;
>      }
>   }
>
[ec2-user@ip-172-31-24-218 ~]$


as you can see I just added an if statement that will become true if the socket created is SOCK_STREAM (TCP :D), and will set the SO_KEEPALIVE option on the socket. After that I just issued ./configure and make, now strace shows something more interesting:

[ec2-user@ip-172-31-24-218 netcat-0.7.1_juan]$ strace ./src/netcat -l -p 3333
execve("./src/netcat", ["./src/netcat", "-l", "-p", "3333"], [/* 33 vars */]) = 0
brk(0)                                  = 0x125f000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fef806cb000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=21099, ...}) = 0
mmap(NULL, 21099, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fef806c5000
close(3)                                = 0

...
blah blah blah
...
blah blah blah
...
read(3, " # Redwood Chat\npdb             "..., 4096) = 4096
read(3, "      # ContinuStor Monitor Port"..., 4096) = 4096
read(3, "   3107/udp                # Bus"..., 4096) = 4096
read(3, "lfap        3145/tcp            "..., 4096) = 4096
read(3, "\nh2gf-w-2m       3179/udp       "..., 4096) = 4096
read(3, "    3212/tcp                # Su"..., 4096) = 4096
read(3, "eo-fe         3245/tcp          "..., 4096) = 4096
read(3, "80/tcp                # VS Serve"..., 4096) = 4096
read(3, "        # SDT License Manager\nof"..., 4096) = 4096
close(3)                                = 0
munmap(0x7fef806ca000, 4096)            = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
setsockopt(3, SOL_SOCKET, SO_LINGER, {onoff=1, linger=0}, 8) = 0
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
setsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
 

bind(3, {sa_family=AF_INET, sin_port=htons(3333), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 4)                            = 0
open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 4
...

blah blah blah
...
select(4, [3], NULL, NULL, NULL^CProcess 6656 detached
 
[ec2-user@ip-172-31-24-218 netcat-0.7.1_juan]$


so now we do have SO_KEEPALIVE in place, lets see if it works:

[ec2-user@ip-172-31-24-218 netcat-0.7.1_juan]$ ./src/netcat -l -p 3333 &
[1] 6657
[ec2-user@ip-172-31-24-218 netcat-0.7.1_juan]$ sudo tcpdump -nn port 3333
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
20:23:48.747981 IP 172.31.24.219.42122 > 172.31.24.218.3333: Flags [S], seq 723623108, win 26883, options [mss 8961,sackOK,TS val 1105802 ecr 0,nop,wscale 6], length 0
20:23:48.748190 IP 172.31.24.218.3333 > 172.31.24.219.42122: Flags [S.], seq 4243448461, ack 723623109, win 26847, options [mss 8961,sackOK,TS val 1106167 ecr 1105802,nop,wscale 6], length 0
20:23:48.748679 IP 172.31.24.219.42122 > 172.31.24.218.3333: Flags [.], ack 1, win 421, options [nop,nop,TS val 1105803 ecr 1106167], length 0


20:23:58.764759 IP 172.31.24.218.3333 > 172.31.24.219.42122: Flags [.], ack 1, win 420, options [nop,nop,TS val 1108672 ecr 1105803], length 0
20:23:58.765399 IP 172.31.24.219.42122 > 172.31.24.218.3333: Flags [.], ack 1, win 421, options [nop,nop,TS val 1108307 ecr 1106167], length 0


20:25:13.773009 IP 172.31.24.218.3333 > 172.31.24.219.42122: Flags [.], ack 1, win 420, options [nop,nop,TS val 1127424 ecr 1108307], length 0
20:25:13.773926 IP 172.31.24.219.42122 > 172.31.24.218.3333: Flags [.], ack 1, win 421, options [nop,nop,TS val 1127059 ecr 1106167], length 0


20:26:29.036973 IP 172.31.24.218.3333 > 172.31.24.219.42122: Flags [.], ack 1, win 420, options [nop,nop,TS val 1146240 ecr 1127059], length 0
20:26:29.037684 IP 172.31.24.219.42122 > 172.31.24.218.3333: Flags [.], ack 1, win 421, options [nop,nop,TS val 1145876 ecr 1106167], length 0


so our fancy workaround actually worked!! we can see how after 10 seconds of inactivity  the keep-alive probes kick in and they are sent every 75 seconds. The probes are basically ACK packets with no real content, here we can see how the probes are answered by instance A with a plain ACK as well.

Test 3 "Let the show begin"


Ok, now we have SO_KEEPALIVE enabled, therefore we should be able to test the all the parameters. Again, to speed up the process we'll reduce some of them again to the following values:

[root@ip-172-31-24-218 netcat-0.7.1]# echo 5 > /proc/sys/net/ipv4/tcp_keepalive_probes
[root@ip-172-31-24-218 netcat-0.7.1]# echo 20 > /proc/sys/net/ipv4/tcp_keepalive_intvl
[root@ip-172-31-24-218 netcat-0.7.1]# cat /proc/sys/net/ipv4/tcp_keepalive_probes
5
[root@ip-172-31-24-218 netcat-0.7.1]# cat /proc/sys/net/ipv4/tcp_keepalive_intvl
20
[root@ip-172-31-24-218 netcat-0.7.1]#


now the probes should be sent every 20 seconds and if 5 of them fail, the connection should be terminated. Ok, but if I run the same test again, the probes won't really fail because the connection is perfectly fine, so I need to cause a problem here.

The easiest way to make sure the connection will be idle and that instance A won't answer the keep-alive probes is by dropping all the packets on instance A right after the connection is ready. I did this by adding the following iptables rules right after the connection was established:

iptables -A OUTPUT --dst 172.31.24.218 -j DROP
iptables -A INPUT --src 172.31.24.218 -j DROP


Note: I dropped everything going out to instance B and everything coming in from instance B.

so there we go...

[ec2-user@ip-172-31-24-218 netcat-0.7.1]$ ./src/netcat -l -p 3333 &
[2] 27020
[ec2-user@ip-172-31-24-218 netcat-0.7.1]$ sudo tcpdump -nn port 3333
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
21:57:41.857514 IP 172.31.24.219.42126 > 172.31.24.218.3333: Flags [S], seq 2971447882, win 26883, options [mss 8961,sackOK,TS val 2514081 ecr 0,nop,wscale 6], length 0
21:57:41.857818 IP 172.31.24.218.3333 > 172.31.24.219.42126: Flags [S.], seq 1633813684, ack 2971447883, win 26847, options [mss 8961,sackOK,TS val 2514445 ecr 2514081,nop,wscale 6], length 0
21:57:41.858211 IP 172.31.24.219.42126 > 172.31.24.218.3333: Flags [.], ack 1, win 421, options [nop,nop,TS val 2514082 ecr 2514445], length 0



21:57:51.884756 IP 172.31.24.218.3333 > 172.31.24.219.42126: Flags [.], ack 1, win 420, options [nop,nop,TS val 2516952 ecr 2514082], length 0
21:58:11.948771 IP 172.31.24.218.3333 > 172.31.24.219.42126: Flags [.], ack 1, win 420, options [nop,nop,TS val 2521968 ecr 2514082], length 0
21:58:31.980765 IP 172.31.24.218.3333 > 172.31.24.219.42126: Flags [.], ack 1, win 420, options [nop,nop,TS val 2526976 ecr 2514082], length 0
21:58:52.012770 IP 172.31.24.218.3333 > 172.31.24.219.42126: Flags [.], ack 1, win 420, options [nop,nop,TS val 2531984 ecr 2514082], length 0
21:59:12.044761 IP 172.31.24.218.3333 > 172.31.24.219.42126: Flags [.], ack 1, win 420, options [nop,nop,TS val 2536992 ecr 2514082], length 0
21:59:32.076768 IP 172.31.24.218.3333 > 172.31.24.219.42126: Flags [R.], seq 1, ack 1, win 420, options [nop,nop,TS val 2542000 ecr 2514082], length 0

^C
9 packets captured
9 packets received by filter
0 packets dropped by kernel

[2]+  Stopped                 ./src/netcat -l -p 3333
[ec2-user@ip-172-31-24-218 netcat-0.7.1]$


interesting, right? keep-alive probes kicked in after 10 seconds as expected, then we have a probe every 20 seconds (no answer from instance A), and after the 5th probe we can see a RST+ACK package going from B to A trying to terminate the connection. This is exactly the behavior we were expecting :D.

So coming back to 20k+ ESTABLISHED connections situation, now we can understand why a situation like that is possible. Basically all the clients, for some awkward and really hard to reproduce reason were crashing and not finishing the connections properly, so on the server side due to the fact that the sockets used for the connections weren't using SO_KEEPALIVE option, the connections remained ESTABLISHED for the eternity.

Could this be a big problem? well it might be:

  • The first thing that comes to my mind is wasted memory. These established connections even though they are not being actively used, they need kernel memory to exist, so do the math :D. 
  • If a new connection comes in to the server and the source IP and source port match with one of the connections in ESTABLISHED state that connection will probably fail.
  • If you have a limit number of sockets available on the server I don't think you can afford having them allocated to this Ghost connections.

So why not having TCP keep-alive enabled by default? Good question... I guess that when we are talking about too many connections, handling the keep-alive could put some overhead on the kernel side. Imagine that for every connection the kernel should have to keep track of the time the last packet came in and then set timers to trigger the keep-alive probes.

I hope I was clear enough, otherwise you can always leave a comment :P.

... it wasn't a short entry after all.

sábado, 12 de diciembre de 2015

Página12 bajo ataque...???

Hace ya un par de días la versión digital del diario Página12 se encuentra fuera de servicio o con un servicio muy reducido. Siendo el diario oficialista por excelencia (pero paradógicamente fundado por el mayor opositor del oficialismo ) la situación levanta muchas sospechas en un momento como el que está cursando Argentina.

Este post NO intenta resolver el misterio, dado que es bastante difícil/imposible de lograr tal cosa sin acceso preciso a los detalles, y como muchas veces en nuestro país posiblemente jamás se sepa la verdad. Sin embargo... hay cosas que podrían no ser cómo las venden.

El problema o ataque de denegación de servicio comenzó aparentemente el Martes 8 de Diciembre (hace unos 4 días), y desde entonces el sitio tuvo cortos períodos de funcionamiento. Un intento de conexión al sitio termina sencillamente en un timeout luego de intentar por unos segundos:

juan@juan-VirtualBox:~$ nc -vz www.pagina12.com.ar 80
nc: connect to www.pagina12.com.ar port 80 (tcp) failed: Connection timed out
juan@juan-VirtualBox:~$


Esto nos indica varias posibles situaciones:
  • El servidor se encuentra realmente ante un JODIDO ataque de denegación de servicio y no es capaz de aceptar nuevas conexiones. Vamos... 5 días de ataque?
  • El servidor se encuentra apagado y/o el tráfico no llega al mismo por algún motivo extra.
Por supuesto que no responde ni ping, ni permite conexiones a otros puertos conocidos:

 juan@juan-VirtualBox:~$ ping -c 3 www.pagina12.com.ar
PING www.pagina12.com.ar (138.0.155.10) 56(84) bytes of data.

--- www.pagina12.com.ar ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2017ms

juan@juan-VirtualBox:~$ nc -vz www.pagina12.com.ar 22 -w 5
nc: connect to www.pagina12.com.ar port 22 (tcp) timed out: Operation now in progress
juan@juan-VirtualBox:~$ nc -vz www.pagina12.com.ar 443 -w 5
nc: connect to www.pagina12.com.ar port 443 (tcp) timed out: Operation now in progress
juan@juan-VirtualBox:~$



Pero bueno, es cierto que todo esto podría estar filtrado en el firewall y por eso no hay respuesta del servidor. Otro detalle no menor es el hecho de que el dominio www.pagina12.com.ar y m.pagina12.com.ar resuelven siempre con la misma IP:

juan@juan-VirtualBox:~$ dig +short www.pagina12.com.ar
138.0.155.10
juan@juan-VirtualBox:~$


no hay ningún tipo de balanceo por DNS o de redirección regional, nada de eso. Esto último lo pueden corroborar con https://dnschecker.org/#A/www.pagina12.com.ar



Dicha IP es propiedad de la gente de Gigared en Bs As:

juan@juan-VirtualBox:~$ whois 138.0.155.10

#
# ARIN WHOIS data and services are subject to the Terms of Use
# available at: https://www.arin.net/whois_tou.html
#
# If you see inaccuracies in the results, please report at
# http://www.arin.net/public/whoisinaccuracy/index.xhtml
#


#
# The following results may also be obtained via:
# http://whois.arin.net/rest/nets;q=138.0.155.10?showDetails=true&showARIN=false&showNonArinTopLevelNet=false&ext=netref2
#

NetRange:       138.0.0.0 - 138.0.255.255
CIDR:           138.0.0.0/16
NetName:        LACNIC-ERX-138-0-0-0
NetHandle:      NET-138-0-0-0-1
Parent:         NET138 (NET-138-0-0-0-0)
NetType:        Transferred to LACNIC
OriginAS:      
Organization:   Latin American and Caribbean IP address Regional Registry (LACNIC)
RegDate:        2010-11-19
Updated:        2010-11-19
Comment:        This IP address range is under LACNIC responsibility
Comment:        for further allocations to users in LACNIC region.
Comment:        Please see http://www.lacnic.net/ for further details,
Comment:        or check the WHOIS server located at http://whois.lacnic.net
Ref:            http://whois.arin.net/rest/net/NET-138-0-0-0-1

ResourceLink:  http://lacnic.net/cgi-bin/lacnic/whois
ResourceLink:  whois.lacnic.net

OrgName:        Latin American and Caribbean IP address Regional Registry
OrgId:          LACNIC
Address:        Rambla Republica de Mexico 6125
City:           Montevideo
StateProv:     
PostalCode:     11400
Country:        UY
RegDate:        2002-07-27
Updated:        2011-09-24
Ref:            http://whois.arin.net/rest/org/LACNIC

ReferralServer:  whois://whois.lacnic.net
ResourceLink:  http://lacnic.net/cgi-bin/lacnic/whois

OrgTechHandle: LACNIC-ARIN
OrgTechName:   LACNIC Whois Info
OrgTechPhone:  999-999-9999
OrgTechEmail:  whois-contact@lacnic.net
OrgTechRef:    http://whois.arin.net/rest/poc/LACNIC-ARIN

OrgAbuseHandle: LACNIC-ARIN
OrgAbuseName:   LACNIC Whois Info
OrgAbusePhone:  999-999-9999
OrgAbuseEmail:  whois-contact@lacnic.net
OrgAbuseRef:    http://whois.arin.net/rest/poc/LACNIC-ARIN


#
# ARIN WHOIS data and services are subject to the Terms of Use
# available at: https://www.arin.net/whois_tou.html
#
# If you see inaccuracies in the results, please report at
# http://www.arin.net/public/whoisinaccuracy/index.xhtml
#



Found a referral to whois.lacnic.net.


% Joint Whois - whois.lacnic.net
%  This server accepts single ASN, IPv4 or IPv6 queries

% LACNIC resource: whois.lacnic.net


% Copyright LACNIC lacnic.net
%  The data below is provided for information purposes
%  and to assist persons in obtaining information about or
%  related to AS and IP numbers registrations
%  By submitting a whois query, you agree to use this data
%  only for lawful purposes.
%  2015-12-12 09:28:12 (BRST -02:00)

inetnum:     138.0.152/22
status:      allocated
aut-num:     N/A
owner:       Gigared S.A.
ownerid:     AR-GISA2-LACNIC
responsible: Roberto Feijoo
address:     Donado, 840,
address:     C1427CZB - Capital Federal -
country:     AR
phone:       +54 11 63106000 [6071]
owner-c:     FER
tech-c:      FER
abuse-c:     FER
inetrev:     138.0.152/22
nserver:     NS1.GIGARED.COM 
nsstat:      20151210 AA
nslastaa:    20151210
nserver:     NS2.GIGARED.COM 
nsstat:      20151210 AA
nslastaa:    20151210
created:     20150102
changed:     20150102

nic-hdl:     FER
person:      Feijoo Roberto
e-mail:      rfeijoo@GIGARED.COM.AR
address:     Donado, 840,
address:     C1427CZB - Capital Federal - BA
country:     AR
phone:       +54 11 604006000 [6030]
created:     20030110
changed:     20150303

% whois.lacnic.net accepts only direct match queries.
% Types of queries are: POCs, ownerid, CIDR blocks, IP
% and AS numbers.

juan@juan-VirtualBox:~$


Osea que bien podrían comunicarse con la gente de Gigared para pedirles una mano y con un poco de maña y recursos podrían reducir el impacto de tal ataque.

Sus DNSs


Simpáticamente la gente de Página12 usa los DNS de Cloudflare (deberían haber usado el CDN también xD, o se estarán mudando gradualmente a Cloudflare???):

juan@juan-VirtualBox:~$ dig -t NS pagina12.com.ar
; <<>> DiG 9.9.5-3ubuntu0.5-Ubuntu <<>> -t NS pagina12.com.ar
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- 33465="" br="" id:="" noerror="" opcode:="" query="" status:="">;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;pagina12.com.ar.        IN    NS

;; ANSWER SECTION:
pagina12.com.ar.    2084    IN    NS    bill.ns.cloudflare.com.
pagina12.com.ar.    2084    IN    NS    edna.ns.cloudflare.com.


;; Query time: 16 msec
;; SERVER: 127.0.1.1#53(127.0.1.1)
;; WHEN: Sat Dec 12 11:37:17 GMT 2015
;; MSG SIZE  rcvd: 88

juan@juan-VirtualBox:~$


esto es una muy buena práctica, pero claro... solo DNS con alta disponibilidad no es suficiente. Insisto deberían haber ampliado al servicio de CDN, podría haberle ahorrado un dolor de cabeza con los beneficios de Cloudflare ante ataques DDOS.

Historia de la IP


En Internet hay mucha historia, por suerte. Así como hay sitios que se encargan de guardar copias de otros sitios para luego comparar como fueron cambiando con el tiempo, hay sitios que guardan la historia de DNS. ViewDNS.info es uno de ellos; qué tiene ese sitio para contarnos sobre www.pagina12.com.ar?:



Al parecer el dominio cambió de IP 3 veces desde 2014, es cierto que podría ser información no muy precisa. Pero.... según viewdns.info el dominio www.pagina12.com.ar cambio IP por última vez hace no muchos días. Previamente (por lo menos hasta el 4 de Diciembre) se encontraba en la IP 190.57.233.170, que corresponde al operador EDITORIAL LA PAGINA S.A. (aunque dentro del SA de Gigared S.A.):

juan@juan-VirtualBox:~$ whois 190.57.233.170

% Joint Whois - whois.lacnic.net
%  This server accepts single ASN, IPv4 or IPv6 queries

% LACNIC resource: whois.lacnic.net


% Copyright LACNIC lacnic.net
%  The data below is provided for information purposes
%  and to assist persons in obtaining information about or
%  related to AS and IP numbers registrations
%  By submitting a whois query, you agree to use this data
%  only for lawful purposes.
%  2015-12-12 09:50:11 (BRST -02:00)

inetnum:     190.57.233.160/28
status:      reallocated
owner:       EDITORIAL LA PAGINA S.A.
ownerid:     AR-ELPS-LACNIC
responsible: LUIS COMAND
address:     SOLIS, 1525,
address:     C1134ADG - CABA -
country:     AR
phone:       +54 011 67724400 [4481]
owner-c:     LUC52
tech-c:      LUC52
abuse-c:     LUC52
created:     20140930
changed:     20140930
inetnum-up:  190.57.224/19

nic-hdl:     LUC52
person:      Luis Comand
e-mail:      comande@PAGINA12.COM.AR
address:     Sol�s, 1525,
address:     C1134ADG - Buenos aires -
country:     AR
phone:       +54 11 67724481 []
created:     20140930
changed:     20140930

% whois.lacnic.net accepts only direct match queries.
% Types of queries are: POCs, ownerid, CIDR blocks, IP
% and AS numbers.

juan@juan-VirtualBox:~$


Por supuesto que no podemos saber a ciencia cierta porque se dio este cambio, pero el cambio existió (podemos asegurarlo porque la IP actual es diferente). Ahora revolviendo un poco mas en el cajón de los recuerdos... vemos...





Todo esto indicaría que la gente de Pagina12 podría haber estado migrando el servidor de un lugar después del 4 de Diciembre. Cambiaron de IP y de DNS registrados en NIC. Podría deberse a esto la caída del servicio? Todos sabemos que las migraciones no suelen ser una tarea sencilla.

Reportes de usuarios


Revolviendo un poco mas, me encontré con un simpático personaje de tweeter (hellr00t) que allá por Marzo se encargó de publicar ciertas falencias en el servidor web de Página12. El tweet en particular es https://twitter.com/hellr00t/status/577938582377271297 donde se puede ver lo que serían las estadísticas del servidor web Apache hospedando Página12. El tweet pasó bastante desapercibido pero dejó en evidencia una buena prueba de lo mal administrado que se encontraba el servidor.

Conclusión


La verdad, desde mi humilde opinión y dejando de lado las teorías conspirativas, es que no se puede saber con precisión qué está pasando con el sitio de Página12. Si alguien me pidiese mi punto de vista (que a poca gente le va a importar xD), NO creo que se trate de un ataque de denegación de servicio como se está hablando. Mas bien me parece que una de las siguientes cosas sucedió:

  • Migración con problemas. Es muy fácil que una migración se complique, malos cálculos de recursos, versiones nuevas de software que generan incompatibilidades, etc, etc etc.
  • No descarto un ataque al sitio, todos sabemos que hay gente mala pululando por ahí. Pero... 5 días de downtime habla peor de los administradores que de los atacantes.
Posiblemente el tiempo aclare alguna de las dudas planteadas, o no. Estoy mas que abierto a opiniones y sugerencias, en caso de que vean algo que yo no vi.

Saludos!!!

Actualización 14 de Diciembre


Al parecer no estaba tan equivocado con respecto a la posible migración en proceso de la versión digital de Pagina12. Al día de hoy el sitio web www.pagina12.com.ar se encuentra respondiendo a través del servicio de CDN de CloudFlare. Podemos confirmarlo primero que nada con las nuevas IPs:

juan@juan-VirtualBox:~$ dig +short www.pagina12.com.ar
104.20.76.37
104.20.75.37

juan@juan-VirtualBox:~$


estas IPs pertenecen a CloudFlare

juan@juan-VirtualBox:~$ whois 104.20.75.37|grep -i orgname
OrgName:        CloudFlare, Inc.

juan@juan-VirtualBox:~$ whois 104.20.76.37|grep -i orgname
OrgName:        CloudFlare, Inc.
juan@juan-VirtualBox:~$


de momento la vieja IP sigue funcionando y se puede acceder sencillamente:

juan@juan-VirtualBox:~$ curl -I 138.0.155.10/index.php -H 'Host:www.pagina12.com.ar'
HTTP/1.1 302 Found
Date: Mon, 14 Dec 2015 22:09:10 GMT
Server: Apache
X-Powered-By: PHP/5.3.3-7+squeeze14
Location: /diario/ultimas/index.html
Vary: Accept-Encoding
Content-Type: text/html; charset=ISO-8859-1

juan@juan-VirtualBox:~$

Al parececr lo que han hecho, básicamente es utilizar el servicio de CDN the CloudFlare para darle una mejor performance al sitio, actuando como cache y además es una muy buena idea para mitigar algunos tipos de ataques.

Pequeña recomendación para los sysadmins del sitio... restrinjan el acceso al puerto 80 del servidor backend solamente a las IPs de los caches de Cloudflare. Si no lo hacen sigue siendo muy sencillo atacar el servidor donde realmente se encuentra hospedado el sitio.

A ciencia cierta esto NO devela del todo el misterio... Mi predicción de migración fue acertada :D, pero probablemente jamás sepamos si la migración fue como acción para mitigar un ataque o... el ataque nunca existió y el problema que se hacía visible era por la migración misma.

Escucho ideas!!!

lunes, 14 de julio de 2014

Cómo hacer un volcado de memoria (Memory Dump) en Linux?

Por diferentes motivos podríamos querer tener un volcado de memoria de un sistema Linux, por ejemplo:

  • Cuestiones legales, como en un caso de análisis forense sobre un host 
  • Cuestiones de debug, ante un crash del sistema
  • Cuestiones de la vida, curiosidad, etc
La idea de esta entrada es presentar una forma razonable de hacerlo en sistemas GNU/Linux.

Primera aproximación, a por /dev/mem

La primera idea y la mas documentada es leer el dispositivo /dev/mem . Gracias a algún programador (Wietse Venema según el man) existe una aplicación llamada memdump que se encarga precisamente de leer este dispositivo y devolvernos por STDOUT el contenido. Hasta acá parecía todo maravilloso y simple. Entonces probemos memdump:

root@corrientes:/home/jpavlik# memdump  > volcado.mem

La linea anterior me llevó directo a un gigantesco kernel panic y un consecuente reinicio de la PC (posiblemente un problema de mi versión de Ubuntu 13.04, dado que la misma prueba en otros sistemas no terminó en un crash pero tampoco en un dump satisfactorio), por lo tanto vamos a buscar otro camino.
Dado que /dev/mem es un dispositivo

root@corrientes:/home/jpavlik# file /dev/mem 
/dev/mem: character special
root@corrientes:/home/jpavlik# 

lo vamos a tratar como tal y leeremos con dd:

root@corrientes:/home/jpavlik# dd if=/dev/mem of=volcado.mem bs=1M 
dd: leyendo «/dev/mem»: Operación no permitida
1+0 registros leídos
1+0 registros escritos
1048576 bytes (1,0 MB) copiados, 0,125726 s, 8,3 MB/s
root@corrientes:/home/jpavlik# 

si bien esta vez no generamos un gran crash, tampoco obtuvimos un volcado real dado que solo logramos leer 1Mb... y la operación fue detenida.

Leyendo un poco en google resulta ser que existe una opción en tiempo de compilación del kernel que define si será posible o no acceder en espacio de usuario al dispositivo /dev/mem de manera irestricta o no. En nuestro caso

root@corrientes:/home/jpavlik# grep "CONFIG_STRICT_DEVMEM" /usr/src/linux-headers-3.8.0-35-generic/.config
CONFIG_STRICT_DEVMEM=y
root@corrientes:/home/jpavlik# 

la restricción se encuentra efectivamente activada. Dado que al parecer no es posible desactivarla en tiempo de ejecución hay que buscar otro camino que nos permita alcanzar nuestro objetivo.

LiME Forensics

LiME, Linux Memory Extractor es un módulo de linux que nos permitirá acceder a la memoria volatil de manera irestricta ya que a diferencia de memdup o dd, no se ejecuta en espacio de usuario sino en espacio de kernel. Algo muy interesante de LiME es que haciendo uso de la compilación cruzada es posible compilar el módulo para correrlo en dispositivos Android y lograr volcados de memoria de los mismos.
El código de LiME está accesible en http://code.google.com/p/lime-forensics/downloads/list?can=1&q=&colspec=Filename+Summary+Uploaded+ReleaseDate+Size+DownloadCount , una vez descargado podemos acceder a su documentación que viene en un PDF o compilarlo sin demasiadas vueltas:

jpavlik@corrientes:~/LiME$ ls
doc  lime-forensics-1.1-r17.tar.gz  src
jpavlik@corrientes:~/LiME$ cd src/
jpavlik@corrientes:~/LiME/src$ make
make -C /lib/modules/3.8.0-35-generic/build M=/home/jpavlik/LiME/src modules
make[1]: se ingresa al directorio «/usr/src/linux-headers-3.8.0-35-generic»
  CC [M]  /home/jpavlik/LiME/src/tcp.o
  CC [M]  /home/jpavlik/LiME/src/disk.o
  CC [M]  /home/jpavlik/LiME/src/main.o
/home/jpavlik/LiME/src/main.c: En la función ‘__check_dio’:
/home/jpavlik/LiME/src/main.c:56:1: aviso: devolución desde un tipo de puntero incompatible [activado por defecto]
  LD [M]  /home/jpavlik/LiME/src/lime.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/jpavlik/LiME/src/lime.mod.o
  LD [M]  /home/jpavlik/LiME/src/lime.ko
make[1]: se sale del directorio «/usr/src/linux-headers-3.8.0-35-generic»
strip --strip-unneeded lime.ko
mv lime.ko lime-3.8.0-35-generic.ko
make tidy
make[1]: se ingresa al directorio «/home/jpavlik/LiME/src»
rm -f *.o *.mod.c Module.symvers Module.markers modules.order \.*.o.cmd \.*.ko.cmd \.*.o.d
rm -rf \.tmp_versions
make[1]: se sale del directorio «/home/jpavlik/LiME/src»
jpavlik@corrientes:~/LiME/src$ 

el módulo debe haber sido compilado en el mismo directorio:

jpavlik@corrientes:~/LiME/src$ file lime-3.8.0-35-generic.ko 
lime-3.8.0-35-generic.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=0xef9209d7b1872ae63655f3df94d98986f7bdd105, not stripped
jpavlik@corrientes:~/LiME/src$ 

como todo módulo es necesario cargarlo para poder hacer uso de sus funcionalidades. Para esto acudimos el comando insmod (como root, claro) y le pasamos los argumentos necesarios para hacer un dump crudo (raw) a través de la red (la prueba la hacemos sobre una VM just in case...):

  • Desde la VM de la cual obtendremos el volcado de memoria ejecutamos
localhost src # insmod lime-3.3.8-gentoo.ko "path=tcp:4444 format=raw"

  • En la máquina donde recibiremos el volcado ejecutamos:
root@corrientes:~# nc 172.16.254.68 4444 > volcado.mem

Luego de unos segundos (dependiendo de la cantidad de ram de la VM y la velocidad de trasnferencia de la red) tendremos el archivo volcado.mem a nuestro disposición:

root@corrientes:~# ll volcado.mem -h
-rw-r--r-- 1 root root 256M jul 14 15:25 volcado.mem
root@corrientes:~# 

Podemos apreciar que el tamaño del archivo nos indica que la VM de origen tiene solo 256Mbytes asignados como memoria RAM. 

Y de esta manera conseguimos nuestro volcado de memoria, ahora habría que analizarlo según los objetivos de cada caso. 

Una primera aproximación de análisis muy simple, podríamos hacerla usando el comando strings y analizar las cadenas obtenidas.