代码如下
问题出在login()
中,scanf
的第二个参数给的不是变量的地址。如果passcode1
和passcode2
的初始值指向不可写的地方,而且scanf
成功,那么就会segfault
于是思路就是,在login()
执行前,在welcome()
中把栈上的值设好。所以这道题和OverTheWire上的Manpage里一道题思路有相似的地方
具体地,name
在welcome()
中的地址是ebp-0x70
,passcode1
和passcode2
在login()
中的地址是ebp-0x10
和ebp-0xc
。正好我们只能改写passcode1
,改不了passcode2
。于是单纯地想把两个都修改为检查值的方法行不通了
但是我们发现,passcode1
那里由于scanf
,可以做到写4 bytes到任意地址。所以我们可以修改程序流程,让他跳到system
读flag那里。
而由于ASLR,想修改返回地址不靠谱,于是我们可以修改exit@got
。这样检查失败后,调用exit(0)
就成了system("/bin/cat flag");
由readelf -r passcode
可知exit@got
在0x0804a018
,于是把passcode1
设为它;然后通过scanf
将其改为0x080485e3=134514147
。注意我们要让passcode2
在scanf
时不能segfault,于是输入非数字让scanf
失败
$ perl -e 'print "A"x96 . "\x18\xa0\x04\x08" . "134514147\n" . "f\n"' | ./passcode