ezthree 复现
1 | GNU C Library (Ubuntu GLIBC 2.23-0ubuntu11.3) stable release version 2.23, by Roland McGrath et |
1 | ➜ ezthree ./ezthree |
1 | ezthree: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /home/yhellow/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so, for GNU/Linux 2.6.32, BuildID[sha1]=a03fffb75b5c647383a7faca81d76966f05f7564, stripped |
64位,dynamically,全开
代码分析
其实前面的代码都没有什么用,关键就是最后可以注入一个 shellcode
1 | if ( LODWORD(buf[5]) ) |
但执行该 shellcode 前,需要先执行以下代码:
1 | pwndbg> telescope 0xf3e03346000 |
限制点:常规寄存器全被清空(除了 RIP),尤其是 RSP,导致 shellcode 不能正常执行
漏洞点:第一次 input 可以无限写入数据
入侵思路
在网上借鉴了其他大佬的 wp 后,我发现 mov rsp, fs:[0x300] 这条指令可以恢复栈,我的思路为:
- 利用第一次 input 在栈上留下 execve(“/bin/sh” , 0 , 0) 的汇编代码(第二次 input 不够长)
- mprotect(rsp , 0x1000 , 7) 使栈获取执行权限
- jmp rsp + jmp $+0x32 执行栈上的 execve(“/bin/sh” , 0 , 0)
完整 exp:
1 | from pwn import* |
结果:
1 | ► 0x7ffd20125212 syscall <SYS_execve> |
1 | pwndbg> ni |
- 虽然获取 shell 了,但是有个无法避免的报错
直接 get shell 不行,我便想试试 ORW,但又有一个问题:
1 | close(0); |
- close 0 1 2,必然要找其他通信方式
网上有一个大佬采用自己创建 socket 管道去通信,orw flag 发送
关于 socket 通信可以参考:Linux socket 本地进程间通信
1 | ► 0x7fff329758b5 syscall <SYS_socket> |
1 | ► 0x7fff329758d5 syscall <SYS_connect> |
关键点就是 SYS_socket 和 SYS_connect ,执行完这两个函数后,就可以开始 ORW 了:
1 | ► 0x7fff3297591e syscall <SYS_open> |
1 | ► 0x7fff3297592f syscall <SYS_read> |
1 | ► 0x7fff3297593b syscall <SYS_write> |
结果:
完整 exp:
1 | from pwn import* |
用于接收 flag 的脚本:
1 | /* gcc recv.c -o recv -g */ |
1 | ► 0x40128a <main+148> call bind@plt <bind@plt> |
- 保证 bind 的
serv_addr和 SYS_connect 的一样就可以了
小结:
当时很坐牢,百思不得其解,赛后复现时才发现自己的知识点不到位,看了大佬们的 wp 后收获很多:
mov rsp, fs:[0x300]这条指令可以恢复栈(fs 寄存器中装有 TLS)- 利用 socket 本地进程间通信来绕过 close