
CTF 챌린지를 위한 Linux 커널 익스플로잇 개발 노트 및 스크립트로, initramfs 추출, msg_msg/ldt_struct 악용, 그리고 권한 상승을 위한 실전 익스플로잇 기법을 다룹니다.
CPIO 아카이브에서 파일 추출
#!/bin/sh
mkdir fs
cd fs
cp ../initramfs.cpio.gz ./initramfs.cpio.gz
gunzip ./initramfs.cpio.gz
cpio -idm < ./initramfs.cpio
rm initramfs.cpio
cd ..
익스플로잇을 컴파일하고, fs에 추가한 다음 실행합니다.
#!/bin/sh
gcc -w -o exploit -static exploit.c -pthread -lrt &&\
# musl-gcc -w -s -static -o3 exploit.c -o exploit -masm=intel &&\
mv exploit ./fs/ &&\
cd fs &&\
find . -print0 | cpio --owner root --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz &&\
cd .. &&\
# gunzip -f initramfs.cpio.gz &&\
./run.sh
ext4 파일시스템 아카이브인 경우
mount ./initramfs.cpio.gz ./fs/
0x20 크기의 구조체로, copy_to_user 호출에 대한 검사가 없습니다.
struct msg_msg {
struct list_head m_list;
long m_type;
size_t m_ts; /* message text size */
struct msg_msgseg *next;
void *security;
/* the actual message follows immediately */
};
사용자 메시지는 msg_msg 구조체 바로 뒤에 저장되며, 0x1000 - 0x30까지 저장된 이후에는 struct msg_msgseg *next에 저장된 청크들의 단일 연결 리스트가 이어집니다. 각 할당의 크기는 최대 0x1000이며, NULL로 종료되어야 합니다.
임의 읽기의 경우:
next와 m_ts를 덮어써서, 덮어쓴 next 포인터로부터 읽어야 하도록 만듭니다.
임의 쓰기의 경우:
msgsnd() // Userland
do_msgsnd() // Kernel land
load_msg()
alloc_msg() // Allocate all the necessary chunks
copy_from_user() // Race here to replace `struct msg_msgseg *next` before its used to copy userdata. Maybe use userfaultfd ;)
msg_msg do_msgsnd load_msg copy_msg
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(0,&cpu_set);
ret=sched_setaffinity(0,sizeof(cpu_set),&cpu_set);