SEED LAB Dirty Cow
TASK 1 Modify a Dummy Read-Only File
任务要求:利用Dirty Cow 写一个只读文件
2.1 Create a Dummy File
在root文件夹中添加一个文件名为zzz,修改权限使它对其他用户只读,写入1111122223333
当其他用户试图写入文件时,因权限不够而失败
目标:通过Dirty Cow把”2222222“改为”*******************“
2.2 Set Up the Memory Mapping Thread
在cow_attack.c文件中,使用MAP_PRIVATE,文件将映射到调用进程私有的内存空间。当进程试图写入文件时,内核会分配一块新的物理内存作为私有拷贝,映射的虚拟内存指向这块私有拷贝,之后的读取和写入操作都在这块私有拷贝中进行,对底层文件没有任何影响。
为了写入底层文件,新建了两个线程madviseThread、writeThread。
2.3 Set Up the write Thread
写线程只负责写入”*******************“。其中offset是文件的偏移量,指出开始改写的位置,在这个样例中是main中传入的char * position,是通过字符串匹配找到的"2222222"的开始位置。
int f=open("/proc/self/mem", O_RDWR);
:
这行代码打开了一个特殊的文件/proc/self/mem
,它是Linux系统中的一个虚拟文件,用于访问当前进程的内存。该文件以读写模式打开,并返回一个文件描述符f
。
lseek(f, offset, SEEK_SET);
:
这行代码使用lseek
函数将文件指针f
移动到偏移量为offset
的位置。SEEK_SET
表示从文件的开头开始计算偏移量。
然后使用write将字符串写入文件。
2.4 The madvise Thread
madvise线程负责改变内存映射,抛弃映射内存的私有拷贝,让页表指回最初映射的内存。其中arg是在main中传入的参数(void *)file_size,是文件/zzz的大小。
2.5 Launch the Attack
The only way for the attack to succeed is to perform the madvise() system call while the write() system call is still running. We cannot always achieve that, so we need to try many times.
如果write()和madvise()交替执行,会出现两种情况:先写入私有拷贝再指回最初映射的内存,或者先指回最初映射的内存再写(再次触发COW),这样写操作一直都在私有拷贝上进行,是不能攻击成功的。攻击成功的情况是当write()正在执行时,madvise()也执行,即当write触发COW后,页表指向私有拷贝,尚未写入时,madvise()修改页表使其指回最初映射的内存,再由write()写入。
write()和madvise()的执行顺序取决于线程的调用顺序,所以需要多次尝试。运行a.out后,按下ctrl c停止,再查看/zzz,发现已经成功修改了/zzz。攻击成功!
Task 2: Modify the Password File to Gain the Root Privilege
任务要求:把/etc/passwd中某一用户(以charlie为例)的UID改为0.
/etc/passwd对所有用户可读,但是只对root可写。这个文件记录了每个用户的信息,其中第三列是用户的UID。当UID=0时,用户具有root权限。
可以看到charlie的UID为1001.
在cow_attack.c文件中修改以下内容:
通过字符串匹配找到charlie的UID:
修改写入内容:
编译并执行文件后,切换到charlie账号,发现已经是root权限的了。
查看/etc/passwd,改动后的记录如下:改变了charlie的UID、GID和备注信息。备注信息的修改没有影响,关键是修改UID提权。为了不修改其他字段,可以注意一下content字符串长度。
攻击成功!