【问题标题】:Stacks are executable even with `noexecstack`即使使用 `noexecstack` 也可以执行堆栈
【发布时间】:2017-04-01 03:07:16
【问题描述】:

我正在尝试保护我的应用程序免受缓冲区溢出攻击。除其他外,我正在使用非可执行堆栈并将我的二进制文件与noexecstack 标志链接(通过将-Wl,-z,noexecstack 传递给gcc)。

一切似乎都很好 - readelf 确认 PT_GNU_STACK 指定了正确的权限:

$ readelf -l target | grep -A1 GNU_STACK
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10

execstack也是如此:

$ execstack -q target
- target

只有一个问题。我所有的堆栈实际上都是可执行的:

root@170ubuntu16p04-64smp-1:~# cat /proc/12878/task/*/maps | grep stack
7ffcac654000-7ffcac675000 rwxp 00000000 00:00 0                          [stack]
7fe540e66000-7fe541666000 rwxp 00000000 00:00 0                          [stack]
7fe540665000-7fe540e65000 rwxp 00000000 00:00 0                          [stack]
7fe53b800000-7fe53c000000 rwxp 00000000 00:00 0                          [stack]

我捕获了allocate_stack 调用并检查了保护标志。 In theory,它们应该根据PT_GNU_STACK进行初始化。但在我的例子中,PT_GNU_STACK 似乎被忽略了,_dl_stack_flags 被初始化为默认权限。

有谁知道是什么原因造成的?一切似乎都正确,但堆栈仍然是可执行的。

我正在使用 gcc 4.8.3 / glibc 2.11。

【问题讨论】:

  • 这是一个多线程应用程序吗?
  • 该选项只是标记可执行文件,但不能保证您的操作系统会注意它。这可能不是编程问题,而是系统管理/配置问题。
  • @BasileStarynkevitch 是的,它是一个多线程应用程序。堆栈由pthread_create分配。
  • @Olaf 操作系统注意了。我已经使用相同的工具链构建了几个应用程序,它们没有可执行堆栈 - 堆栈是 mmaped 和 rw-p。这就是为什么我认为我忽略了一些东西。
  • 好吧,您可能会使用未设置该标志的库/目标文件。这样一来,整个应用程序就不能了。

标签: c linux gcc linker glibc


【解决方案1】:

是什么原因造成的?

除了主可执行文件的PT_GNU_STACK 具有正确的权限之外,您需要在每个 直接链接的共享库中拥有具有正确权限的PT_GNU_STACK

如果这些库中的任何一个根本没有PT_GNU_STACK,或者有一个具有可执行权限的库,它将“毒化”所有具有可执行权限的堆栈。

所以跑

for j in $(ldd target | grep -o '=> .* ' | sed -e 's/=> //' -e '/^ *$/d' ); do
  out=$(readelf -Wl $j | grep STACK)
  [[ -z "$out" ]] &&  echo "missing GNU_STACK in $j"
  echo $out | grep -q RWE && echo "executable GNU_STACK in $j"
done

您可能会看到至少一个库缺少或可执行堆栈。

附:我看到 Olaf 已经(部分)提出了这个建议。

【讨论】:

    【解决方案2】:

    Olaf 和 Employed Russian 将我推向了正确的方向。第三方共享对象毒害了我的堆栈。

    但它没有直接链接到我的主要可执行文件。 lddlddtree 都没有显示任何带有 RWE 堆栈的库,所以我决定深入挖掘并编写一个脚本来检查当前映射到进程内存中的所有共享对象:

    #!/bin/bash
    
    if [ -z "$1" ]; then
        echo "Usage: $0 <target>"
        exit 1;
    fi
    
    kav_pid=`pidof $1`
    for so in `cat /proc/$kav_pid/task/*/maps | awk '/.so$/ {print $6}' | sort | uniq`; do
        stack_perms=`readelf -Wl $so | awk '/GNU_STACK/ {print $7}'`
        if [ -z "$stack_perms" ]; then
            echo "$so doesn't have PT_GNU_STACK"
        elif [ "$stack_perms" != "RW" ]; then
            echo "$so has unexpected permissions: $stack_perms"
        fi
    done
    

    它奏效了!我找到了一个具有 RWE 权限的库:

    $ ./find_execstack.sh target
    /target/dir/lib64/lib3rdparty.so has unexpected permissions: RWE
    

    为了确保是这个库毒害了我的堆栈,我用gdb 打开了我的应用程序,并在dlopen 中设置了一个断点。还有宾果游戏!以下是dlopening lib3rdparty.so 之前的权限:

    7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
    

    这是dlopen之后的它们:

    7ffffffde000-7ffffffff000 rwxp 00000000 00:00 0                          [stack]
    

    事实证明,lib3rdparty.so 是使用不同的工具链构建的,并且现在没有被注意到。

    Olaf,受雇于俄罗斯人,谢谢!

    【讨论】:

      猜你喜欢
      • 2020-05-16
      • 1970-01-01
      • 2012-08-23
      • 2012-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-19
      • 2011-11-25
      相关资源
      最近更新 更多