wtorek, 28 lutego 2012

Linux terminal session live hijacking!

Przepraszam za krzykliwy angielski tytuł ale nie mogłem się powstrzymać :)

Wyobraźcie sobie taką scene:

Oto admin widzi że system spowalnia. Loguje się przez ssh i sprawdza kto jest zalogowany, jakie procesy konsumują czas procesora oraz I/O. Ma podejrzenie, że jest to użytkownik psuj. By sprawdzić co też nasz psuj psuje, mógłby wykonywać co chwile polecenie w oraz obserwować procesy poleceniem top. Chciałby jednak obserwować sesje użytkownika na żywo (on live).

Niestety psuj nie uruchomił programu script, a w systemie również nie mamy innych narzędzi monitorujących. Co powinien zrobić nasz sprytny admin i czy jest w ogóle możliwy taki podgląd? Systemy Unixowe mają ogromne możliwości i zaraz się o tym przekonacie na własne oczy :)



Nasz admin, chce zrobić nic innego jak przekierować wyjście z powłoki użytkownika w miejsce gdzie będzie mógł je obserwować i następnie przekierować dane tam gdzie powinny trafić, czyli do terminala użytkownika. Taki mały atak "man in the middle" :)

Chcąc pomóc naszemu adminowi wydajemy polecenie ps uf i widzimy, że psuj jest połączony poprzez ssh, a jego powłoką jest proces /bin/bash numer 4122. Następnie sprawdzamy z jakiego terminala korzysta ta powłoka:

# lsof | grep 4122
bash 4122 psuj 0u CHR 136,1 0t0 4 /dev/pts/1
bash 4122 psuj 1u CHR 136,1 0t0 4 /dev/pts/1
bash 4122 psuj 2u CHR 136,1 0t0 4 /dev/pts/1
bash 4122 psuj 255u CHR 136,1 0t0 4 /dev/pts/1


Widać tutaj, że deskryptory 0,1,2 czyli standardowe wejście, wyjście i wyjście błędów są przypięte do /dev/pts/1. Pierwsze zatem co trzeba zrobić to miejsce przez które przekierujemy te strumienie danych:

# pwd
/root
# mkfifo ttyout
# cat ttyout | tee "/dev/pts/1"


Utworzyliśmy potok ttyout oraz przy pomocy polecenia tee rozwidliliśmy dane jakie tam wpadają, przekierowując je na nasz terminal i z powrotem do terminala powłoki użytkownika psuj. Połowa drogi już za nami, teraz musimy przekierować strumienie do naszego nowo utworzonego potoku ttyout :) Wchodzimy zatem na następną powłokę i wydajemy polecenia:

# gdb -p 4122
(gdb) call open( "/root/ttyout", 0x1 )
$1 = 3
(gdb) call dup2( $1, 1 )
$2 = 1
(gdb) call dup2( $1, 2 )
$3 = 2
(gdb) call close( $1 )
$4 = 0
(gdb) q
A debugging session is active.

Inferior 1 [process 4122] will be detached.

Quit anyway? (y or n) y
Detaching from program: /bin/bash, process 4122

... i już :) Debugger gdb został przyłączony do powłoki użytkownika, potem otworzyliśmy potok do zapisu przy pomocy wywołania systemowego open. Na końcu przekierowaliśmy deskryptory nr 1 i 2 do potoku i zamknęliśmy nie używany już deskryptor pliku. Polecenie lsof zwraca teraz taki wynik:

# lsof | grep 4122
bash 4122 psuj 0u CHR 136,1 0t0 4 /dev/pts/1
bash 4122 psuj 1u FIFO 8,3 0t0 86963 /root/stdout
bash 4122 psuj 2u FIFO 8,3 0t0 86963 /root/stdout
bash 4122 psuj 255u CHR 136,1 0t0 4 /dev/pts/1


Na powłoce gdzie wydaliśmy polecenie cat widzimy na żywo co też nasz psuj robi. Jeżeli już się napatrzyliśmy, możemy przekierować strumienie z powrotem do terminala, wydając identyczną sekwencje poleceń gdb. Przy czym na początku otwieramy oczywiście terminal zamiast naszego potoku: call open( "/dev/pts/1", 0x1 )

To jeszcze nie wszystko... czy nigdy nie zdarzyło Wam się, że straciliście połączenie i na serwerze została wisząca sesja z edytorem vim, czy czymś innym? Tak, teraz jesteśmy w stanie sobie poradzić z tym problemem w kilka sekund i przypiąć z powrotem taki program do terminala :)