如何 link 使用 "handmade compiled" 版本的 glibc 的程序?
How to link a program with a "handmade compiled" version of glibc?
首先,由于这是我在 Whosebug 上提出的第一个问题,我没有足够的声誉来包含超过 2 links。但是,我需要包含远远超过 2 个 link 才能使我的问题完整且易于理解。这就是为什么我在下面 Gist 中写下了所有有问题的参考资料。后来每次看到[XXX],都是指前面提到的Gist中对应的link
让我们来解决问题本身:我遇到了一个涉及 glibc 的编译问题。
简而言之,作为我课程的一部分,我有机会学习计算机安全。值得注意的是,我必须深入研究一些 CVE。我选择查看 [GHOST - CVE-2015-0235]:GetHOSTbyxxx 函数中的缓冲区溢出,允许远程代码执行。
为此,我想尝试重现 [Qualys exploit]。
这就是为什么我基于最新的 LTS Ubuntu 发行版 (16.04) 设置了一个 Docker 环境,我想在其中编译 [glibc] (2.17) 的易受攻击版本和易受攻击的版本[Exim 邮件服务器] (4.77) 的版本 - 这是在 Qualys exploit 中被利用的软件。
第一步是下载、编译和安装(在/usr/local/lib中)glibc。到目前为止,还不错。
为了验证我可以使用 gcc linking 编译一些代码到这个版本的 glibc,我编译了 Qualys 提供的 [GHOST 漏洞检查],感谢以下命令(灵感来自来自 Whosebug 的两个答案:[1] 和 [2]):
gcc vulnerability_check.c -o vulnerability_check \
-Wl,--rpath=/usr/local/lib \
-Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2
完全没问题。因此,我尝试将 Exim 邮件服务器 linking 编译为易受攻击的 glibc 版本。根据与 Exim 邮件服务器相关的文档,可以通过将以下行附加到 Local/Makefile(必须由用户创建,来自 src/EDITME)来添加编译标志:
CFLAGS="-Wl,--rpath=/usr/local/lib -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2"
但是,我遇到了一些 "undefined reference" 错误:
/usr/local/lib/libpthread.so.0: undefined reference to `h_errno@GLIBC_PRIVATE'
/usr/local/lib/libpthread.so.0: undefined reference to `__vdso_clock_gettime@GLIBC_PRIVATE'
collect2: error: ld returned 1 exit status
Makefile:517: recipe for target 'eximon.bin' failed
据我理解,这意味着"eximon"的源代码中使用的一些符号(h_errno和clock_gettime),通常定义在共享静态库中,是在我编译的glibc版本中没有找到。为了确保它们确实没有定义,我在 [GHOST 漏洞检查] 代码中添加了对这两个符号的虚拟调用,并对其进行了编译。完全没问题。
我不确定下一步该怎么做才能继续跟踪问题的根源。我一直在寻找分析沿 glibc 编译的静态库内容的方法(nm 似乎可以解决问题)。我尝试深入研究编译工具链的文档,从 gcc 到 ld。我还发现了 PatchELF,但我认为这不是我需要的(没有第三方库可以修改)。但是,我找不到解决方案或解决方法。
因此,如果有任何关于使用编译后的 glibc 进行 link Exim 的建议,使用编译工具链的正确方法,解决此类编译问题的正确方法,我将不胜感激;或者您认为可以让我成为更好的程序员的任何建议。
非常感谢你。
In order to verify that I can compile some code with gcc linking to this version of the glibc,
您没有使用此版本的 glibc 编译和link代码。
I compiled the [GHOST vulnerability check] supplied by Qualys, thanks to the following command (inspired from those two answers from Whosebug: [1] and [2]):
您似乎丢失了参考文献 [1] 和 [2]。
gcc vulnerability_check.c -o vulnerability_check \
-Wl,--rpath=/usr/local/lib \
-Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2
以上命令使 GCC 使用 标准 位置用于 include
(即 /usr/include
)和 lib
(即 /usr/lib
) , 但安排在 运行时 .
使用 GLIBC 的替代版本(来自 /usr/local
的版本)
也就是说,有 3 个不同的步骤:
- 使用一些头文件编译源代码
- 使用一些
.o
和 .so
文件和 执行(静态)link
- 在将控制权传递给应用程序之前执行运行时 linking/loading。
您只安排了第 3 步使用您的 newly-built GLIBC。
要使用 newly-built GLIBC(假设它是 配置的 安装到 /usr/local
),你应该使用类似的东西:
gcc -o t -nostdlib -nostartfiles -I/usr/local/include \
/usr/local/lib/crt1.o \
/usr/local/lib/crti.o \
$(gcc --print-file-name=crtbegin.o) \
t.c \
/usr/local/lib/libc.so.6 \
/usr/local/lib/libc_nonshared.a \
/usr/local/lib/ld-linux-x86-64.so.2 \
$(gcc --print-file-name=crtend.o) \
/usr/local/lib/crtn.o \
-Wl,--rpath=/usr/local/lib \
-Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2`
CFLAGS="-Wl,--rpath=/usr/local/lib -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2"
上面的命令又是错误的:它在静态 link 时间(在上面的第 2 步)使用了不匹配的 ld-linux.so
和 libc.so.6
,并且失败了。
TL;DR: link反对 non-standard GLIBC 很复杂。您最好改用 chroot 环境或虚拟机。
更新:
CFLAGS="-I/usr/local/include -Wl,--rpath=/usr/local/lib -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2"
以上设置意义不大:-Wl,...
是 linker 标志,它们属于 LDFLAGS
.
LDFLAGS="-nostdlib -nostartfiles /usr/local/lib/crt1.o /usr/local/lib/crti.o $(gcc --print-file-name=crtbegin.o) /usr/local/lib/libc.so.6 /usr/local/lib/libc_nonshared.a /usr/local/lib/ld-linux-x86-64.so.2 $(gcc --print-file-name=crtend.o) /usr/local/lib/crtn.o"
... Anything wrong ?
是的。请注意 crti.o
、您的 objects/sources、libc.so.6
和 crtn.o
的顺序非常重要 ,并且必须完全是我展示的顺序。
我不认为有任何方法可以通过在 LDFLAGS
中指定来实现这样的顺序。您需要手动执行命令行,或者为您正在构建的程序大量修改 Makefile
。
你真的最好在 chroot 或 VM 中执行此操作。
首先,由于这是我在 Whosebug 上提出的第一个问题,我没有足够的声誉来包含超过 2 links。但是,我需要包含远远超过 2 个 link 才能使我的问题完整且易于理解。这就是为什么我在下面 Gist 中写下了所有有问题的参考资料。后来每次看到[XXX],都是指前面提到的Gist中对应的link
让我们来解决问题本身:我遇到了一个涉及 glibc 的编译问题。
简而言之,作为我课程的一部分,我有机会学习计算机安全。值得注意的是,我必须深入研究一些 CVE。我选择查看 [GHOST - CVE-2015-0235]:GetHOSTbyxxx 函数中的缓冲区溢出,允许远程代码执行。
为此,我想尝试重现 [Qualys exploit]。 这就是为什么我基于最新的 LTS Ubuntu 发行版 (16.04) 设置了一个 Docker 环境,我想在其中编译 [glibc] (2.17) 的易受攻击版本和易受攻击的版本[Exim 邮件服务器] (4.77) 的版本 - 这是在 Qualys exploit 中被利用的软件。
第一步是下载、编译和安装(在/usr/local/lib中)glibc。到目前为止,还不错。
为了验证我可以使用 gcc linking 编译一些代码到这个版本的 glibc,我编译了 Qualys 提供的 [GHOST 漏洞检查],感谢以下命令(灵感来自来自 Whosebug 的两个答案:[1] 和 [2]):
gcc vulnerability_check.c -o vulnerability_check \
-Wl,--rpath=/usr/local/lib \
-Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2
完全没问题。因此,我尝试将 Exim 邮件服务器 linking 编译为易受攻击的 glibc 版本。根据与 Exim 邮件服务器相关的文档,可以通过将以下行附加到 Local/Makefile(必须由用户创建,来自 src/EDITME)来添加编译标志:
CFLAGS="-Wl,--rpath=/usr/local/lib -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2"
但是,我遇到了一些 "undefined reference" 错误:
/usr/local/lib/libpthread.so.0: undefined reference to `h_errno@GLIBC_PRIVATE'
/usr/local/lib/libpthread.so.0: undefined reference to `__vdso_clock_gettime@GLIBC_PRIVATE'
collect2: error: ld returned 1 exit status
Makefile:517: recipe for target 'eximon.bin' failed
据我理解,这意味着"eximon"的源代码中使用的一些符号(h_errno和clock_gettime),通常定义在共享静态库中,是在我编译的glibc版本中没有找到。为了确保它们确实没有定义,我在 [GHOST 漏洞检查] 代码中添加了对这两个符号的虚拟调用,并对其进行了编译。完全没问题。
我不确定下一步该怎么做才能继续跟踪问题的根源。我一直在寻找分析沿 glibc 编译的静态库内容的方法(nm 似乎可以解决问题)。我尝试深入研究编译工具链的文档,从 gcc 到 ld。我还发现了 PatchELF,但我认为这不是我需要的(没有第三方库可以修改)。但是,我找不到解决方案或解决方法。
因此,如果有任何关于使用编译后的 glibc 进行 link Exim 的建议,使用编译工具链的正确方法,解决此类编译问题的正确方法,我将不胜感激;或者您认为可以让我成为更好的程序员的任何建议。
非常感谢你。
In order to verify that I can compile some code with gcc linking to this version of the glibc,
您没有使用此版本的 glibc 编译和link代码。
I compiled the [GHOST vulnerability check] supplied by Qualys, thanks to the following command (inspired from those two answers from Whosebug: [1] and [2]):
您似乎丢失了参考文献 [1] 和 [2]。
gcc vulnerability_check.c -o vulnerability_check \ -Wl,--rpath=/usr/local/lib \ -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2
以上命令使 GCC 使用 标准 位置用于 include
(即 /usr/include
)和 lib
(即 /usr/lib
) , 但安排在 运行时 .
/usr/local
的版本)
也就是说,有 3 个不同的步骤:
- 使用一些头文件编译源代码
- 使用一些
.o
和.so
文件和 执行(静态)link
- 在将控制权传递给应用程序之前执行运行时 linking/loading。
您只安排了第 3 步使用您的 newly-built GLIBC。
要使用 newly-built GLIBC(假设它是 配置的 安装到 /usr/local
),你应该使用类似的东西:
gcc -o t -nostdlib -nostartfiles -I/usr/local/include \
/usr/local/lib/crt1.o \
/usr/local/lib/crti.o \
$(gcc --print-file-name=crtbegin.o) \
t.c \
/usr/local/lib/libc.so.6 \
/usr/local/lib/libc_nonshared.a \
/usr/local/lib/ld-linux-x86-64.so.2 \
$(gcc --print-file-name=crtend.o) \
/usr/local/lib/crtn.o \
-Wl,--rpath=/usr/local/lib \
-Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2`
CFLAGS="-Wl,--rpath=/usr/local/lib -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2"
上面的命令又是错误的:它在静态 link 时间(在上面的第 2 步)使用了不匹配的 ld-linux.so
和 libc.so.6
,并且失败了。
TL;DR: link反对 non-standard GLIBC 很复杂。您最好改用 chroot 环境或虚拟机。
更新:
CFLAGS="-I/usr/local/include -Wl,--rpath=/usr/local/lib -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2"
以上设置意义不大:-Wl,...
是 linker 标志,它们属于 LDFLAGS
.
LDFLAGS="-nostdlib -nostartfiles /usr/local/lib/crt1.o /usr/local/lib/crti.o $(gcc --print-file-name=crtbegin.o) /usr/local/lib/libc.so.6 /usr/local/lib/libc_nonshared.a /usr/local/lib/ld-linux-x86-64.so.2 $(gcc --print-file-name=crtend.o) /usr/local/lib/crtn.o"
... Anything wrong ?
是的。请注意 crti.o
、您的 objects/sources、libc.so.6
和 crtn.o
的顺序非常重要 ,并且必须完全是我展示的顺序。
我不认为有任何方法可以通过在 LDFLAGS
中指定来实现这样的顺序。您需要手动执行命令行,或者为您正在构建的程序大量修改 Makefile
。
你真的最好在 chroot 或 VM 中执行此操作。