Hace un tiempo noté que los nombres de usuario y contraseñas dados curl
como argumentos de línea de comando no aparecen en la ps
salida (aunque, por supuesto, pueden aparecer en su historial de bash).
Tampoco aparecen en /proc/PID/cmdline
.
(Sin embargo, la longitud del argumento combinado de nombre de usuario / contraseña puede derivarse).
Demostración a continuación:
[root@localhost ~]# nc -l 80 &
[1] 3342
[root@localhost ~]# curl -u iamsam:samiam localhost &
[2] 3343
[root@localhost ~]# GET / HTTP/1.1
Authorization: Basic aWFtc2FtOnNhbWlhbQ==
User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.15.3 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Host: localhost
Accept: */*
[1]+ Stopped nc -l 80
[root@localhost ~]# jobs
[1]+ Stopped nc -l 80
[2]- Running curl -u iamsam:samiam localhost &
[root@localhost ~]# ps -ef | grep curl
root 3343 3258 0 22:37 pts/1 00:00:00 curl -u localhost
root 3347 3258 0 22:38 pts/1 00:00:00 grep curl
[root@localhost ~]# od -xa /proc/3343/cmdline
0000000 7563 6c72 2d00 0075 2020 2020 2020 2020
c u r l nul - u nul sp sp sp sp sp sp sp sp
0000020 2020 2020 0020 6f6c 6163 686c 736f 0074
sp sp sp sp sp nul l o c a l h o s t nul
0000040
[root@localhost ~]#
¿Cómo se logra este efecto? ¿Está en algún lugar del código fuente de curl
? (¿Asumo que es una curl
característica, no una ps
característica? ¿O es una característica del núcleo de algún tipo?)
Además: ¿ se puede lograr esto desde fuera del código fuente de un ejecutable binario? Por ejemplo, mediante el uso de comandos de shell, probablemente combinado con permisos de root?
En otras palabras, ¿podría alguna manera enmascarar un argumento de aparecer en /proc
o en la ps
salida (lo mismo, creo) que pasé a algunos arbitraria de comandos shell? (Supongo que la respuesta a esto es "no", pero parece que vale la pena incluir esta media pregunta adicional).
environ
directamente para acceder a las variables de entorno? - el resultado final: la lista de argumentos, como la lista de variables de entorno, está en la memoria de proceso de lectura / escritura del usuario, y puede ser modificada por el proceso del usuario.grep
patrón sea una clase de personaje. Ej .ps -ef | grep '[c]url'
curl
coincidecurl
pero[c]url
no coincide[c]url
. Si necesita más detalles, haga una nueva pregunta y estaremos encantados de responder.Respuestas:
Cuando el núcleo ejecuta un proceso, copia los argumentos de la línea de comandos en la memoria de lectura y escritura que pertenece al proceso (en la pila, al menos en Linux). El proceso puede escribir en esa memoria como cualquier otra memoria. Cuando
ps
muestra el argumento, vuelve a leer lo que esté almacenado en esa dirección en particular en la memoria del proceso. La mayoría de los programas mantienen los argumentos originales, pero es posible cambiarlos. La descripción POSIX deps
estados queLa razón por la que se menciona esto es que la mayoría de las variantes de Unix reflejan el cambio, pero las implementaciones POSIX en otros tipos de sistemas operativos pueden no hacerlo.
Esta característica es de uso limitado porque el proceso no puede realizar cambios arbitrarios. Como mínimo, la longitud total de los argumentos no se puede aumentar, porque el programa no puede cambiar la ubicación donde
ps
buscará los argumentos y no puede extender el área más allá de su tamaño original. La longitud se puede disminuir efectivamente colocando bytes nulos al final, porque los argumentos son cadenas terminadas en nulo estilo C (esto no se puede distinguir de tener un montón de argumentos vacíos al final).Si realmente quiere excavar, puede ver el origen de una implementación de código abierto. En Linux, la fuente de
ps
no es interesante, todo lo que verá allí es que lee los argumentos de la línea de comandos del sistema de archivos proc , en . El código que genera el contenido de este archivo está en el kernel, en in . La parte de la memoria del proceso (a la que se accede con ) va de la dirección a ; Estas direcciones se registran en el núcleo cuando se inicia el proceso y no se pueden cambiar después./proc/PID/cmdline
proc_pid_cmdline_read
fs/proc/base.c
access_remote_vm
mm->arg_start
mm->arg_end
Algunos demonios usan esta capacidad para reflejar su estado, por ejemplo, cambian su
argv[1]
cadena por una comostarting
oavailable
oexiting
. Muchas variantes de Unix tienen unasetproctitle
función para hacer esto. Algunos programas usan esta capacidad para ocultar datos confidenciales. Tenga en cuenta que esto es de uso limitado ya que los argumentos de la línea de comandos son visibles mientras se inicia el proceso.La mayoría de los lenguajes de alto nivel copian los argumentos en los objetos de cadena y no ofrecen una forma de modificar el almacenamiento original. Aquí hay un programa en C que demuestra esta habilidad cambiando
argv
elementos directamente.Salida de muestra:
Puedes ver
argv
modificaciones en el código fuente curl. Curl define una funcióncleanarg
en lasrc/tool_paramhlp.c
que se usa para cambiar un argumento a todos los espacios usandomemset
. Ensrc/tool_getparam.c
esta función se usa varias veces, por ejemplo, al redactar la contraseña del usuario . Dado que la función se llama desde el análisis de parámetros, ocurre temprano en una invocación curl, pero al volcar la línea de comando antes de que esto suceda, aún se mostrarán las contraseñas.Como los argumentos se almacenan en la memoria del proceso, no se pueden cambiar desde el exterior, excepto mediante el uso de un depurador.
fuente
ps
argumentos de informe de la memoria de ese núcleo, ignorando cualquier cambio realizado en la memoria de lectura y escritura de los procesos? Pero (¿si lo entendí bien?) La mayoría de las variaciones de UNIX ni siquiera hacen lo primero, por lo que no puede hacer que unaps
implementación haga lo segundo sin modificaciones del núcleo, ya que los datos originales no se guardan en ningún lado.argv
las entradas a cambiar (no se puede establecerargv[i]
, pero se puede escribir enargv[i][0]
a travésargv[i][strlen(argv[i])]
), por lo que no tiene que ser una copia en la memoria del proceso.ps
resultado, muchos argumentos vacíos parecen que no hay nada allí, pero sí, hace una diferencia si verifica cuántos espacios hay y puede observar más directamente desde/proc/PID/cmdline
.Las otras respuestas responden bien a la pregunta de manera general. Para responder específicamente " ¿Cómo se logra este efecto? ¿Está en algún lugar del código fuente de curl? ":
En la sección de análisis de argumentos del código fuente curl , la
-u
opción se maneja de la siguiente manera:Y la
cleanarg()
función se define de la siguiente manera:Por lo tanto, podemos ver explícitamente que el argumento nombre de usuario: contraseña
argv
se sobrescribe con espacios, como se describe en las otras respuestas.fuente
cleanarg
estados explícitamente indique que está haciendo lo que hace la pregunta!Un proceso no solo puede leer sus parámetros sino también escribirlos.
No soy desarrollador, así que no estoy familiarizado con estas cosas, pero puede ser posible desde el exterior con un enfoque similar al cambio de los parámetros del entorno:
https://stackoverflow.com/questions/205064/is-there-a-way-to-change-another-processs-environment-variables
fuente
bash -c 'awk 1 /proc/$$/cmdline; set -- something; awk 1 /proc/$$/cmdline'
muestra que al menos en el shell, establecer los parámetros es distinto de modificar lo que el núcleo ve como los parámetros del proceso.