Boas xentiña.
Hoxe traiovos unha vella técnica ca que estiven fuchicando estes días. Trátase dun ataque para obter sudo se outra persoa que estea conectada na mesma máquina ca mesma usuaria ca nos o ten desbloqueado. Esta técnica xa foi documentada por nongiach no seu repo sudo_inject. Sen embargo, na súa implementación requirense varios ficheiros e dependencias para o ataque, polo que para simplificalo, e tamén aprender sobre esta técnica, desenvolvín a ferramenta sudohunt.
Para poñernos en materia, sudo
é un programa usando en sistemas basados en Unix
(como GNU/Linux) que permite executar programas como outra usuaria. Por defecto e
xeral, soense executar os comandos como root (ou sexa, o administrador de
GNU/Linux). Tedes mais info na páxina do manual de sudo. Daquela, ser capaz de
utilizar sudo
prácticamente significa que imos poder facer o que queiramos
na máquina.
Polo tanto, poñámonos na seguinte situación: nun pentest conseguimos unha clave
SSH que nos permite conectarnos a unha máquina ca usuaria it
. Ben, ao
conectarnos descubrimos que dita usuaria pode executar programas con sudo
,
mais se nos pide un contrasinal que non sabemos.
$ ssh -i itkey it@itserver
it@itserver:~$ sudo id
[sudo] password for it:
Podemos comprobar se hai outra persoa conectada á mesma máquina usando a usuaria
it
. Para iso pódese usar o comando w
ou who
:
it@itserver:~$ w
14:16:16 up 15 min, 2 users, load average: 0.00, 0.00, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
it pts/0 146.89.128.11 12:14 0.00s 0.01s ? w
it pts/2 192.168.2.12 12:05 20.00s 0.01s 0.01s -bash
Vemos que hai outra sesión iniciada da usuaria it
na máquina obxetivo.
Nesta situación podemos intentar inxectar un comando na sesión da outra persoa,
e no caso de que teña sudo
desbloqueado, tentar desbloquear sudo na nosa
sesión. A que me refiro con sudo
desbloqueado? Pois a que sudo non pida
contrasinal. Cando se executa sudo
por primeira vez nunha sesión, este pide
contrasinal, mais para non estar amolando á usuaria, se se executan máis
comandos con sudo
nun breve espazo de tempo, 15 minutos por defecto, o
contrasinal non se volve pedir.
Isto podemos comprobalo executando un comando con sudo
dúas veces seguidas.
Por exemplo:
$ sudo id
[sudo] password for user:
uid=0(root) gid=0(root) groups=0(root)
$ sudo id
uid=0(root) gid=0(root) groups=0(root)
Como vemos sudo
so pide o contrasinal a primeira vez que executamos o comando.
E como fai isto? E como nos podemos aproveitar deste comportamento?
Vaiamos por partes. Respondendo á primeira pregunta, sudo
mantén un rexistro
das usuarias autenticadas por sesión. Para cada usuaria mantén un ficheiro no
cartafol /run/sudo/ts/
. Podemos listar os ficheiros de dito cartafol:
$ sudo ls -l /run/sudo/ts/
total 4
-rw------- 1 root it 224 Mar 3 14:51 it
Vemos que hai un ficheiro para a usuaria it
, que so pode ser lido e escrito
por root. Estes ficheiros teñen un formato binario descrito na páxina de manual
sudoers_timestamp. Sen embargo, podemos leelos usando o comando read de
sudohunt
. Aquí vai un exemplo:
$ sudo ./sudohunt read
Timestamp file: /run/sudo/ts/it
version: 2
size: 56
type: 4 TS_LOCKEXCL
flags: 0
auth_uid: 0
sid: 0
start_time: 0.0
ts: 0.0
id: 0
version: 2
size: 56
type: 2 TS_TTY
flags: 0
auth_uid: 1000 it
sid: 2210 -bash
start_time: 931.530000000 (1933.998431745 seconds ago)
ts: 2865.526131254 (0.2300491 seconds ago)
tty: 34818 /dev/pts/2
Vemos que hai dous rexistros no ficheiro /run/sudo/ts/it
. O primeiro podemos
ignoralo xa que é un rexistro de control do propio ficheiro. O que nos interesa
é o segundo rexistro, que nos indica que sudo
está permitido para a usuaria
it
(co uid
1000) na sesión 2210
(cuxo programa líder é unha shell de
bash
) que se está a executar no terminal /dev/pts/2
(isto concorda ca saída
do comando w
que executamos antes). Ademais podemos ver no campo ts
que
transcorreron 0.23
segundos dende a última vez que se usou sudo
, un tempo
normal tendo en conta que se acaba de executar para leer este ficheiro.
Tendo isto en conta, e respondendo á nosa segunda cuestión, o obxetivo do noso
ataque será incluir un novo rexistro neste ficheiro que indique que a nosa
sesión tamén executou sudo
fai pouco (menos de 15 minutos) para poder usalo
sen precisar contrasinal. sudohunt
inclúe o comando write
que permite
escribir novos rexistros nos ficheiros de sesións de sudo
.
E como imos facer isto sabendo que so root pode engadir novos rexistros?
Pois lembrade que se poden executar cousas como root usando sudo
. Polo tanto,
o que imos facer é forzar a outra sesión que teña sudo
desbloqueado a escribir
o rexistro por nos. Para isto imos a ser inxectar un proceso na sesión da
persoa que desbloqueou sudo
que engada un novo rexistro para a nosa sesión.
Hai que lembrar que tanto a nosa sesión de atacante como o obxetivo da inxección
están a usar a mesma usuaria: it
.
Por defecto, algunhas distribucións de GNU/Linux coma Debian ou Alma Linux permiten a unha usuaria depurar calquera dos seus procesos coa syscall ptrace inda que estean noutra sesión. Isto implica que se pode leer a memoria do proceso obxetivo, modificar os seus rexistros ou establecer breakpoints, entre outros, polo que podemos inxectar código (e por tanto procesos) noutras sesións.
Para verificar que se pode usar ptrace sobre procesos de outras sesións temos
que comprobar que o ficheiro /proc/sys/kernel/yama/ptrace_scope
ten escrito o
valor 0
. No caso de ser outro valor non se poderán realizar inxeccións con
ptrace a outras sesións.
Ademais do indicado en
/proc/sys/kernel/yama/ptrace_scope
podería haber outros mecanismos de seguridade coma SELinux que nos poderían impedir usar ptrace sobre outros procesos, mais neste caso asumimos que non os hai.
Unha vez que comprobemos que os requisitos se cumplen o que intentaremos será
que a sesión doutra persoa execute o comando sudo sudohunt write --pid
<sesion>
. Isto escribirá como root un rexistro no ficheiro
/run/sudo/ts/<user>
que lle dará sudo á sesión co identificador <session>
(que substituiremos pola nosa sesión actual).
Polo tanto o ataque, que se executa co comando sudohunt inject
terá as
seguintes fases:
-
Búscanse procesos noutras sesións da usuaria. Xa que so se precisa localizar un proceso por sesión, búscanse os líderes de sesión, que son os procesos cuxo pid sexa igual ao número de sesión (sid) e que teñan unha terminal asociada (sesións interactivas).
-
Unha vez localizado os procesos, inxéctase en cada un un novo proceso
sudo sudohunt write
. No caso de que a sesión obxetivo teña sudo habilitado o comando anterior escribe un rexistro que concede sudo á sesión actual.
Isto pódese comprobar executando sudohunt
ca nosa usuaria it
:
it@itserver:~$ ./sudohunt inject
Injection work. sudo may work now. If not, retry injection later.
it@itserver:~$ sudo id
uid=0(root) gid=0(root) groups=0(root)
E desta forma conseguimos sudo para executar comandos como root!!
Podes ver un exemplo deste ataque no seguinte asciinema:
No caso de que teñas curiosidade de que pasa na inxección, este é o procedemento mais detallado para un proceso dunha sesión obxetivo (se queres inda mais detalles terás que revisar o código de sudohunt):
-
sudohunt
acóplase con ptrace a o proceso obxetivo, no noso casobash
. -
Faise que bash execute a syscall fork para crear un proceso fillo e evitar interferencias no propio bash que pode estar usando outra persoa.
-
sudohunt
acóplase ao proceso fillo. -
Libérase o proceso
bash
(pai) da nosa influencia para que continue con normalidade. -
Faise que o proceso fillo execute o comando
sudo sudohunt write
mediante a syscall execve. Unha cousa curiosa é que antes de que o proceso fillo execute execve hai que se desacoplarse del para que sudo sea capaz de lanzarse como root, xa que nos procesos depurados ignórase o flagsetuid
dos programas (que fai que se executen como root).
Aquí queda un esquema de como sería a inxección:
E de momento isto e todo xente, agardo que vos gustase este pequeno artigo e vémonos nas redes!!