moectf2024知识点汇总
前言
本次比赛对基础的要求可谓是很深啊,记录一些自己需要学习的或者是基础不牢固,所需要学习的点
NotEnoughTime
运用正则匹配运算数学式子
- 贴一份官方wp
1 | from pwn import * |
- 自己解题时候的exp(重度依赖gpt)
1 | import time |
这是什么?random!
真随机数爆破
在我写的这篇文章里面已经提到过了
这是什么?GOT!
理解plt和got表之间的关系,已经函数真实地址是从哪里来的
调用过程解析
- 程序启动时:
- 当程序编译并链接时,外部库函数(如
system
)的实际地址在编译期并不确定,尤其是动态链接库中的函数。为了处理这种不确定性,编译器生成了PLT
(Procedure Linkage Table,过程链接表)和GOT
(Global Offset Table,全球偏移表)。- 第一次调用
system
时:
- 当程序第一次调用
system
函数时,程序并不知道该函数的实际内存地址。所以,程序会先跳转到system@plt
,即位于PLT
表中的system
函数条目。- 这个
system@plt
代码(你提到的.plt:0000000000401056
的片段)会将某个索引值(push 2
)压入栈,然后跳转到PLT
的解析函数,也就是sub_401020
。这个解析函数会负责动态链接的符号解析。- 动态链接器解析:
- 当执行到
sub_401020
时,动态链接器会检查GOT
表,看system
函数的实际地址是否已经加载到GOT
中。- 如果
GOT
中还没有system
的地址(这是第一次调用时的情况),动态链接器会调用ld.so
来查找system
函数的地址(比如从 libc.so 库中),并将这个地址填入GOT
中。- **后续调用
system
**:
- 一旦动态链接器找到了
system
函数的实际地址并将其写入到GOT
表中,后续对system
的调用将直接通过GOT
表获取其地址,而不再经过system@plt
进行跳转。这样可以提高性能,因为避免了每次调用时的跳转和解析。总结
- 第一次调用
system
时,会通过system@plt
进行跳转和解析,因为程序还不知道system
的实际地址。- 后续调用
system
则会直接使用GOT
表中缓存的地址,从而加快函数调用的速度。这个机制是动态链接库的一部分,目的是让程序在运行时动态解析函数地址,而不是在编译时就绑定函数地址。
- 在第一次调用system的时候,会去
0x401056
地址,而elf.plt[‘system’]是0x401050,下面理解一下为什么:
PLT 机制概述
PLT
(Procedure Linkage Table) 是 ELF 文件中的一个结构,用于延迟绑定动态链接库中的函数地址。每个动态函数(如system
)在PLT
中有一个条目。这个条目主要包含两部分:
PLT Entry
(
1 system@plt):
- 每个函数在
PLT
中有一个入口,负责跳转到实际的函数实现。- 第一次调用该函数时,入口会跳转到动态链接解析器来解析函数地址。
PLT Stub
:
- 每个函数的
PLT
条目包含一些指令,用来做跳转以及参数压栈等操作。- 这些指令位于
PLT
中稍后的位置(通常会偏移几个字节)。具体情况:为什么跳到
0x401056
而不是0x401050
?在你的情况中,
PLT
入口为0x401050
,但第一次调用实际跳转到了0x401056
,这是因为0x401050
到0x401056
之间是一个跳转指令的预留区域,而实际的指令从0x401056
开始。以下是细节解释:汇编代码回顾:
1
2
3 asm复制代码.plt:0000000000401050 ; [00000006 BYTES: COLLAPSED FUNCTION _system. PRESS CTRL-NUMPAD+ TO EXPAND]
.plt:0000000000401056 push 2
.plt:000000000040105B jmp sub_401020
0x401050
是system@plt
的条目起始地址,但它不是第一条实际执行的指令。- 在 ELF 文件中,每个
PLT
条目可能会有一个跳转表格或者占位符,通常第一个几字节可能是与跳转无关的内容。- 从
0x401056
开始,真正的指令才会执行:
push 2
:将值2
压入栈。这通常用于标识该PLT
条目,表示它是system
函数的第 2 个条目(索引2
),用于传递给链接解析器。jmp sub_401020
:这是跳转到PLT
的解析器函数,用于解析动态链接库中的函数地址。为什么是
0x401056
?
- 地址布局:
0x401050
只是system@plt
条目的起始地址。实际的指令从0x401056
开始,因为0x401050
到0x401056
可能被填充为跳转表或用于其他目的(如预留空间)。- 跳转到指令的设计:ELF 文件和
PLT
的设计通常会在每个函数条目之间留有一些空间,使得跳转和解析可以分阶段进行。因此,0x401056
是system@plt
中实际用于跳转和解析的指令起始点。总结
0x401050
是system@plt
的入口地址,但它可能只是一个占位符或跳转表的开始地址。0x401056
是system@plt
条目中的实际指令起始地址,第一次调用system
函数时跳转到了这里,因为这里包含了负责跳转和解析system
函数地址的指令(如push 2
和jmp sub_401020
)。
Catch_the_canary!
arc4random真随机数爆破 : 这篇文章
跳过scanf的输入
泄露canary
下面看如何跳过scanf输入的
- 要求输入的不变,我们可以:
1 | scanf要求输入数字的时候,输入'+' or '-' |
- 泄露canary
利用printf、puts
输出遇到\x00会截断和canary
首字节是\x00来泄露canary
1 | # 只需填充canary的\x00,再利用printf将canary输出即可 |
shellcode_revenge
有限字节shellcode再次调用read
1 | mmap((void *)0x20240000, 0x1000uLL, 7, 50, -1, 0LL); |
- 很明显0xd字节写入shellcode长度是不够的,那么我们可以再次调用read,写入shellcode
- 为什么会想到
read
?观察执行shellcode前的寄存器,rax=0
,只要syscall
就会执行read
注意其他几个寄存器
- 因此在
syscall
之前还要修改rsi的值,因为我们往mmap地址写入了调用read的汇编代码
1 | mov rdx , 100 |
- 随后正常写入shellcode即可
1 | addr = 0x20240000 |
Pwn_it_off!
知识点
子函数栈结构的利用以及gdb调试
1 | int __cdecl __noreturn main(int argc, const char **argv, const char **envp) |
- 向上面这种结构,一旦输入超过栈空间就会影响到下面的函数,通过gdb动调可以明显发现
这是什么?32-bit!
知识点
1 | getchar(); |
- 关键点就在于这两个函数
getchar()
用sendline填充__isoc99_scanf("%[^\n]s", v1);
代表着无限长度输入
- 标题: moectf2024知识点汇总
- 作者: D0wnBe@t
- 创建于 : 2024-10-15 17:56:24
- 更新于 : 2024-11-06 13:04:36
- 链接: http://downbeat.top/2024/10/15/moectf2024知识点汇总/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论