1. 소개
본격적인 Kernel exploit tech에 들어가기 앞서 커널 공간을 디버깅 하기위해 qemu 설치와 사용법 등을 알아보자.
Qemu ?
- Linux의 대표적 에뮬레이터 이다.
- bzImage, cpio 와 같은 이미지 파일을 통해 가상머신을 구동시킬 수 있다.
- x86, ARM 등 다양한 아키텍처를 지원한다.
왜 Qemu를 사용할까 ?
- ELF 바이너리를 exploit 할때 버그를 일으키면 프로세스가 종료되고 끝이지만 우리가 사용하는 커널 공간을 조작하다 에러가 발생할 경우 치명적으로 다가올 수 있다.
- Qemu는 동적 디버깅을 위한 옵션을 지원하기 때문에 디버깅이 좀 더 수월하다는 장점이 있다.
2. 레퍼런스
본 글에서 필요한 예제파일은 ptr-yudai님의 github에 올라와 있는 파일을 사용 하였다.
https://github.com/ptr-yudai/pawnyable/tree/master/learn/linux-kernel/LK01
3. 설치
example download
mkdir /kernel; cd /kernel
wget https://pawnyable.cafe/linux-kernel/LK01/distfiles/LK01.tar.gz
tar -xzvf LK01.tar.gz
qemu-system install
# apt install qemu-system
# qemu-system-x86_64 -version
QEMU emulator version 6.2.0 (Debian 1:6.2+dfsg-2ubuntu6.15)
Copyright (c) 2003-2021 Fabrice Bellard and the QEMU Project developers
- 위와 같이 뜬다면 성공적으로 설치 된것이다.
4. 이미지 파일
Cpio
- 가상 머신을 구동하기 위해서는 별도로 마운트 될 디스크 이미지가 필요하다.
- cpio 파일은 경량화 된 디스크 이미지 파일로 CTF와 같은 대회에 자주 사용된다.
- qemu를 실행할 때 옵션으로 .cpio 확장자 파일을 넘기게 되며 안에는 시스템 부팅시 필요한 초기화 파일들과 기본 디렉터리 등이 있다.
Uncompressed Cpio
# mkdir root # 압축 해제할 디렉터리 생성
# cd root; cpio -idv < ../rootfs.cpio # cpio 파일 이름
# cd root
root@LAPTOP-IAMFG96H:/kernel/LK01/qemu/root# ls # 압축 해제시 다음과 같은 파일이 있음을 알 수 있다.
bin etc init lib64 media opt root sbin tmp var
dev lib linuxrc mnt proc run sys usr
- 파일이 gz으로 압축되어 있을경우 gz 압축을 먼저 해제하고 cpio 해제를 해주어야 한다.
init.d
# find . -name *99*
./etc/init.d/S99pawnyable
- 부팅 시 실행되는 스크립트 중 우리가 보아야 할건 S99pawnyable 이라는 파일이다.
#!/bin/sh
##
## Setup
##
mdev -s
mount -t proc none /proc
mkdir -p /dev/pts
mount -vt devpts -o gid=4,mode=620 none /dev/pts
chmod 666 /dev/ptmx
stty -opost
#echo 2 > /proc/sys/kernel/kptr_restrict
#echo 1 > /proc/sys/kernel/dmesg_restrict
##
## Install driver
##
insmod /root/vuln.ko
mknod -m 666 /dev/holstein c `grep holstein /proc/devices | awk '{print $1;}
'` 0
##
## User shell
##
echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
echo "[ Holstein v1 (LK01) - Pawnyable ]"
setsid cttyhack setuidgid 0 sh
##
## Cleanup
##
umount /proc
poweroff -d 0 -f
- 여기서 지금 우리가 볼 부분은 User shell 이다.
- setsid cttyhack setuidgid 는 실행시 유저의 uid gid를 설정 해준다.
- 0 으로 설정 시 root 권한으로 실행하게 되고 sh 는 /bin/sh을 의미 한다.
Recompress
# find . -print0 | cpio -o --format=newc --null > ../rootfs_updated.cpio
- cpio 파일은 권한과 관련된 작업도 수행하므로 소유자를 root로 해두어야 하는데,
root 사용자가 아닐땐 옵션으로 --owner=root 를 주면 된다.
5. Qemu 실행
본격적으로 qemu를 실행하기 위해서 run.sh 파일을 열어보자
#!/bin/sh
qemu-system-x86_64 \
-m 64M \
-nographic \
-kernel bzImage \
-append "console=ttyS0 loglevel=3 oops=panic panic=-1 nopti nokaslr" \
-no-reboot \
-cpu qemu64 \
-smp 1 \
-monitor /dev/null \
-initrd rootfs_updated.cpio \
-net nic,model=virtio \
-net user \
-gdb tcp::1234
- qemu-system-x86_64 명령어로 qemu를 실행할 수 있다.
- -m : 가상 RAM 크기 지정
- -nographic : CLI 설정
- -kernel : 커널 이미지 파일 지정
- -append : 커널의 관한 설정을 추가
- -cpu : 가상 cpu 설정
- -smp : cpu 소켓, 코어, 쓰레드 설정
- -monitor : qemu 실행 중 디버깅 정보를 표시할 모니터 콘솔
- -initrd : 디스크 이미지 파일 지정
- -net : 네트워크 카드 설정
- -gdb : gdb로 디버깅하기 위한 옵션
그럼 run.sh를 실행 해보자
# ./run.sh
Starting syslogd: OK
Starting klogd: OK
Running sysctl: OK
Saving random seed: OK
Starting network: udhcpc: started, v1.34.0
udhcpc: broadcasting discover
udhcpc: broadcasting select for 10.0.2.15, server 10.0.2.2
udhcpc: lease of 10.0.2.15 obtained from 10.0.2.2, lease time 86400
deleting routers
adding dns 10.0.2.3
OK
Starting dhcpcd...
dhcpcd-9.4.0 starting
DUID 00:01:00:01:2d:12:e2:d5:52:54:00:12:34:56
eth0: IAID 00:12:34:56
eth0: soliciting a DHCP lease
eth0: offered 10.0.2.15 from 10.0.2.2
eth0: leased 10.0.2.15 for 86400 seconds
eth0: adding route to 10.0.2.0/24
eth0: adding default route via 10.0.2.2
forked to background, child pid 105
Boot took 5.68 seconds
[ Holstein v1 (LK01) - Pawnyable ]
/ #
- 정상적으로 구동이 완료된 모습이다.
Gdb로 attach
우리가 run.sh 에 -gdb tcp::1234 옵션을 주었기 때문에 gdb로 디버깅이 가능하다.
root@LAPTOP-IAMFG96H:/home/igunis# gdb
pwndbg: loaded 148 pwndbg commands and 47 shell commands. Type pwndbg [--shell | --all] [filter] for a list.
pwndbg: created $rebase, $ida GDB functions (can be used with print/break)
------- tip of the day (disable with set show-tips off) -------
Pwndbg sets the SIGLARM, SIGBUS, SIGPIPE and SIGSEGV signals so they are not passed to the app; see info signals for full GDB signals configuration
pwndbg> target remote localhost:1234
- gdb 에서 target remote localhost:포트 를 입력하면 된다.
6. 마치며
여기까지 qemu의 사용법과 gdb로 디버깅 하는 방법에 대해 알아보았다.
다음엔 커널의 보호기법에 대해 알아보자.
'Kernel' 카테고리의 다른 글
[Kernel] KROP & KPTI (0) | 2024.03.15 |
---|---|
[Kernel] Kernel Stack Overflow & Commit_creds (0) | 2024.02.18 |
[Kernel] Holstein Module (1) | 2024.02.12 |
[Kernel] 커널의 보호 기법 (1) | 2024.01.04 |
[Kernel] Introduce Kernel (0) | 2023.12.15 |