欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]利用auxv控制canary

[原创]利用auxv控制canary

利用绕过canary的另一种方法。通过修改AUXV(Auxiliary Vector)结构体使 canary 值可控。因为在ld的时候,canary是通过AUXV中的一个成员生成的。

2017-TCTF-Final-upxof

题目文件
(文件在附件中也上传了)

分析

 happy@ubuntu  ~/pwn/20170602-TCTF-Final/pwn-upxof  checksec upxof 

[*] '/home/happy/pwn/20170602-TCTF-Final/pwn-upxof/upxof'

    Arch:     amd64-64-little

    RELRO:    No RELRO

    Stack:    No canary found

    NX:       NX disabled

    PIE:      No PIE (0x400000)

    RWX:      Has RWX segments

    Packer:   Packed with UPX

发现upx有壳,upx -d一下(附件中depack文件时脱壳后的),然后发现脱壳后的程序有canary

 happy@ubuntu  ~/pwn/20170602-TCTF-Final/pwn-upxof  checksec depack 

[*] '/home/happy/pwn/20170602-TCTF-Final/pwn-upxof/depack'

    Arch:     amd64-64-little

    RELRO:    Partial RELRO

    Stack:    Canary found

    NX:       NX enabled

    PIE:      No PIE (0x400000)

脱壳后的main函数,很明显gets有个栈溢出。但是有canary,这里通过修改AUXV中的AT_RANDOM来控制我们的canary,后面会介绍。

int __cdecl main(int argc, const char **argv, const char **envp)

{

  char v4; // [rsp+0h] [rbp-410h]

  unsigned __int64 v5; // [rsp+408h] [rbp-8h]

  v5 = __readfsqword(0x28u);

  setvbuf(stdin, 0LL, 2, 0LL);

  setvbuf(stdout, 0LL, 2, 0LL);

  setvbuf(stderr, 0LL, 2, 0LL);

  printf("let's go:", 0LL);

  gets(&v4);

  return 0;

}

Auxiliary Vector & Canary原理分析

简言之,canary是由ld.so进行初始化的,而这个值又是通过Auxiliary Vector
参考
https://www.elttam.com.au/blog/playing-with-canaries/
auxv结构可以在elf/elf.h里看到:

/* Auxiliary vector.  */

/* This vector is normally only used by the program interpreter.  The

   usual definition in an ABI supplement uses the name auxv_t.  The

   vector is not usually defined in a standard <elf.h> file, but it

   can't hurt.  We rename it to avoid conflicts.  The sizes of these

   types are an arrangement between the exec server and the program

   interpreter, so we don't fully specify them here.  */

typedef struct

{

  uint32_t a_type;        /* Entry type */

  union

    {

      uint32_t a_val;        /* Integer value */

      /* We use to have pointer elements added here.  We cannot do that,

     though, since it does not work when using 32-bit definitions

     on 64-bit platforms and vice versa.  */

    } a_un;

} Elf32_auxv_t;

typedef struct

{

  uint64_t a_type;        /* Entry type */

  union

    {

      uint64_t a_val;        /* Integer value */

      /* We use to have pointer elements added here.  We cannot do that,

     though, since it does not work when using 32-bit definitions

     on 64-bit platforms and vice versa.  */

    } a_un;

} Elf64_auxv_t;

这是一个entry struct,以AT_HWCAP为例,这个结构体就会是p64(entry_type_no) + a_un
这个a_type的取值可以参见源码,以下列举部分

/* Legal values for a_type (entry type).  */

#define AT_NULL        0        /* End of vector */

#define AT_IGNORE    1        /* Entry should be ignored */

#define AT_EXECFD    2        /* File descriptor of program */

#define AT_PHDR        3        /* Program headers for program */

#define AT_PHENT    4        /* Size of program header entry */

#define AT_PHNUM    5        /* Number of program headers */

#define AT_PAGESZ    6        /* System page size */

#define AT_BASE        7        /* Base address of interpreter */

#define AT_FLAGS    8        /* Flags */

#define AT_ENTRY    9        /* Entry point of program */

#define AT_NOTELF    10        /* Program is not ELF */

#define AT_UID        11        /* Real uid */

#define AT_EUID        12        /* Effective uid */

#define AT_GID        13        /* Real gid */

#define AT_EGID        14        /* Effective gid */

#define AT_CLKTCK    17        /* Frequency of times() */

...

/* This entry gives some information about the FPU initialization

   performed by the kernel.  */

#define AT_FPUCW    18        /* Used FPU control word.  */

...

/* A special ignored value for PPC, used by the kernel to control the

   interpretation of the AUXV. Must be > 16.  */

#define AT_IGNOREPPC    22        /* Entry should be ignored.  */

#define    AT_SECURE    23        /* Boolean, was exec setuid-like?  */

#define AT_BASE_PLATFORM 24        /* String identifying real platforms.*/

#define AT_RANDOM    25        /* Address of 16 random bytes.  */

#define AT_HWCAP2    26        /* More machine-dependent hints about

                       processor capabilities.  */

#define AT_EXECFN    31        /* Filename of executable.  */

...

我们关注的是这里面的AT_RANDOM,在libc中,它和生成canary有着紧密的关系。

static inline uintptr_t __attribute__ ((always_inline))

_dl_setup_stack_chk_guard (void *dl_random)

{

  union

  {

    uintptr_t num;

    unsigned char bytes[sizeof (uintptr_t)];

  } ret = { 0 };

  if (dl_random == NULL)

    {

      ret.bytes[sizeof (ret) - 1] = 255;

      ret.bytes[sizeof (ret) - 2] = '\n';

    }

  else

    {

      memcpy (ret.bytes, dl_random, sizeof (ret));

#if BYTE_ORDER == LITTLE_ENDIAN

      ret.num &= ~(uintptr_t) 0xff;

#elif BYTE_ORDER == BIG_ENDIAN

      ret.num &= ~((uintptr_t) 0xff << (8 * (sizeof (ret) - 1)));

#else

#error "BYTE_ORDER unknown"

#endif

    }

  return ret.num;

}

也就是说,canary是通过dl_random上设置的。
通过测试和文章分析可知,AUXV结构体中AT_RANDOM的值对应了canary的值(The value is a pointer to sixteen random bytes provided by the kernel. The dynamic linker uses this to implement a stack canary)

上面的这篇文章也介绍了通过程序获取auxv的方法

#include <sys/auxv.h>

unsigned long int getauxval(unsigned long int type);

其中,type传入auxv的a_type即可。

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功