CTF

二进制分析实战第五章(3)

Posted by Kody Black on September 11, 2023

第五章 Linux二进制分析

第三题:分析lvl3文件

$ readelf -h lvl3
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 0b 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            Novell - Modesto
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Motorola Coldfire
  Version:                           0x1
  Entry point address:               0x4005d0
  Start of program headers:          4022250974 (bytes into file)
  Start of section headers:          4480 (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
readelf: Error: Reading 0x1f8 bytes extends past end of file for program headers

OS/ABI和Machine是一个没见过的类型,程序头的位置明显有问题。

使用010 Editor修改一下程序:

修改前:

16944473829001694447382723.png

修改后:

16944474298921694447429417.png

$ readelf -h lvl3 
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:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x4005d0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          4480 (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

尝试运行:

$ ./lvl3 
0e2ada7381d04d4d2ed31be82b121aa3  ./lvl3
$ ltrace -i ./lvl3 
[0x4005f9] __libc_start_main(0x400550, 1, 0x7fff4cb74e98, 0x4006d0 <unfinished ...>
[0x40058c] __strcat_chk(0x7fff4cb74990, 0x400754, 1024, 0) = 0x7fff4cb74990
[0x4005a2] __strncat_chk(0x7fff4cb74990, 0x7fff4cb7539d, 1016, 1024) = 0x7fff4cb74990
[0x4005aa] system("md5sum ./lvl3"0e2ada7381d04d4d2ed31be82b121aa3  ./lvl3
 <no return ...>
[0x7f914a66d730] --- SIGCHLD (Child exited) ---
[0x4005aa] <... system resumed> )         = 0
[0xffffffffffffffff] +++ exited (status 0) +++
$ md5sum ./lvl3 
0e2ada7381d04d4d2ed31be82b121aa3  ./lvl3

程序执行的输出为该程序的md5散列,但是0e2ada7381d04d4d2ed31be82b121aa3并不是flag

 $ readelf -S lvl3 
 ......
  [12] .plt              PROGBITS         00000000004004e0  000004e0
       0000000000000060  0000000000000010  AX       0     0     16
  [13] .plt.got          PROGBITS         0000000000400540  00000540
       0000000000000008  0000000000000000  AX       0     0     8
  [14] .text             NOBITS           0000000000400550  00000550
       00000000000001f2  0000000000000000  AX       0     0     16
  [15] .fini             PROGBITS         0000000000400744  00000744
       0000000000000009  0000000000000000  AX       0     0     4
  [16] .rodata           PROGBITS         0000000000400750  00000750
       000000000000000c  0000000000000000   A       0     0     4
......

注意到.text节的类型是NOBITS,这显然不合适,正常情况下其类型应该为PROGBITS

.text节的位置=4480+14*64=5376=0x1500

将0x1504处的08修改为01,即将.text的类型修改为PROGBITS。

$ md5sum ./lvl3 
3a5c381e40d2fffd95ba4452a0fb4a40  ./lvl3
$ ./oracle 3a5c381e40d2fffd95ba4452a0fb4a40
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| Level 3 completed, unlocked lvl4         |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
Run oracle with -h to show a hint

补充

对于上述lvl3的.text节头,其内容如下:

16944489795061694448979460.png

readelf的结果为:

[Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
[14] .text             PROGBITS         0000000000400550  00000550
       00000000000001f2  0000000000000000  AX       0     0     16

可以从中看到对应的关系。

以下是一些常见的节类型及其相应的编码:

  1. NULL(0x00):表示一个无效的节头。通常不包含实际数据,只是一个占位符。
  2. PROGBITS(0x01):包含可执行程序或数据的实际位。
  3. SYMTAB(0x02):包含符号表,用于存储程序中的符号信息。
  4. STRTAB(0x03):包含字符串表,用于存储字符串,如符号名称。
  5. STRTAB(0x04):包含重定位表,用于重定位信息。
  6. HASHTAB(0x05):包含哈希表,用于加速符号查找。
  7. DYNAMIC(0x06):包含动态链接信息,如共享库的依赖关系。
  8. NOTE(0x07):包含备注信息,通常用于存储与程序或库相关的附加信息。
  9. NOBITS(0x08):类似于PROGBITS,但不占用实际的文件空间,通常用于未初始化的数据段。
  10. REL(0x09):包含重定位信息,但是重定位信息存储在一个独立的重定位节中。
  11. SHLIB(0x0A):保留,不再使用。
  12. DYNSYM(0x0B):包含动态符号表,与SYMTAB不同,用于动态链接。
  13. INIT_ARRAY(0x0E):包含初始化函数指针数组,用于在程序启动时执行初始化操作。
  14. FINI_ARRAY(0x0F):包含终结函数指针数组,用于在程序结束时执行清理操作。
  15. PREINIT_ARRAY(0x10):包含预初始化函数指针数组,用于在主函数之前执行初始化操作。
  16. GROUP(0x11):用于将多个节组合到一个组中,通常用于支持特殊链接选项。

这些是一些常见的ELF节类型,每种类型都有其特定的用途和语义。请注意,ELF规范还可以允许用户定义的自定义节类型。不同的操作系统和工具链可能会使用不同的自定义类型。在使用readelf等工具时,您可以查看特定ELF文件的节类型以了解其结构和内容。