C 利用漏洞代码中指针的说明
在一些获取根shell的漏洞中,我经常看到这样一个指针: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 <
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,那么转换就会出错。