SFTP Chroot的开发历程

 
  • 研究OpenSSH源码!
    • 发现OpenSSH是先auth,然后chroot + setuid(如果配了ChrootDirectory的话),然后再根据session的类型调用相应的subsystem
    • 问题:在走到session之前chroot所需的capability CAP_SYS_CHROOT就已经被drop了,然而我们到了session才能知道这个SSH连接到底是shell,还是scp,还是sftp
    • 思路:在setuid之前,保留CAP_SYS_CHROOT权限,这样就能chroot了
  • 精读OpenSSH源码
    • OpenSSH在auth成功后,在do_setusercontext执行Drop privilege的逻辑
    • do_setusercontext调用permanently_set_uid执行具体的setuid逻辑
    • 如果是sftp的session,则在最后的逻辑调用sftp_server_main
  • 开始Hook
    • 首先是找到sftp_server_main函数,然后hook上,在里面执行chroot
    • 然后是hook permanently_set_uid里面的setresuid函数,在setuid发生前,执行PR_SET_KEEPCAPS保留capability,然后自定义保留的Capability为CAP_SYS_CHROOT
  • Debug
    • 很神奇的是,在某些时机里,sshd竟然没法写入/tmp(已经排除了权限问题,即使用随机文件名都写不进去),只好xjb猜
    • LightHook没处理指令重定位的逻辑,所以得写个逻辑绕开指令重定位,否则程序就crash了
    • LightHook的指令长度解析有问题,所有的sub XXX, imm32都被解析成了imm64,导致长度有问题