Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 利用漏洞代码中指针的说明_C_Linux_Pointers_Exploit - Fatal编程技术网

C 利用漏洞代码中指针的说明

C 利用漏洞代码中指针的说明,c,linux,pointers,exploit,C,Linux,Pointers,Exploit,在一些获取根shell的漏洞中,我经常看到这样一个指针: int i; unsigned *p = *(unsigned**)(((unsigned long)&i) & ~8191); 谁能解释一下这个指针吗?我认为8191是内核堆栈的大小p指向内核堆栈的底部? 以下是指针p的使用方法: int i; unsigned *p = *(unsigned**)(((unsigned long)&i) & ~8191); for (i = 0; i <

在一些获取根shell的漏洞中,我经常看到这样一个指针:

int i;
unsigned *p = *(unsigned**)(((unsigned long)&i) & ~8191); 
谁能解释一下这个指针吗?我认为8191是内核堆栈的大小
p
指向内核堆栈的底部? 以下是指针
p
的使用方法:

int i; 
unsigned *p = *(unsigned**)(((unsigned long)&i) & ~8191); 
for (i = 0; i < 1024-13; i++) { 
    if (p[0] == uid && p[1] == uid && 
        p[2] == uid && p[3] == uid && 
        p[4] == gid && p[5] == gid && 
        p[6] == gid && p[7] == gid) { 
            p[0] = p[1] = p[2] = p[3] = 0; 
            p[4] = p[5] = p[6] = p[7] = 0; 
            p = (unsigned *) ((char *)(p + 8) + sizeof(void *)); 
            p[0] = p[1] = p[2] = ~0; 
            break; 
        } 
    p++; 
} 
inti;
无符号*p=*(无符号**)((无符号长)和~8191);
对于(i=0;i<1024-13;i++){
如果(p[0]==uid&&p[1]==uid&&
p[2]==uid&&p[3]==uid&&
p[4]==gid&&p[5]==gid&&
p[6]==gid&&p[7]==gid{
p[0]=p[1]=p[2]=p[3]=0;
p[4]=p[5]=p[6]=p[7]=0;
p=(无符号*)((字符*)(p+8)+sizeof(空*);
p[0]=p[1]=p[2]=0;
打破
} 
p++;
} 

该代码获取局部变量
i
的地址,以获取指向当前堆栈帧的指针。然后,它将地址与8K页面对齐(这就是您使用
x&~8191
:8191是2^13-1,这意味着
~8191
是除低13位之外的所有数字,因此将其与数字相加将清除低13位,即将数字与2^13的最低位倍数对齐,换句话说,与8K边界对齐)

然后,它将该地址解释为指向指针的指针,并从中加载指向的地址。有关更多信息,请参阅

之后,它试图找到存储在该地址后面的特定结构:它查看以下
1024-13
无符号的
s,试图在内存中找到存储当前进程信息(可能)的位置:当它找到一块内存,其中包含当前UID和GID的多个副本时,它假定它已经找到了它。在这种情况下,它会对其进行修改,使当前进程获得UID和GID 0,从而使该进程在根目录下运行(加上它会将所有这些存储到以下功能标志中)


Cf..

我将发布另一个答案,因为这里确实有一些东西需要补充

unsigned *p = *(unsigned**)(((unsigned long)&i) & ~8191); 
结果p是指向8192字节大小内存块开始的指针。然而,代码是错误的。如果p大于INT_MAX(它可以是或将被转换为无符号,而不是无符号长),则高位会被掩码切掉。正确代码如下:

unsigned *p = *(unsigned**)(((ptrdiff_t)&i) & ~(ptrdiff_t)8191);
或使用uintptr\t:

unsigned *p = *(unsigned**)(((uintptr_t)&i) & ~(uintptr_t)8191U);

必须强制转换为整数并返回指针,代码才能工作;然而,为了保证整数大小的指针需要使用ptrdiff_t(我们记得,对于按位操作,有符号和无符号的行为完全相同)。至于他们为什么不写十六进制常量,谁在乎呢。做这类事情的人都知道2的力量。读取8191可能比读取0x1FF更快。

二进制中的值
8191
1111111
,而
long
类型为32位。我想要给你一个明确的答案,我们需要看看
*p
指针是如何使用的。
&
运算符可能是某种类型的掩码。@TimBiegeleisen感谢您的回复。我已经编辑了它。为了严格的ISO正确性,在这两个地方都使用了
uintptpr\u t
而不是
ptrdiff\u t
。然而,所有的Linux ABI都保证所有T都是
sizeof(unsigned long)==sizeof(T*)
。因此,在Linux内核漏洞攻击的上下文中,使代码正确的最小更改就是
&~8191UL
,而不是
&~8191
。当
~8191
,类型为
int
,在
&
-表达式中使用,左侧带有
无符号长
,将应用符号扩展名。因此,高位不会从掩模上剪掉。这也是为什么
uint64\u t x=-1将所有64位都设置为1。@mortehu:我在别处用那个片段烧死了。如果int的位数少于无符号long,那么转换就会出错。