Pwnable.tw start-orw-calc



start

题目的binary很小
没有开启NX,考虑注入shellcode,思路大致如下:

  • 1.泄露栈地址leak stack
  • 2.控制shellcode,由于程序溢出最多60个字节,shellcode尽量控制在30个字节以内,否则会被截断
  • 3.计算offset,跳转到stack上执行shellcode

orw

程序写shellcode地址,之后跳转到shellcode执行,shellcode地址在bss段上,所以程序开启的canary没有意义

由于限制了只能够使用open,read,write等syscall,所以也就是需要自己写shllcode,大致流程如下:

由于flag比较长,至少0x30才能够接收到完整的flag

calc



reverse

题目实现了一个简单的计算器解释器,是通过两个栈来实现的,一个栈保存运算的结果,另一个栈保存所有的运算符。

其中calc的逻辑还是比较清晰的,获取expression表达式,处理并输出结果。

其中它支持的运算符号有:
+ – / \ %*

程序的主要逻辑在parse_expr函数中,主要实现了一套解释器
该解释器分成两个部分:解析运算表达式、计算运算结果。
下面是IDA后的结果对变量名进行了修改,便于查看:

主要说明:

  • parse_expr接受两个参数,expr是用户输入的表达式,res是存贮结果的数组
  • parse_expr中的两个栈,一个栈是结果栈res,一个栈是符号栈polish。
  • *res即调用函数的v1,res[0]存储最终结果的下标即top,即result=res[*res]
  • polish按照一定规则栈规则储存过程中出现的运算符,在出栈入栈时主要考虑运算符的优先级

主要流程:

  1. 遇到运算符operaotr,即+-*/%才开始进行处理
  2. 通过number数字串的长度将数字串截取出来,并作为中间结果储存在res数组中
  3. polish数组中储存运算符,当运算符满足优先级条件时,调用eval进行运算,否则,按照逆波兰算法的规则将运算符依次存在polish数组中,最后通过

计算结果。

最后,通过calc中的printf,根据结果存储的下标将结果打印出来
printf((const char *)&unk_80BF804, v2[v1 - 1]);

vulnerability

首先,容易发现,题目的表达式是无法处理负数的,我们重点关注当表达式为负数时,parse_expr 的流程即可发现漏洞:
漏洞就在下面的语句中:

正数同理
如果我们输入表达式:“+100",在运算时,由于表达式中不存在左值,所以在处理+时,就将数字栈中的第一数,也就是代表表达式结果的numver,修改为了100,那么打印时就会打印数字栈v1[100]的值,这明显是一个栈中的值。

而通过上面的语句,如果我们首先通过”+n"类型的表达式修改数字结果栈中的结果的指针number,之后通过其就可修改栈中相应位置的值,如下图:

这种修改能够Bypass Canary,达到栈中任意4字节写。

计算好偏移,首先打印栈中原本的值,之后通过"+“”-“修改为Rop chain中的值,即可在calc返回时执行Rop,通过调用syscall执行execve("/bin/sh")

sciprt

发表评论