首页
社区
课程
招聘
PWN入门-8-CSU喜相逢
发表于: 2024-8-5 21:08 5311

PWN入门-8-CSU喜相逢

2024-8-5 21:08
5311

CSU的全名的C Start Up,对于GCC编译出来的程序来讲,静态链接程序需要通过__libc_csu_init完成初始化的工作,当然它并不会直接运行main函数,main函数的启动仍是由__libc_start_main函数负责的。

GLibC源代码的下载路径:

对于GLibC版本小于2.34的版本来讲,由它生成的程序仍然是包含__libc_csu_init的,但是2.34版本以后,__libc_csu_init函数就已经消失了,这一改动的首要影响就是编译出来的文件内,文件中的二进制信息内不再含有__libc_csu_init函数了。

__libc_csu_init函数的源代码位于GLibC(<2.34)中csu目录下,对应的源代码文件是elf-init.c,所有的静态链接程序在最终的二进制信息中都会被插入这段代码。

对于GLibC来讲,不管是动态链接程序还是静态链接程序,其ELF文件头信息中的程序入口地址始终会指定_start函数,这是一段代码由GCC编译器插入进去的代码,_start函数标志着程序正式开始启动。

_start函数肩负起了程序启动的重任,它的主要职责就是就是调用__libc_start_main函数,调用的方式是call指令,*0x..(%rip)代表rip+0x..地址上数据,这段数据在编译时会位于可读可写段内,当程序开始运行时,最先运行的LD会将该地址上的数据设置为__libc_start_main函数地址,然后再将该段的前部分设置为只读状态,此时应用程序就可以正确的对__libc_start_main函数进行调用,且不能修改只读部分的内存信息。

这时我们将视线专注于__libc_start_main函数调用CSU的部分以及CSU负责的操作上。

由于__libc_csu_init是和应用程序链接在一起的,所以函数地址在链接期就可以确定下来,_start函数只需要将函数的地址信息交给rcx寄存器,然后__libc_start_main函数的内部将rcx寄存器中的函数地址交给r14寄存器,最后通过call指令进行调用就可以了。

__libc_csu_init函数的内部,首先处理的是寄存器参数,由于r15r14r13等寄存器原本是调用者占用的,考虑到在本函数(被调用者)内还需要使用这些寄存器,所以先将它们保存到栈上,等函数结束时再恢复过来,这样既不耽误被调用者对寄存器的使用,也不耽误返回时调用函数对寄存器的使用。

完成寄存器的数据处理后,rbp寄存器中的地址存储着__do_global_dtors_aux函数的地址,r12寄存器中的地址存储着frame_dummy函数的地址(这个两个函数都是编译器放入ELF文件内的),接下来会将rbpr12中的地址相减并右移3位,右移3位相当于书中除以8,这个操作相当于获得一段区域占用的空间大小,然后根据单个元素的大小计算空间内的元素数量,暂时猜测这里的每一个元素都是地址(64位系统下的8位地址)。

通过查看ELF文件的节信息可以确定,rbp寄存器(地址:600e18)和r12寄存器(地址:600e10)分别对应.init_array节的结束和起始位置。

完成元素个数的计算后,会调用_init函数,在函数调用前后设置edirsi寄存器,是因为它们是调用者使用的寄存器,避免_init函数的内部改变寄存器数据,使得__libc_csu_init函数无法使用它们,_init函数也是GCC编译器将它假如到二进制文件内的,这里我们先略过它。

_init函数结束之后,就会根据元素个数决定是否进入循环,其中test指令是不改变操作数的与运算,只有操作数为0时才是假的,否则一直为真,已经循环的次数通过ebx寄存器统计,addcmp指令使得ebx不断递增1并和总次数rbp进行比较。

循环体的内部,rdirsirdx负责传递三个参数,被调用的函数则由r12加上ebx乘8得到的地址决定的(每次偏移一个地址)。

分析完上面的反汇编代码后,我们可以了解到__libc_csu_init函数的主要作用就是根据.init_array节中函数进行初始化。

当GLibC的版本来到2.34时,根据.init_array节进行初始化的操作当然还在,只不过将代码放到了动态链接库内,不再与二进制文件绑定在一起。

__libc_csu_init函数中可以知道,生成的汇编代码内存在着大量pop寄存器的操作,而且ret指令与它们相距很近,造成该现象的原因由两个,一是调用.init_array节中函数前有其他函数被调用(_init函数),二是__libc_csu_init函数会将接收到的参数直接进行传递,这就导致很多寄存器都有了先保存到栈后再恢复的操作。

在这大量的pop寄存器操作中,由于pop r数值的特殊性(最后一个字节对应寄存器的pop操作),使得可以利用的寄存器有获得了一次扩充的机会。

除了pop指令外,下面的call指令也是一段很好的利用区域。

通过查看程序的反汇编结果可以知道,程序由main函数和vulnerable_function函数两个部分组成,其中vulnerable_function函数存在明显的溢出(缓冲区变量大小0x40,接收0x200),除此之外main函数中还存在一个puts函数,打印rdi保存地址上字符串。

当前程序来自于CtfHub中PWN技能树内的rop,保护情况如下所示。

梳理一下我们现在能干些什么!

首先我们只知道ELF文件的地址,对堆栈及动态链接库的地址一无所知,其次由于金丝雀的确实,尽管栈是不可执行的状态,但我们可以肆无忌惮的利用ROP达到想要的目的,谁让是CSU提供给我们足够的利用空间并且让我们可以掌握了它的地址呢!

漏洞利用脚本的构造分成两个部分,第一个部分通过CSU设置puts需要泄露的LibC信息,然后返回主函数中的puts对信息进行泄露,此时vulnerable_function会再次执行,我们也会再一次获得栈溢出的机会,随后根据泄露的LibC地址,获取LibC的基地址,构造调用system("/bin/sh")的ROP。

运行漏洞利用脚本后,成功获取Shell!

https://ftp.gnu.org/gnu/glibc/
https://ftp.gnu.org/gnu/glibc/
2.33版本存在elf-init.c:
ls ./glibc-2.33/csu/
abi-note.c   dso_handle.c  errno.c      gmon-start.c  init-first.c  libc-tls.c  start.c         sysdep.c   Versions
check_fds.c  elf-init.c    errno-loc.c  init.c        libc-start.c  Makefile    static-reloc.c  version.c
 
2.34版本不存在elf-init.c:
ls ./glibc-2.34/csu/
abi-note.c   dso_handle.c  errno-loc.c   init.c        libc-start.c  Makefile  static-reloc.c  version.c
check_fds.c  errno.c       gmon-start.c  init-first.c  libc-tls.c    start.c   sysdep.c        Versions
2.33版本存在elf-init.c:
ls ./glibc-2.33/csu/
abi-note.c   dso_handle.c  errno.c      gmon-start.c  init-first.c  libc-tls.c  start.c         sysdep.c   Versions
check_fds.c  elf-init.c    errno-loc.c  init.c        libc-start.c  Makefile    static-reloc.c  version.c
 
2.34版本不存在elf-init.c:
ls ./glibc-2.34/csu/
abi-note.c   dso_handle.c  errno-loc.c   init.c        libc-start.c  Makefile  static-reloc.c  version.c
check_fds.c  errno.c       gmon-start.c  init-first.c  libc-tls.c    start.c   sysdep.c        Versions
头信息:
Entry point address:               0x4004d0
 
00000000004004d0 <_start>:
   ......
   105f:       ff 15 5b 2f 00 00       call   *0x2f5b(%rip)
   ......
头信息:
Entry point address:               0x4004d0
 
00000000004004d0 <_start>:
   ......
   105f:       ff 15 5b 2f 00 00       call   *0x2f5b(%rip)
   ......
5号段:
  LOAD           0x0000000000002dd0 0x0000000000003dd0 0x0000000000003dd0
                 0x0000000000000248 0x0000000000000250  RW     0x1000
 
只读保护段(可以看到只读保护段与5号段部分重合):
  GNU_RELRO      0x0000000000002dd0 0x0000000000003dd0 0x0000000000003dd0
                 0x0000000000000230 0x0000000000000230  R      0x1
 
05     .init_array .fini_array .dynamic .got .got.plt .data .bss
5号段:
  LOAD           0x0000000000002dd0 0x0000000000003dd0 0x0000000000003dd0
                 0x0000000000000248 0x0000000000000250  RW     0x1000
 
只读保护段(可以看到只读保护段与5号段部分重合):
  GNU_RELRO      0x0000000000002dd0 0x0000000000003dd0 0x0000000000003dd0
                 0x0000000000000230 0x0000000000000230  R      0x1
 
05     .init_array .fini_array .dynamic .got .got.plt .data .bss
_start函数的赋值代码:
0x00000000004004e6 <+22>:    mov    $0x400620,%rcx
 
__libc_start_main函数调用的代码:
call   *%r14
 
r14寄存器信息:
info registers r14
r14            0x400620            4195872
 
__libc_csu_init函数地址信息:
info functions __libc_csu_init
0x0000000000400620  __libc_csu_init
_start函数的赋值代码:
0x00000000004004e6 <+22>:    mov    $0x400620,%rcx
 
__libc_start_main函数调用的代码:
call   *%r14
 
r14寄存器信息:
info registers r14
r14            0x400620            4195872
 
__libc_csu_init函数地址信息:
info functions __libc_csu_init
0x0000000000400620  __libc_csu_init
[18] .init_array       INIT_ARRAY       0000000000600e10  00000e10
     0000000000000008  0000000000000008  WA       0     0     8
[18] .init_array       INIT_ARRAY       0000000000600e10  00000e10
     0000000000000008  0000000000000008  WA       0     0     8
0000000000400620 <__libc_csu_init>:
  400620:       41 57                   push   %r15
  400622:       41 56                   push   %r14
  400624:       49 89 d7                mov    %rdx,%r15
  400627:       41 55                   push   %r13
  400629:       41 54                   push   %r12
  40062b:       4c 8d 25 de 07 20 00    lea    0x2007de(%rip),%r12        # 600e10 <__frame_dummy_init_array_entry>
  400632:       55                      push   %rbp
  400633:       48 8d 2d de 07 20 00    lea    0x2007de(%rip),%rbp        # 600e18 <__do_global_dtors_aux_fini_array_entry>
  40063a:       53                      push   %rbx
  寄存器数据处理阶段,保存调用者使用的寄存器数据
 
  40063b:       41 89 fd                mov    %edi,%r13d
  40063e:       49 89 f6                mov    %rsi,%r14
  400641:       4c 29 e5                sub    %r12,%rbp
  400644:       48 83 ec 08             sub    $0x8,%rsp
  400648:       48 c1 fd 03             sar    $0x3,%rbp
  循环次数的计算
 
  40064c:       e8 27 fe ff ff          call   400478 <_init>
  函数调用
 
  400651:       48 85 ed                test   %rbp,%rbp
  400654:       74 20                   je     400676 <__libc_csu_init+0x56>
  400656:       31 db                   xor    %ebx,%ebx
  400658:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
  40065f:       00
  400660:       4c 89 fa                mov    %r15,%rdx
  400663:       4c 89 f6                mov    %r14,%rsi
  400666:       44 89 ef                mov    %r13d,%edi
  400669:       41 ff 14 dc             call   *(%r12,%rbx,8)
  40066d:       48 83 c3 01             add    $0x1,%rbx
  400671:       48 39 dd                cmp    %rbx,%rbp
  400674:       75 ea                   jne    400660 <__libc_csu_init+0x40>
  400676:       48 83 c4 08             add    $0x8,%rsp
 
  下面操作对应寄存器数据处理阶段,用于还原调用者使用的寄存器数据
  40067a:       5b                      pop    %rbx
  40067b:       5d                      pop    %rbp
  40067c:       41 5c                   pop    %r12
  40067e:       41 5d                   pop    %r13
  400680:       41 5e                   pop    %r14
  400682:       41 5f                   pop    %r15
  400684:       c3                      ret
  400685:       90                      nop
  400686:       66 2e 0f 1f 84 00 00    cs nopw 0x0(%rax,%rax,1)
  40068d:       00 00 00
0000000000400620 <__libc_csu_init>:
  400620:       41 57                   push   %r15
  400622:       41 56                   push   %r14
  400624:       49 89 d7                mov    %rdx,%r15
  400627:       41 55                   push   %r13
  400629:       41 54                   push   %r12
  40062b:       4c 8d 25 de 07 20 00    lea    0x2007de(%rip),%r12        # 600e10 <__frame_dummy_init_array_entry>
  400632:       55                      push   %rbp
  400633:       48 8d 2d de 07 20 00    lea    0x2007de(%rip),%rbp        # 600e18 <__do_global_dtors_aux_fini_array_entry>
  40063a:       53                      push   %rbx
  寄存器数据处理阶段,保存调用者使用的寄存器数据
 
  40063b:       41 89 fd                mov    %edi,%r13d
  40063e:       49 89 f6                mov    %rsi,%r14
  400641:       4c 29 e5                sub    %r12,%rbp
  400644:       48 83 ec 08             sub    $0x8,%rsp
  400648:       48 c1 fd 03             sar    $0x3,%rbp
  循环次数的计算
 
  40064c:       e8 27 fe ff ff          call   400478 <_init>
  函数调用
 
  400651:       48 85 ed                test   %rbp,%rbp
  400654:       74 20                   je     400676 <__libc_csu_init+0x56>
  400656:       31 db                   xor    %ebx,%ebx
  400658:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
  40065f:       00
  400660:       4c 89 fa                mov    %r15,%rdx
  400663:       4c 89 f6                mov    %r14,%rsi
  400666:       44 89 ef                mov    %r13d,%edi
  400669:       41 ff 14 dc             call   *(%r12,%rbx,8)
  40066d:       48 83 c3 01             add    $0x1,%rbx
  400671:       48 39 dd                cmp    %rbx,%rbp
  400674:       75 ea                   jne    400660 <__libc_csu_init+0x40>
  400676:       48 83 c4 08             add    $0x8,%rsp
 
  下面操作对应寄存器数据处理阶段,用于还原调用者使用的寄存器数据
  40067a:       5b                      pop    %rbx
  40067b:       5d                      pop    %rbp
  40067c:       41 5c                   pop    %r12
  40067e:       41 5d                   pop    %r13
  400680:       41 5e                   pop    %r14
  400682:       41 5f                   pop    %r15
  400684:       c3                      ret
  400685:       90                      nop
  400686:       66 2e 0f 1f 84 00 00    cs nopw 0x0(%rax,%rax,1)
  40068d:       00 00 00
static void
call_init (int argc, char **argv, char **envp)
{
  /* For static executables, preinit happens right before init.  */
  {
    const size_t size = __preinit_array_end - __preinit_array_start;
    size_t i;
    for (i = 0; i < size; i++)
      (*__preinit_array_start [i]) (argc, argv, envp);
  }
 
# if ELF_INITFINI
  _init ();
# endif
 
  const size_t size = __init_array_end - __init_array_start;
  for (size_t i = 0; i < size; i++)
      (*__init_array_start [i]) (argc, argv, envp);
}
static void
call_init (int argc, char **argv, char **envp)
{
  /* For static executables, preinit happens right before init.  */
  {
    const size_t size = __preinit_array_end - __preinit_array_start;
    size_t i;
    for (i = 0; i < size; i++)
      (*__preinit_array_start [i]) (argc, argv, envp);
  }
 
# if ELF_INITFINI
  _init ();
# endif
 
  const size_t size = __init_array_end - __init_array_start;
  for (size_t i = 0; i < size; i++)
      (*__init_array_start [i]) (argc, argv, envp);
}
-----------------------------------
| 指令    | 字节 ; 指令    | 字节  |
| pop rax | 58  ; pop r8  | 41 58 |
| pop rcx | 59  ; pop r9  | 41 59 |
| pop rdx | 5a  ; pop r10 | 41 5a |
| pop rbx | 5b  ; pop r11 | 41 5b |
| pop rsp | 5c  ; pop r12 | 41 4c |
| pop rbp | 5d  ; pop r13 | 41 5d |
| pop rsi | 5e  ; pop r14 | 41 5e |
| pop rdi | 5f  ; pop r15 | 41 5f |
-----------------------------------
-----------------------------------
| 指令    | 字节 ; 指令    | 字节  |
| pop rax | 58  ; pop r8  | 41 58 |
| pop rcx | 59  ; pop r9  | 41 59 |
| pop rdx | 5a  ; pop r10 | 41 5a |
| pop rbx | 5b  ; pop r11 | 41 5b |
| pop rsp | 5c  ; pop r12 | 41 4c |
| pop rbp | 5d  ; pop r13 | 41 5d |
| pop rsi | 5e  ; pop r14 | 41 5e |
| pop rdi | 5f  ; pop r15 | 41 5f |
-----------------------------------
400660:       4c 89 fa                mov    %r15,%rdx
400663:       4c 89 f6                mov    %r14,%rsi
400666:       44 89 ef                mov    %r13d,%edi
400669:       41 ff 14 dc             call   *(%r12,%rbx,8)
400660:       4c 89 fa                mov    %r15,%rdx
400663:       4c 89 f6                mov    %r14,%rsi
400666:       44 89 ef                mov    %r13d,%edi
400669:       41 ff 14 dc             call   *(%r12,%rbx,8)
00000000004005b7 <vulnerable_function>:
  4005b7:       55                      push   %rbp
  4005b8:       48 89 e5                mov    %rsp,%rbp
  4005bb:       48 83 ec 40             sub    $0x40,%rsp
  4005bf:       48 8d 45 c0             lea    -0x40(%rbp),%rax
  4005c3:       ba 00 02 00 00          mov    $0x200,%edx
  4005c8:       48 89 c6                mov    %rax,%rsi
  4005cb:       bf 00 00 00 00          mov    $0x0,%edi
  4005d0:       e8 db fe ff ff          call   4004b0 <read@plt>
  4005d5:       90                      nop
  4005d6:       c9                      leave
  4005d7:       c3                      ret
 
00000000004005d8 <main>:
  4005d8:       55                      push   %rbp
  4005d9:       48 89 e5                mov    %rsp,%rbp
  4005dc:       48 83 ec 50             sub    $0x50,%rsp
  4005e0:       89 7d bc                mov    %edi,-0x44(%rbp)
  4005e3:       48 89 75 b0             mov    %rsi,-0x50(%rbp)
  4005e7:       48 8d 3d ba 00 00 00    lea    0xba(%rip),%rdi        # 4006a8 <_IO_stdin_used+0x8>
  4005ee:       e8 ad fe ff ff          call   4004a0 <puts@plt>
  4005f3:       48 8b 05 46 0a 20 00    mov    0x200a46(%rip),%rax        # 601040 <stdout@GLIBC_2.2.5>
  4005fa:       48 89 c7                mov    %rax,%rdi
  4005fd:       e8 be fe ff ff          call   4004c0 <fflush@plt>
  400602:       b8 00 00 00 00          mov    $0x0,%eax
  400607:       e8 ab ff ff ff          call   4005b7 <vulnerable_function>
  40060c:       b8 00 00 00 00          mov    $0x0,%eax
  400611:       c9                      leave
  400612:       c3                      ret
  400613:       66 2e 0f 1f 84 00 00    cs nopw 0x0(%rax,%rax,1)
  40061a:       00 00 00
  40061d:       0f 1f 00                nopl   (%rax)
 
0000000000400620 <__libc_csu_init>:
  400620:       41 57                   push   %r15
  400622:       41 56                   push   %r14
  400624:       49 89 d7                mov    %rdx,%r15
  400627:       41 55                   push   %r13
  400629:       41 54                   push   %r12
  40062b:       4c 8d 25 de 07 20 00    lea    0x2007de(%rip),%r12        # 600e10 <__frame_dummy_init_array_entry>
  400632:       55                      push   %rbp
  400633:       48 8d 2d de 07 20 00    lea    0x2007de(%rip),%rbp        # 600e18 <__do_global_dtors_aux_fini_array_entry>
  40063a:       53                      push   %rbx
  40063b:       41 89 fd                mov    %edi,%r13d
  40063e:       49 89 f6                mov    %rsi,%r14
  400641:       4c 29 e5                sub    %r12,%rbp
  400644:       48 83 ec 08             sub    $0x8,%rsp
  400648:       48 c1 fd 03             sar    $0x3,%rbp
  40064c:       e8 27 fe ff ff          call   400478 <_init>
  400651:       48 85 ed                test   %rbp,%rbp
  400654:       74 20                   je     400676 <__libc_csu_init+0x56>
  400656:       31 db                   xor    %ebx,%ebx
  400658:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
  40065f:       00
  400660:       4c 89 fa                mov    %r15,%rdx
  400663:       4c 89 f6                mov    %r14,%rsi
  400666:       44 89 ef                mov    %r13d,%edi
  400669:       41 ff 14 dc             call   *(%r12,%rbx,8)
  40066d:       48 83 c3 01             add    $0x1,%rbx
  400671:       48 39 dd                cmp    %rbx,%rbp
  400674:       75 ea                   jne    400660 <__libc_csu_init+0x40>
  400676:       48 83 c4 08             add    $0x8,%rsp
  40067a:       5b                      pop    %rbx
  40067b:       5d                      pop    %rbp
  40067c:       41 5c                   pop    %r12
  40067e:       41 5d                   pop    %r13
  400680:       41 5e                   pop    %r14
  400682:       41 5f                   pop    %r15
  400684:       c3                      ret
  400685:       90                      nop
  400686:       66 2e 0f 1f 84 00 00    cs nopw 0x0(%rax,%rax,1)
  40068d:       00 00 00
00000000004005b7 <vulnerable_function>:
  4005b7:       55                      push   %rbp

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//