极客大挑战2024复现(更新中)
ez shellcode
分析
checksec
发现开了nx,没开canary
分析main函数
发现第一次read获取输入填入bss段的shellcode中,但bss段可读可写不可执行,找找有没有提权函数,没开canary可以利用gets部分截取执行流。
发现提权函数gift(真的是一个好gift)
mprotect()函数将bss段的shellcode部分设置为可执行
mprotect()函数注释
mprotect(shellcode, 0x500uLL, 4) 是一个调用 mprotect() 函数的语句,其作用是改变从地址 shellcode 开始、长度为 0x500 字节(即1280字节)的内存区域的保护属性。这里的参数解释如下:
shellcode:这是指向需要修改权限的内存区域起始地址的指针。
0x500uLL:表示要修改权限的内存区域的长度,单位是字节。这里使用无符号长整型(unsigned long long),确保可以处理较大的值。
4
:新的保护标志,通常代表可读、可写和可执行权限。在Linux中,这个值通常是通过宏定义组合而成的:
- PROT_READ (1) | PROT_WRITE (2) | PROT_EXEC (4)
mprotect() 函数是一个在Unix和类Unix操作系统中使用的系统调用,其主要作用是改变一个内存区域的访问权限。具体来说:
- 修改保护属性:mprotect() 允许程序动态地更改指定内存页的访问权限(如可读、可写、可执行等)。
- 参数说明:
- addr:要修改权限的起始地址。
- len:需要修改权限的内存区域的长度。
- prot:新的保护标志,可以是以下几种值的组合:
- PROT_NONE:不可访问
- PROT_READ:可读
- PROT_WRITE:可写
- PROT_EXEC:可执行
思路
首先通过read函数写入64位的shellcode(注意:使用pwntools直接生成的shellcode默认是32位的),本次用的是现成的shellcode
接着通过gets函数进行栈溢出控制执行流到gift函数提权位于bss段存放的shellcode使其可执行
exp
1 | from pwn import* |
注意:send()与sendline()的区别,send会直接将指定的数据发送到连接的另一端不会添加任何额外字符,sendline会在发送完数据后自动加上一个换行符。使用send传shellcode防止其被破坏。
1 | from pwn import * |
简单的签到(随机数)
分析
简单的执行接收数据后返回,搞懂程序运行逻辑即可得解
checksec
IDA分析
程序逻辑很简单,首先生成两个随机数,需要我们在3秒内计算并返回乘积,返回正确即可获得shell
运行程序发现开始会输出一串字符,提示按Enter开始挑战,回车后出现两个数相乘
思路
首先利用recv()接收之前的无用数据
利用sendline()传入一个换行符模拟回车
由于输出的数字乘积题目为字符串,需特定接收数字并将其转换为整型,利用recvuntil()接收数字并加int将其转换为整型供后续使用
将数据计算后利用str转换为字符串再利用sendline()传入最后获得shell
exp
1 | from pwn import * |
你会栈溢出吗
简单的64位栈溢出,注意别忘了堆栈平衡
1 | from pwn import* |
000000(随机数)
分析:
程序保护全开主要逻辑是通过从/dev/urand设备文件中读取随机数据来作为密码,接着获取输入,将输入数据与password利用strcmp函数进行对比,输入数据正确即可获得flag
思路:
密码有128位,爆破不太现实,strcmp函数当检测到\0
后结束比较
通过
/dev/urandom
生成的随机数的每一位数据实际上是一个字节(8位),其值的范围是从0到255(即0x00到0xFF)。这是因为一个字节可以表示256个不同的值(2^8)。因此,对于通过该代码生成的随机数的第一位数据,有256种可能的值。这包括了从0到255的所有整数,涵盖了所有的ASCII控制字符、可打印字符以及其他非打印字符。每次从/dev/urandom
读取时,每一位都是独立且随机的,因此每个可能的字节值出现的概率是相等的。
有1/256的概率第一位是\x00
即\0
字符,故发送一个字符\0
进行循环尝试
exp
1 | from pwn import * |