PWN study 0x03

file ./level5

1
2
root@93393c52261a:/pwn# file level5
level5: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=f01f8fd41061f9dafb9399e723eb52d249a9b34d, not stripped

dynamically linked 动态链接程序
not stripped 没有去除符号表
stripped

动态库文件,也就是 .so 文件

1
2
3
4
5
╭─root@97b3a7509c5a /pwn/jarvisoj/level6/level6
╰─# ldd freenote_x86
linux-gate.so.1 => (0xf7f61000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d9f000)
/lib/ld-linux.so.2 (0xf7f63000)

libc 库文件 libc.so.6
起始地址后三位是 0

想我们之后如果泄露 libc 地址,我们经常会看他的后三位是零,然后来判断这个地址泄露的是否正确

  • 动态链接文件
  • 静态链接文件
  • 可以动过 file 指令或者 ldd 指令进行区分

ELF 文件格式

readelf

ELF 文件格式解析

我们可以用,readelf 命令和一些参数去查看 elf 文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
╭─root@97b3a7509c5a /pwn/jarvisoj/level6/level6
╰─# readelf -h freenote_x86
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x804857a
Start of program headers: 52 (bytes into file)
Start of section headers: 5132 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 8
Size of section headers: 40 (bytes)
Number of section headers: 28
Section header string table index: 27

-h 读取ELF文件头
有时候需要 dump binary ,有一个很重要的参考标准就是我是不是 dump 到地方了或者是哪个地方开始才是我们的二进制文件,我们就可以以 magic number 开头的 7f 作为一个标准
magic number : \x7f

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
╭─root@97b3a7509c5a /pwn/jarvisoj/level6/level6
╰─# readelf -l freenote_x86

Elf file type is EXEC (Executable file)
Entry point 0x804857a
There are 8 program headers, starting at offset 52

Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x00100 0x00100 R E 0x4
INTERP 0x000134 0x08048134 0x08048134 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x01190 0x01190 R E 0x1000
LOAD 0x001190 0x0804a190 0x0804a190 0x00138 0x00160 RW 0x1000
DYNAMIC 0x00119c 0x0804a19c 0x0804a19c 0x000e8 0x000e8 RW 0x4
NOTE 0x000148 0x08048148 0x08048148 0x00044 0x00044 R 0x4
GNU_EH_FRAME 0x000d5c 0x08048d5c 0x08048d5c 0x0007c 0x0007c R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10

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 .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07

-l 参数显示程序头表,可以帮我们看一下这个 segment 有哪些
program headers 程序头表

  • 描述文件的各种 segment
  • 系统如何创建进行映像
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
╭─root@97b3a7509c5a /pwn/jarvisoj/level6/level6
╰─# readelf -S freenote_x86
There are 28 section headers, starting at offset 0x140c:

Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048134 000134 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048148 000148 000020 00 A 0 0 4
[ 3] .note.gnu.build-i NOTE 08048168 000168 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0804818c 00018c 00002c 04 A 5 0 4
[ 5] .dynsym DYNSYM 080481b8 0001b8 0000f0 10 A 6 1 4
[ 6] .dynstr STRTAB 080482a8 0002a8 00008c 00 A 0 0 1
[ 7] .gnu.version VERSYM 08048334 000334 00001e 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 08048354 000354 000020 00 A 6 1 4
[ 9] .rel.dyn REL 08048374 000374 000018 08 A 5 0 4
[10] .rel.plt REL 0804838c 00038c 000058 08 AI 5 12 4
[11] .init PROGBITS 080483e4 0003e4 000023 00 AX 0 0 4
[12] .plt PROGBITS 08048410 000410 0000c0 04 AX 0 0 16
[13] .text PROGBITS 080484d0 0004d0 000702 00 AX 0 0 16
[14] .fini PROGBITS 08048bd4 000bd4 000014 00 AX 0 0 4
[15] .rodata PROGBITS 08048be8 000be8 000174 00 A 0 0 4
[16] .eh_frame_hdr PROGBITS 08048d5c 000d5c 00007c 00 A 0 0 4
[17] .eh_frame PROGBITS 08048dd8 000dd8 0003b8 00 A 0 0 4
[18] .init_array INIT_ARRAY 0804a190 001190 000004 00 WA 0 0 4
[19] .fini_array FINI_ARRAY 0804a194 001194 000004 00 WA 0 0 4
[20] .jcr PROGBITS 0804a198 001198 000004 00 WA 0 0 4
[21] .dynamic DYNAMIC 0804a19c 00119c 0000e8 08 WA 6 0 4
[22] .got PROGBITS 0804a284 001284 000004 04 WA 0 0 4
[23] .got.plt PROGBITS 0804a288 001288 000038 04 WA 0 0 4
[24] .data PROGBITS 0804a2c0 0012c0 000008 00 WA 0 0 4
[25] .bss NOBITS 0804a2e0 0012c8 000010 00 WA 0 0 32
[26] .comment PROGBITS 00000000 0012c8 00004e 01 MS 0 0 1
[27] .shstrtab STRTAB 00000000 001316 0000f6 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)

-S 读取节头表
section headers : 文件节区的信息,大小和偏移等等

一些常见的 section 和功能

  • .init_array 程序开始时执行的函数组

  • .fini_array 程序退出时执行的函数组 ⚠️

  • .text 代码段

  • .rodata 存放只读数据(字符串等等)

  • .data 初始化的全局变量

  • .bss 未初始化的全局变量

  • .plt 进程链接表

  • .got 全局偏移表
    demo

  • 不同的 segment 对应的权限也不同

    • data :rw-
    • code :r-x
    • stack :rw-
    • heap :rw-
  • 调用 blic 中的函数并不一定需要通过 plt 表、got 表

  • 通过系统调用也可以调用函数

    • int 0x80
    • syscall

syscall

  • 32 bit
  • eax 保存系统调用号
  • ebx,ecx,edx,esi,edi 保存函数调用参数
  • int 0x80 进行系统调用
  • 返回值保存在 eax 中

write(1,esp,0xf0)
1 标准输出 stdout,改成0(stdin)也可以输出
esp 从esp开始
0xf0 输出0xf0个字节
注意⚠️:返回值保存在 eax 中

syscall64

  • 64 bit
  • rax 保存系统调用号,前三个参数通过 rdi,rsi,rdx 储存
  • 返回值保存在 rax 中
参考链接

https://blog.csdn.net/edonlii/article/details/8779075
ELF格式文件符号表全解析及readelf命令使用方法
https://blog.csdn.net/RobinZZX/article/details/96106184
关于 .init .fini .init_array .fini_array
https://visualgdb.com/gdbreference/commands/x
gdb x 命令
http://syscalls.kernelgrok.com/
32 linux syscall regerence
http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/
用于X86 64的LINUX系统调用表